| @@ -1,9 +1,12 @@ | |||||
| using System; | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Text; | using System.Text; | ||||
| namespace Tensorflow.Keras.ArgsDefinition { | namespace Tensorflow.Keras.ArgsDefinition { | ||||
| public class ELUArgs : LayerArgs { | |||||
| public float Alpha { get; set; } = 0.1f; | |||||
| } | |||||
| public class ELUArgs : AutoSerializeLayerArgs | |||||
| { | |||||
| [JsonProperty("alpha")] | |||||
| public float Alpha { get; set; } = 0.1f; | |||||
| } | |||||
| } | } | ||||
| @@ -1,14 +1,16 @@ | |||||
| using System; | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Text; | using System.Text; | ||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| public class LeakyReLuArgs : LayerArgs | |||||
| public class LeakyReLuArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Negative slope coefficient. | /// Negative slope coefficient. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("alpha")] | |||||
| public float Alpha { get; set; } = 0.3f; | public float Alpha { get; set; } = 0.3f; | ||||
| } | } | ||||
| } | } | ||||
| @@ -4,15 +4,9 @@ using System.Collections.Generic; | |||||
| using System.Text; | using System.Text; | ||||
| namespace Tensorflow.Keras.ArgsDefinition { | namespace Tensorflow.Keras.ArgsDefinition { | ||||
| public class SoftmaxArgs : LayerArgs | |||||
| public class SoftmaxArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| [JsonProperty("axis")] | [JsonProperty("axis")] | ||||
| public Axis axis { get; set; } = -1; | public Axis axis { get; set; } = -1; | ||||
| [JsonProperty("name")] | |||||
| public override string Name { get => base.Name; set => base.Name = value; } | |||||
| [JsonProperty("trainable")] | |||||
| public override bool Trainable { get => base.Trainable; set => base.Trainable = value; } | |||||
| [JsonProperty("dtype")] | |||||
| public override TF_DataType DType { get => base.DType; set => base.DType = value; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,3 +1,5 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| public class AttentionArgs : BaseDenseAttentionArgs | public class AttentionArgs : BaseDenseAttentionArgs | ||||
| @@ -6,6 +8,7 @@ namespace Tensorflow.Keras.ArgsDefinition | |||||
| /// <summary> | /// <summary> | ||||
| /// If `true`, will create a scalar variable to scale the attention scores. | /// If `true`, will create a scalar variable to scale the attention scores. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("use_scale")] | |||||
| public bool use_scale { get; set; } = false; | public bool use_scale { get; set; } = false; | ||||
| /// <summary> | /// <summary> | ||||
| @@ -14,6 +17,7 @@ namespace Tensorflow.Keras.ArgsDefinition | |||||
| /// and key vectors. `"concat"` refers to the hyperbolic tangent of the | /// and key vectors. `"concat"` refers to the hyperbolic tangent of the | ||||
| /// concatenation of the query and key vectors. | /// concatenation of the query and key vectors. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("score_mode")] | |||||
| public string score_mode { get; set; } = "dot"; | public string score_mode { get; set; } = "dot"; | ||||
| } | } | ||||
| @@ -1,6 +1,8 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| public class BaseDenseAttentionArgs : LayerArgs | |||||
| public class BaseDenseAttentionArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| @@ -14,6 +16,7 @@ namespace Tensorflow.Keras.ArgsDefinition | |||||
| /// Float between 0 and 1. Fraction of the units to drop for the | /// Float between 0 and 1. Fraction of the units to drop for the | ||||
| /// attention scores. | /// attention scores. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("dropout")] | |||||
| public float dropout { get; set; } = 0f; | public float dropout { get; set; } = 0f; | ||||
| } | } | ||||
| @@ -1,22 +1,40 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System; | using System; | ||||
| using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| public class MultiHeadAttentionArgs : LayerArgs | |||||
| public class MultiHeadAttentionArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| [JsonProperty("num_heads")] | |||||
| public int NumHeads { get; set; } | public int NumHeads { get; set; } | ||||
| [JsonProperty("key_dim")] | |||||
| public int KeyDim { get; set; } | public int KeyDim { get; set; } | ||||
| [JsonProperty("value_dim")] | |||||
| public int? ValueDim { get; set; } = null; | public int? ValueDim { get; set; } = null; | ||||
| [JsonProperty("dropout")] | |||||
| public float Dropout { get; set; } = 0f; | public float Dropout { get; set; } = 0f; | ||||
| [JsonProperty("use_bias")] | |||||
| public bool UseBias { get; set; } = true; | public bool UseBias { get; set; } = true; | ||||
| [JsonProperty("output_shape")] | |||||
| public Shape OutputShape { get; set; } = null; | public Shape OutputShape { get; set; } = null; | ||||
| [JsonProperty("attention_axes")] | |||||
| public Shape AttentionAxis { get; set; } = null; | public Shape AttentionAxis { get; set; } = null; | ||||
| [JsonProperty("kernel_initializer")] | |||||
| public IInitializer KernelInitializer { get; set; } = tf.glorot_uniform_initializer; | public IInitializer KernelInitializer { get; set; } = tf.glorot_uniform_initializer; | ||||
| [JsonProperty("bias_initializer")] | |||||
| public IInitializer BiasInitializer { get; set; } = tf.zeros_initializer; | public IInitializer BiasInitializer { get; set; } = tf.zeros_initializer; | ||||
| [JsonProperty("kernel_regularizer")] | |||||
| public IRegularizer KernelRegularizer { get; set; } = null; | public IRegularizer KernelRegularizer { get; set; } = null; | ||||
| [JsonProperty("bias_regularizer")] | |||||
| public IRegularizer BiasRegularizer { get; set; } = null; | public IRegularizer BiasRegularizer { get; set; } = null; | ||||
| [JsonProperty("kernel_constraint")] | |||||
| public Action KernelConstraint { get; set; } = null; | public Action KernelConstraint { get; set; } = null; | ||||
| [JsonProperty("bias_constraint")] | |||||
| public Action BiasConstraint { get; set; } = null; | public Action BiasConstraint { get; set; } = null; | ||||
| [JsonProperty("activity_regularizer")] | |||||
| public override IRegularizer ActivityRegularizer { get => base.ActivityRegularizer; set => base.ActivityRegularizer = value; } | |||||
| // TODO: Add `key_shape`, `value_shape`, `query_shape`. | |||||
| } | } | ||||
| } | } | ||||
| @@ -5,6 +5,12 @@ using System.Text; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| /// <summary> | |||||
| /// This class has nothing but the attributes different from `LayerArgs`. | |||||
| /// It's used to serialize the model to `tf` format. | |||||
| /// If the `get_config` of a `Layer` in python code of tensorflow contains `super().get_config`, | |||||
| /// then the Arg definition should inherit `utoSerializeLayerArgs` instead of `LayerArgs`. | |||||
| /// </summary> | |||||
| public class AutoSerializeLayerArgs: LayerArgs | public class AutoSerializeLayerArgs: LayerArgs | ||||
| { | { | ||||
| [JsonProperty("name")] | [JsonProperty("name")] | ||||
| @@ -1,31 +1,65 @@ | |||||
| using System; | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| public class ConvolutionalArgs : LayerArgs | |||||
| public class ConvolutionalArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| public int Rank { get; set; } = 2; | public int Rank { get; set; } = 2; | ||||
| [JsonProperty("filters")] | |||||
| public int Filters { get; set; } | public int Filters { get; set; } | ||||
| public int NumSpatialDims { get; set; } = Unknown; | public int NumSpatialDims { get; set; } = Unknown; | ||||
| [JsonProperty("kernel_size")] | |||||
| public Shape KernelSize { get; set; } = 5; | public Shape KernelSize { get; set; } = 5; | ||||
| /// <summary> | /// <summary> | ||||
| /// specifying the stride length of the convolution. | /// specifying the stride length of the convolution. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("strides")] | |||||
| public Shape Strides { get; set; } = (1, 1); | public Shape Strides { get; set; } = (1, 1); | ||||
| [JsonProperty("padding")] | |||||
| public string Padding { get; set; } = "valid"; | public string Padding { get; set; } = "valid"; | ||||
| [JsonProperty("data_format")] | |||||
| public string DataFormat { get; set; } | public string DataFormat { get; set; } | ||||
| [JsonProperty("dilation_rate")] | |||||
| public Shape DilationRate { get; set; } = (1, 1); | public Shape DilationRate { get; set; } = (1, 1); | ||||
| [JsonProperty("groups")] | |||||
| public int Groups { get; set; } = 1; | public int Groups { get; set; } = 1; | ||||
| public Activation Activation { get; set; } | public Activation Activation { get; set; } | ||||
| private string _activationName; | |||||
| [JsonProperty("activation")] | |||||
| public string ActivationName | |||||
| { | |||||
| get | |||||
| { | |||||
| if (string.IsNullOrEmpty(_activationName)) | |||||
| { | |||||
| return Activation.Method.Name; | |||||
| } | |||||
| else | |||||
| { | |||||
| return _activationName; | |||||
| } | |||||
| } | |||||
| set | |||||
| { | |||||
| _activationName = value; | |||||
| } | |||||
| } | |||||
| [JsonProperty("use_bias")] | |||||
| public bool UseBias { get; set; } | public bool UseBias { get; set; } | ||||
| [JsonProperty("kernel_initializer")] | |||||
| public IInitializer KernelInitializer { get; set; } = tf.glorot_uniform_initializer; | public IInitializer KernelInitializer { get; set; } = tf.glorot_uniform_initializer; | ||||
| [JsonProperty("bias_initializer")] | |||||
| public IInitializer BiasInitializer { get; set; } = tf.zeros_initializer; | public IInitializer BiasInitializer { get; set; } = tf.zeros_initializer; | ||||
| [JsonProperty("kernel_regularizer")] | |||||
| public IRegularizer KernelRegularizer { get; set; } | public IRegularizer KernelRegularizer { get; set; } | ||||
| [JsonProperty("bias_regularizer")] | |||||
| public IRegularizer BiasRegularizer { get; set; } | public IRegularizer BiasRegularizer { get; set; } | ||||
| [JsonProperty("kernel_constraint")] | |||||
| public Action KernelConstraint { get; set; } | public Action KernelConstraint { get; set; } | ||||
| [JsonProperty("bias_constraint")] | |||||
| public Action BiasConstraint { get; set; } | public Action BiasConstraint { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,9 +1,10 @@ | |||||
| using Newtonsoft.Json; | |||||
| using System; | using System; | ||||
| using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| namespace Tensorflow.Keras.ArgsDefinition.Core | |||||
| { | { | ||||
| public class EinsumDenseArgs : LayerArgs | |||||
| public class EinsumDenseArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// An equation describing the einsum to perform. This equation must | /// An equation describing the einsum to perform. This equation must | ||||
| @@ -11,6 +12,7 @@ namespace Tensorflow.Keras.ArgsDefinition | |||||
| /// `ab...,bc->ac...` where 'ab', 'bc', and 'ac' can be any valid einsum axis | /// `ab...,bc->ac...` where 'ab', 'bc', and 'ac' can be any valid einsum axis | ||||
| /// expression sequence. | /// expression sequence. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("equation")] | |||||
| public string Equation { get; set; } | public string Equation { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -19,6 +21,7 @@ namespace Tensorflow.Keras.ArgsDefinition | |||||
| /// None for any dimension that is unknown or can be inferred from the input | /// None for any dimension that is unknown or can be inferred from the input | ||||
| /// shape. | /// shape. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("output_shape")] | |||||
| public Shape OutputShape { get; set; } | public Shape OutputShape { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -26,41 +29,70 @@ namespace Tensorflow.Keras.ArgsDefinition | |||||
| /// Each character in the `bias_axes` string should correspond to a character | /// Each character in the `bias_axes` string should correspond to a character | ||||
| /// in the output portion of the `equation` string. | /// in the output portion of the `equation` string. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("bias_axes")] | |||||
| public string BiasAxes { get; set; } = null; | public string BiasAxes { get; set; } = null; | ||||
| /// <summary> | /// <summary> | ||||
| /// Activation function to use. | /// Activation function to use. | ||||
| /// </summary> | /// </summary> | ||||
| public Activation Activation { get; set; } | public Activation Activation { get; set; } | ||||
| private string _activationName; | |||||
| [JsonProperty("activation")] | |||||
| public string ActivationName | |||||
| { | |||||
| get | |||||
| { | |||||
| if (string.IsNullOrEmpty(_activationName)) | |||||
| { | |||||
| return Activation.Method.Name; | |||||
| } | |||||
| else | |||||
| { | |||||
| return _activationName; | |||||
| } | |||||
| } | |||||
| set | |||||
| { | |||||
| _activationName = value; | |||||
| } | |||||
| } | |||||
| /// <summary> | /// <summary> | ||||
| /// Initializer for the `kernel` weights matrix. | /// Initializer for the `kernel` weights matrix. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("kernel_initializer")] | |||||
| public IInitializer KernelInitializer { get; set; } = tf.glorot_uniform_initializer; | public IInitializer KernelInitializer { get; set; } = tf.glorot_uniform_initializer; | ||||
| /// <summary> | /// <summary> | ||||
| /// Initializer for the bias vector. | /// Initializer for the bias vector. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("bias_initializer")] | |||||
| public IInitializer BiasInitializer { get; set; } = tf.zeros_initializer; | public IInitializer BiasInitializer { get; set; } = tf.zeros_initializer; | ||||
| /// <summary> | /// <summary> | ||||
| /// Regularizer function applied to the `kernel` weights matrix. | /// Regularizer function applied to the `kernel` weights matrix. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("kernel_regularizer")] | |||||
| public IRegularizer KernelRegularizer { get; set; } | public IRegularizer KernelRegularizer { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| /// Regularizer function applied to the bias vector. | /// Regularizer function applied to the bias vector. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("bias_regularizer")] | |||||
| public IRegularizer BiasRegularizer { get; set; } | public IRegularizer BiasRegularizer { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| /// Constraint function applied to the `kernel` weights matrix. | /// Constraint function applied to the `kernel` weights matrix. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("kernel_constraint")] | |||||
| public Action KernelConstraint { get; set; } | public Action KernelConstraint { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| /// Constraint function applied to the bias vector. | /// Constraint function applied to the bias vector. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("bias_constraint")] | |||||
| public Action BiasConstraint { get; set; } | public Action BiasConstraint { get; set; } | ||||
| [JsonProperty("activity_regularizer")] | |||||
| public override IRegularizer ActivityRegularizer { get => base.ActivityRegularizer; set => base.ActivityRegularizer = value; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,11 +1,22 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | { | ||||
| public class EmbeddingArgs : LayerArgs | |||||
| public class EmbeddingArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| [JsonProperty("input_dim")] | |||||
| public int InputDim { get; set; } | public int InputDim { get; set; } | ||||
| [JsonProperty("output_dim")] | |||||
| public int OutputDim { get; set; } | public int OutputDim { get; set; } | ||||
| [JsonProperty("mask_zero")] | |||||
| public bool MaskZero { get; set; } | public bool MaskZero { get; set; } | ||||
| [JsonProperty("input_length")] | |||||
| public int InputLength { get; set; } = -1; | public int InputLength { get; set; } = -1; | ||||
| [JsonProperty("embeddings_initializer")] | |||||
| public IInitializer EmbeddingsInitializer { get; set; } | public IInitializer EmbeddingsInitializer { get; set; } | ||||
| [JsonProperty("activity_regularizer")] | |||||
| public override IRegularizer ActivityRegularizer { get => base.ActivityRegularizer; set => base.ActivityRegularizer = value; } | |||||
| // TODO: `embeddings_regularizer`, `embeddings_constraint`. | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,16 +0,0 @@ | |||||
| using Tensorflow.NumPy; | |||||
| namespace Tensorflow.Keras.ArgsDefinition { | |||||
| public class Cropping2DArgs : LayerArgs { | |||||
| /// <summary> | |||||
| /// channel last: (b, h, w, c) | |||||
| /// channels_first: (b, c, h, w) | |||||
| /// </summary> | |||||
| public enum DataFormat { channels_first = 0, channels_last = 1 } | |||||
| /// <summary> | |||||
| /// Accept: int[1][2], int[1][1], int[2][2] | |||||
| /// </summary> | |||||
| public NDArray cropping { get; set; } | |||||
| public DataFormat data_format { get; set; } = DataFormat.channels_last; | |||||
| } | |||||
| } | |||||
| @@ -1,16 +0,0 @@ | |||||
| using Tensorflow.NumPy; | |||||
| namespace Tensorflow.Keras.ArgsDefinition { | |||||
| public class Cropping3DArgs : LayerArgs { | |||||
| /// <summary> | |||||
| /// channel last: (b, h, w, c) | |||||
| /// channels_first: (b, c, h, w) | |||||
| /// </summary> | |||||
| public enum DataFormat { channels_first = 0, channels_last = 1 } | |||||
| /// <summary> | |||||
| /// Accept: int[1][3], int[1][1], int[3][2] | |||||
| /// </summary> | |||||
| public NDArray cropping { get; set; } | |||||
| public DataFormat data_format { get; set; } = DataFormat.channels_last; | |||||
| } | |||||
| } | |||||
| @@ -1,10 +0,0 @@ | |||||
| using Tensorflow.NumPy; | |||||
| namespace Tensorflow.Keras.ArgsDefinition { | |||||
| public class CroppingArgs : LayerArgs { | |||||
| /// <summary> | |||||
| /// Accept length 1 or 2 | |||||
| /// </summary> | |||||
| public NDArray cropping { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -1,6 +0,0 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition.Lstm | |||||
| { | |||||
| public class LSTMCellArgs : LayerArgs | |||||
| { | |||||
| } | |||||
| } | |||||
| @@ -4,6 +4,7 @@ using System.Text; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| // TODO: complete the implementation | |||||
| public class MergeArgs : LayerArgs | public class MergeArgs : LayerArgs | ||||
| { | { | ||||
| public Tensors Inputs { get; set; } | public Tensors Inputs { get; set; } | ||||
| @@ -1,21 +1,37 @@ | |||||
| using static Tensorflow.Binding; | |||||
| using Newtonsoft.Json; | |||||
| using static Tensorflow.Binding; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| public class BatchNormalizationArgs : LayerArgs | |||||
| public class BatchNormalizationArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| [JsonProperty("axis")] | |||||
| public Shape Axis { get; set; } = -1; | public Shape Axis { get; set; } = -1; | ||||
| [JsonProperty("momentum")] | |||||
| public float Momentum { get; set; } = 0.99f; | public float Momentum { get; set; } = 0.99f; | ||||
| [JsonProperty("epsilon")] | |||||
| public float Epsilon { get; set; } = 1e-3f; | public float Epsilon { get; set; } = 1e-3f; | ||||
| [JsonProperty("center")] | |||||
| public bool Center { get; set; } = true; | public bool Center { get; set; } = true; | ||||
| [JsonProperty("scale")] | |||||
| public bool Scale { get; set; } = true; | public bool Scale { get; set; } = true; | ||||
| [JsonProperty("beta_initializer")] | |||||
| public IInitializer BetaInitializer { get; set; } = tf.zeros_initializer; | public IInitializer BetaInitializer { get; set; } = tf.zeros_initializer; | ||||
| [JsonProperty("gamma_initializer")] | |||||
| public IInitializer GammaInitializer { get; set; } = tf.ones_initializer; | public IInitializer GammaInitializer { get; set; } = tf.ones_initializer; | ||||
| [JsonProperty("moving_mean_initializer")] | |||||
| public IInitializer MovingMeanInitializer { get; set; } = tf.zeros_initializer; | public IInitializer MovingMeanInitializer { get; set; } = tf.zeros_initializer; | ||||
| [JsonProperty("moving_variance_initializer")] | |||||
| public IInitializer MovingVarianceInitializer { get; set; } = tf.ones_initializer; | public IInitializer MovingVarianceInitializer { get; set; } = tf.ones_initializer; | ||||
| [JsonProperty("beta_regularizer")] | |||||
| public IRegularizer BetaRegularizer { get; set; } | public IRegularizer BetaRegularizer { get; set; } | ||||
| [JsonProperty("gamma_regularizer")] | |||||
| public IRegularizer GammaRegularizer { get; set; } | public IRegularizer GammaRegularizer { get; set; } | ||||
| // TODO: `beta_constraint` and `gamma_constraint`. | |||||
| [JsonProperty("renorm")] | |||||
| public bool Renorm { get; set; } | public bool Renorm { get; set; } | ||||
| // TODO: `renorm_clipping` and `virtual_batch_size`. | |||||
| [JsonProperty("renorm_momentum")] | |||||
| public float RenormMomentum { get; set; } = 0.99f; | public float RenormMomentum { get; set; } = 0.99f; | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,16 +1,27 @@ | |||||
| using static Tensorflow.Binding; | |||||
| using Newtonsoft.Json; | |||||
| using static Tensorflow.Binding; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| public class LayerNormalizationArgs : LayerArgs | |||||
| public class LayerNormalizationArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| [JsonProperty("axis")] | |||||
| public Axis Axis { get; set; } = -1; | public Axis Axis { get; set; } = -1; | ||||
| [JsonProperty("epsilon")] | |||||
| public float Epsilon { get; set; } = 1e-3f; | public float Epsilon { get; set; } = 1e-3f; | ||||
| [JsonProperty("center")] | |||||
| public bool Center { get; set; } = true; | public bool Center { get; set; } = true; | ||||
| [JsonProperty("scale")] | |||||
| public bool Scale { get; set; } = true; | public bool Scale { get; set; } = true; | ||||
| [JsonProperty("beta_initializer")] | |||||
| public IInitializer BetaInitializer { get; set; } = tf.zeros_initializer; | public IInitializer BetaInitializer { get; set; } = tf.zeros_initializer; | ||||
| [JsonProperty("gamma_initializer")] | |||||
| public IInitializer GammaInitializer { get; set; } = tf.ones_initializer; | public IInitializer GammaInitializer { get; set; } = tf.ones_initializer; | ||||
| [JsonProperty("beta_regularizer")] | |||||
| public IRegularizer BetaRegularizer { get; set; } | public IRegularizer BetaRegularizer { get; set; } | ||||
| [JsonProperty("gamma_regularizer")] | |||||
| public IRegularizer GammaRegularizer { get; set; } | public IRegularizer GammaRegularizer { get; set; } | ||||
| // TODO: `beta_constraint` and `gamma_constraint`. | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,6 +1,8 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | { | ||||
| public class Pooling1DArgs : LayerArgs | |||||
| public class Pooling1DArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// The pooling function to apply, e.g. `tf.nn.max_pool2d`. | /// The pooling function to apply, e.g. `tf.nn.max_pool2d`. | ||||
| @@ -10,11 +12,13 @@ | |||||
| /// <summary> | /// <summary> | ||||
| /// specifying the size of the pooling window. | /// specifying the size of the pooling window. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("pool_size")] | |||||
| public int PoolSize { get; set; } | public int PoolSize { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| /// specifying the strides of the pooling operation. | /// specifying the strides of the pooling operation. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("strides")] | |||||
| public int Strides { | public int Strides { | ||||
| get { return _strides.HasValue ? _strides.Value : PoolSize; } | get { return _strides.HasValue ? _strides.Value : PoolSize; } | ||||
| set { _strides = value; } | set { _strides = value; } | ||||
| @@ -24,11 +28,13 @@ | |||||
| /// <summary> | /// <summary> | ||||
| /// The padding method, either 'valid' or 'same'. | /// The padding method, either 'valid' or 'same'. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("padding")] | |||||
| public string Padding { get; set; } = "valid"; | public string Padding { get; set; } = "valid"; | ||||
| /// <summary> | /// <summary> | ||||
| /// one of `channels_last` (default) or `channels_first`. | /// one of `channels_last` (default) or `channels_first`. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("data_format")] | |||||
| public string DataFormat { get; set; } | public string DataFormat { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,6 +1,8 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | { | ||||
| public class Pooling2DArgs : LayerArgs | |||||
| public class Pooling2DArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// The pooling function to apply, e.g. `tf.nn.max_pool2d`. | /// The pooling function to apply, e.g. `tf.nn.max_pool2d`. | ||||
| @@ -10,21 +12,25 @@ | |||||
| /// <summary> | /// <summary> | ||||
| /// specifying the size of the pooling window. | /// specifying the size of the pooling window. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("pool_size")] | |||||
| public Shape PoolSize { get; set; } | public Shape PoolSize { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| /// specifying the strides of the pooling operation. | /// specifying the strides of the pooling operation. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("strides")] | |||||
| public Shape Strides { get; set; } | public Shape Strides { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| /// The padding method, either 'valid' or 'same'. | /// The padding method, either 'valid' or 'same'. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("padding")] | |||||
| public string Padding { get; set; } = "valid"; | public string Padding { get; set; } = "valid"; | ||||
| /// <summary> | /// <summary> | ||||
| /// one of `channels_last` (default) or `channels_first`. | /// one of `channels_last` (default) or `channels_first`. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("data_format")] | |||||
| public string DataFormat { get; set; } | public string DataFormat { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -4,7 +4,7 @@ using System.Text; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| public class PreprocessingLayerArgs : LayerArgs | |||||
| public class PreprocessingLayerArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,12 @@ | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | |||||
| public class RescalingArgs : AutoSerializeLayerArgs | |||||
| { | |||||
| [JsonProperty("scale")] | |||||
| public float Scale { get; set; } | |||||
| [JsonProperty("offset")] | |||||
| public float Offset { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,6 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| // TODO: no corresponding class found in keras python, maybe obselete? | |||||
| public class ResizingArgs : PreprocessingLayerArgs | public class ResizingArgs : PreprocessingLayerArgs | ||||
| { | { | ||||
| public int Height { get; set; } | public int Height { get; set; } | ||||
| @@ -1,4 +1,5 @@ | |||||
| using System; | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Text; | using System.Text; | ||||
| @@ -6,11 +7,19 @@ namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | { | ||||
| public class TextVectorizationArgs : PreprocessingLayerArgs | public class TextVectorizationArgs : PreprocessingLayerArgs | ||||
| { | { | ||||
| [JsonProperty("standardize")] | |||||
| public Func<Tensor, Tensor> Standardize { get; set; } | public Func<Tensor, Tensor> Standardize { get; set; } | ||||
| [JsonProperty("split")] | |||||
| public string Split { get; set; } = "standardize"; | public string Split { get; set; } = "standardize"; | ||||
| [JsonProperty("max_tokens")] | |||||
| public int MaxTokens { get; set; } = -1; | public int MaxTokens { get; set; } = -1; | ||||
| [JsonProperty("output_mode")] | |||||
| public string OutputMode { get; set; } = "int"; | public string OutputMode { get; set; } = "int"; | ||||
| [JsonProperty("output_sequence_length")] | |||||
| public int OutputSequenceLength { get; set; } = -1; | public int OutputSequenceLength { get; set; } = -1; | ||||
| [JsonProperty("vocabulary")] | |||||
| public string[] Vocabulary { get; set; } | public string[] Vocabulary { get; set; } | ||||
| // TODO: Add `ngrams`, `sparse`, `ragged`, `idf_weights`, `encoding` | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,21 +1,26 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | { | ||||
| public class DropoutArgs : LayerArgs | |||||
| public class DropoutArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Float between 0 and 1. Fraction of the input units to drop. | /// Float between 0 and 1. Fraction of the input units to drop. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("rate")] | |||||
| public float Rate { get; set; } | public float Rate { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| /// 1D integer tensor representing the shape of the | /// 1D integer tensor representing the shape of the | ||||
| /// binary dropout mask that will be multiplied with the input. | /// binary dropout mask that will be multiplied with the input. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("noise_shape")] | |||||
| public Shape NoiseShape { get; set; } | public Shape NoiseShape { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| /// random seed. | /// random seed. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("seed")] | |||||
| public int? Seed { get; set; } | public int? Seed { get; set; } | ||||
| public bool SupportsMasking { get; set; } | public bool SupportsMasking { get; set; } | ||||
| @@ -1,8 +0,0 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | |||||
| public class RescalingArgs : LayerArgs | |||||
| { | |||||
| public float Scale { get; set; } | |||||
| public float Offset { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,18 @@ | |||||
| using Tensorflow.NumPy; | |||||
| namespace Tensorflow.Keras.ArgsDefinition.Reshaping | |||||
| { | |||||
| public class Cropping2DArgs : LayerArgs | |||||
| { | |||||
| /// <summary> | |||||
| /// channel last: (b, h, w, c) | |||||
| /// channels_first: (b, c, h, w) | |||||
| /// </summary> | |||||
| public enum DataFormat { channels_first = 0, channels_last = 1 } | |||||
| /// <summary> | |||||
| /// Accept: int[1][2], int[1][1], int[2][2] | |||||
| /// </summary> | |||||
| public NDArray cropping { get; set; } | |||||
| public DataFormat data_format { get; set; } = DataFormat.channels_last; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,18 @@ | |||||
| using Tensorflow.NumPy; | |||||
| namespace Tensorflow.Keras.ArgsDefinition.Reshaping | |||||
| { | |||||
| public class Cropping3DArgs : LayerArgs | |||||
| { | |||||
| /// <summary> | |||||
| /// channel last: (b, h, w, c) | |||||
| /// channels_first: (b, c, h, w) | |||||
| /// </summary> | |||||
| public enum DataFormat { channels_first = 0, channels_last = 1 } | |||||
| /// <summary> | |||||
| /// Accept: int[1][3], int[1][1], int[3][2] | |||||
| /// </summary> | |||||
| public NDArray cropping { get; set; } | |||||
| public DataFormat data_format { get; set; } = DataFormat.channels_last; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| using Tensorflow.NumPy; | |||||
| namespace Tensorflow.Keras.ArgsDefinition.Reshaping | |||||
| { | |||||
| public class Cropping1DArgs : LayerArgs | |||||
| { | |||||
| /// <summary> | |||||
| /// Accept length 1 or 2 | |||||
| /// </summary> | |||||
| public NDArray cropping { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,9 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition { | |||||
| public class PermuteArgs : LayerArgs { | |||||
| public int[] dims { get; set; } | |||||
| } | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition { | |||||
| public class PermuteArgs : AutoSerializeLayerArgs | |||||
| { | |||||
| [JsonProperty("dims")] | |||||
| public int[] dims { get; set; } | |||||
| } | |||||
| } | } | ||||
| @@ -1,7 +1,10 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | { | ||||
| public class ReshapeArgs : LayerArgs | |||||
| public class ReshapeArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| [JsonProperty("target_shape")] | |||||
| public Shape TargetShape { get; set; } | public Shape TargetShape { get; set; } | ||||
| public object[] TargetShapeObjects { get; set; } | public object[] TargetShapeObjects { get; set; } | ||||
| } | } | ||||
| @@ -1,12 +1,17 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| using Newtonsoft.Json; | |||||
| namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | { | ||||
| public class UpSampling2DArgs : LayerArgs | |||||
| public class UpSampling2DArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| [JsonProperty("size")] | |||||
| public Shape Size { get; set; } | public Shape Size { get; set; } | ||||
| [JsonProperty("data_format")] | |||||
| public string DataFormat { get; set; } | public string DataFormat { get; set; } | ||||
| /// <summary> | /// <summary> | ||||
| /// 'nearest', 'bilinear' | /// 'nearest', 'bilinear' | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("interpolation")] | |||||
| public string Interpolation { get; set; } = "nearest"; | public string Interpolation { get; set; } = "nearest"; | ||||
| } | } | ||||
| } | } | ||||
| @@ -2,6 +2,7 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition | namespace Tensorflow.Keras.ArgsDefinition | ||||
| { | { | ||||
| // TODO: complete the implementation | |||||
| public class ZeroPadding2DArgs : LayerArgs | public class ZeroPadding2DArgs : LayerArgs | ||||
| { | { | ||||
| public NDArray Padding { get; set; } | public NDArray Padding { get; set; } | ||||
| @@ -1,9 +1,8 @@ | |||||
| using Tensorflow.Keras.ArgsDefinition.Rnn; | |||||
| namespace Tensorflow.Keras.ArgsDefinition.Lstm | |||||
| namespace Tensorflow.Keras.ArgsDefinition.Rnn | |||||
| { | { | ||||
| public class LSTMArgs : RNNArgs | public class LSTMArgs : RNNArgs | ||||
| { | { | ||||
| // TODO: maybe change the `RNNArgs` and implement this class. | |||||
| public bool UnitForgetBias { get; set; } | public bool UnitForgetBias { get; set; } | ||||
| public float Dropout { get; set; } | public float Dropout { get; set; } | ||||
| public float RecurrentDropout { get; set; } | public float RecurrentDropout { get; set; } | ||||
| @@ -0,0 +1,7 @@ | |||||
| namespace Tensorflow.Keras.ArgsDefinition.Rnn | |||||
| { | |||||
| // TODO: complete the implementation | |||||
| public class LSTMCellArgs : LayerArgs | |||||
| { | |||||
| } | |||||
| } | |||||
| @@ -1,21 +1,30 @@ | |||||
| using System.Collections.Generic; | |||||
| using Newtonsoft.Json; | |||||
| using System.Collections.Generic; | |||||
| namespace Tensorflow.Keras.ArgsDefinition.Rnn | namespace Tensorflow.Keras.ArgsDefinition.Rnn | ||||
| { | { | ||||
| public class RNNArgs : LayerArgs | |||||
| public class RNNArgs : AutoSerializeLayerArgs | |||||
| { | { | ||||
| public interface IRnnArgCell : ILayer | public interface IRnnArgCell : ILayer | ||||
| { | { | ||||
| object state_size { get; } | object state_size { get; } | ||||
| } | } | ||||
| [JsonProperty("cell")] | |||||
| // TODO: the cell should be serialized with `serialize_keras_object`. | |||||
| public IRnnArgCell Cell { get; set; } = null; | public IRnnArgCell Cell { get; set; } = null; | ||||
| [JsonProperty("return_sequences")] | |||||
| public bool ReturnSequences { get; set; } = false; | public bool ReturnSequences { get; set; } = false; | ||||
| [JsonProperty("return_state")] | |||||
| public bool ReturnState { get; set; } = false; | public bool ReturnState { get; set; } = false; | ||||
| [JsonProperty("go_backwards")] | |||||
| public bool GoBackwards { get; set; } = false; | public bool GoBackwards { get; set; } = false; | ||||
| [JsonProperty("stateful")] | |||||
| public bool Stateful { get; set; } = false; | public bool Stateful { get; set; } = false; | ||||
| [JsonProperty("unroll")] | |||||
| public bool Unroll { get; set; } = false; | public bool Unroll { get; set; } = false; | ||||
| [JsonProperty("time_major")] | |||||
| public bool TimeMajor { get; set; } = false; | public bool TimeMajor { get; set; } = false; | ||||
| // TODO: Add `num_constants` and `zero_output_for_mask`. | |||||
| public Dictionary<string, object> Kwargs { get; set; } = null; | public Dictionary<string, object> Kwargs { get; set; } = null; | ||||
| public int Units { get; set; } | public int Units { get; set; } | ||||
| @@ -1,5 +1,5 @@ | |||||
| using System; | using System; | ||||
| using Tensorflow.Keras.ArgsDefinition; | |||||
| using Tensorflow.Keras.ArgsDefinition.Reshaping; | |||||
| using Tensorflow.NumPy; | using Tensorflow.NumPy; | ||||
| namespace Tensorflow.Keras.Layers | namespace Tensorflow.Keras.Layers | ||||
| @@ -0,0 +1,82 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| using Tensorflow.Operations.Activation; | |||||
| using static Tensorflow.Binding; | |||||
| namespace Tensorflow.Keras | |||||
| { | |||||
| public class Activations | |||||
| { | |||||
| private static Dictionary<string, Activation> _nameActivationMap; | |||||
| private static Dictionary<Activation, string> _activationNameMap; | |||||
| private static Activation _linear = (features, name) => features; | |||||
| private static Activation _relu = (features, name) | |||||
| => tf.Context.ExecuteOp("Relu", name, new ExecuteOpArgs(features)); | |||||
| private static Activation _sigmoid = (features, name) | |||||
| => tf.Context.ExecuteOp("Sigmoid", name, new ExecuteOpArgs(features)); | |||||
| private static Activation _softmax = (features, name) | |||||
| => tf.Context.ExecuteOp("Softmax", name, new ExecuteOpArgs(features)); | |||||
| private static Activation _tanh = (features, name) | |||||
| => tf.Context.ExecuteOp("Tanh", name, new ExecuteOpArgs(features)); | |||||
| /// <summary> | |||||
| /// Register the name-activation mapping in this static class. | |||||
| /// </summary> | |||||
| /// <param name="name"></param> | |||||
| /// <param name="Activation"></param> | |||||
| private static void RegisterActivation(string name, Activation activation) | |||||
| { | |||||
| _nameActivationMap[name] = activation; | |||||
| _activationNameMap[activation] = name; | |||||
| } | |||||
| static Activations() | |||||
| { | |||||
| _nameActivationMap = new Dictionary<string, Activation>(); | |||||
| _activationNameMap= new Dictionary<Activation, string>(); | |||||
| RegisterActivation("relu", _relu); | |||||
| RegisterActivation("linear", _linear); | |||||
| RegisterActivation("sigmoid", _sigmoid); | |||||
| RegisterActivation("softmax", _softmax); | |||||
| RegisterActivation("tanh", _tanh); | |||||
| } | |||||
| public Activation Linear => _linear; | |||||
| public Activation Relu => _relu; | |||||
| public Activation Sigmoid => _sigmoid; | |||||
| public Activation Softmax => _softmax; | |||||
| public Activation Tanh => _tanh; | |||||
| public static Activation GetActivationByName(string name) | |||||
| { | |||||
| if (!_nameActivationMap.TryGetValue(name, out var res)) | |||||
| { | |||||
| throw new Exception($"Activation {name} not found"); | |||||
| } | |||||
| else | |||||
| { | |||||
| return res; | |||||
| } | |||||
| } | |||||
| public static string GetNameByActivation(Activation activation) | |||||
| { | |||||
| if(!_activationNameMap.TryGetValue(activation, out var name)) | |||||
| { | |||||
| throw new Exception($"Activation {activation} not found"); | |||||
| } | |||||
| else | |||||
| { | |||||
| return name; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,10 +0,0 @@ | |||||
| namespace Tensorflow.Keras | |||||
| { | |||||
| public partial class Activations | |||||
| { | |||||
| /// <summary> | |||||
| /// Linear activation function (pass-through). | |||||
| /// </summary> | |||||
| public Activation Linear = (features, name) => features; | |||||
| } | |||||
| } | |||||
| @@ -1,10 +0,0 @@ | |||||
| using static Tensorflow.Binding; | |||||
| namespace Tensorflow.Keras | |||||
| { | |||||
| public partial class Activations | |||||
| { | |||||
| public Activation Relu = (features, name) | |||||
| => tf.Context.ExecuteOp("Relu", name, new ExecuteOpArgs(features)); | |||||
| } | |||||
| } | |||||
| @@ -1,11 +0,0 @@ | |||||
| using System; | |||||
| using static Tensorflow.Binding; | |||||
| namespace Tensorflow.Keras | |||||
| { | |||||
| public partial class Activations | |||||
| { | |||||
| public Activation Sigmoid = (features, name) | |||||
| => tf.Context.ExecuteOp("Sigmoid", name, new ExecuteOpArgs(features)); | |||||
| } | |||||
| } | |||||
| @@ -1,11 +0,0 @@ | |||||
| using System; | |||||
| using static Tensorflow.Binding; | |||||
| namespace Tensorflow.Keras | |||||
| { | |||||
| public partial class Activations | |||||
| { | |||||
| public Activation Softmax = (features, name) | |||||
| => tf.Context.ExecuteOp("Softmax", name, new ExecuteOpArgs(features)); | |||||
| } | |||||
| } | |||||
| @@ -1,11 +0,0 @@ | |||||
| using System; | |||||
| using static Tensorflow.Binding; | |||||
| namespace Tensorflow.Keras | |||||
| { | |||||
| public partial class Activations | |||||
| { | |||||
| public Activation Tanh = (features, name) | |||||
| => tf.Context.ExecuteOp("Tanh", name, new ExecuteOpArgs(features)); | |||||
| } | |||||
| } | |||||
| @@ -1,4 +1,5 @@ | |||||
| using Tensorflow.Keras.ArgsDefinition; | using Tensorflow.Keras.ArgsDefinition; | ||||
| using Tensorflow.Keras.ArgsDefinition.Core; | |||||
| using Tensorflow.Keras.Engine; | using Tensorflow.Keras.Engine; | ||||
| using Tensorflow.NumPy; | using Tensorflow.NumPy; | ||||
| using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
| @@ -4,8 +4,8 @@ using System.Collections; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Linq; | using System.Linq; | ||||
| using System.Text.RegularExpressions; | using System.Text.RegularExpressions; | ||||
| using Tensorflow.Keras.ArgsDefinition; | |||||
| using Tensorflow.Keras.Engine; | using Tensorflow.Keras.Engine; | ||||
| using Tensorflow.Keras.ArgsDefinition.Core; | |||||
| namespace Tensorflow.Keras.Layers | namespace Tensorflow.Keras.Layers | ||||
| { | { | ||||
| @@ -1,114 +0,0 @@ | |||||
| using Tensorflow.Keras.ArgsDefinition; | |||||
| using Tensorflow.Keras.Engine; | |||||
| namespace Tensorflow.Keras.Layers { | |||||
| /// <summary> | |||||
| /// Crop the input along axis 1 and 2. | |||||
| /// <para> For example: </para> | |||||
| /// <para> shape (1, 5, 5, 5) -- crop2D ((1, 2), (1, 3)) --> shape (1, 2, 1, 5) </para> | |||||
| /// </summary> | |||||
| public class Cropping2D : Layer { | |||||
| Cropping2DArgs args; | |||||
| public Cropping2D ( Cropping2DArgs args ) : base(args) { | |||||
| this.args = args; | |||||
| } | |||||
| public override void build(Shape input_shape) { | |||||
| built = true; | |||||
| _buildInputShape = input_shape; | |||||
| } | |||||
| protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||||
| Tensor output = inputs; | |||||
| if ( output.rank != 4 ) { | |||||
| // throw an ValueError exception | |||||
| throw new ValueError("Expected dim=4, found dim=" + output.rank); | |||||
| } | |||||
| if ( args.cropping.shape == new Shape(1) ) { | |||||
| int crop = args.cropping[0]; | |||||
| if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||||
| output = output[new Slice(), | |||||
| new Slice(crop, ( int ) output.shape[1] - crop), | |||||
| new Slice(crop, ( int ) output.shape[2] - crop), | |||||
| new Slice()]; | |||||
| } | |||||
| else { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(crop, ( int ) output.shape[2] - crop), | |||||
| new Slice(crop, ( int ) output.shape[3] - crop)]; | |||||
| } | |||||
| } | |||||
| // a tuple of 2 integers | |||||
| else if ( args.cropping.shape == new Shape(2) ) { | |||||
| int crop_1 = args.cropping[0]; | |||||
| int crop_2 = args.cropping[1]; | |||||
| if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||||
| output = output[new Slice(), | |||||
| new Slice(crop_1, ( int ) output.shape[1] - crop_1), | |||||
| new Slice(crop_2, ( int ) output.shape[2] - crop_2), | |||||
| new Slice()]; | |||||
| } | |||||
| else { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(crop_1, ( int ) output.shape[2] - crop_1), | |||||
| new Slice(crop_2, ( int ) output.shape[3] - crop_2)]; | |||||
| } | |||||
| } | |||||
| else if ( args.cropping.shape[0] == 2 && args.cropping.shape[1] == 2 ) { | |||||
| int x_start = args.cropping[0, 0], x_end = args.cropping[0, 1]; | |||||
| int y_start = args.cropping[1, 0], y_end = args.cropping[1, 1]; | |||||
| if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||||
| output = output[new Slice(), | |||||
| new Slice(x_start, ( int ) output.shape[1] - x_end), | |||||
| new Slice(y_start, ( int ) output.shape[2] - y_end), | |||||
| new Slice()]; | |||||
| } | |||||
| else { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(x_start, ( int ) output.shape[2] - x_end), | |||||
| new Slice(y_start, ( int ) output.shape[3] - y_end) | |||||
| ]; | |||||
| } | |||||
| } | |||||
| return output; | |||||
| } | |||||
| public override Shape ComputeOutputShape ( Shape input_shape ) { | |||||
| if ( args.cropping.shape == new Shape(1) ) { | |||||
| int crop = args.cropping[0]; | |||||
| if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop * 2, ( int ) input_shape[2] - crop * 2, ( int ) input_shape[3]); | |||||
| } | |||||
| else { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - crop * 2, ( int ) input_shape[3] - crop * 2); | |||||
| } | |||||
| } | |||||
| // a tuple of 2 integers | |||||
| else if ( args.cropping.shape == new Shape(2) ) { | |||||
| int crop_1 = args.cropping[0], crop_2 = args.cropping[1]; | |||||
| if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop_1 * 2, ( int ) input_shape[2] - crop_2 * 2, ( int ) input_shape[3]); | |||||
| } | |||||
| else { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - crop_1 * 2, ( int ) input_shape[3] - crop_2 * 2); | |||||
| } | |||||
| } | |||||
| else if ( args.cropping.shape == new Shape(2, 2) ) { | |||||
| int crop_1_start = args.cropping[0, 0], crop_1_end = args.cropping[0, 1]; | |||||
| int crop_2_start = args.cropping[1, 0], crop_2_end = args.cropping[1, 1]; | |||||
| if ( args.data_format == Cropping2DArgs.DataFormat.channels_last ) { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop_1_start - crop_1_end, | |||||
| ( int ) input_shape[2] - crop_2_start - crop_2_end, ( int ) input_shape[3]); | |||||
| } | |||||
| else { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1], | |||||
| ( int ) input_shape[2] - crop_1_start - crop_1_end, ( int ) input_shape[3] - crop_2_start - crop_2_end); | |||||
| } | |||||
| } | |||||
| else { | |||||
| throw new ValueError(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,124 +0,0 @@ | |||||
| using Tensorflow.Keras.ArgsDefinition; | |||||
| using Tensorflow.Keras.Engine; | |||||
| namespace Tensorflow.Keras.Layers { | |||||
| /// <summary> | |||||
| /// Similar to copping 2D | |||||
| /// </summary> | |||||
| public class Cropping3D : Layer { | |||||
| Cropping3DArgs args; | |||||
| public Cropping3D ( Cropping3DArgs args ) : base(args) { | |||||
| this.args = args; | |||||
| } | |||||
| public override void build(Shape input_shape) { | |||||
| built = true; | |||||
| _buildInputShape = input_shape; | |||||
| } | |||||
| protected override Tensors Call ( Tensors inputs, Tensor state = null, bool? training = null ) { | |||||
| Tensor output = inputs; | |||||
| if ( output.rank != 5 ) { | |||||
| // throw an ValueError exception | |||||
| throw new ValueError("Expected dim=5, found dim=" + output.rank); | |||||
| } | |||||
| if ( args.cropping.shape == new Shape(1) ) { | |||||
| int crop = args.cropping[0]; | |||||
| if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||||
| output = output[new Slice(), | |||||
| new Slice(crop, ( int ) output.shape[1] - crop), | |||||
| new Slice(crop, ( int ) output.shape[2] - crop), | |||||
| new Slice(crop, ( int ) output.shape[3] - crop), | |||||
| new Slice()]; | |||||
| } | |||||
| else { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(crop, ( int ) output.shape[2] - crop), | |||||
| new Slice(crop, ( int ) output.shape[3] - crop), | |||||
| new Slice(crop, ( int ) output.shape[4] - crop)]; | |||||
| } | |||||
| } | |||||
| // int[1][3] equivalent to a tuple of 3 integers | |||||
| else if ( args.cropping.shape == new Shape(3) ) { | |||||
| var crop_1 = args.cropping[0]; | |||||
| var crop_2 = args.cropping[1]; | |||||
| var crop_3 = args.cropping[2]; | |||||
| if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||||
| output = output[new Slice(), | |||||
| new Slice(crop_1, ( int ) output.shape[1] - crop_1), | |||||
| new Slice(crop_2, ( int ) output.shape[2] - crop_2), | |||||
| new Slice(crop_3, ( int ) output.shape[3] - crop_3), | |||||
| new Slice()]; | |||||
| } | |||||
| else { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(crop_1, ( int ) output.shape[2] - crop_1), | |||||
| new Slice(crop_2, ( int ) output.shape[3] - crop_2), | |||||
| new Slice(crop_3, ( int ) output.shape[4] - crop_3)]; | |||||
| } | |||||
| } | |||||
| else if ( args.cropping.shape[0] == 3 && args.cropping.shape[1] == 2 ) { | |||||
| int x = args.cropping[0, 0], x_end = args.cropping[0, 1]; | |||||
| int y = args.cropping[1, 0], y_end = args.cropping[1, 1]; | |||||
| int z = args.cropping[2, 0], z_end = args.cropping[2, 1]; | |||||
| if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||||
| output = output[new Slice(), | |||||
| new Slice(x, ( int ) output.shape[1] - x_end), | |||||
| new Slice(y, ( int ) output.shape[2] - y_end), | |||||
| new Slice(z, ( int ) output.shape[3] - z_end), | |||||
| new Slice()]; | |||||
| } | |||||
| else { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(x, ( int ) output.shape[2] - x_end), | |||||
| new Slice(y, ( int ) output.shape[3] - y_end), | |||||
| new Slice(z, ( int ) output.shape[4] - z_end) | |||||
| ]; | |||||
| } | |||||
| } | |||||
| return output; | |||||
| } | |||||
| public override Shape ComputeOutputShape ( Shape input_shape ) { | |||||
| if ( args.cropping.shape == new Shape(1) ) { | |||||
| int crop = args.cropping[0]; | |||||
| if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop * 2, ( int ) input_shape[2] - crop * 2, ( int ) input_shape[3] - crop * 2, ( int ) input_shape[4]); | |||||
| } | |||||
| else { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - crop * 2, ( int ) input_shape[3] - crop * 2, ( int ) input_shape[4] - crop * 2); | |||||
| } | |||||
| } | |||||
| // int[1][3] equivalent to a tuple of 3 integers | |||||
| else if ( args.cropping.shape == new Shape(3) ) { | |||||
| var crop_start_1 = args.cropping[0]; | |||||
| var crop_start_2 = args.cropping[1]; | |||||
| var crop_start_3 = args.cropping[2]; | |||||
| if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - crop_start_1 * 2, ( int ) input_shape[2] - crop_start_2 * 2, ( int ) input_shape[3] - crop_start_3 * 2, ( int ) input_shape[4]); | |||||
| } | |||||
| else { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - crop_start_1 * 2, ( int ) input_shape[3] - crop_start_2 * 2, ( int ) input_shape[4] - crop_start_3 * 2); | |||||
| } | |||||
| } | |||||
| else if ( args.cropping.shape == new Shape(3, 2) ) { | |||||
| int x = args.cropping[0, 0], x_end = args.cropping[0, 1]; | |||||
| int y = args.cropping[1, 0], y_end = args.cropping[1, 1]; | |||||
| int z = args.cropping[2, 0], z_end = args.cropping[2, 1]; | |||||
| if ( args.data_format == Cropping3DArgs.DataFormat.channels_last ) { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1] - x - x_end, ( int ) input_shape[2] - y - y_end, ( int ) input_shape[3] - z - z_end, ( int ) input_shape[4]); | |||||
| } | |||||
| else { | |||||
| return new Shape(( int ) input_shape[0], ( int ) input_shape[1], ( int ) input_shape[2] - x - x_end, ( int ) input_shape[3] - y - y_end, ( int ) input_shape[4] - z - z_end); | |||||
| } | |||||
| } | |||||
| else { | |||||
| throw new ValueError(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -2,16 +2,18 @@ | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Text; | using System.Text; | ||||
| using Tensorflow.Keras.ArgsDefinition; | |||||
| using Tensorflow.Keras.Layers.Reshaping; | |||||
| using Tensorflow.Keras.ArgsDefinition.Reshaping; | |||||
| namespace Tensorflow.Keras.Layers { | |||||
| public partial class LayersApi { | |||||
| namespace Tensorflow.Keras.Layers | |||||
| { | |||||
| public partial class LayersApi { | |||||
| /// <summary> | /// <summary> | ||||
| /// Cropping layer for 1D input | /// Cropping layer for 1D input | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="cropping">cropping size</param> | /// <param name="cropping">cropping size</param> | ||||
| public ILayer Cropping1D ( NDArray cropping ) | public ILayer Cropping1D ( NDArray cropping ) | ||||
| => new Cropping1D(new CroppingArgs { | |||||
| => new Cropping1D(new Cropping1DArgs { | |||||
| cropping = cropping | cropping = cropping | ||||
| }); | }); | ||||
| @@ -1,9 +1,8 @@ | |||||
| using System; | using System; | ||||
| using Tensorflow.Keras.ArgsDefinition; | using Tensorflow.Keras.ArgsDefinition; | ||||
| using Tensorflow.Keras.ArgsDefinition.Lstm; | |||||
| using Tensorflow.Keras.ArgsDefinition.Core; | |||||
| using Tensorflow.Keras.ArgsDefinition.Rnn; | using Tensorflow.Keras.ArgsDefinition.Rnn; | ||||
| using Tensorflow.Keras.Engine; | using Tensorflow.Keras.Engine; | ||||
| using Tensorflow.Keras.Layers.Lstm; | |||||
| using Tensorflow.Keras.Layers.Rnn; | using Tensorflow.Keras.Layers.Rnn; | ||||
| using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
| using static Tensorflow.KerasApi; | using static Tensorflow.KerasApi; | ||||
| @@ -108,7 +107,7 @@ namespace Tensorflow.Keras.Layers | |||||
| DilationRate = dilation_rate, | DilationRate = dilation_rate, | ||||
| Groups = groups, | Groups = groups, | ||||
| UseBias = use_bias, | UseBias = use_bias, | ||||
| Activation = GetActivationByName(activation), | |||||
| Activation = Activations.GetActivationByName(activation), | |||||
| KernelInitializer = GetInitializerByName(kernel_initializer), | KernelInitializer = GetInitializerByName(kernel_initializer), | ||||
| BiasInitializer = GetInitializerByName(bias_initializer) | BiasInitializer = GetInitializerByName(bias_initializer) | ||||
| }); | }); | ||||
| @@ -163,7 +162,7 @@ namespace Tensorflow.Keras.Layers | |||||
| BiasInitializer = bias_initializer == null ? tf.zeros_initializer : bias_initializer, | BiasInitializer = bias_initializer == null ? tf.zeros_initializer : bias_initializer, | ||||
| BiasRegularizer = bias_regularizer, | BiasRegularizer = bias_regularizer, | ||||
| ActivityRegularizer = activity_regularizer, | ActivityRegularizer = activity_regularizer, | ||||
| Activation = activation ?? keras.activations.Linear | |||||
| Activation = activation ?? keras.activations.Linear, | |||||
| }); | }); | ||||
| /// <summary> | /// <summary> | ||||
| @@ -210,7 +209,8 @@ namespace Tensorflow.Keras.Layers | |||||
| UseBias = use_bias, | UseBias = use_bias, | ||||
| KernelInitializer = GetInitializerByName(kernel_initializer), | KernelInitializer = GetInitializerByName(kernel_initializer), | ||||
| BiasInitializer = GetInitializerByName(bias_initializer), | BiasInitializer = GetInitializerByName(bias_initializer), | ||||
| Activation = GetActivationByName(activation) | |||||
| Activation = Activations.GetActivationByName(activation), | |||||
| ActivationName = activation | |||||
| }); | }); | ||||
| /// <summary> | /// <summary> | ||||
| @@ -255,7 +255,7 @@ namespace Tensorflow.Keras.Layers | |||||
| UseBias = use_bias, | UseBias = use_bias, | ||||
| KernelInitializer = GetInitializerByName(kernel_initializer), | KernelInitializer = GetInitializerByName(kernel_initializer), | ||||
| BiasInitializer = GetInitializerByName(bias_initializer), | BiasInitializer = GetInitializerByName(bias_initializer), | ||||
| Activation = GetActivationByName(activation) | |||||
| Activation = Activations.GetActivationByName(activation) | |||||
| }); | }); | ||||
| /// <summary> | /// <summary> | ||||
| @@ -300,7 +300,7 @@ namespace Tensorflow.Keras.Layers | |||||
| => new Dense(new DenseArgs | => new Dense(new DenseArgs | ||||
| { | { | ||||
| Units = units, | Units = units, | ||||
| Activation = GetActivationByName("linear"), | |||||
| Activation = Activations.GetActivationByName("linear"), | |||||
| ActivationName = "linear" | ActivationName = "linear" | ||||
| }); | }); | ||||
| @@ -321,7 +321,7 @@ namespace Tensorflow.Keras.Layers | |||||
| => new Dense(new DenseArgs | => new Dense(new DenseArgs | ||||
| { | { | ||||
| Units = units, | Units = units, | ||||
| Activation = GetActivationByName(activation), | |||||
| Activation = Activations.GetActivationByName(activation), | |||||
| ActivationName = activation, | ActivationName = activation, | ||||
| InputShape = input_shape | InputShape = input_shape | ||||
| }); | }); | ||||
| @@ -666,7 +666,7 @@ namespace Tensorflow.Keras.Layers | |||||
| => new SimpleRNN(new SimpleRNNArgs | => new SimpleRNN(new SimpleRNNArgs | ||||
| { | { | ||||
| Units = units, | Units = units, | ||||
| Activation = GetActivationByName(activation), | |||||
| Activation = Activations.GetActivationByName(activation), | |||||
| KernelInitializer = GetInitializerByName(kernel_initializer), | KernelInitializer = GetInitializerByName(kernel_initializer), | ||||
| RecurrentInitializer = GetInitializerByName(recurrent_initializer), | RecurrentInitializer = GetInitializerByName(recurrent_initializer), | ||||
| BiasInitializer = GetInitializerByName(bias_initializer), | BiasInitializer = GetInitializerByName(bias_initializer), | ||||
| @@ -814,24 +814,7 @@ namespace Tensorflow.Keras.Layers | |||||
| public ILayer GlobalMaxPooling2D(string data_format = "channels_last") | public ILayer GlobalMaxPooling2D(string data_format = "channels_last") | ||||
| => new GlobalMaxPooling2D(new Pooling2DArgs { DataFormat = data_format }); | => new GlobalMaxPooling2D(new Pooling2DArgs { DataFormat = data_format }); | ||||
| /// <summary> | |||||
| /// Get an activation function layer from its name. | |||||
| /// </summary> | |||||
| /// <param name="name">The name of the activation function. One of linear, relu, sigmoid, and tanh.</param> | |||||
| /// <returns></returns> | |||||
| Activation GetActivationByName(string name) | |||||
| => name switch | |||||
| { | |||||
| "linear" => keras.activations.Linear, | |||||
| "relu" => keras.activations.Relu, | |||||
| "sigmoid" => keras.activations.Sigmoid, | |||||
| "tanh" => keras.activations.Tanh, | |||||
| "softmax" => keras.activations.Softmax, | |||||
| _ => throw new Exception($"Activation {name} not found") | |||||
| }; | |||||
| Activation GetActivationByName(string name) => Activations.GetActivationByName(name); | |||||
| /// <summary> | /// <summary> | ||||
| /// Get an weights initializer from its name. | /// Get an weights initializer from its name. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -58,7 +58,7 @@ namespace Tensorflow.Keras.Layers | |||||
| var ndims = input_shape.ndim; | var ndims = input_shape.ndim; | ||||
| foreach (var (idx, x) in enumerate(axis)) | foreach (var (idx, x) in enumerate(axis)) | ||||
| if (x < 0) | if (x < 0) | ||||
| axis[idx] = ndims + x; | |||||
| args.Axis.dims[idx] = axis[idx] = ndims + x; | |||||
| fused = ndims == 4; | fused = ndims == 4; | ||||
| @@ -1,11 +1,12 @@ | |||||
| using Tensorflow.Keras.ArgsDefinition; | |||||
| using Tensorflow.Keras.ArgsDefinition.Reshaping; | |||||
| using Tensorflow.Keras.Engine; | using Tensorflow.Keras.Engine; | ||||
| namespace Tensorflow.Keras.Layers { | |||||
| namespace Tensorflow.Keras.Layers.Reshaping | |||||
| { | |||||
| public class Cropping1D : Layer | public class Cropping1D : Layer | ||||
| { | { | ||||
| CroppingArgs args; | |||||
| public Cropping1D(CroppingArgs args) : base(args) | |||||
| Cropping1DArgs args; | |||||
| public Cropping1D(Cropping1DArgs args) : base(args) | |||||
| { | { | ||||
| this.args = args; | this.args = args; | ||||
| } | } | ||||
| @@ -41,7 +42,7 @@ namespace Tensorflow.Keras.Layers { | |||||
| else | else | ||||
| { | { | ||||
| int crop_start = args.cropping[0], crop_end = args.cropping[1]; | int crop_start = args.cropping[0], crop_end = args.cropping[1]; | ||||
| output = output[new Slice(), new Slice(crop_start, (int)(output.shape[1]) - crop_end), new Slice()]; | |||||
| output = output[new Slice(), new Slice(crop_start, (int)output.shape[1] - crop_end), new Slice()]; | |||||
| } | } | ||||
| return output; | return output; | ||||
| } | } | ||||
| @@ -51,12 +52,12 @@ namespace Tensorflow.Keras.Layers { | |||||
| if (args.cropping.shape[0] == 1) | if (args.cropping.shape[0] == 1) | ||||
| { | { | ||||
| int crop = args.cropping[0]; | int crop = args.cropping[0]; | ||||
| return new Shape((int)(input_shape[0]), (int)(input_shape[1] - crop * 2), (int)(input_shape[2])); | |||||
| return new Shape((int)input_shape[0], (int)(input_shape[1] - crop * 2), (int)input_shape[2]); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| int crop_start = args.cropping[0], crop_end = args.cropping[1]; | int crop_start = args.cropping[0], crop_end = args.cropping[1]; | ||||
| return new Shape((int)(input_shape[0]), (int)(input_shape[1] - crop_start - crop_end), (int)(input_shape[2])); | |||||
| return new Shape((int)input_shape[0], (int)(input_shape[1] - crop_start - crop_end), (int)input_shape[2]); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,140 @@ | |||||
| using Tensorflow.Keras.ArgsDefinition.Reshaping; | |||||
| using Tensorflow.Keras.Engine; | |||||
| namespace Tensorflow.Keras.Layers.Reshaping | |||||
| { | |||||
| /// <summary> | |||||
| /// Crop the input along axis 1 and 2. | |||||
| /// <para> For example: </para> | |||||
| /// <para> shape (1, 5, 5, 5) -- crop2D ((1, 2), (1, 3)) --> shape (1, 2, 1, 5) </para> | |||||
| /// </summary> | |||||
| public class Cropping2D : Layer | |||||
| { | |||||
| Cropping2DArgs args; | |||||
| public Cropping2D(Cropping2DArgs args) : base(args) | |||||
| { | |||||
| this.args = args; | |||||
| } | |||||
| public override void build(Shape input_shape) | |||||
| { | |||||
| built = true; | |||||
| _buildInputShape = input_shape; | |||||
| } | |||||
| protected override Tensors Call(Tensors inputs, Tensor state = null, bool? training = null) | |||||
| { | |||||
| Tensor output = inputs; | |||||
| if (output.rank != 4) | |||||
| { | |||||
| // throw an ValueError exception | |||||
| throw new ValueError("Expected dim=4, found dim=" + output.rank); | |||||
| } | |||||
| if (args.cropping.shape == new Shape(1)) | |||||
| { | |||||
| int crop = args.cropping[0]; | |||||
| if (args.data_format == Cropping2DArgs.DataFormat.channels_last) | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(crop, (int)output.shape[1] - crop), | |||||
| new Slice(crop, (int)output.shape[2] - crop), | |||||
| new Slice()]; | |||||
| } | |||||
| else | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(crop, (int)output.shape[2] - crop), | |||||
| new Slice(crop, (int)output.shape[3] - crop)]; | |||||
| } | |||||
| } | |||||
| // a tuple of 2 integers | |||||
| else if (args.cropping.shape == new Shape(2)) | |||||
| { | |||||
| int crop_1 = args.cropping[0]; | |||||
| int crop_2 = args.cropping[1]; | |||||
| if (args.data_format == Cropping2DArgs.DataFormat.channels_last) | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(crop_1, (int)output.shape[1] - crop_1), | |||||
| new Slice(crop_2, (int)output.shape[2] - crop_2), | |||||
| new Slice()]; | |||||
| } | |||||
| else | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(crop_1, (int)output.shape[2] - crop_1), | |||||
| new Slice(crop_2, (int)output.shape[3] - crop_2)]; | |||||
| } | |||||
| } | |||||
| else if (args.cropping.shape[0] == 2 && args.cropping.shape[1] == 2) | |||||
| { | |||||
| int x_start = args.cropping[0, 0], x_end = args.cropping[0, 1]; | |||||
| int y_start = args.cropping[1, 0], y_end = args.cropping[1, 1]; | |||||
| if (args.data_format == Cropping2DArgs.DataFormat.channels_last) | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(x_start, (int)output.shape[1] - x_end), | |||||
| new Slice(y_start, (int)output.shape[2] - y_end), | |||||
| new Slice()]; | |||||
| } | |||||
| else | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(x_start, (int)output.shape[2] - x_end), | |||||
| new Slice(y_start, (int)output.shape[3] - y_end) | |||||
| ]; | |||||
| } | |||||
| } | |||||
| return output; | |||||
| } | |||||
| public override Shape ComputeOutputShape(Shape input_shape) | |||||
| { | |||||
| if (args.cropping.shape == new Shape(1)) | |||||
| { | |||||
| int crop = args.cropping[0]; | |||||
| if (args.data_format == Cropping2DArgs.DataFormat.channels_last) | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1] - crop * 2, (int)input_shape[2] - crop * 2, (int)input_shape[3]); | |||||
| } | |||||
| else | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1], (int)input_shape[2] - crop * 2, (int)input_shape[3] - crop * 2); | |||||
| } | |||||
| } | |||||
| // a tuple of 2 integers | |||||
| else if (args.cropping.shape == new Shape(2)) | |||||
| { | |||||
| int crop_1 = args.cropping[0], crop_2 = args.cropping[1]; | |||||
| if (args.data_format == Cropping2DArgs.DataFormat.channels_last) | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1] - crop_1 * 2, (int)input_shape[2] - crop_2 * 2, (int)input_shape[3]); | |||||
| } | |||||
| else | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1], (int)input_shape[2] - crop_1 * 2, (int)input_shape[3] - crop_2 * 2); | |||||
| } | |||||
| } | |||||
| else if (args.cropping.shape == new Shape(2, 2)) | |||||
| { | |||||
| int crop_1_start = args.cropping[0, 0], crop_1_end = args.cropping[0, 1]; | |||||
| int crop_2_start = args.cropping[1, 0], crop_2_end = args.cropping[1, 1]; | |||||
| if (args.data_format == Cropping2DArgs.DataFormat.channels_last) | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1] - crop_1_start - crop_1_end, | |||||
| (int)input_shape[2] - crop_2_start - crop_2_end, (int)input_shape[3]); | |||||
| } | |||||
| else | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1], | |||||
| (int)input_shape[2] - crop_1_start - crop_1_end, (int)input_shape[3] - crop_2_start - crop_2_end); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| throw new ValueError(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,150 @@ | |||||
| using Tensorflow.Keras.ArgsDefinition.Reshaping; | |||||
| using Tensorflow.Keras.Engine; | |||||
| namespace Tensorflow.Keras.Layers.Reshaping | |||||
| { | |||||
| /// <summary> | |||||
| /// Similar to copping 2D | |||||
| /// </summary> | |||||
| public class Cropping3D : Layer | |||||
| { | |||||
| Cropping3DArgs args; | |||||
| public Cropping3D(Cropping3DArgs args) : base(args) | |||||
| { | |||||
| this.args = args; | |||||
| } | |||||
| public override void build(Shape input_shape) | |||||
| { | |||||
| built = true; | |||||
| _buildInputShape = input_shape; | |||||
| } | |||||
| protected override Tensors Call(Tensors inputs, Tensor state = null, bool? training = null) | |||||
| { | |||||
| Tensor output = inputs; | |||||
| if (output.rank != 5) | |||||
| { | |||||
| // throw an ValueError exception | |||||
| throw new ValueError("Expected dim=5, found dim=" + output.rank); | |||||
| } | |||||
| if (args.cropping.shape == new Shape(1)) | |||||
| { | |||||
| int crop = args.cropping[0]; | |||||
| if (args.data_format == Cropping3DArgs.DataFormat.channels_last) | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(crop, (int)output.shape[1] - crop), | |||||
| new Slice(crop, (int)output.shape[2] - crop), | |||||
| new Slice(crop, (int)output.shape[3] - crop), | |||||
| new Slice()]; | |||||
| } | |||||
| else | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(crop, (int)output.shape[2] - crop), | |||||
| new Slice(crop, (int)output.shape[3] - crop), | |||||
| new Slice(crop, (int)output.shape[4] - crop)]; | |||||
| } | |||||
| } | |||||
| // int[1][3] equivalent to a tuple of 3 integers | |||||
| else if (args.cropping.shape == new Shape(3)) | |||||
| { | |||||
| var crop_1 = args.cropping[0]; | |||||
| var crop_2 = args.cropping[1]; | |||||
| var crop_3 = args.cropping[2]; | |||||
| if (args.data_format == Cropping3DArgs.DataFormat.channels_last) | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(crop_1, (int)output.shape[1] - crop_1), | |||||
| new Slice(crop_2, (int)output.shape[2] - crop_2), | |||||
| new Slice(crop_3, (int)output.shape[3] - crop_3), | |||||
| new Slice()]; | |||||
| } | |||||
| else | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(crop_1, (int)output.shape[2] - crop_1), | |||||
| new Slice(crop_2, (int)output.shape[3] - crop_2), | |||||
| new Slice(crop_3, (int)output.shape[4] - crop_3)]; | |||||
| } | |||||
| } | |||||
| else if (args.cropping.shape[0] == 3 && args.cropping.shape[1] == 2) | |||||
| { | |||||
| int x = args.cropping[0, 0], x_end = args.cropping[0, 1]; | |||||
| int y = args.cropping[1, 0], y_end = args.cropping[1, 1]; | |||||
| int z = args.cropping[2, 0], z_end = args.cropping[2, 1]; | |||||
| if (args.data_format == Cropping3DArgs.DataFormat.channels_last) | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(x, (int)output.shape[1] - x_end), | |||||
| new Slice(y, (int)output.shape[2] - y_end), | |||||
| new Slice(z, (int)output.shape[3] - z_end), | |||||
| new Slice()]; | |||||
| } | |||||
| else | |||||
| { | |||||
| output = output[new Slice(), | |||||
| new Slice(), | |||||
| new Slice(x, (int)output.shape[2] - x_end), | |||||
| new Slice(y, (int)output.shape[3] - y_end), | |||||
| new Slice(z, (int)output.shape[4] - z_end) | |||||
| ]; | |||||
| } | |||||
| } | |||||
| return output; | |||||
| } | |||||
| public override Shape ComputeOutputShape(Shape input_shape) | |||||
| { | |||||
| if (args.cropping.shape == new Shape(1)) | |||||
| { | |||||
| int crop = args.cropping[0]; | |||||
| if (args.data_format == Cropping3DArgs.DataFormat.channels_last) | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1] - crop * 2, (int)input_shape[2] - crop * 2, (int)input_shape[3] - crop * 2, (int)input_shape[4]); | |||||
| } | |||||
| else | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1], (int)input_shape[2] - crop * 2, (int)input_shape[3] - crop * 2, (int)input_shape[4] - crop * 2); | |||||
| } | |||||
| } | |||||
| // int[1][3] equivalent to a tuple of 3 integers | |||||
| else if (args.cropping.shape == new Shape(3)) | |||||
| { | |||||
| var crop_start_1 = args.cropping[0]; | |||||
| var crop_start_2 = args.cropping[1]; | |||||
| var crop_start_3 = args.cropping[2]; | |||||
| if (args.data_format == Cropping3DArgs.DataFormat.channels_last) | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1] - crop_start_1 * 2, (int)input_shape[2] - crop_start_2 * 2, (int)input_shape[3] - crop_start_3 * 2, (int)input_shape[4]); | |||||
| } | |||||
| else | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1], (int)input_shape[2] - crop_start_1 * 2, (int)input_shape[3] - crop_start_2 * 2, (int)input_shape[4] - crop_start_3 * 2); | |||||
| } | |||||
| } | |||||
| else if (args.cropping.shape == new Shape(3, 2)) | |||||
| { | |||||
| int x = args.cropping[0, 0], x_end = args.cropping[0, 1]; | |||||
| int y = args.cropping[1, 0], y_end = args.cropping[1, 1]; | |||||
| int z = args.cropping[2, 0], z_end = args.cropping[2, 1]; | |||||
| if (args.data_format == Cropping3DArgs.DataFormat.channels_last) | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1] - x - x_end, (int)input_shape[2] - y - y_end, (int)input_shape[3] - z - z_end, (int)input_shape[4]); | |||||
| } | |||||
| else | |||||
| { | |||||
| return new Shape((int)input_shape[0], (int)input_shape[1], (int)input_shape[2] - x - x_end, (int)input_shape[3] - y - y_end, (int)input_shape[4] - z - z_end); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| throw new ValueError(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,9 +1,8 @@ | |||||
| using System.Linq; | using System.Linq; | ||||
| using Tensorflow.Keras.ArgsDefinition.Lstm; | |||||
| using Tensorflow.Keras.ArgsDefinition.Rnn; | |||||
| using Tensorflow.Keras.Engine; | using Tensorflow.Keras.Engine; | ||||
| using Tensorflow.Keras.Layers.Rnn; | |||||
| namespace Tensorflow.Keras.Layers.Lstm | |||||
| namespace Tensorflow.Keras.Layers.Rnn | |||||
| { | { | ||||
| /// <summary> | /// <summary> | ||||
| /// Long Short-Term Memory layer - Hochreiter 1997. | /// Long Short-Term Memory layer - Hochreiter 1997. | ||||
| @@ -1,7 +1,7 @@ | |||||
| using Tensorflow.Keras.ArgsDefinition.Lstm; | |||||
| using Tensorflow.Keras.ArgsDefinition.Rnn; | |||||
| using Tensorflow.Keras.Engine; | using Tensorflow.Keras.Engine; | ||||
| namespace Tensorflow.Keras.Layers.Lstm | |||||
| namespace Tensorflow.Keras.Layers.Rnn | |||||
| { | { | ||||
| public class LSTMCell : Layer | public class LSTMCell : Layer | ||||
| { | { | ||||
| @@ -3,7 +3,6 @@ using System.Collections.Generic; | |||||
| using Tensorflow.Keras.ArgsDefinition; | using Tensorflow.Keras.ArgsDefinition; | ||||
| using Tensorflow.Keras.ArgsDefinition.Rnn; | using Tensorflow.Keras.ArgsDefinition.Rnn; | ||||
| using Tensorflow.Keras.Engine; | using Tensorflow.Keras.Engine; | ||||
| using Tensorflow.Keras.Layers.Lstm; | |||||
| // from tensorflow.python.distribute import distribution_strategy_context as ds_context; | // from tensorflow.python.distribute import distribution_strategy_context as ds_context; | ||||
| namespace Tensorflow.Keras.Layers.Rnn | namespace Tensorflow.Keras.Layers.Rnn | ||||
| @@ -1,82 +0,0 @@ | |||||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
| using Tensorflow.NumPy; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| using Tensorflow; | |||||
| using static Tensorflow.Binding; | |||||
| using static Tensorflow.KerasApi; | |||||
| using Tensorflow.Keras; | |||||
| using Tensorflow.Keras.ArgsDefinition; | |||||
| using Tensorflow.Keras.Engine; | |||||
| using Tensorflow.Keras.Layers; | |||||
| using Tensorflow.Keras.Losses; | |||||
| using Tensorflow.Keras.Metrics; | |||||
| using Tensorflow.Keras.Optimizers; | |||||
| using Tensorflow.Operations; | |||||
| namespace TensorFlowNET.Keras.UnitTest.SaveModel; | |||||
| [TestClass] | |||||
| public class SequentialModelTest | |||||
| { | |||||
| [TestMethod] | |||||
| public void SimpleModelFromAutoCompile() | |||||
| { | |||||
| var inputs = new KerasInterface().Input((28, 28, 1)); | |||||
| var x = new Flatten(new FlattenArgs()).Apply(inputs); | |||||
| x = new Dense(new DenseArgs() { Units = 100, Activation = tf.nn.relu }).Apply(x); | |||||
| x = new LayersApi().Dense(units: 10).Apply(x); | |||||
| var outputs = new LayersApi().Softmax(axis: 1).Apply(x); | |||||
| var model = new KerasInterface().Model(inputs, outputs); | |||||
| model.compile(new Adam(0.001f), new LossesApi().SparseCategoricalCrossentropy(), new string[] { "accuracy" }); | |||||
| var data_loader = new MnistModelLoader(); | |||||
| var num_epochs = 1; | |||||
| var batch_size = 50; | |||||
| var dataset = data_loader.LoadAsync(new ModelLoadSetting | |||||
| { | |||||
| TrainDir = "mnist", | |||||
| OneHot = false, | |||||
| ValidationSize = 10000, | |||||
| }).Result; | |||||
| model.fit(dataset.Train.Data, dataset.Train.Labels, batch_size, num_epochs); | |||||
| model.save("C:\\Work\\tf.net\\tf_test\\tf.net.simple.compile", save_format: "tf"); | |||||
| } | |||||
| [TestMethod] | |||||
| public void SimpleModelFromSequential() | |||||
| { | |||||
| Model model = KerasApi.keras.Sequential(new List<ILayer>() | |||||
| { | |||||
| keras.layers.InputLayer((28, 28, 1)), | |||||
| keras.layers.Flatten(), | |||||
| keras.layers.Dense(100, "relu"), | |||||
| keras.layers.Dense(10), | |||||
| keras.layers.Softmax(1) | |||||
| }); | |||||
| model.compile(new Adam(0.001f), new LossesApi().SparseCategoricalCrossentropy(), new string[] { "accuracy" }); | |||||
| var data_loader = new MnistModelLoader(); | |||||
| var num_epochs = 1; | |||||
| var batch_size = 50; | |||||
| var dataset = data_loader.LoadAsync(new ModelLoadSetting | |||||
| { | |||||
| TrainDir = "mnist", | |||||
| OneHot = false, | |||||
| ValidationSize = 10000, | |||||
| }).Result; | |||||
| model.fit(dataset.Train.Data, dataset.Train.Labels, batch_size, num_epochs); | |||||
| model.save("C:\\Work\\tf.net\\tf_test\\tf.net.simple.sequential", save_format: "tf"); | |||||
| } | |||||
| } | |||||