| @@ -0,0 +1,32 @@ | |||
| /***************************************************************************** | |||
| Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||
| you may not use this file except in compliance with the License. | |||
| You may obtain a copy of the License at | |||
| http://www.apache.org/licenses/LICENSE-2.0 | |||
| Unless required by applicable law or agreed to in writing, software | |||
| distributed under the License is distributed on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| See the License for the specific language governing permissions and | |||
| limitations under the License. | |||
| ******************************************************************************/ | |||
| using System; | |||
| using System.Runtime.InteropServices; | |||
| namespace Tensorflow | |||
| { | |||
| public partial class c_api | |||
| { | |||
| /// <summary> | |||
| /// Specify the device for `desc`. Defaults to empty, meaning unconstrained. | |||
| /// </summary> | |||
| /// <param name="desc"></param> | |||
| /// <param name="device"></param> | |||
| [DllImport(TensorFlowLibName)] | |||
| public static extern void TF_SetDevice(IntPtr desc, string device); | |||
| } | |||
| } | |||
| @@ -69,7 +69,9 @@ namespace Tensorflow | |||
| _new_stack = false; | |||
| } | |||
| _seen_nodes = new List<ITensorOrOperation>(); | |||
| _seen_nodes = new List<ITensorOrOperation>(); | |||
| _old_stack = null; | |||
| _old_control_flow_context = null; | |||
| } | |||
| public void add_op(ITensorOrOperation op) | |||
| @@ -139,7 +139,7 @@ namespace Tensorflow.Keras.Layers | |||
| built = true; | |||
| } | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null) | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null, Tensor state = null) | |||
| { | |||
| Tensor outputs = null; | |||
| @@ -108,7 +108,7 @@ namespace Tensorflow.Keras.Layers | |||
| built = true; | |||
| } | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null) | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null, Tensor state = null) | |||
| { | |||
| var outputs = _convolution_op.__call__(inputs, kernel); | |||
| if (use_bias) | |||
| @@ -72,7 +72,7 @@ namespace Tensorflow.Keras.Layers | |||
| built = true; | |||
| } | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null) | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null, Tensor state = null) | |||
| { | |||
| Tensor outputs = null; | |||
| var rank = inputs.rank; | |||
| @@ -50,7 +50,7 @@ namespace Tensorflow.Keras.Layers | |||
| built = true; | |||
| } | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null) | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null, Tensor state = null) | |||
| { | |||
| var dtype = inputs.dtype; | |||
| if (dtype != tf.int32 && dtype != tf.int64) | |||
| @@ -52,6 +52,7 @@ namespace Tensorflow.Keras.Layers | |||
| protected InputSpec input_spec; | |||
| protected bool supports_masking; | |||
| protected List<VariableV1> _trainable_weights; | |||
| protected List<VariableV1> _non_trainable_weights; | |||
| private string _name; | |||
| public string name => _name; | |||
| protected string _base_name; | |||
| @@ -84,6 +85,7 @@ namespace Tensorflow.Keras.Layers | |||
| _init_set_name(name); | |||
| _trainable_weights = new List<VariableV1>(); | |||
| _non_trainable_weights = new List<VariableV1>(); | |||
| _compute_previous_mask = false; | |||
| _updates = new List<Operation>(); | |||
| @@ -103,6 +105,7 @@ namespace Tensorflow.Keras.Layers | |||
| public (Tensor, Tensor) __call__(Tensor[] inputs, | |||
| Tensor training = null, | |||
| Tensor state = null, | |||
| VariableScope scope = null) | |||
| { | |||
| var input_list = inputs; | |||
| @@ -139,7 +142,9 @@ namespace Tensorflow.Keras.Layers | |||
| // overridden). | |||
| _maybe_build(inputs[0]); | |||
| (input, outputs) = call(inputs[0], training: training); | |||
| (input, outputs) = call(inputs[0], | |||
| training: training, | |||
| state: state); | |||
| (input, outputs) = _set_connectivity_metadata_(input, outputs); | |||
| _handle_activity_regularization(inputs[0], outputs); | |||
| _set_mask_metadata(inputs[0], outputs, null); | |||
| @@ -173,7 +178,7 @@ namespace Tensorflow.Keras.Layers | |||
| return null; | |||
| } | |||
| protected virtual (Tensor, Tensor) call(Tensor inputs, Tensor training = null) | |||
| protected virtual (Tensor, Tensor) call(Tensor inputs, Tensor training = null, Tensor state = null) | |||
| { | |||
| return (inputs, inputs); | |||
| } | |||
| @@ -233,7 +238,10 @@ namespace Tensorflow.Keras.Layers | |||
| initializer: initializer, | |||
| trainable: trainable.Value); | |||
| //backend.track_variable(variable); | |||
| _trainable_weights.Add(variable); | |||
| if (trainable == true) | |||
| _trainable_weights.Add(variable); | |||
| else | |||
| _non_trainable_weights.Add(variable); | |||
| return variable; | |||
| } | |||
| @@ -43,7 +43,7 @@ namespace Tensorflow.Keras.Layers | |||
| this.input_spec = new InputSpec(ndim: 4); | |||
| } | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null) | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null, Tensor state = null) | |||
| { | |||
| int[] pool_shape; | |||
| if (data_format == "channels_last") | |||
| @@ -43,6 +43,7 @@ namespace Tensorflow.Layers | |||
| // Avoid an incorrect lint error | |||
| _trainable_weights = new List<VariableV1>(); | |||
| _non_trainable_weights = new List<VariableV1>(); | |||
| this.built = false; | |||
| _keras_style = false; | |||
| } | |||
| @@ -54,6 +55,7 @@ namespace Tensorflow.Layers | |||
| public (Tensor, Tensor) __call__(Tensor inputs, | |||
| Tensor training = null, | |||
| Tensor state = null, | |||
| VariableScope scope = null) | |||
| { | |||
| _set_scope(scope); | |||
| @@ -76,7 +78,9 @@ namespace Tensorflow.Layers | |||
| { | |||
| _current_scope = scope2; | |||
| // Actually call layer | |||
| outputs = base.__call__(new Tensor[] { inputs }, training: training); | |||
| outputs = base.__call__(new Tensor[] { inputs }, | |||
| training: training, | |||
| state: state); | |||
| }); | |||
| @@ -121,6 +125,11 @@ namespace Tensorflow.Layers | |||
| Graph init_graph = null; | |||
| VariableV1[] existing_variables = null; | |||
| if (synchronization == VariableSynchronization.OnRead) | |||
| trainable = false; | |||
| else if (!trainable.HasValue) | |||
| trainable = true; | |||
| if (default_graph.building_function) | |||
| { | |||
| throw new NotImplementedException("add_weight"); | |||
| @@ -66,7 +66,7 @@ namespace Tensorflow | |||
| built = true; | |||
| } | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor state = null) | |||
| protected override (Tensor, Tensor) call(Tensor inputs, Tensor training = null, Tensor state = null) | |||
| { | |||
| // Most basic RNN: output = new_state = act(W * input + U * state + B). | |||
| var concat = array_ops.concat(new[] { inputs, state }, 1); | |||
| @@ -307,12 +307,6 @@ namespace Tensorflow.Operations | |||
| protected override void _AddOpInternal(Operation op) | |||
| { | |||
| if(op.name == "rnn/while/basic_rnn_cell/MatMul" || | |||
| op.name == "rnn/while/TensorArrayReadV3") | |||
| { | |||
| } | |||
| Operation[] external_inputs = new Operation[0]; | |||
| if (op.inputs.Length == 0) | |||
| { | |||
| @@ -412,10 +406,12 @@ namespace Tensorflow.Operations | |||
| } | |||
| if (_outer_context != null) | |||
| { | |||
| result = _outer_context.AddValue(val); | |||
| } | |||
| if (tf.get_default_graph()._nodes_by_name.Count >= 83) | |||
| { | |||
| } | |||
| // Create an Enter to make `result` known to this loop context. | |||
| Tensor enter = null; | |||
| tf_with(ops.control_dependencies(null), delegate | |||
| @@ -16,6 +16,7 @@ | |||
| using System; | |||
| using System.Linq; | |||
| using static Tensorflow.Binding; | |||
| namespace Tensorflow.Operations.Initializers | |||
| { | |||
| @@ -214,7 +214,7 @@ namespace Tensorflow.Operations | |||
| if (sequence_length != null) | |||
| throw new NotImplementedException("sequence_length != null"); | |||
| else | |||
| a = cell.__call__(input_t_t, state1); | |||
| a = cell.__call__(input_t_t, state: state1); | |||
| return item; | |||
| }; | |||
| @@ -32,9 +32,7 @@ namespace Tensorflow | |||
| public void _control_flow_post_processing() | |||
| { | |||
| foreach(Tensor input_tensor in inputs) | |||
| { | |||
| control_flow_util.CheckInputFromValidContext(this, input_tensor.op); | |||
| } | |||
| if (_control_flow_context != null) | |||
| _control_flow_context.AddOp(this); | |||
| @@ -78,6 +78,7 @@ namespace Tensorflow | |||
| #if SERIALIZABLE | |||
| [JsonIgnore] | |||
| #endif | |||
| bool _is_stateful; | |||
| public NodeDef node_def | |||
| { | |||
| get | |||
| @@ -173,6 +174,8 @@ namespace Tensorflow | |||
| } | |||
| } | |||
| _id_value = _graph._next_id(); | |||
| // Dict mapping op name to file and line information for op colocation | |||
| // context managers. | |||
| _control_flow_context = graph._get_control_flow_context(); | |||
| @@ -184,6 +187,8 @@ namespace Tensorflow | |||
| var grouped_inputs = _reconstruct_sequence_inputs(op_def, inputs, node_def.Attr); | |||
| _handle = ops._create_c_op(g, node_def, grouped_inputs, control_input_ops.ToArray()); | |||
| _is_stateful = op_def.IsStateful; | |||
| // Initialize self._outputs. | |||
| output_types = new TF_DataType[NumOutputs]; | |||
| for (int i = 0; i < NumOutputs; i++) | |||
| @@ -71,7 +71,7 @@ namespace Tensorflow | |||
| return tf_with(ops.name_scope(name, "random_uniform", new { shape, minval, maxval }), scope => | |||
| { | |||
| name = scope; | |||
| var tensorShape = _ShapeTensor(shape); | |||
| var tensorShape = tensor_util.shape_tensor(shape); | |||
| var minTensor = ops.convert_to_tensor(minval, dtype: dtype, name: "min"); | |||
| var maxTensor = ops.convert_to_tensor(maxval, dtype: dtype, name: "max"); | |||
| var rnd = gen_random_ops.random_uniform(tensorShape, dtype); | |||
| @@ -335,5 +335,10 @@ namespace Tensorflow | |||
| return shape; | |||
| } | |||
| public static Tensor shape_tensor(int[] shape) | |||
| { | |||
| return ops.convert_to_tensor(shape, dtype: TF_DataType.TF_INT32, name: "shape"); | |||
| } | |||
| } | |||
| } | |||
| @@ -133,66 +133,69 @@ namespace Tensorflow | |||
| if (trainable && !collections.Contains(tf.GraphKeys.TRAINABLE_VARIABLES)) | |||
| collections.Add(tf.GraphKeys.TRAINABLE_VARIABLES); | |||
| ops.init_scope(); | |||
| var values = init_from_fn ? new object[0] : new object[] { initial_value }; | |||
| tf_with(ops.name_scope(name, "Variable", values), scope => | |||
| tf_with(ops.init_scope2(), delegate | |||
| { | |||
| name = scope; | |||
| if (init_from_fn) | |||
| var values = init_from_fn ? new object[0] : new object[] { initial_value }; | |||
| tf_with(ops.name_scope(name, "Variable", values), scope => | |||
| { | |||
| // Use attr_scope and device(None) to simulate the behavior of | |||
| // colocate_with when the variable we want to colocate with doesn't | |||
| // yet exist. | |||
| string true_name = ops.name_from_scope_name(name); | |||
| var attr = new AttrValue | |||
| name = scope; | |||
| if (init_from_fn) | |||
| { | |||
| List = new AttrValue.Types.ListValue() | |||
| }; | |||
| attr.List.S.Add(ByteString.CopyFromUtf8($"loc:{true_name}")); | |||
| tf_with(ops.name_scope("Initializer"), scope2 => | |||
| // Use attr_scope and device(None) to simulate the behavior of | |||
| // colocate_with when the variable we want to colocate with doesn't | |||
| // yet exist. | |||
| string true_name = ops.name_from_scope_name(name); | |||
| var attr = new AttrValue | |||
| { | |||
| List = new AttrValue.Types.ListValue() | |||
| }; | |||
| attr.List.S.Add(ByteString.CopyFromUtf8($"loc:{true_name}")); | |||
| tf_with(ops.name_scope("Initializer"), scope2 => | |||
| { | |||
| _initial_value = (initial_value as Func<Tensor>)(); | |||
| _initial_value = ops.convert_to_tensor(_initial_value, name: "initial_value", dtype: dtype); | |||
| }); | |||
| _variable = state_ops.variable_op_v2(_initial_value.shape, _initial_value.dtype.as_base_dtype(), name: name); | |||
| } | |||
| // Or get the initial value from a Tensor or Python object. | |||
| else | |||
| { | |||
| _initial_value = (initial_value as Func<Tensor>)(); | |||
| _initial_value = ops.convert_to_tensor(_initial_value, name: "initial_value", dtype: dtype); | |||
| }); | |||
| _variable = state_ops.variable_op_v2(_initial_value.shape, _initial_value.dtype.as_base_dtype(), name: name); | |||
| } | |||
| // Or get the initial value from a Tensor or Python object. | |||
| else | |||
| { | |||
| _initial_value = ops.convert_to_tensor(initial_value, name: "initial_value", dtype: dtype); | |||
| _initial_value = ops.convert_to_tensor(initial_value, name: "initial_value", dtype: dtype); | |||
| var shape = _initial_value.shape; | |||
| dtype = _initial_value.dtype; | |||
| _variable = gen_state_ops.variable_v2(shape, dtype.as_base_dtype(), scope); | |||
| } | |||
| var shape = _initial_value.shape; | |||
| dtype = _initial_value.dtype; | |||
| _variable = gen_state_ops.variable_v2(shape, dtype.as_base_dtype(), scope); | |||
| } | |||
| // Manually overrides the variable's shape with the initial value's. | |||
| if (validate_shape) | |||
| { | |||
| var initial_value_shape = _initial_value.TensorShape; | |||
| if (!initial_value_shape.is_fully_defined()) | |||
| throw new ValueError($"initial_value must have a shape specified: {_initial_value}"); | |||
| } | |||
| // Manually overrides the variable's shape with the initial value's. | |||
| if (validate_shape) | |||
| { | |||
| var initial_value_shape = _initial_value.TensorShape; | |||
| if (!initial_value_shape.is_fully_defined()) | |||
| throw new ValueError($"initial_value must have a shape specified: {_initial_value}"); | |||
| } | |||
| // If 'initial_value' makes use of other variables, make sure we don't | |||
| // have an issue if these other variables aren't initialized first by | |||
| // using their initialized_value() method. | |||
| var _initial_value2 = _try_guard_against_uninitialized_dependencies(name, _initial_value); | |||
| // If 'initial_value' makes use of other variables, make sure we don't | |||
| // have an issue if these other variables aren't initialized first by | |||
| // using their initialized_value() method. | |||
| var _initial_value2 = _try_guard_against_uninitialized_dependencies(name, _initial_value); | |||
| _initializer_op = gen_state_ops.assign(_variable, _initial_value2, validate_shape).op; | |||
| _initializer_op = gen_state_ops.assign(_variable, _initial_value2, validate_shape).op; | |||
| if (!String.IsNullOrEmpty(caching_device)) | |||
| { | |||
| if (!String.IsNullOrEmpty(caching_device)) | |||
| { | |||
| } | |||
| else | |||
| { | |||
| ops.colocate_with(_initializer_op); | |||
| } | |||
| else | |||
| { | |||
| ops.colocate_with(_initializer_op); | |||
| _snapshot = gen_array_ops.identity(_variable, name = "read"); | |||
| } | |||
| _snapshot = gen_array_ops.identity(_variable, name = "read"); | |||
| } | |||
| ops.add_to_collections(collections, this as VariableV1); | |||
| ops.add_to_collections(collections, this as VariableV1); | |||
| }); | |||
| }); | |||
| } | |||
| @@ -186,12 +186,7 @@ namespace Tensorflow | |||
| /// operations constructed within the context. | |||
| /// </returns> | |||
| public static _ControlDependenciesController control_dependencies(object[] control_inputs) | |||
| { | |||
| return get_default_graph().control_dependencies(control_inputs); | |||
| } | |||
| public static _ControlDependenciesController control_dependencies(ITensorOrOperation[] control_inputs) | |||
| => control_dependencies(control_inputs == null ? null : control_inputs.OfType<object>().ToArray()); | |||
| => get_default_graph().control_dependencies(control_inputs); | |||
| /// <summary> | |||
| /// Creates a TF_Operation. | |||
| @@ -212,9 +207,9 @@ namespace Tensorflow | |||
| { | |||
| var op_desc = graph.NewOperation(node_def.Op, node_def.Name); | |||
| //TODO: Implement TF_SetDevice | |||
| //if node_def.device: | |||
| // c_api.TF_SetDevice(op_desc, compat.as_str(node_def.device)) | |||
| if (!string.IsNullOrEmpty(node_def.Device)) | |||
| c_api.TF_SetDevice(op_desc, node_def.Device); | |||
| // Add inputs | |||
| foreach (var op_input in inputs) | |||
| { | |||
| @@ -310,6 +305,22 @@ namespace Tensorflow | |||
| }); | |||
| } | |||
| public static IObjectLife init_scope2() | |||
| { | |||
| // Retrieve the active name scope: entering an `init_scope` preserves | |||
| // the name scope of the current context. | |||
| var default_graph = get_default_graph(); | |||
| var scope = default_graph.get_name_scope(); | |||
| if (!String.IsNullOrEmpty(scope) && !scope.EndsWith("/")) | |||
| // Names that end with trailing slashes are treated by `name_scope` as | |||
| // absolute. | |||
| scope += "/"; | |||
| // inner_device_stack = default_graph._device_function_stack | |||
| // var outer_context = default_graph.as_default; | |||
| return ops.control_dependencies(null); | |||
| } | |||
| private static int uid_number = 0; | |||
| /// <summary> | |||