| @@ -265,15 +265,17 @@ namespace Tensorflow | |||
| yield return (i, values[i]); | |||
| } | |||
| public static IEnumerable<(int, T)> enumerate<T>(IEnumerable<T> values, int start = 0) | |||
| public static IEnumerable<(int, T)> enumerate<T>(IEnumerable<T> values, int start = 0, int step = 1) | |||
| { | |||
| int i = 0; | |||
| foreach(var val in values) | |||
| foreach (var val in values) | |||
| { | |||
| if (i++ < start) | |||
| i += step; | |||
| if (i < start) | |||
| continue; | |||
| yield return (i - start, val); | |||
| yield return (i - step - start, val); | |||
| } | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| using NumSharp; | |||
| using System; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using Tensorflow.Data; | |||
| namespace Tensorflow | |||
| { | |||
| @@ -9,5 +9,8 @@ namespace Tensorflow | |||
| { | |||
| public IDatasetV2 from_tensor_slices(Tensor features, Tensor labels) | |||
| => new TensorSliceDataset(features, labels); | |||
| public IDatasetV2 range(int count, TF_DataType output_type = TF_DataType.TF_INT64) | |||
| => new RangeDataset(count, output_type: output_type); | |||
| } | |||
| } | |||
| @@ -78,9 +78,8 @@ namespace Tensorflow | |||
| { | |||
| var ownedIterator = new OwnedIterator(this); | |||
| bool stop = false; | |||
| Tensor[] results = null; | |||
| while (!stop) | |||
| while (true) | |||
| { | |||
| try | |||
| { | |||
| @@ -88,10 +87,10 @@ namespace Tensorflow | |||
| } | |||
| catch (StopIteration) | |||
| { | |||
| stop = true; | |||
| break; | |||
| } | |||
| yield return (results[0], results[1]); | |||
| yield return (results[0], results.Length == 1 ? null : results[1]); | |||
| } | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using Tensorflow.Framework.Models; | |||
| using static Tensorflow.Binding; | |||
| namespace Tensorflow.Data | |||
| { | |||
| public class RangeDataset : DatasetSource | |||
| { | |||
| Tensor start; | |||
| Tensor step; | |||
| Tensor stop; | |||
| public RangeDataset(int stop, | |||
| int start = 0, | |||
| int step = 1, | |||
| TF_DataType output_type = TF_DataType.TF_INT64) | |||
| { | |||
| this.start = tf.convert_to_tensor((long)start); | |||
| this.step = tf.convert_to_tensor((long)step); | |||
| this.stop = tf.convert_to_tensor((long)stop); | |||
| structure = new TensorSpec[] { new TensorSpec(new int[0], dtype: output_type) }; | |||
| variant_tensor = ops.range_dataset(this.start, this.stop, this.step, output_types, output_shapes); | |||
| } | |||
| } | |||
| } | |||
| @@ -7,7 +7,7 @@ using System.Text; | |||
| using Tensorflow.Framework.Models; | |||
| using static Tensorflow.Binding; | |||
| namespace Tensorflow | |||
| namespace Tensorflow.Data | |||
| { | |||
| public class TensorSliceDataset : DatasetSource | |||
| { | |||
| @@ -0,0 +1,23 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using Tensorflow.Keras.Engine; | |||
| namespace Tensorflow.Keras.ArgsDefinition | |||
| { | |||
| public class DataHandlerArgs | |||
| { | |||
| public Tensor X { get; set; } | |||
| public Tensor Y { get; set; } | |||
| public int BatchSize { get; set; } = 32; | |||
| public int StepsPerEpoch { get; set; } = -1; | |||
| public int InitialEpoch { get; set; } = 0; | |||
| public int Epochs { get; set; } = 1; | |||
| public bool Shuffle { get; set; } = false; | |||
| public int MaxQueueSize { get; set; } = 10; | |||
| public int Workers { get; set; } = 1; | |||
| public bool UseMultiprocessing { get; set; } = false; | |||
| public Model Model { get; set; } | |||
| public IVariableV1 StepsPerExecution { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,12 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using Tensorflow.Keras.Engine; | |||
| namespace Tensorflow.Keras.ArgsDefinition | |||
| { | |||
| public class SequentialArgs : ModelArgs | |||
| { | |||
| public List<Layer> Layers { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using Tensorflow.Keras.ArgsDefinition; | |||
| namespace Tensorflow.Keras.Engine.DataAdapters | |||
| { | |||
| /// <summary> | |||
| /// Handles iterating over epoch-level `tf.data.Iterator` objects. | |||
| /// </summary> | |||
| public class DataHandler | |||
| { | |||
| DataHandlerArgs args; | |||
| Tensor x => args.X; | |||
| Tensor y => args.Y; | |||
| int batch_size => args.BatchSize; | |||
| int steps_per_epoch => args.StepsPerEpoch; | |||
| int initial_epoch => args.InitialEpoch; | |||
| int epochs => args.Epochs; | |||
| bool shuffle => args.Shuffle; | |||
| int max_queue_size => args.MaxQueueSize; | |||
| int workers => args.Workers; | |||
| bool use_multiprocessing => args.UseMultiprocessing; | |||
| Model model => args.Model; | |||
| IVariableV1 steps_per_execution => args.StepsPerExecution; | |||
| public DataHandler(DataHandlerArgs args) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| namespace Tensorflow.Keras.Engine.DataAdapters | |||
| { | |||
| /// <summary> | |||
| /// In TF 2.0, tf.data is the preferred API for user to feed in data. In order | |||
| /// to simplify the training code path, all the input data object will be | |||
| /// converted to `tf.data.Dataset` if possible. | |||
| /// </summary> | |||
| public interface IDataAdapter | |||
| { | |||
| /// <summary> | |||
| /// Whether the current DataAdapter could handle the input x and y. | |||
| /// </summary> | |||
| /// <param name="x">input features</param> | |||
| /// <param name="y">target labels</param> | |||
| /// <returns></returns> | |||
| bool CanHandle(Tensor x, Tensor y = null); | |||
| } | |||
| } | |||
| @@ -0,0 +1,23 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using static Tensorflow.Binding; | |||
| namespace Tensorflow.Keras.Engine.DataAdapters | |||
| { | |||
| /// <summary> | |||
| /// Adapter that handles Tensor-like objects, e.g. EagerTensor and NumPy. | |||
| /// </summary> | |||
| public class TensorLikeDataAdapter : IDataAdapter | |||
| { | |||
| public TensorLikeDataAdapter() | |||
| { | |||
| tf.data.Dataset.range(5); | |||
| } | |||
| public bool CanHandle(Tensor x, Tensor y = null) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,4 +1,6 @@ | |||
| using Tensorflow.Keras.ArgsDefinition; | |||
| using NumSharp; | |||
| using System; | |||
| using Tensorflow.Keras.ArgsDefinition; | |||
| using Tensorflow.Keras.Optimizers; | |||
| namespace Tensorflow.Keras.Engine | |||
| @@ -39,5 +41,30 @@ namespace Tensorflow.Keras.Engine | |||
| // Prepare list of loss functions, same size of model outputs. | |||
| } | |||
| /// <summary> | |||
| /// Generates output predictions for the input samples. | |||
| /// </summary> | |||
| /// <param name="x">Input samples</param> | |||
| /// <param name="batch_size">Number of samples per batch</param> | |||
| /// <param name="verbose">Verbosity mode</param> | |||
| /// <param name="steps"> | |||
| /// Total number of steps (batches of samples) | |||
| /// before declaring the prediction round finished. | |||
| /// </param> | |||
| /// <param name="max_queue_size"></param> | |||
| /// <param name="workers"></param> | |||
| /// <param name="use_multiprocessing"></param> | |||
| /// <returns></returns> | |||
| public Tensor predict(Tensor x, | |||
| int batch_size = 32, | |||
| int verbose = 0, | |||
| int steps = -1, | |||
| int max_queue_size = 10, | |||
| int workers = 1, | |||
| bool use_multiprocessing = false) | |||
| { | |||
| throw new NotImplementedException(""); | |||
| } | |||
| } | |||
| } | |||
| @@ -26,8 +26,9 @@ namespace Tensorflow.Keras.Engine | |||
| /// `Sequential` groups a linear stack of layers into a `tf.keras.Model`. | |||
| /// `Sequential` provides training and inference features on this model. | |||
| /// </summary> | |||
| public class Sequential | |||
| public class Sequential : Model | |||
| { | |||
| SequentialArgs args; | |||
| bool _is_graph_network; | |||
| Tensor inputs; | |||
| Tensor outputs; | |||
| @@ -37,13 +38,19 @@ namespace Tensorflow.Keras.Engine | |||
| TensorShape inferredInputShape; | |||
| bool hasExplicitInputShape; | |||
| TF_DataType inputDType; | |||
| List<Layer> layers; | |||
| List<Layer> layers => args.Layers; | |||
| public TensorShape output_shape => outputs.TensorShape; | |||
| bool built = false; | |||
| public Sequential(Layer[] layers = null, string name = null) | |||
| public Sequential(SequentialArgs args) | |||
| : base(new ModelArgs | |||
| { | |||
| Name = args.Name | |||
| }) | |||
| { | |||
| this.layers = layers == null ? new List<Layer>() : layers.ToList(); | |||
| this.args = args; | |||
| if (args.Layers == null) | |||
| args.Layers = new List<Layer>(); | |||
| // SupportsMasking = true; | |||
| computeOutputAndMaskJointly = true; | |||
| autoTrackSubLayers = false; | |||
| @@ -1,4 +1,5 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Data; | |||
| using System.Linq; | |||
| using Tensorflow.Keras; | |||
| @@ -19,10 +20,13 @@ namespace Tensorflow | |||
| public BackendImpl backend { get; } = new BackendImpl(); | |||
| public Models models { get; } = new Models(); | |||
| public Sequential Sequential() | |||
| => new Sequential(); | |||
| public Sequential Sequential(List<Layer> layers = null, | |||
| string name = null) | |||
| => new Sequential(new SequentialArgs | |||
| { | |||
| Layers = layers, | |||
| Name = name | |||
| }); | |||
| /// <summary> | |||
| /// Instantiate a Keras tensor. | |||
| @@ -1,13 +0,0 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using Tensorflow.Keras.Engine; | |||
| namespace Tensorflow.Keras | |||
| { | |||
| public class Models | |||
| { | |||
| public Sequential Sequential() | |||
| => new Sequential(); | |||
| } | |||
| } | |||
| @@ -33,6 +33,22 @@ namespace Tensorflow | |||
| throw new NotImplementedException(""); | |||
| } | |||
| public Tensor range_dataset(Tensor start, Tensor stop, Tensor step, TF_DataType[] output_types, TensorShape[] output_shapes, string name = null) | |||
| { | |||
| if (tf.Context.executing_eagerly()) | |||
| { | |||
| var results = tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||
| "RangeDataset", name, | |||
| null, | |||
| start, stop, step, | |||
| "output_types", output_types, | |||
| "output_shapes", output_shapes); | |||
| return results[0]; | |||
| } | |||
| throw new NotImplementedException(""); | |||
| } | |||
| public Tensor repeat_dataset(Tensor input_dataset, Tensor count, TF_DataType[] output_types, TensorShape[] output_shapes, string name = null) | |||
| { | |||
| if (tf.Context.executing_eagerly()) | |||
| @@ -0,0 +1,30 @@ | |||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| using Tensorflow.UnitTest; | |||
| using static Tensorflow.Binding; | |||
| namespace TensorFlowNET.UnitTest.Dataset | |||
| { | |||
| [TestClass] | |||
| public class DatasetTest : EagerModeTestBase | |||
| { | |||
| [TestMethod] | |||
| public void Range() | |||
| { | |||
| int iStep = 0; | |||
| long value = 0; | |||
| var dataset = tf.data.Dataset.range(3); | |||
| foreach(var (step, item) in enumerate(dataset)) | |||
| { | |||
| Assert.AreEqual(iStep, step); | |||
| iStep++; | |||
| Assert.AreEqual(value, (long)item.Item1); | |||
| value++; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -19,7 +19,7 @@ namespace TensorFlowNET.UnitTest.Keras | |||
| [TestMethod] | |||
| public void Sequential() | |||
| { | |||
| var model = tf.keras.models.Sequential(); | |||
| var model = tf.keras.Sequential(); | |||
| model.add(tf.keras.Input(shape: 16)); | |||
| } | |||
| @@ -29,7 +29,7 @@ namespace TensorFlowNET.UnitTest.Keras | |||
| [TestMethod] | |||
| public void Embedding() | |||
| { | |||
| var model = new Sequential(); | |||
| var model = tf.keras.Sequential(); | |||
| var layer = tf.keras.layers.Embedding(1000, 64, input_length: 10); | |||
| model.add(layer); | |||
| // the model will take as input an integer matrix of size (batch, | |||
| @@ -39,8 +39,8 @@ namespace TensorFlowNET.UnitTest.Keras | |||
| // now model.output_shape == (None, 10, 64), where None is the batch | |||
| // dimension. | |||
| var input_array = np.random.randint(1000, size: (32, 10)); | |||
| // model.compile("rmsprop", "mse"); | |||
| // output_array = model.predict(input_array) | |||
| model.compile("rmsprop", "mse"); | |||
| var output_array = model.predict(input_array); | |||
| } | |||
| /// <summary> | |||