Browse Source

Add _StridedSliceGrad, _StridedSliceGradGrad, tf.math.lgamma

tags/v0.10
Oceania2018 6 years ago
parent
commit
4a367470b6
9 changed files with 288 additions and 4 deletions
  1. +9
    -0
      src/TensorFlowNET.Core/APIs/tf.math.cs
  2. +36
    -1
      src/TensorFlowNET.Core/APIs/tf.tensor.cs
  3. +61
    -0
      src/TensorFlowNET.Core/Gradients/array_grad.cs
  4. +24
    -0
      src/TensorFlowNET.Core/Gradients/math_grad.cs
  5. +65
    -0
      src/TensorFlowNET.Core/Operations/gen_array_ops.cs
  6. +37
    -0
      src/TensorFlowNET.Core/Operations/gen_math_ops.cs
  7. +13
    -0
      src/TensorFlowNET.Core/Operations/math_ops.cs
  8. +4
    -3
      src/TensorFlowNET.Core/TensorFlowNET.Core.csproj
  9. +39
    -0
      test/TensorFlowNET.UnitTest/GradientTest.cs

+ 9
- 0
src/TensorFlowNET.Core/APIs/tf.math.cs View File

@@ -153,6 +153,15 @@ namespace Tensorflow
public static Tensor less<Tx, Ty>(Tx x, Ty y, string name = null) public static Tensor less<Tx, Ty>(Tx x, Ty y, string name = null)
=> gen_math_ops.less(x, y, name); => gen_math_ops.less(x, y, name);


/// <summary>
/// Computes the log of the absolute value of `Gamma(x)` element-wise.
/// </summary>
/// <param name="x">A `Tensor`. Must be one of the following types: `bfloat16`, `half`, `float32`, `float64`.</param>
/// <param name="name">A name for the operation (optional).</param>
/// <returns>A `Tensor`. Has the same type as `x`.</returns>
public static Tensor lgamma(Tensor x, string name = null)
=> gen_math_ops.lgamma(x, name: name);

/// <summary> /// <summary>
/// Returns the truth value of (x <= y) element-wise. /// Returns the truth value of (x <= y) element-wise.
/// </summary> /// </summary>


+ 36
- 1
src/TensorFlowNET.Core/APIs/tf.tensor.cs View File

@@ -18,6 +18,41 @@ namespace Tensorflow
{ {
public static partial class tf public static partial class tf
{ {
public static Tensor convert_to_tensor(object value, string name = null) => ops.convert_to_tensor(value, name: name);
public static Tensor convert_to_tensor(object value,
string name = null) => ops.convert_to_tensor(value, name: name);

public static Tensor strided_slice(Tensor input, Tensor begin, Tensor end, Tensor strides = null,
int begin_mask = 0,
int end_mask = 0,
int ellipsis_mask = 0,
int new_axis_mask = 0,
int shrink_axis_mask = 0,
string name = null) => gen_array_ops.strided_slice(input: input,
begin: begin,
end: end,
strides: strides,
begin_mask: begin_mask,
end_mask: end_mask,
ellipsis_mask: ellipsis_mask,
new_axis_mask: new_axis_mask,
shrink_axis_mask: shrink_axis_mask,
name: name);

public static Tensor strided_slice<T>(Tensor input, T[] begin, T[] end, T[] strides = null,
int begin_mask = 0,
int end_mask = 0,
int ellipsis_mask = 0,
int new_axis_mask = 0,
int shrink_axis_mask = 0,
string name = null) => gen_array_ops.strided_slice(input: input,
begin: begin,
end: end,
strides: strides,
begin_mask: begin_mask,
end_mask: end_mask,
ellipsis_mask: ellipsis_mask,
new_axis_mask: new_axis_mask,
shrink_axis_mask: shrink_axis_mask,
name: name);
} }
} }

+ 61
- 0
src/TensorFlowNET.Core/Gradients/array_grad.cs View File

@@ -196,6 +196,67 @@ namespace Tensorflow.Gradients
return new Tensor[] { _ReshapeToInput(op, grads[0]) }; return new Tensor[] { _ReshapeToInput(op, grads[0]) };
} }


/// <summary>
/// Gradient for StridedSlice op.
/// </summary>
/// <param name="op"></param>
/// <param name="grads"></param>
/// <returns></returns>
[RegisterGradient("StridedSlice")]
public static Tensor[] _StridedSliceGrad(Operation op, Tensor[] grads)
{
var grad = grads[0];
var begin = op.inputs[1];
var end = op.inputs[2];
var strides = op.inputs[3];

var x = array_ops.shape(op.inputs[0], out_type: begin.dtype);

return new Tensor[]
{
gen_array_ops.strided_slice_grad(
x,
begin,
end,
strides,
grad,
begin_mask: (int)op.get_attr("begin_mask"),
end_mask: (int)op.get_attr("end_mask"),
ellipsis_mask: (int)op.get_attr("ellipsis_mask"),
new_axis_mask: (int)op.get_attr("new_axis_mask"),
shrink_axis_mask: (int)op.get_attr("shrink_axis_mask")),
null,
null,
null
};
}

[RegisterGradient("StridedSliceGrad")]
public static Tensor[] _StridedSliceGradGrad(Operation op, Tensor[] grads)
{
var grad = grads[0];
var begin = op.inputs[1];
var end = op.inputs[2];
var strides = op.inputs[3];

return new Tensor[]
{
null,
null,
null,
gen_array_ops.strided_slice(
grad,
begin,
end,
strides,
begin_mask: (int)op.get_attr("begin_mask"),
end_mask: (int)op.get_attr("end_mask"),
ellipsis_mask: (int)op.get_attr("ellipsis_mask"),
new_axis_mask: (int)op.get_attr("new_axis_mask"),
shrink_axis_mask: (int)op.get_attr("shrink_axis_mask"))
};
}

private static Tensor _ReshapeToInput(Operation op, Tensor grad) private static Tensor _ReshapeToInput(Operation op, Tensor grad)
{ {
return array_ops.reshape(grad, array_ops.shape(op.inputs[0])); return array_ops.reshape(grad, array_ops.shape(op.inputs[0]));


+ 24
- 0
src/TensorFlowNET.Core/Gradients/math_grad.cs View File

@@ -92,6 +92,17 @@ namespace Tensorflow.Gradients
return new Tensor[] { grads[0] }; return new Tensor[] { grads[0] };
} }


[RegisterGradient("Lgamma")]
public static Tensor[] _LgammaGrad(Operation op, Tensor[] grads)
{
var grad = grads[0];
var x = op.inputs[0];
return with(ops.control_dependencies(new Operation[] { grad }), dp => {
x = math_ops.conj(x);
return new Tensor[] { grad * math_ops.digamma(x) };
});
}

[RegisterGradient("Log")] [RegisterGradient("Log")]
public static Tensor[] _LogGrad(Operation op, Tensor[] grads) public static Tensor[] _LogGrad(Operation op, Tensor[] grads)
{ {
@@ -431,6 +442,19 @@ namespace Tensorflow.Gradients
}); });
} }


[RegisterGradient("Tanh")]
public static Tensor[] _TanhGrad(Operation op, Tensor[] grads)
{
var grad = grads[0];
var y = op.outputs[0];

return with(ops.control_dependencies(grads), delegate
{
y = math_ops.conj(y);
return new Tensor[] { gen_math_ops.tanh_grad(y, grad) };
});
}

[RegisterGradient("Pow")] [RegisterGradient("Pow")]
public static Tensor[] _PowGrad(Operation op, Tensor[] grads) public static Tensor[] _PowGrad(Operation op, Tensor[] grads)
{ {


+ 65
- 0
src/TensorFlowNET.Core/Operations/gen_array_ops.cs View File

@@ -381,6 +381,71 @@ namespace Tensorflow
return _op.outputs[0]; return _op.outputs[0];
} }


public static Tensor strided_slice<T>(Tensor input, T[] begin, T[] end, T[] strides,
int begin_mask = 0,
int end_mask = 0,
int ellipsis_mask = 0,
int new_axis_mask = 0,
int shrink_axis_mask = 0,
string name = null)
{
var _op = _op_def_lib._apply_op_helper("StridedSlice", name, new
{
input,
begin,
end,
strides,
begin_mask,
end_mask,
ellipsis_mask,
new_axis_mask,
shrink_axis_mask
});

return _op.outputs[0];
}

/// <summary>
/// Returns the gradient of `StridedSlice`.
///
/// Since `StridedSlice` cuts out pieces of its `input` which is size
/// `shape`, its gradient will have the same shape (which is passed here
/// as `shape`). The gradient will be zero in any element that the slice
/// does not select.
/// </summary>
/// <param name="shape">Must be one of the following types: `int32`, `int64`.</param>
/// <param name="begin">Must have the same type as `shape`.</param>
/// <param name="end">Must have the same type as `shape`.</param>
/// <param name="strides">Must have the same type as `shape`.</param>
/// <param name="dy">A `Tensor`.</param>
/// <param name="begin_mask">An optional `int`. Defaults to `0`.</param>
/// <param name="end_mask">An optional `int`. Defaults to `0`.</param>
/// <param name="ellipsis_mask">An optional `int`. Defaults to `0`.</param>
/// <param name="new_axis_mask">An optional `int`. Defaults to `0`.</param>
/// <param name="shrink_axis_mask">An optional `int`. Defaults to `0`.</param>
/// <param name="name">A name for the operation (optional).</param>
/// <returns>A `Tensor`. Has the same type as `dy`.</returns>
public static Tensor strided_slice_grad(Tensor shape, Tensor begin, Tensor end, Tensor strides, Tensor dy,
int begin_mask = 0, int end_mask = 0, int ellipsis_mask = 0, int new_axis_mask = 0,
int shrink_axis_mask = 0, string name = null)
{
var op = _op_def_lib._apply_op_helper("StridedSliceGrad", name: name, args: new
{
shape,
begin,
end,
strides,
dy,
begin_mask,
end_mask,
ellipsis_mask,
new_axis_mask,
shrink_axis_mask
});

return op.output;
}

public static Tensor slice<Tb, Ts>(Tensor input, Tb[] begin, Ts[] size, string name = null) public static Tensor slice<Tb, Ts>(Tensor input, Tb[] begin, Ts[] size, string name = null)
{ {
var _op = _op_def_lib._apply_op_helper("Slice", name, new { input, begin, size }); var _op = _op_def_lib._apply_op_helper("Slice", name, new { input, begin, size });


+ 37
- 0
src/TensorFlowNET.Core/Operations/gen_math_ops.cs View File

@@ -62,6 +62,15 @@ namespace Tensorflow
public static Tensor arg_min(Tensor input, int dimension, TF_DataType output_type= TF_DataType.TF_INT64, string name= null) public static Tensor arg_min(Tensor input, int dimension, TF_DataType output_type= TF_DataType.TF_INT64, string name= null)
=>_op_def_lib._apply_op_helper("ArgMin", name, args: new { input, dimension, output_type }).outputs[0]; =>_op_def_lib._apply_op_helper("ArgMin", name, args: new { input, dimension, output_type }).outputs[0];
/// <summary>
/// Computes Psi, the derivative of Lgamma (the log of the absolute value of
/// `Gamma(x)`), element-wise.
/// </summary>
/// <param name="x"></param>
/// <param name="name"></param>
/// <returns></returns>
public static Tensor digamma(Tensor x, string name = null)
=> _op_def_lib._apply_op_helper("Digamma", name, args: new { x }).output;
/// <summary> /// <summary>
/// Returns 0 if the denominator is zero. /// Returns 0 if the denominator is zero.
@@ -250,6 +259,16 @@ namespace Tensorflow
return _op.outputs[0]; return _op.outputs[0];
} }
/// <summary>
/// Computes the gradient for the tanh of `x` wrt its input.
/// </summary>
/// <param name="y"></param>
/// <param name="dy"></param>
/// <param name="name"></param>
/// <returns></returns>
public static Tensor tanh_grad(Tensor y, Tensor dy, string name = "TanhGrad")
=> _op_def_lib._apply_op_helper("TanhGrad", name: name, args: new { y, dy }).output;
public static Tensor floor(Tensor x, string name = null) public static Tensor floor(Tensor x, string name = null)
{ {
var _op = _op_def_lib._apply_op_helper("Floor", name, args: new { x }); var _op = _op_def_lib._apply_op_helper("Floor", name, args: new { x });
@@ -271,6 +290,24 @@ namespace Tensorflow
return _op.outputs[0]; return _op.outputs[0];
} }
/// <summary>
/// Computes the log of the absolute value of `Gamma(x)` element-wise.
/// </summary>
/// <param name="x">
/// A `Tensor`. Must be one of the following types: `bfloat16`, `half`, `float32`, `float64`.
/// </param>
/// <param name="name">
/// </param>
/// <returns>
/// The Operation can be fetched from the resulting Tensor, by fetching the Operation property from the result.
/// </returns>
public static Tensor lgamma(Tensor x, string name = null)
{
var op = _op_def_lib._apply_op_helper("Lgamma", name: name, args: new { x });
return op.output;
}
public static Tensor greater_equal<Tx, Ty>(Tx x, Ty y, string name = null) public static Tensor greater_equal<Tx, Ty>(Tx x, Ty y, string name = null)
{ {
var _op = _op_def_lib._apply_op_helper("GreaterEqual", name: name, args: new { x, y }); var _op = _op_def_lib._apply_op_helper("GreaterEqual", name: name, args: new { x, y });


+ 13
- 0
src/TensorFlowNET.Core/Operations/math_ops.cs View File

@@ -80,6 +80,16 @@ namespace Tensorflow
}); });
} }


/// <summary>
/// Computes Psi, the derivative of Lgamma (the log of the absolute value of
/// `Gamma(x)`), element-wise.
/// </summary>
/// <param name="x"></param>
/// <param name="name"></param>
/// <returns></returns>
public static Tensor digamma(Tensor x, string name = null)
=> gen_math_ops.digamma(x, name: name);

/// <summary> /// <summary>
/// Divide two values using Python 2 semantics. Used for Tensor.__div__. /// Divide two values using Python 2 semantics. Used for Tensor.__div__.
/// </summary> /// </summary>
@@ -234,6 +244,9 @@ namespace Tensorflow
return gen_math_ops.log(x, name); return gen_math_ops.log(x, name);
} }


public static Tensor lgamma(Tensor x, string name = null)
=> gen_math_ops.lgamma(x, name: name);

/// <summary> /// <summary>
/// Helper function for reduction ops. /// Helper function for reduction ops.
/// </summary> /// </summary>


+ 4
- 3
src/TensorFlowNET.Core/TensorFlowNET.Core.csproj View File

@@ -5,7 +5,7 @@
<AssemblyName>TensorFlow.NET</AssemblyName> <AssemblyName>TensorFlow.NET</AssemblyName>
<RootNamespace>Tensorflow</RootNamespace> <RootNamespace>Tensorflow</RootNamespace>
<TargetTensorFlow>1.14.0</TargetTensorFlow> <TargetTensorFlow>1.14.0</TargetTensorFlow>
<Version>0.10.0-rc</Version>
<Version>0.10.0</Version>
<Authors>Haiping Chen, Meinrad Recheis</Authors> <Authors>Haiping Chen, Meinrad Recheis</Authors>
<Company>SciSharp STACK</Company> <Company>SciSharp STACK</Company>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
@@ -25,7 +25,8 @@ Learn more about .NET AI: https://medium.com/scisharp</Description>
2. Take dependency on SciSharp.TensorFlow.Redist. 2. Take dependency on SciSharp.TensorFlow.Redist.
3. Create Tensor from array without copying. 3. Create Tensor from array without copying.
4. Fix path issue of Transfer Learning example on Linux. 4. Fix path issue of Transfer Learning example on Linux.
5. Add back gen_ops.cs.</PackageReleaseNotes>
5. Add back gen_ops.cs.
5. Add StridedSliceGrad.</PackageReleaseNotes>
<LangVersion>7.2</LangVersion> <LangVersion>7.2</LangVersion>
<FileVersion>0.10.0.0</FileVersion> <FileVersion>0.10.0.0</FileVersion>
<PackageLicenseFile>LICENSE</PackageLicenseFile> <PackageLicenseFile>LICENSE</PackageLicenseFile>
@@ -59,7 +60,7 @@ Learn more about .NET AI: https://medium.com/scisharp</Description>


<ItemGroup> <ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.9.0" /> <PackageReference Include="Google.Protobuf" Version="3.9.0" />
<PackageReference Include="NumSharp" Version="0.10.4" />
<PackageReference Include="NumSharp" Version="0.10.5" />
<PackageReference Include="SciSharp.TensorFlow.Redist" Version="1.14.0" /> <PackageReference Include="SciSharp.TensorFlow.Redist" Version="1.14.0" />
</ItemGroup> </ItemGroup>




+ 39
- 0
test/TensorFlowNET.UnitTest/GradientTest.cs View File

@@ -1,4 +1,6 @@
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using NumSharp;
using System.Linq;
using Tensorflow; using Tensorflow;


namespace TensorFlowNET.UnitTest namespace TensorFlowNET.UnitTest
@@ -25,5 +27,42 @@ namespace TensorFlowNET.UnitTest
Assert.AreEqual(g[0].name, "gradients/Fill:0"); Assert.AreEqual(g[0].name, "gradients/Fill:0");
Assert.AreEqual(g[1].name, "gradients/Fill:0"); Assert.AreEqual(g[1].name, "gradients/Fill:0");
} }

[TestMethod]
public void StridedSlice()
{
var graph = tf.Graph().as_default();

var t = tf.constant(np.array(new int[,,]
{
{
{ 11, 12, 13 },
{ 21, 22, 23 }
},
{
{ 31, 32, 33 },
{ 41, 42, 43 }
},
{
{ 51, 52, 53 },
{ 61, 62, 63 }
}
}));

var slice = tf.strided_slice(t,
begin: new[] { 0, 0, 0 },
end: new[] { 3, 2, 3 },
strides: new[] { 2, 2, 2 });

var y = slice + slice;

var g = tf.gradients(y, new Tensor[] { slice, slice });

var r = slice.eval();

Assert.IsTrue(Enumerable.SequenceEqual(r.shape, new[] { 2, 1, 2 }));
Assert.IsTrue(Enumerable.SequenceEqual(r[0].GetData<int>(), new[] { 11, 13 }));
Assert.IsTrue(Enumerable.SequenceEqual(r[1].GetData<int>(), new[] { 51, 53 }));
}
} }
} }

Loading…
Cancel
Save