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)
=> 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>
/// Returns the truth value of (x <= y) element-wise.
/// </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 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]) };
}

/// <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)
{
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] };
}

[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")]
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")]
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];
}

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)
{
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)
=>_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>
/// Returns 0 if the denominator is zero.
@@ -250,6 +259,16 @@ namespace Tensorflow
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)
{
var _op = _op_def_lib._apply_op_helper("Floor", name, args: new { x });
@@ -271,6 +290,24 @@ namespace Tensorflow
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)
{
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>
/// Divide two values using Python 2 semantics. Used for Tensor.__div__.
/// </summary>
@@ -234,6 +244,9 @@ namespace Tensorflow
return gen_math_ops.log(x, name);
}

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

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


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

@@ -5,7 +5,7 @@
<AssemblyName>TensorFlow.NET</AssemblyName>
<RootNamespace>Tensorflow</RootNamespace>
<TargetTensorFlow>1.14.0</TargetTensorFlow>
<Version>0.10.0-rc</Version>
<Version>0.10.0</Version>
<Authors>Haiping Chen, Meinrad Recheis</Authors>
<Company>SciSharp STACK</Company>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
@@ -25,7 +25,8 @@ Learn more about .NET AI: https://medium.com/scisharp</Description>
2. Take dependency on SciSharp.TensorFlow.Redist.
3. Create Tensor from array without copying.
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>
<FileVersion>0.10.0.0</FileVersion>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
@@ -59,7 +60,7 @@ Learn more about .NET AI: https://medium.com/scisharp</Description>

<ItemGroup>
<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" />
</ItemGroup>



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

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

namespace TensorFlowNET.UnitTest
@@ -25,5 +27,42 @@ namespace TensorFlowNET.UnitTest
Assert.AreEqual(g[0].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