@@ -64,6 +64,9 @@ namespace Tensorflow | |||||
public Tensor substr(string input, int pos, int len, | public Tensor substr(string input, int pos, int len, | ||||
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 Tensor split(Tensor input, string sep = "", int maxsplit = -1, string name = null) | |||||
=> ops.string_split_v2(input, sep: sep, maxsplit : maxsplit, name : name); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -68,6 +68,17 @@ namespace Tensorflow | |||||
public IDatasetV2 map(Func<Tensors, Tensors> map_func, int num_parallel_calls) | public IDatasetV2 map(Func<Tensors, Tensors> map_func, int num_parallel_calls) | ||||
=> new ParallelMapDataset(this, map_func, num_parallel_calls: num_parallel_calls); | => new ParallelMapDataset(this, map_func, num_parallel_calls: num_parallel_calls); | ||||
public OwnedIterator make_one_shot_iterator() | |||||
{ | |||||
if (tf.Context.executing_eagerly()) | |||||
{ | |||||
// with ops.colocate_with(self._variant_tensor) | |||||
return new OwnedIterator(this); | |||||
} | |||||
throw new NotImplementedException(""); | |||||
} | |||||
public IDatasetV2 flat_map(Func<Tensor, IDatasetV2> map_func) | public IDatasetV2 flat_map(Func<Tensor, IDatasetV2> map_func) | ||||
=> new FlatMapDataset(this, map_func); | => new FlatMapDataset(this, map_func); | ||||
@@ -72,6 +72,8 @@ namespace Tensorflow | |||||
IDatasetV2 map(Func<Tensors, Tensors> map_func, | IDatasetV2 map(Func<Tensors, Tensors> map_func, | ||||
int num_parallel_calls); | int num_parallel_calls); | ||||
OwnedIterator make_one_shot_iterator(); | |||||
IDatasetV2 flat_map(Func<Tensor, IDatasetV2> map_func); | IDatasetV2 flat_map(Func<Tensor, IDatasetV2> map_func); | ||||
IDatasetV2 model(AutotuneAlgorithm algorithm, long cpu_budget); | IDatasetV2 model(AutotuneAlgorithm algorithm, long cpu_budget); | ||||
@@ -26,6 +26,7 @@ namespace Tensorflow | |||||
dataset = dataset.apply_options(); | dataset = dataset.apply_options(); | ||||
_dataset = dataset; | _dataset = dataset; | ||||
_element_spec = dataset.element_spec; | _element_spec = dataset.element_spec; | ||||
// _flat_output_types = | |||||
(_iterator_resource, _deleter) = ops.anonymous_iterator_v2(_dataset.output_types, _dataset.output_shapes); | (_iterator_resource, _deleter) = ops.anonymous_iterator_v2(_dataset.output_types, _dataset.output_shapes); | ||||
ops.make_iterator(dataset.variant_tensor, _iterator_resource); | ops.make_iterator(dataset.variant_tensor, _iterator_resource); | ||||
} | } | ||||
@@ -11,5 +11,6 @@ namespace Tensorflow.Keras.ArgsDefinition | |||||
public int MaxTokens { get; set; } = -1; | public int MaxTokens { get; set; } = -1; | ||||
public string OutputMode { get; set; } = "int"; | public string OutputMode { get; set; } = "int"; | ||||
public int OutputSequenceLength { get; set; } = -1; | public int OutputSequenceLength { get; set; } = -1; | ||||
public string[] Vocabulary { get; set; } | |||||
} | } | ||||
} | } |
@@ -41,5 +41,10 @@ namespace Tensorflow | |||||
string @uint = "BYTE", string name = null) | string @uint = "BYTE", string name = null) | ||||
=> 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 Tensor string_split_v2(Tensor input, string sep = "", int maxsplit = -1, string name = null) | |||||
{ | |||||
return null; | |||||
} | |||||
} | } | ||||
} | } |
@@ -8,11 +8,23 @@ namespace Tensorflow.Keras.Engine | |||||
public class CombinerPreprocessingLayer : Layer | public class CombinerPreprocessingLayer : Layer | ||||
{ | { | ||||
PreprocessingLayerArgs args; | PreprocessingLayerArgs args; | ||||
protected ICombiner combiner; | |||||
protected bool _previously_updated; | |||||
public CombinerPreprocessingLayer(PreprocessingLayerArgs args) | public CombinerPreprocessingLayer(PreprocessingLayerArgs args) | ||||
: base(args) | : base(args) | ||||
{ | { | ||||
_previously_updated = false; | |||||
} | |||||
public virtual void adapt(IDatasetV2 data, bool reset_state = true) | |||||
{ | |||||
IAccumulator accumulator; | |||||
if (!reset_state) | |||||
accumulator = combiner.Restore(); | |||||
var next_data = data.make_one_shot_iterator(); | |||||
var data_element = next_data.next(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,10 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace Tensorflow.Keras.Engine | |||||
{ | |||||
public interface IAccumulator | |||||
{ | |||||
} | |||||
} |
@@ -0,0 +1,19 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace Tensorflow.Keras.Engine | |||||
{ | |||||
/// <summary> | |||||
/// Functional object that defines a shardable computation. | |||||
/// </summary> | |||||
public interface ICombiner | |||||
{ | |||||
void Compute(Tensor values, IAccumulator accumulator = null); | |||||
void Merge(); | |||||
void Extract(); | |||||
IAccumulator Restore(); | |||||
void Serialize(); | |||||
void Deserialize(); | |||||
} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Tensorflow.Keras.ArgsDefinition; | |||||
using Tensorflow.Keras.Engine; | |||||
namespace Tensorflow.Keras.Layers | |||||
{ | |||||
public class IndexLookup : CombinerPreprocessingLayer | |||||
{ | |||||
public IndexLookup(int max_tokens = -1, | |||||
int num_oov_indices = 1, | |||||
string mask_token = "", | |||||
string oov_token = "[UNK]", | |||||
string encoding = "utf-8", | |||||
bool invert = false) : base(new PreprocessingLayerArgs()) | |||||
{ | |||||
var num_mask_tokens = mask_token == null ? 0 : 1; | |||||
var vocab_size = max_tokens - (num_oov_indices + num_mask_tokens); | |||||
combiner = new IndexLookupCombiner(vocab_size, mask_token); | |||||
} | |||||
public override void adapt(IDatasetV2 data, bool reset_state = true) | |||||
{ | |||||
if (!reset_state) | |||||
throw new ValueError("IndexLookup does not support streaming adapts."); | |||||
base.adapt(data, reset_state); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,16 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Tensorflow.Keras.Engine; | |||||
namespace Tensorflow.Keras.Layers | |||||
{ | |||||
public class IndexLookupAccumulator : IAccumulator | |||||
{ | |||||
public Dictionary<string, int> CountDict { get; set; } | |||||
public IndexLookupAccumulator() | |||||
{ | |||||
CountDict = new Dictionary<string, int>(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,55 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Tensorflow.Keras.Engine; | |||||
namespace Tensorflow.Keras.Layers | |||||
{ | |||||
/// <summary> | |||||
/// Combiner for the IndexLookup preprocessing layer. | |||||
/// </summary> | |||||
public class IndexLookupCombiner : ICombiner | |||||
{ | |||||
int _vocab_size; | |||||
string _mask_value; | |||||
public IndexLookupCombiner(int vocab_size = -1, string mask_value = null) | |||||
{ | |||||
_vocab_size = vocab_size; | |||||
_mask_value = mask_value; | |||||
} | |||||
public void Compute(Tensor values, IAccumulator accumulator = null) | |||||
{ | |||||
if(accumulator == null) | |||||
{ | |||||
accumulator = new IndexLookupAccumulator(); | |||||
} | |||||
} | |||||
public void Deserialize() | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public void Extract() | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public void Merge() | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAccumulator Restore() | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public void Serialize() | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,23 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace Tensorflow.Keras.Layers | |||||
{ | |||||
/// <summary> | |||||
/// Maps strings from a vocabulary to integer indices. | |||||
/// </summary> | |||||
class StringLookup : IndexLookup | |||||
{ | |||||
public StringLookup(int max_tokens = -1, | |||||
int num_oov_indices = 1, | |||||
string mask_token = "", | |||||
string[] vocabulary = null, | |||||
string oov_token = "[UNK]", | |||||
string encoding = "utf-8", | |||||
bool invert = false) | |||||
{ | |||||
} | |||||
} | |||||
} |
@@ -3,12 +3,14 @@ using System.Collections.Generic; | |||||
using System.Text; | using System.Text; | ||||
using Tensorflow.Keras.ArgsDefinition; | using Tensorflow.Keras.ArgsDefinition; | ||||
using Tensorflow.Keras.Engine; | using Tensorflow.Keras.Engine; | ||||
using static Tensorflow.Binding; | |||||
namespace Tensorflow.Keras.Layers | namespace Tensorflow.Keras.Layers | ||||
{ | { | ||||
public class TextVectorization : CombinerPreprocessingLayer | public class TextVectorization : CombinerPreprocessingLayer | ||||
{ | { | ||||
TextVectorizationArgs args; | TextVectorizationArgs args; | ||||
IndexLookup _index_lookup_layer; | |||||
public TextVectorization(TextVectorizationArgs args) | public TextVectorization(TextVectorizationArgs args) | ||||
: base(args) | : base(args) | ||||
@@ -16,6 +18,11 @@ namespace Tensorflow.Keras.Layers | |||||
this.args = args; | this.args = args; | ||||
args.DType = TF_DataType.TF_STRING; | args.DType = TF_DataType.TF_STRING; | ||||
// string standardize = "lower_and_strip_punctuation", | // string standardize = "lower_and_strip_punctuation", | ||||
var mask_token = args.OutputMode == "int" ? "" : null; | |||||
_index_lookup_layer = new StringLookup(max_tokens: args.MaxTokens, | |||||
mask_token: mask_token, | |||||
vocabulary: args.Vocabulary); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -23,13 +30,14 @@ namespace Tensorflow.Keras.Layers | |||||
/// </summary> | /// </summary> | ||||
/// <param name="data"></param> | /// <param name="data"></param> | ||||
/// <param name="reset_state"></param> | /// <param name="reset_state"></param> | ||||
public void adapt(IDatasetV2 data, bool reset_state = true) | |||||
public override void adapt(IDatasetV2 data, bool reset_state = true) | |||||
{ | { | ||||
var shape = data.output_shapes[0]; | var shape = data.output_shapes[0]; | ||||
if (shape.rank == 1) | if (shape.rank == 1) | ||||
data = data.map(tensor => array_ops.expand_dims(tensor, -1)); | data = data.map(tensor => array_ops.expand_dims(tensor, -1)); | ||||
build(data.variant_tensor); | build(data.variant_tensor); | ||||
var preprocessed_inputs = data.map(_preprocess); | var preprocessed_inputs = data.map(_preprocess); | ||||
_index_lookup_layer.adapt(preprocessed_inputs); | |||||
} | } | ||||
protected override void build(Tensors inputs) | protected override void build(Tensors inputs) | ||||
@@ -45,6 +53,8 @@ namespace Tensorflow.Keras.Layers | |||||
{ | { | ||||
if (inputs.shape.ndim > 1) | if (inputs.shape.ndim > 1) | ||||
inputs = array_ops.squeeze(inputs, axis: new[] { -1 }); | inputs = array_ops.squeeze(inputs, axis: new[] { -1 }); | ||||
if (args.Split == "whitespace") | |||||
inputs = tf.strings.split(inputs); | |||||
} | } | ||||
return inputs; | return inputs; | ||||
} | } | ||||
@@ -1,4 +1,5 @@ | |||||
using NumSharp; | using NumSharp; | ||||
using System; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.IO; | using System.IO; | ||||
using System.Linq; | using System.Linq; | ||||
@@ -60,6 +61,7 @@ namespace Tensorflow.Keras.Preprocessings | |||||
} | } | ||||
} | } | ||||
Console.WriteLine($"Found {return_file_paths.Length} files belonging to {class_names.Length} classes."); | |||||
return (return_file_paths, return_labels, class_names); | return (return_file_paths, return_labels, class_names); | ||||
} | } | ||||
} | } | ||||
@@ -63,10 +63,6 @@ Keras is an API designed for human beings, not machines. Keras follows best prac | |||||
</None> | </None> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<Folder Include="Engine\Interfaces\" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | <ItemGroup> | ||||
<ProjectReference Include="..\TensorFlowNET.Core\Tensorflow.Binding.csproj" /> | <ProjectReference Include="..\TensorFlowNET.Core\Tensorflow.Binding.csproj" /> | ||||
</ItemGroup> | </ItemGroup> | ||||