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