| @@ -76,13 +76,13 @@ namespace Tensorflow | |||||
| /// <param name="dtype"></param> | /// <param name="dtype"></param> | ||||
| /// <returns></returns> | /// <returns></returns> | ||||
| public IInitializer variance_scaling_initializer(float factor = 1.0f, | public IInitializer variance_scaling_initializer(float factor = 1.0f, | ||||
| string mode = "FAN_IN", | |||||
| bool uniform = false, | |||||
| string mode = "fan_in", | |||||
| string distribution = "truncated_normal", | |||||
| int? seed = null, | int? seed = null, | ||||
| TF_DataType dtype = TF_DataType.TF_FLOAT) => new VarianceScaling( | TF_DataType dtype = TF_DataType.TF_FLOAT) => new VarianceScaling( | ||||
| factor: factor, | |||||
| scale: factor, | |||||
| mode: mode, | mode: mode, | ||||
| uniform: uniform, | |||||
| distribution: distribution, | |||||
| seed: seed, | seed: seed, | ||||
| dtype: dtype); | dtype: dtype); | ||||
| @@ -6,34 +6,34 @@ namespace Tensorflow.Keras.ArgsDefinition | |||||
| { | { | ||||
| public class ConvolutionalArgs : AutoSerializeLayerArgs | public class ConvolutionalArgs : AutoSerializeLayerArgs | ||||
| { | { | ||||
| public int Rank { get; set; } = 2; | |||||
| public int Rank { get; set; } | |||||
| [JsonProperty("filters")] | [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")] | [JsonProperty("kernel_size")] | ||||
| public Shape KernelSize { get; set; } = 5; | |||||
| public Shape KernelSize { get; set; } | |||||
| /// <summary> | /// <summary> | ||||
| /// specifying the stride length of the convolution. | /// specifying the stride length of the convolution. | ||||
| /// </summary> | /// </summary> | ||||
| [JsonProperty("strides")] | [JsonProperty("strides")] | ||||
| public Shape Strides { get; set; } = (1, 1); | |||||
| public Shape Strides { get; set; } | |||||
| [JsonProperty("padding")] | [JsonProperty("padding")] | ||||
| public string Padding { get; set; } = "valid"; | |||||
| public string Padding { get; set; } | |||||
| [JsonProperty("data_format")] | [JsonProperty("data_format")] | ||||
| public string DataFormat { get; set; } | public string DataFormat { get; set; } | ||||
| [JsonProperty("dilation_rate")] | [JsonProperty("dilation_rate")] | ||||
| public Shape DilationRate { get; set; } = (1, 1); | |||||
| public Shape DilationRate { get; set; } | |||||
| [JsonProperty("groups")] | [JsonProperty("groups")] | ||||
| public int Groups { get; set; } = 1; | |||||
| public int Groups { get; set; } | |||||
| [JsonProperty("activation")] | [JsonProperty("activation")] | ||||
| public Activation Activation { get; set; } | public Activation Activation { get; set; } | ||||
| [JsonProperty("use_bias")] | [JsonProperty("use_bias")] | ||||
| public bool UseBias { get; set; } | public bool UseBias { get; set; } | ||||
| [JsonProperty("kernel_initializer")] | [JsonProperty("kernel_initializer")] | ||||
| public IInitializer KernelInitializer { get; set; } = tf.glorot_uniform_initializer; | |||||
| public IInitializer KernelInitializer { get; set; } | |||||
| [JsonProperty("bias_initializer")] | [JsonProperty("bias_initializer")] | ||||
| public IInitializer BiasInitializer { get; set; } = tf.zeros_initializer; | |||||
| public IInitializer BiasInitializer { get; set; } | |||||
| [JsonProperty("kernel_regularizer")] | [JsonProperty("kernel_regularizer")] | ||||
| public IRegularizer KernelRegularizer { get; set; } | public IRegularizer KernelRegularizer { get; set; } | ||||
| [JsonProperty("bias_regularizer")] | [JsonProperty("bias_regularizer")] | ||||
| @@ -0,0 +1,68 @@ | |||||
| using Newtonsoft.Json.Linq; | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| using Tensorflow.Operations; | |||||
| using Tensorflow.Operations.Initializers; | |||||
| namespace Tensorflow.Keras.Common | |||||
| { | |||||
| class InitializerInfo | |||||
| { | |||||
| public string class_name { get; set; } | |||||
| public JObject config { get; set; } | |||||
| } | |||||
| public class CustomizedIinitializerJsonConverter : JsonConverter | |||||
| { | |||||
| public override bool CanConvert(Type objectType) | |||||
| { | |||||
| return objectType == typeof(IInitializer); | |||||
| } | |||||
| public override bool CanRead => true; | |||||
| public override bool CanWrite => true; | |||||
| public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) | |||||
| { | |||||
| var initializer = value as IInitializer; | |||||
| if(initializer is null) | |||||
| { | |||||
| JToken.FromObject(null).WriteTo(writer); | |||||
| return; | |||||
| } | |||||
| JToken.FromObject(new InitializerInfo() | |||||
| { | |||||
| class_name = initializer.ClassName, | |||||
| config = JObject.FromObject(initializer.Config) | |||||
| }, serializer).WriteTo(writer); | |||||
| } | |||||
| public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) | |||||
| { | |||||
| var info = serializer.Deserialize<InitializerInfo>(reader); | |||||
| if(info is null) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| return info.class_name switch | |||||
| { | |||||
| "Constant" => new Constant<float>(info.config["value"].ToObject<float>()), | |||||
| "GlorotUniform" => new GlorotUniform(seed: info.config["seed"].ToObject<int?>()), | |||||
| "Ones" => new Ones(), | |||||
| "Orthogonal" => new Orthogonal(info.config["gain"].ToObject<float>(), info.config["seed"].ToObject<int?>()), | |||||
| "RandomNormal" => new RandomNormal(info.config["mean"].ToObject<float>(), info.config["stddev"].ToObject<float>(), | |||||
| info.config["seed"].ToObject<int?>()), | |||||
| "RandomUniform" => new RandomUniform(minval:info.config["minval"].ToObject<float>(), | |||||
| maxval:info.config["maxval"].ToObject<float>(), seed: info.config["seed"].ToObject<int?>()), | |||||
| "TruncatedNormal" => new TruncatedNormal(info.config["mean"].ToObject<float>(), info.config["stddev"].ToObject<float>(), | |||||
| info.config["seed"].ToObject<int?>()), | |||||
| "VarianceScaling" => new VarianceScaling(info.config["scale"].ToObject<float>(), info.config["mode"].ToObject<string>(), | |||||
| info.config["distribution"].ToObject<string>(), info.config["seed"].ToObject<int?>()), | |||||
| "Zeros" => new Zeros(), | |||||
| _ => throw new ValueError($"The specified initializer {info.class_name} cannot be recognized.") | |||||
| }; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -60,12 +60,20 @@ namespace Tensorflow.Keras.Common | |||||
| public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) | public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) | ||||
| { | { | ||||
| var shape_info_from_python = serializer.Deserialize<ShapeInfoFromPython>(reader); | |||||
| if (shape_info_from_python is null) | |||||
| long?[] dims; | |||||
| try | |||||
| { | { | ||||
| return null; | |||||
| var shape_info_from_python = serializer.Deserialize<ShapeInfoFromPython>(reader); | |||||
| if (shape_info_from_python is null) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| dims = shape_info_from_python.items; | |||||
| } | |||||
| catch(JsonSerializationException) | |||||
| { | |||||
| dims = serializer.Deserialize<long?[]>(reader); | |||||
| } | } | ||||
| long ?[]dims = shape_info_from_python.items; | |||||
| long[] convertedDims = new long[dims.Length]; | long[] convertedDims = new long[dims.Length]; | ||||
| for(int i = 0; i < dims.Length; i++) | for(int i = 0; i < dims.Length; i++) | ||||
| { | { | ||||
| @@ -26,12 +26,12 @@ namespace Tensorflow.Operations.Initializers | |||||
| public override IDictionary<string, object> Config => _config; | public override IDictionary<string, object> Config => _config; | ||||
| public GlorotUniform(float scale = 1.0f, | public GlorotUniform(float scale = 1.0f, | ||||
| string mode = "FAN_AVG", | |||||
| bool uniform = true, | |||||
| string mode = "fan_avg", | |||||
| string distribution = "uniform", | |||||
| int? seed = null, | int? seed = null, | ||||
| TF_DataType dtype = TF_DataType.TF_FLOAT) : base(factor: scale, | |||||
| TF_DataType dtype = TF_DataType.TF_FLOAT) : base(scale: scale, | |||||
| mode: mode, | mode: mode, | ||||
| uniform: uniform, | |||||
| distribution: distribution, | |||||
| seed: seed, | seed: seed, | ||||
| dtype: dtype) | dtype: dtype) | ||||
| { | { | ||||
| @@ -16,9 +16,11 @@ | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using Tensorflow.Keras.Common; | |||||
| namespace Tensorflow | namespace Tensorflow | ||||
| { | { | ||||
| [JsonConverter(typeof(CustomizedIinitializerJsonConverter))] | |||||
| public interface IInitializer | public interface IInitializer | ||||
| { | { | ||||
| [JsonProperty("class_name")] | [JsonProperty("class_name")] | ||||
| @@ -28,35 +28,42 @@ namespace Tensorflow.Operations.Initializers | |||||
| { | { | ||||
| protected float _scale; | protected float _scale; | ||||
| protected string _mode; | protected string _mode; | ||||
| protected string _distribution; | |||||
| protected int? _seed; | protected int? _seed; | ||||
| protected TF_DataType _dtype; | protected TF_DataType _dtype; | ||||
| protected bool _uniform; | |||||
| protected string _distribution; | |||||
| private readonly Dictionary<string, object> _config; | private readonly Dictionary<string, object> _config; | ||||
| public virtual string ClassName => "VarianceScaling"; | public virtual string ClassName => "VarianceScaling"; | ||||
| public virtual IDictionary<string, object> Config => _config; | public virtual IDictionary<string, object> Config => _config; | ||||
| public VarianceScaling(float factor = 2.0f, | |||||
| string mode = "FAN_IN", | |||||
| bool uniform = false, | |||||
| public VarianceScaling(float scale = 1.0f, | |||||
| string mode = "fan_in", | |||||
| string distribution = "truncated_normal", | |||||
| int? seed = null, | int? seed = null, | ||||
| TF_DataType dtype = TF_DataType.TF_FLOAT) | TF_DataType dtype = TF_DataType.TF_FLOAT) | ||||
| { | { | ||||
| if (!dtype.is_floating()) | if (!dtype.is_floating()) | ||||
| throw new TypeError("Cannot create initializer for non-floating point type."); | throw new TypeError("Cannot create initializer for non-floating point type."); | ||||
| if (!new string[] { "FAN_IN", "FAN_OUT", "FAN_AVG" }.Contains(mode)) | |||||
| throw new TypeError($"Unknown {mode} %s [FAN_IN, FAN_OUT, FAN_AVG]"); | |||||
| if (!new string[] { "fan_in", "fan_out", "fan_avg" }.Contains(mode)) | |||||
| throw new TypeError($"Unknown {mode} %s [fan_in, fan_out, fan_avg]"); | |||||
| if(distribution == "normal") | |||||
| { | |||||
| distribution = "truncated_normal"; | |||||
| } | |||||
| if(!new string[] { "uniform", "truncated_normal", "untruncated_normal" }.Contains(distribution)) | |||||
| { | |||||
| throw new ValueError($"Invalid `distribution` argument: {distribution}"); | |||||
| } | |||||
| if (factor < 0) | |||||
| if (scale <= 0) | |||||
| throw new ValueError("`scale` must be positive float."); | throw new ValueError("`scale` must be positive float."); | ||||
| _scale = factor; | |||||
| _scale = scale; | |||||
| _mode = mode; | _mode = mode; | ||||
| _seed = seed; | _seed = seed; | ||||
| _dtype = dtype; | _dtype = dtype; | ||||
| _uniform = uniform; | |||||
| _distribution = distribution; | |||||
| _config = new(); | _config = new(); | ||||
| _config["scale"] = _scale; | _config["scale"] = _scale; | ||||
| @@ -72,23 +79,28 @@ namespace Tensorflow.Operations.Initializers | |||||
| float n = 0; | float n = 0; | ||||
| var (fan_in, fan_out) = _compute_fans(args.Shape); | var (fan_in, fan_out) = _compute_fans(args.Shape); | ||||
| if (_mode == "FAN_IN") | |||||
| n = fan_in; | |||||
| else if (_mode == "FAN_OUT") | |||||
| n = fan_out; | |||||
| else if (_mode == "FAN_AVG") | |||||
| n = (fan_in + fan_out) / 2.0f; | |||||
| var scale = this._scale; | |||||
| if (_mode == "fan_in") | |||||
| scale /= Math.Max(1.0f, fan_in); | |||||
| else if (_mode == "fan_out") | |||||
| scale /= Math.Max(1.0f, fan_out); | |||||
| else | |||||
| scale /= Math.Max(1.0f, (fan_in + fan_out) / 2); | |||||
| if (_uniform) | |||||
| if(_distribution == "truncated_normal") | |||||
| { | { | ||||
| var limit = Convert.ToSingle(Math.Sqrt(3.0f * _scale / n)); | |||||
| return random_ops.random_uniform(args.Shape, -limit, limit, args.DType); | |||||
| var stddev = Math.Sqrt(scale) / .87962566103423978f; | |||||
| return random_ops.truncated_normal(args.Shape, 0.0f, (float)stddev, args.DType); | |||||
| } | |||||
| else if(_distribution == "untruncated_normal") | |||||
| { | |||||
| var stddev = Math.Sqrt(scale); | |||||
| return random_ops.random_normal(args.Shape, 0.0f, (float)stddev, args.DType); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| var trunc_stddev = Convert.ToSingle(Math.Sqrt(1.3f * _scale / n)); | |||||
| return random_ops.truncated_normal(args.Shape, 0.0f, trunc_stddev, args.DType, | |||||
| seed: _seed); | |||||
| var limit = (float)Math.Sqrt(scale * 3.0f); | |||||
| return random_ops.random_uniform(args.Shape, -limit, limit, args.DType); | |||||
| } | } | ||||
| } | } | ||||
| @@ -29543,7 +29543,7 @@ namespace Tensorflow.Operations | |||||
| /// if &lt; 0, <c>scale * features</c> otherwise. | /// if &lt; 0, <c>scale * features</c> otherwise. | ||||
| /// | /// | ||||
| /// To be used together with | /// To be used together with | ||||
| /// <c>initializer = tf.variance_scaling_initializer(factor=1.0, mode='FAN_IN')</c>. | |||||
| /// <c>initializer = tf.variance_scaling_initializer(scale=1.0, mode='fan_in')</c>. | |||||
| /// For correct dropout, use <c>tf.contrib.nn.alpha_dropout</c>. | /// For correct dropout, use <c>tf.contrib.nn.alpha_dropout</c>. | ||||
| /// | /// | ||||
| /// See [Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515) | /// See [Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515) | ||||
| @@ -27,7 +27,7 @@ public partial class InitializersApi : IInitializersApi | |||||
| /// <returns></returns> | /// <returns></returns> | ||||
| public IInitializer HeNormal(int? seed = null) | public IInitializer HeNormal(int? seed = null) | ||||
| { | { | ||||
| return new VarianceScaling(factor: 2.0f, mode: "fan_in", seed: seed); | |||||
| return new VarianceScaling(scale: 2.0f, mode: "fan_in", seed: seed); | |||||
| } | } | ||||
| public IInitializer Orthogonal(float gain = 1.0f, int? seed = null) | public IInitializer Orthogonal(float gain = 1.0f, int? seed = null) | ||||
| @@ -20,9 +20,46 @@ namespace Tensorflow.Keras.Layers | |||||
| { | { | ||||
| public class Conv1D : Convolutional | public class Conv1D : Convolutional | ||||
| { | { | ||||
| public Conv1D(Conv1DArgs args) : base(args) | |||||
| public Conv1D(Conv1DArgs args) : base(InitializeUndefinedArgs(args)) | |||||
| { | { | ||||
| } | } | ||||
| private static Conv1DArgs InitializeUndefinedArgs(Conv1DArgs args) | |||||
| { | |||||
| if(args.Rank == 0) | |||||
| { | |||||
| args.Rank = 1; | |||||
| } | |||||
| if(args.Strides is null) | |||||
| { | |||||
| args.Strides = 1; | |||||
| } | |||||
| if (string.IsNullOrEmpty(args.Padding)) | |||||
| { | |||||
| args.Padding = "valid"; | |||||
| } | |||||
| if (string.IsNullOrEmpty(args.DataFormat)) | |||||
| { | |||||
| args.DataFormat = "channels_last"; | |||||
| } | |||||
| if(args.DilationRate == 0) | |||||
| { | |||||
| args.DilationRate = 1; | |||||
| } | |||||
| if(args.Groups == 0) | |||||
| { | |||||
| args.Groups = 1; | |||||
| } | |||||
| if(args.KernelInitializer is null) | |||||
| { | |||||
| args.KernelInitializer = tf.glorot_uniform_initializer; | |||||
| } | |||||
| if(args.BiasInitializer is null) | |||||
| { | |||||
| args.BiasInitializer = tf.zeros_initializer; | |||||
| } | |||||
| return args; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -20,9 +20,42 @@ namespace Tensorflow.Keras.Layers | |||||
| { | { | ||||
| public class Conv2D : Convolutional | public class Conv2D : Convolutional | ||||
| { | { | ||||
| public Conv2D(Conv2DArgs args) : base(args) | |||||
| public Conv2D(Conv2DArgs args) : base(InitializeUndefinedArgs(args)) | |||||
| { | { | ||||
| } | } | ||||
| private static Conv2DArgs InitializeUndefinedArgs(Conv2DArgs args) | |||||
| { | |||||
| if(args.Rank == 0) | |||||
| { | |||||
| args.Rank = 2; | |||||
| } | |||||
| if (args.Strides is null) | |||||
| { | |||||
| args.Strides = (1, 1); | |||||
| } | |||||
| if (string.IsNullOrEmpty(args.Padding)) | |||||
| { | |||||
| args.Padding = "valid"; | |||||
| } | |||||
| if (args.DilationRate == 0) | |||||
| { | |||||
| args.DilationRate = (1, 1); | |||||
| } | |||||
| if (args.Groups == 0) | |||||
| { | |||||
| args.Groups = 1; | |||||
| } | |||||
| if (args.KernelInitializer is null) | |||||
| { | |||||
| args.KernelInitializer = tf.glorot_uniform_initializer; | |||||
| } | |||||
| if (args.BiasInitializer is null) | |||||
| { | |||||
| args.BiasInitializer = tf.zeros_initializer; | |||||
| } | |||||
| return args; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -24,11 +24,40 @@ namespace Tensorflow.Keras.Layers | |||||
| { | { | ||||
| public class Conv2DTranspose : Conv2D | public class Conv2DTranspose : Conv2D | ||||
| { | { | ||||
| public Conv2DTranspose(Conv2DArgs args) : base(args) | |||||
| public Conv2DTranspose(Conv2DArgs args) : base(InitializeUndefinedArgs(args)) | |||||
| { | { | ||||
| } | } | ||||
| private static Conv2DArgs InitializeUndefinedArgs(Conv2DArgs args) | |||||
| { | |||||
| if (args.Strides is null) | |||||
| { | |||||
| args.Strides = (1, 1); | |||||
| } | |||||
| if (string.IsNullOrEmpty(args.Padding)) | |||||
| { | |||||
| args.Padding = "valid"; | |||||
| } | |||||
| if (args.DilationRate == 0) | |||||
| { | |||||
| args.DilationRate = (1, 1); | |||||
| } | |||||
| if (args.Groups == 0) | |||||
| { | |||||
| args.Groups = 1; | |||||
| } | |||||
| if (args.KernelInitializer is null) | |||||
| { | |||||
| args.KernelInitializer = tf.glorot_uniform_initializer; | |||||
| } | |||||
| if (args.BiasInitializer is null) | |||||
| { | |||||
| args.BiasInitializer = tf.zeros_initializer; | |||||
| } | |||||
| return args; | |||||
| } | |||||
| public override void build(Shape input_shape) | public override void build(Shape input_shape) | ||||
| { | { | ||||
| if (len(input_shape) != 4) | if (len(input_shape) != 4) | ||||