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