| @@ -32,6 +32,28 @@ namespace Tensorflow | |||
| /// <returns></returns> | |||
| public Tensor erf(Tensor x, string name = null) | |||
| => math_ops.erf(x, name); | |||
| /// <summary> | |||
| /// | |||
| /// </summary> | |||
| /// <param name="arr"></param> | |||
| /// <param name="weights"></param> | |||
| /// <param name="minlength"></param> | |||
| /// <param name="maxlength"></param> | |||
| /// <param name="dtype"></param> | |||
| /// <param name="name"></param> | |||
| /// <param name="axis"></param> | |||
| /// <param name="binary_output"></param> | |||
| /// <returns></returns> | |||
| public Tensor bincount(Tensor arr, Tensor weights = null, | |||
| Tensor minlength = null, | |||
| Tensor maxlength = null, | |||
| TF_DataType dtype = TF_DataType.TF_INT32, | |||
| string name = null, | |||
| TensorShape axis = null, | |||
| bool binary_output = false) | |||
| => math_ops.bincount(arr, weights: weights, minlength: minlength, maxlength: maxlength, | |||
| dtype: dtype, name: name, axis: axis, binary_output: binary_output); | |||
| } | |||
| public Tensor abs(Tensor x, string name = null) | |||
| @@ -67,7 +67,7 @@ namespace Tensorflow | |||
| string name = null, string @uint = "BYTE") | |||
| => ops.substr(input, pos, len, @uint: @uint, name: name); | |||
| public SparseTensor split(Tensor input, string sep = "", int maxsplit = -1, string name = null) | |||
| public RaggedTensor split(Tensor input, string sep = "", int maxsplit = -1, string name = null) | |||
| => ops.string_split_v2(input, sep: sep, maxsplit : maxsplit, name : name); | |||
| } | |||
| } | |||
| @@ -249,13 +249,6 @@ namespace Tensorflow | |||
| return _op.outputs[0]; | |||
| } | |||
| public static Tensor cumsum<T>(Tensor x, T axis, bool exclusive = false, bool reverse = false, string name = null) | |||
| { | |||
| var _op = tf.OpDefLib._apply_op_helper("Cumsum", name, args: new { x, axis, exclusive, reverse }); | |||
| return _op.outputs[0]; | |||
| } | |||
| /// <summary> | |||
| /// Computes the sum along segments of a tensor. | |||
| /// </summary> | |||
| @@ -168,15 +168,12 @@ namespace Tensorflow | |||
| } | |||
| public static Tensor cumsum<T>(Tensor x, T axis = default, bool exclusive = false, bool reverse = false, string name = null) | |||
| { | |||
| return tf_with(ops.name_scope(name, "Cumsum", new { x }), scope => | |||
| { | |||
| name = scope; | |||
| x = ops.convert_to_tensor(x, name: "x"); | |||
| return gen_math_ops.cumsum(x, axis: axis, exclusive: exclusive, reverse: reverse, name: name); | |||
| }); | |||
| } | |||
| => tf_with(ops.name_scope(name, "Cumsum", new { x }), scope => | |||
| { | |||
| name = scope; | |||
| return tf.Context.ExecuteOp("Cumsum", name, new ExecuteOpArgs(x, axis) | |||
| .SetAttributes(new { exclusive, reverse })); | |||
| }); | |||
| /// <summary> | |||
| /// Computes Psi, the derivative of Lgamma (the log of the absolute value of | |||
| @@ -807,6 +804,31 @@ namespace Tensorflow | |||
| .SetAttributes(new { adj_x, adj_y })); | |||
| }); | |||
| public static Tensor bincount(Tensor arr, Tensor weights = null, | |||
| Tensor minlength = null, | |||
| Tensor maxlength = null, | |||
| TF_DataType dtype = TF_DataType.TF_INT32, | |||
| string name = null, | |||
| TensorShape axis = null, | |||
| bool binary_output = false) | |||
| => tf_with(ops.name_scope(name, "bincount"), scope => | |||
| { | |||
| name = scope; | |||
| if(!binary_output && axis == null) | |||
| { | |||
| var array_is_nonempty = math_ops.reduce_prod(array_ops.shape(arr)) > 0; | |||
| var output_size = math_ops.cast(array_is_nonempty, dtypes.int32) * (math_ops.reduce_max(arr) + 1); | |||
| if (minlength != null) | |||
| output_size = math_ops.maximum(minlength, output_size); | |||
| if (maxlength != null) | |||
| output_size = math_ops.minimum(maxlength, output_size); | |||
| var weights = constant_op.constant(new long[0], dtype: dtype); | |||
| return tf.Context.ExecuteOp("Bincount", name, new ExecuteOpArgs(arr, output_size, weights)); | |||
| } | |||
| throw new NotImplementedException(""); | |||
| }); | |||
| /// <summary> | |||
| /// Returns the complex conjugate of a complex number. | |||
| /// </summary> | |||
| @@ -14,6 +14,7 @@ | |||
| limitations under the License. | |||
| ******************************************************************************/ | |||
| using NumSharp; | |||
| using Tensorflow.Framework; | |||
| using static Tensorflow.Binding; | |||
| @@ -43,7 +44,7 @@ namespace Tensorflow | |||
| => tf.Context.ExecuteOp("Substr", name, new ExecuteOpArgs(input, pos, len) | |||
| .SetAttributes(new { unit = @uint })); | |||
| public SparseTensor string_split_v2(Tensor input, string sep = "", int maxsplit = -1, string name = null) | |||
| public RaggedTensor string_split_v2(Tensor input, string sep = "", int maxsplit = -1, string name = null) | |||
| { | |||
| return tf_with(ops.name_scope(name, "StringSplit"), scope => | |||
| { | |||
| @@ -60,7 +61,12 @@ namespace Tensorflow | |||
| indices.set_shape(new TensorShape(-1, 2)); | |||
| values.set_shape(new TensorShape(-1)); | |||
| shape.set_shape(new TensorShape(2)); | |||
| return new SparseTensor(indices, values, shape); | |||
| var sparse_result = new SparseTensor(indices, values, shape); | |||
| return RaggedTensor.from_value_rowids(sparse_result.values, | |||
| value_rowids: sparse_result.indices[Slice.All, 0], | |||
| nrows: sparse_result.dense_shape[0], | |||
| validate: false); | |||
| }); | |||
| } | |||
| } | |||
| @@ -50,6 +50,7 @@ tf.net 0.4x.x aligns with TensorFlow v2.4.1 native library.</PackageReleaseNotes | |||
| <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |||
| <DefineConstants>TRACE;DEBUG</DefineConstants> | |||
| <PlatformTarget>x64</PlatformTarget> | |||
| <DocumentationFile>TensorFlow.NET.xml</DocumentationFile> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||
| @@ -17,6 +17,7 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using System.Linq; | |||
| using Tensorflow.Framework; | |||
| using static Tensorflow.Binding; | |||
| @@ -27,9 +28,30 @@ namespace Tensorflow | |||
| /// </summary> | |||
| public class RaggedTensor : CompositeTensor | |||
| { | |||
| public RaggedTensor(Tensor values, RowPartition row_partition, bool validate = true) | |||
| Tensor _values; | |||
| RowPartition _row_partition; | |||
| public TF_DataType dtype => _values.dtype; | |||
| public TensorShape shape | |||
| { | |||
| get | |||
| { | |||
| var nrows = _row_partition.static_nrows; | |||
| var ncols = _row_partition.static_uniform_row_length; | |||
| return new TensorShape(nrows, ncols); | |||
| } | |||
| } | |||
| public RaggedTensor(Tensor values, | |||
| bool @internal = true, | |||
| RowPartition row_partition = null) | |||
| { | |||
| _values = values; | |||
| _row_partition = row_partition; | |||
| } | |||
| public static RaggedTensor from_row_partition(Tensor values, RowPartition row_partition, bool validate = true) | |||
| { | |||
| return new RaggedTensor(values, @internal: true, row_partition: row_partition); | |||
| } | |||
| /// <summary> | |||
| @@ -49,8 +71,21 @@ namespace Tensorflow | |||
| var row_partition = RowPartition.from_value_rowids(value_rowids, | |||
| nrows: nrows, | |||
| validate: validate); | |||
| return new RaggedTensor(values, row_partition, validate: validate); | |||
| return from_row_partition(values, row_partition, validate: validate); | |||
| }); | |||
| } | |||
| public override string ToString() | |||
| => $"tf.RaggedTensor: shape={shape} [{string.Join(", ", _values.StringData().Take(10))}]"; | |||
| public static implicit operator Tensor(RaggedTensor indexedSlices) | |||
| { | |||
| return indexedSlices._values; | |||
| } | |||
| public static implicit operator RaggedTensor(Tensor tensor) | |||
| { | |||
| return tensor.Tag as RaggedTensor; | |||
| } | |||
| } | |||
| } | |||
| @@ -27,11 +27,35 @@ namespace Tensorflow | |||
| /// </summary> | |||
| public class RowPartition : CompositeTensor | |||
| { | |||
| Tensor _row_splits; | |||
| Tensor _row_lengths; | |||
| Tensor _value_rowids; | |||
| Tensor _nrows; | |||
| public int static_nrows | |||
| { | |||
| get | |||
| { | |||
| return _row_splits.shape[0] - 1; | |||
| } | |||
| } | |||
| public int static_uniform_row_length | |||
| { | |||
| get | |||
| { | |||
| return -1; | |||
| } | |||
| } | |||
| public RowPartition(Tensor row_splits, | |||
| Tensor row_lengths = null, Tensor value_rowids = null, Tensor nrows = null, | |||
| Tensor uniform_row_length = null) | |||
| { | |||
| _row_splits = row_splits; | |||
| _row_lengths = row_lengths; | |||
| _value_rowids = value_rowids; | |||
| _nrows = nrows; | |||
| } | |||
| /// <summary> | |||
| @@ -47,8 +71,18 @@ namespace Tensorflow | |||
| { | |||
| return tf_with(ops.name_scope(null, "RowPartitionFromValueRowIds"), scope => | |||
| { | |||
| Tensor row_lengths = null; | |||
| Tensor row_splits = null; | |||
| var value_rowids_int32 = math_ops.cast(value_rowids, dtypes.int32); | |||
| var nrows_int32 = math_ops.cast(nrows, dtypes.int32); | |||
| var row_lengths = tf.math.bincount(value_rowids_int32, | |||
| minlength: nrows_int32, | |||
| maxlength: nrows_int32, | |||
| dtype: value_rowids.dtype); | |||
| var row_splits = array_ops.concat(new object[] | |||
| { | |||
| ops.convert_to_tensor(new long[] { 0 }), | |||
| tf.cumsum(row_lengths) | |||
| }, axis: 0); | |||
| return new RowPartition(row_splits, | |||
| row_lengths: row_lengths, | |||
| value_rowids: value_rowids, | |||
| @@ -49,6 +49,10 @@ Keras is an API designed for human beings, not machines. Keras follows best prac | |||
| <AllowUnsafeBlocks>false</AllowUnsafeBlocks> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||
| <DocumentationFile>Tensorflow.Keras.xml</DocumentationFile> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="MethodBoundaryAspect.Fody" Version="2.0.138" /> | |||
| <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | |||
| @@ -62,8 +62,9 @@ namespace TensorFlowNET.UnitTest.ManagedAPI | |||
| [TestMethod] | |||
| public void StringSplit() | |||
| { | |||
| var tensor = tf.constant(new[] { "hello world", "tensorflow .net" }); | |||
| tf.strings.split(tensor); | |||
| var tensor = tf.constant(new[] { "hello world", "tensorflow .net csharp", "fsharp" }); | |||
| var ragged_tensor = tf.strings.split(tensor); | |||
| Assert.AreEqual((3, -1), ragged_tensor.shape); | |||
| } | |||
| } | |||
| } | |||