@@ -32,6 +32,28 @@ namespace Tensorflow | |||||
/// <returns></returns> | /// <returns></returns> | ||||
public Tensor erf(Tensor x, string name = null) | public Tensor erf(Tensor x, string name = null) | ||||
=> math_ops.erf(x, name); | => 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) | public Tensor abs(Tensor x, string name = null) | ||||
@@ -67,7 +67,7 @@ namespace Tensorflow | |||||
string name = null, string @uint = "BYTE") | string name = null, string @uint = "BYTE") | ||||
=> ops.substr(input, pos, len, @uint: @uint, name: name); | => 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); | => ops.string_split_v2(input, sep: sep, maxsplit : maxsplit, name : name); | ||||
} | } | ||||
} | } | ||||
@@ -249,13 +249,6 @@ namespace Tensorflow | |||||
return _op.outputs[0]; | 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> | /// <summary> | ||||
/// Computes the sum along segments of a tensor. | /// Computes the sum along segments of a tensor. | ||||
/// </summary> | /// </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) | 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> | /// <summary> | ||||
/// Computes Psi, the derivative of Lgamma (the log of the absolute value of | /// 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 })); | .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> | /// <summary> | ||||
/// Returns the complex conjugate of a complex number. | /// Returns the complex conjugate of a complex number. | ||||
/// </summary> | /// </summary> | ||||
@@ -14,6 +14,7 @@ | |||||
limitations under the License. | limitations under the License. | ||||
******************************************************************************/ | ******************************************************************************/ | ||||
using NumSharp; | |||||
using Tensorflow.Framework; | using Tensorflow.Framework; | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
@@ -43,7 +44,7 @@ namespace Tensorflow | |||||
=> tf.Context.ExecuteOp("Substr", name, new ExecuteOpArgs(input, pos, len) | => tf.Context.ExecuteOp("Substr", name, new ExecuteOpArgs(input, pos, len) | ||||
.SetAttributes(new { unit = @uint })); | .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 => | return tf_with(ops.name_scope(name, "StringSplit"), scope => | ||||
{ | { | ||||
@@ -60,7 +61,12 @@ namespace Tensorflow | |||||
indices.set_shape(new TensorShape(-1, 2)); | indices.set_shape(new TensorShape(-1, 2)); | ||||
values.set_shape(new TensorShape(-1)); | values.set_shape(new TensorShape(-1)); | ||||
shape.set_shape(new TensorShape(2)); | 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> | <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||
<DefineConstants>TRACE;DEBUG</DefineConstants> | <DefineConstants>TRACE;DEBUG</DefineConstants> | ||||
<PlatformTarget>x64</PlatformTarget> | <PlatformTarget>x64</PlatformTarget> | ||||
<DocumentationFile>TensorFlow.NET.xml</DocumentationFile> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | ||||
@@ -17,6 +17,7 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Text; | using System.Text; | ||||
using System.Linq; | |||||
using Tensorflow.Framework; | using Tensorflow.Framework; | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
@@ -27,9 +28,30 @@ namespace Tensorflow | |||||
/// </summary> | /// </summary> | ||||
public class RaggedTensor : CompositeTensor | 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> | /// <summary> | ||||
@@ -49,8 +71,21 @@ namespace Tensorflow | |||||
var row_partition = RowPartition.from_value_rowids(value_rowids, | var row_partition = RowPartition.from_value_rowids(value_rowids, | ||||
nrows: nrows, | nrows: nrows, | ||||
validate: validate); | 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> | /// </summary> | ||||
public class RowPartition : CompositeTensor | 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, | public RowPartition(Tensor row_splits, | ||||
Tensor row_lengths = null, Tensor value_rowids = null, Tensor nrows = null, | Tensor row_lengths = null, Tensor value_rowids = null, Tensor nrows = null, | ||||
Tensor uniform_row_length = null) | Tensor uniform_row_length = null) | ||||
{ | { | ||||
_row_splits = row_splits; | |||||
_row_lengths = row_lengths; | |||||
_value_rowids = value_rowids; | |||||
_nrows = nrows; | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -47,8 +71,18 @@ namespace Tensorflow | |||||
{ | { | ||||
return tf_with(ops.name_scope(null, "RowPartitionFromValueRowIds"), scope => | 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, | return new RowPartition(row_splits, | ||||
row_lengths: row_lengths, | row_lengths: row_lengths, | ||||
value_rowids: value_rowids, | 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> | <AllowUnsafeBlocks>false</AllowUnsafeBlocks> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||||
<DocumentationFile>Tensorflow.Keras.xml</DocumentationFile> | |||||
</PropertyGroup> | |||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="MethodBoundaryAspect.Fody" Version="2.0.138" /> | <PackageReference Include="MethodBoundaryAspect.Fody" Version="2.0.138" /> | ||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | ||||
@@ -62,8 +62,9 @@ namespace TensorFlowNET.UnitTest.ManagedAPI | |||||
[TestMethod] | [TestMethod] | ||||
public void StringSplit() | 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); | |||||
} | } | ||||
} | } | ||||
} | } |