| @@ -7,7 +7,12 @@ namespace Tensorflow | |||||
| public static partial class tf | public static partial class tf | ||||
| { | { | ||||
| public static IInitializer zeros_initializer => new Zeros(); | public static IInitializer zeros_initializer => new Zeros(); | ||||
| public static IInitializer glorot_uniform => new GlorotUniform(); | |||||
| public static variable_scope variable_scope(string name_or_scope, | |||||
| string default_name = null, | |||||
| object values = null) => new variable_scope(name_or_scope, default_name, values); | |||||
| public class Zeros : IInitializer | public class Zeros : IInitializer | ||||
| { | { | ||||
| private TF_DataType dtype; | private TF_DataType dtype; | ||||
| @@ -30,5 +35,105 @@ namespace Tensorflow | |||||
| return new { dtype = dtype.name() }; | return new { dtype = dtype.name() }; | ||||
| } | } | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Initializer capable of adapting its scale to the shape of weights tensors. | |||||
| /// </summary> | |||||
| public class VarianceScaling : IInitializer | |||||
| { | |||||
| protected float _scale; | |||||
| protected string _mode; | |||||
| protected string _distribution; | |||||
| protected int? _seed; | |||||
| protected TF_DataType _dtype; | |||||
| public VarianceScaling(float scale = 1.0f, | |||||
| string mode = "fan_in", | |||||
| string distribution= "truncated_normal", | |||||
| int? seed = null, | |||||
| TF_DataType dtype = TF_DataType.TF_FLOAT) | |||||
| { | |||||
| if (scale < 0) | |||||
| throw new ValueError("`scale` must be positive float."); | |||||
| _scale = scale; | |||||
| _mode = mode; | |||||
| _distribution = distribution; | |||||
| _seed = seed; | |||||
| _dtype = dtype; | |||||
| } | |||||
| public Tensor call(TensorShape shape, TF_DataType dtype) | |||||
| { | |||||
| var (fan_in, fan_out) = _compute_fans(shape); | |||||
| if (_mode == "fan_in") | |||||
| _scale /= Math.Max(1, fan_in); | |||||
| else if (_mode == "fan_out") | |||||
| _scale /= Math.Max(1, fan_out); | |||||
| else | |||||
| _scale /= Math.Max(1, (fan_in + fan_out) / 2); | |||||
| if (_distribution == "normal" || _distribution == "truncated_normal") | |||||
| { | |||||
| throw new NotImplementedException("truncated_normal"); | |||||
| } | |||||
| else if(_distribution == "untruncated_normal") | |||||
| { | |||||
| throw new NotImplementedException("truncated_normal"); | |||||
| } | |||||
| else | |||||
| { | |||||
| var limit = Math.Sqrt(3.0f * _scale); | |||||
| return random_ops.random_uniform(shape, (float)-limit, (float)limit, dtype, seed: _seed); | |||||
| } | |||||
| } | |||||
| private (int, int) _compute_fans(int[] shape) | |||||
| { | |||||
| if (shape.Length < 1) | |||||
| return (1, 1); | |||||
| if (shape.Length == 1) | |||||
| return (shape[0], shape[0]); | |||||
| if (shape.Length == 2) | |||||
| return (shape[0], shape[1]); | |||||
| else | |||||
| throw new NotImplementedException("VarianceScaling._compute_fans"); | |||||
| } | |||||
| public virtual object get_config() | |||||
| { | |||||
| return new | |||||
| { | |||||
| scale = _scale, | |||||
| mode = _mode, | |||||
| distribution = _distribution, | |||||
| seed = _seed, | |||||
| dtype = _dtype | |||||
| }; | |||||
| } | |||||
| } | |||||
| public class GlorotUniform : VarianceScaling | |||||
| { | |||||
| public GlorotUniform(float scale = 1.0f, | |||||
| string mode = "fan_avg", | |||||
| string distribution = "uniform", | |||||
| int? seed = null, | |||||
| TF_DataType dtype = TF_DataType.TF_FLOAT) : base(scale, mode, distribution, seed, dtype) | |||||
| { | |||||
| } | |||||
| public object get_config() | |||||
| { | |||||
| return new | |||||
| { | |||||
| scale = _scale, | |||||
| mode = _mode, | |||||
| distribution = _distribution, | |||||
| seed = _seed, | |||||
| dtype = _dtype | |||||
| }; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -4,8 +4,18 @@ using System.Text; | |||||
| namespace Tensorflow | namespace Tensorflow | ||||
| { | { | ||||
| public class random_ops | |||||
| public class random_ops : Python | |||||
| { | { | ||||
| /// <summary> | |||||
| /// | |||||
| /// </summary> | |||||
| /// <param name="shape"></param> | |||||
| /// <param name="mean"></param> | |||||
| /// <param name="stddev"></param> | |||||
| /// <param name="dtype"></param> | |||||
| /// <param name="seed"></param> | |||||
| /// <param name="name"></param> | |||||
| /// <returns></returns> | |||||
| public static Tensor random_normal(int[] shape, | public static Tensor random_normal(int[] shape, | ||||
| float mean = 0.0f, | float mean = 0.0f, | ||||
| float stddev = 1.0f, | float stddev = 1.0f, | ||||
| @@ -26,6 +36,30 @@ namespace Tensorflow | |||||
| }); | }); | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Outputs random values from a uniform distribution. | |||||
| /// </summary> | |||||
| /// <param name="shape"></param> | |||||
| /// <param name="minval"></param> | |||||
| /// <param name="maxval"></param> | |||||
| /// <param name="dtype">The type of the output</param> | |||||
| /// <param name="seed">Used to create a random seed for the distribution.</param> | |||||
| /// <param name="name">A name for the operation</param> | |||||
| /// <returns>A tensor of the specified shape filled with random uniform values.</returns> | |||||
| public static Tensor random_uniform(int[] shape, | |||||
| float minval = 0, | |||||
| float? maxval = null, | |||||
| TF_DataType dtype = TF_DataType.TF_FLOAT, | |||||
| int? seed = null, | |||||
| string name = null) | |||||
| { | |||||
| return with<ops.name_scope, Tensor>(new ops.name_scope(name, "random_uniform", new { shape, minval, maxval }), scope => | |||||
| { | |||||
| name = scope; | |||||
| return null; | |||||
| }); | |||||
| } | |||||
| private static Tensor _ShapeTensor(int[] shape) | private static Tensor _ShapeTensor(int[] shape) | ||||
| { | { | ||||
| return ops.convert_to_tensor(shape, name: "shape"); | return ops.convert_to_tensor(shape, name: "shape"); | ||||
| @@ -4,7 +4,7 @@ | |||||
| <TargetFramework>netstandard2.0</TargetFramework> | <TargetFramework>netstandard2.0</TargetFramework> | ||||
| <AssemblyName>TensorFlow.NET</AssemblyName> | <AssemblyName>TensorFlow.NET</AssemblyName> | ||||
| <RootNamespace>Tensorflow</RootNamespace> | <RootNamespace>Tensorflow</RootNamespace> | ||||
| <Version>0.4.0</Version> | |||||
| <Version>0.4.1</Version> | |||||
| <Authors>Haiping Chen</Authors> | <Authors>Haiping Chen</Authors> | ||||
| <Company>SciSharp STACK</Company> | <Company>SciSharp STACK</Company> | ||||
| <GeneratePackageOnBuild>true</GeneratePackageOnBuild> | <GeneratePackageOnBuild>true</GeneratePackageOnBuild> | ||||
| @@ -16,11 +16,11 @@ | |||||
| <PackageTags>TensorFlow, NumSharp, SciSharp, MachineLearning, TensorFlow.NET</PackageTags> | <PackageTags>TensorFlow, NumSharp, SciSharp, MachineLearning, TensorFlow.NET</PackageTags> | ||||
| <Description>Google's TensorFlow binding in .NET Standard. | <Description>Google's TensorFlow binding in .NET Standard. | ||||
| Docs: https://tensorflownet.readthedocs.io</Description> | Docs: https://tensorflownet.readthedocs.io</Description> | ||||
| <AssemblyVersion>0.4.0.0</AssemblyVersion> | |||||
| <PackageReleaseNotes>Added Linear Regression example. | |||||
| </PackageReleaseNotes> | |||||
| <AssemblyVersion>0.4.1.0</AssemblyVersion> | |||||
| <PackageReleaseNotes>Added ConfigProto to control CPU and GPU resource. | |||||
| Fixed import name scope issue.</PackageReleaseNotes> | |||||
| <LangVersion>7.2</LangVersion> | <LangVersion>7.2</LangVersion> | ||||
| <FileVersion>0.4.0.0</FileVersion> | |||||
| <FileVersion>0.4.1.0</FileVersion> | |||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | ||||
| @@ -0,0 +1,58 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| namespace Tensorflow | |||||
| { | |||||
| public class PureVariableScope : IPython | |||||
| { | |||||
| private string _name_or_scope; | |||||
| private string _new_name; | |||||
| private string _old_name_scope; | |||||
| private bool _reuse; | |||||
| private _VariableStore _var_store; | |||||
| private VariableScope _old; | |||||
| private _VariableScopeStore _var_scope_store; | |||||
| private VariableScope variable_scope_object; | |||||
| public PureVariableScope(string name_or_scope, | |||||
| string old_name_scope = null, | |||||
| TF_DataType dtype = TF_DataType.DtInvalid) | |||||
| { | |||||
| _name_or_scope = name_or_scope; | |||||
| _old_name_scope = old_name_scope; | |||||
| _var_store = variable_scope._get_default_variable_store(); | |||||
| _var_scope_store = variable_scope.get_variable_scope_store(); | |||||
| } | |||||
| public void __enter__() | |||||
| { | |||||
| _old = _var_scope_store.current_scope; | |||||
| _new_name = string.IsNullOrEmpty(_old.name) ? _name_or_scope : _old.name + "/" + _name_or_scope; | |||||
| _reuse = _reuse || _old.resue; | |||||
| string name_scope = _old_name_scope == null ? _name_or_scope : _old_name_scope; | |||||
| variable_scope_object = new VariableScope(_reuse, | |||||
| name: _new_name, | |||||
| name_scope: name_scope); | |||||
| _var_scope_store.open_variable_scope(_new_name); | |||||
| _var_scope_store.current_scope = variable_scope_object; | |||||
| } | |||||
| public void Dispose() | |||||
| { | |||||
| } | |||||
| public void __exit__() | |||||
| { | |||||
| } | |||||
| public static implicit operator VariableScope(PureVariableScope scope) | |||||
| { | |||||
| return scope.variable_scope_object; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -4,17 +4,26 @@ using System.Text; | |||||
| namespace Tensorflow | namespace Tensorflow | ||||
| { | { | ||||
| /// <summary> | |||||
| /// Variable scope object to carry defaults to provide to `get_variable` | |||||
| /// </summary> | |||||
| public class VariableScope | public class VariableScope | ||||
| { | { | ||||
| public bool use_resource { get; set; } | public bool use_resource { get; set; } | ||||
| private _ReuseMode _reuse { get; set; } | |||||
| private _ReuseMode _reuse; | |||||
| public bool resue; | |||||
| private object _regularizer; | |||||
| private TF_DataType _dtype; | private TF_DataType _dtype; | ||||
| public string name { get; set; } | public string name { get; set; } | ||||
| public string name_scope { get; set; } | |||||
| public VariableScope(TF_DataType dtype = TF_DataType.TF_FLOAT) | |||||
| public VariableScope(bool reuse, | |||||
| string name = "", | |||||
| string name_scope = "", | |||||
| TF_DataType dtype = TF_DataType.TF_FLOAT) | |||||
| { | { | ||||
| this.name = name; | |||||
| this.name_scope = name_scope; | |||||
| _reuse = _ReuseMode.AUTO_REUSE; | _reuse = _ReuseMode.AUTO_REUSE; | ||||
| _dtype = dtype; | _dtype = dtype; | ||||
| } | } | ||||
| @@ -29,7 +38,7 @@ namespace Tensorflow | |||||
| VariableAggregation aggregation= VariableAggregation.NONE) | VariableAggregation aggregation= VariableAggregation.NONE) | ||||
| { | { | ||||
| string full_name = !string.IsNullOrEmpty(this.name) ? this.name + "/" + name : name; | string full_name = !string.IsNullOrEmpty(this.name) ? this.name + "/" + name : name; | ||||
| return Python.with<ops.name_scope, RefVariable>(new ops.name_scope(""), scope => | |||||
| return Python.with<ops.name_scope, RefVariable>(new ops.name_scope(null), scope => | |||||
| { | { | ||||
| if (dtype == TF_DataType.DtInvalid) | if (dtype == TF_DataType.DtInvalid) | ||||
| dtype = _dtype; | dtype = _dtype; | ||||
| @@ -7,10 +7,20 @@ namespace Tensorflow | |||||
| public class _VariableScopeStore | public class _VariableScopeStore | ||||
| { | { | ||||
| public VariableScope current_scope { get; set; } | public VariableScope current_scope { get; set; } | ||||
| private Dictionary<string, int> variable_scopes_count; | |||||
| public _VariableScopeStore() | public _VariableScopeStore() | ||||
| { | { | ||||
| current_scope = new VariableScope(); | |||||
| current_scope = new VariableScope(false); | |||||
| variable_scopes_count = new Dictionary<string, int>(); | |||||
| } | |||||
| public void open_variable_scope(string scope_name) | |||||
| { | |||||
| if (variable_scopes_count.ContainsKey(scope_name)) | |||||
| variable_scopes_count[scope_name] += 1; | |||||
| else | |||||
| variable_scopes_count[scope_name] = 1; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -87,6 +87,14 @@ namespace Tensorflow | |||||
| } | } | ||||
| Tensor init_val = null; | Tensor init_val = null; | ||||
| // Create the tensor to initialize the variable with default value. | |||||
| if (initializer == null) | |||||
| { | |||||
| if (dtype.is_floating()) | |||||
| initializer = tf.glorot_uniform; | |||||
| } | |||||
| ops.init_scope(); | ops.init_scope(); | ||||
| { | { | ||||
| if (initializing_from_value) | if (initializing_from_value) | ||||
| @@ -20,8 +20,8 @@ namespace Tensorflow | |||||
| VariableSynchronization synchronization = VariableSynchronization.AUTO, | VariableSynchronization synchronization = VariableSynchronization.AUTO, | ||||
| VariableAggregation aggregation = VariableAggregation.NONE) | VariableAggregation aggregation = VariableAggregation.NONE) | ||||
| { | { | ||||
| var scope = variable_scope.get_variable_scope(); | |||||
| var store = variable_scope._get_default_variable_store(); | |||||
| var scope = Tensorflow.variable_scope.get_variable_scope(); | |||||
| var store = Tensorflow.variable_scope._get_default_variable_store(); | |||||
| return scope.get_variable(store, | return scope.get_variable(store, | ||||
| name, | name, | ||||
| shape: shape, | shape: shape, | ||||
| @@ -4,12 +4,59 @@ using System.Text; | |||||
| namespace Tensorflow | namespace Tensorflow | ||||
| { | { | ||||
| public class variable_scope | |||||
| public class variable_scope : IPython | |||||
| { | { | ||||
| public static string _VARSTORE_KEY = "__variable_store"; | public static string _VARSTORE_KEY = "__variable_store"; | ||||
| public static string _VARSCOPESTORE_KEY = "__varscope"; | public static string _VARSCOPESTORE_KEY = "__varscope"; | ||||
| public static bool _DEFAULT_USE_RESOURCE = false; | public static bool _DEFAULT_USE_RESOURCE = false; | ||||
| private bool _use_resource; | |||||
| public bool UseResource => _use_resource; | |||||
| private string _name_or_scope; | |||||
| private string _default_name; | |||||
| private object _values; | |||||
| private string _current_name_scope; | |||||
| private PureVariableScope _cached_pure_variable_scope; | |||||
| public variable_scope(string name_or_scope, string default_name = "", object values = null) | |||||
| { | |||||
| _name_or_scope = name_or_scope; | |||||
| _default_name = default_name; | |||||
| _values = values; | |||||
| _current_name_scope = null; | |||||
| _use_resource = false; | |||||
| if (_default_name == null && _name_or_scope == null) | |||||
| throw new TypeError("If default_name is None then name_or_scope is required"); | |||||
| } | |||||
| public void __enter__() | |||||
| { | |||||
| _enter_scope_uncached(); | |||||
| } | |||||
| public VariableScope _enter_scope_uncached() | |||||
| { | |||||
| ops.name_scope current_name_scope = null; | |||||
| if(_name_or_scope != null) | |||||
| { | |||||
| var name_scope = _name_or_scope; | |||||
| if (name_scope != null || current_name_scope != null) | |||||
| current_name_scope = new ops.name_scope(name_scope); | |||||
| current_name_scope.__enter__(); | |||||
| string current_name_scope_name = current_name_scope; | |||||
| _current_name_scope = current_name_scope; | |||||
| string old_name_scope = current_name_scope_name; | |||||
| var pure_variable_scope = new PureVariableScope(_name_or_scope, old_name_scope: old_name_scope); | |||||
| pure_variable_scope.__enter__(); | |||||
| VariableScope entered_pure_variable_scope = pure_variable_scope; | |||||
| _cached_pure_variable_scope = pure_variable_scope; | |||||
| return entered_pure_variable_scope; | |||||
| } | |||||
| throw new NotImplementedException("_enter_scope_uncached"); | |||||
| } | |||||
| public static RefVariable default_variable_creator(object initial_value, | public static RefVariable default_variable_creator(object initial_value, | ||||
| string name = null, | string name = null, | ||||
| bool? trainable = null, | bool? trainable = null, | ||||
| @@ -101,5 +148,15 @@ namespace Tensorflow | |||||
| return trainable.Value; | return trainable.Value; | ||||
| } | } | ||||
| public void __exit__() | |||||
| { | |||||
| } | |||||
| public void Dispose() | |||||
| { | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -20,7 +20,7 @@ namespace Tensorflow | |||||
| public static RefVariable Variable<T>(T data, string name = null, TF_DataType dtype = TF_DataType.DtInvalid) | public static RefVariable Variable<T>(T data, string name = null, TF_DataType dtype = TF_DataType.DtInvalid) | ||||
| { | { | ||||
| return variable_scope.default_variable_creator(data, name: name, dtype: TF_DataType.DtInvalid); | |||||
| return Tensorflow.variable_scope.default_variable_creator(data, name: name, dtype: TF_DataType.DtInvalid); | |||||
| } | } | ||||
| public static unsafe Tensor placeholder(TF_DataType dtype, TensorShape shape = null) | public static unsafe Tensor placeholder(TF_DataType dtype, TensorShape shape = null) | ||||
| @@ -1,7 +1,7 @@ | |||||
| <Project Sdk="Microsoft.NET.Sdk"> | <Project Sdk="Microsoft.NET.Sdk"> | ||||
| <PropertyGroup> | <PropertyGroup> | ||||
| <TargetFramework>netcoreapp2.1</TargetFramework> | |||||
| <TargetFramework>netcoreapp2.2</TargetFramework> | |||||
| <IsPackable>false</IsPackable> | <IsPackable>false</IsPackable> | ||||
| </PropertyGroup> | </PropertyGroup> | ||||
| @@ -30,6 +30,18 @@ namespace TensorFlowNET.UnitTest | |||||
| var mammal2 = tf.Variable("Tiger"); | var mammal2 = tf.Variable("Tiger"); | ||||
| } | } | ||||
| [TestMethod] | |||||
| public void SimpleScope() | |||||
| { | |||||
| with(tf.variable_scope("foo"), delegate | |||||
| { | |||||
| with(tf.variable_scope("bar"), delegate | |||||
| { | |||||
| var v = tf.get_variable("v", new TensorShape(1)); | |||||
| }); | |||||
| }); | |||||
| } | |||||
| [TestMethod] | [TestMethod] | ||||
| public void ScalarVar() | public void ScalarVar() | ||||
| { | { | ||||