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