| @@ -78,15 +78,15 @@ namespace Tensorflow | |||||
| /// <param name="axis"></param> | /// <param name="axis"></param> | ||||
| /// <param name="name"></param> | /// <param name="name"></param> | ||||
| /// <returns>A `Tensor` resulting from concatenation of the input tensors.</returns> | /// <returns>A `Tensor` resulting from concatenation of the input tensors.</returns> | ||||
| public Tensor concat(IList<Tensor> values, int axis, string name = "concat") | |||||
| public Tensor concat(IEnumerable<Tensor> values, int axis, string name = "concat") | |||||
| { | { | ||||
| if (values.Count == 1) | |||||
| if (values.Count() == 1) | |||||
| { | { | ||||
| return tf_with(ops.name_scope(name), scope => | return tf_with(ops.name_scope(name), scope => | ||||
| { | { | ||||
| var tensor = ops.convert_to_tensor(axis, name: "concat_dim", dtype: dtypes.int32); | var tensor = ops.convert_to_tensor(axis, name: "concat_dim", dtype: dtypes.int32); | ||||
| Debug.Assert(tensor.TensorShape.ndim == 0); | Debug.Assert(tensor.TensorShape.ndim == 0); | ||||
| return identity(values[0], name: scope); | |||||
| return identity(values.First(), name: scope); | |||||
| }); | }); | ||||
| } | } | ||||
| @@ -19,15 +19,18 @@ namespace Tensorflow | |||||
| public partial class tensorflow | public partial class tensorflow | ||||
| { | { | ||||
| public Tensor reshape(Tensor tensor, | public Tensor reshape(Tensor tensor, | ||||
| TensorShape shape, | |||||
| string name = null) => gen_array_ops.reshape(tensor, shape, name); | |||||
| TensorShape shape, | |||||
| string name = null) | |||||
| => gen_array_ops.reshape(tensor, shape, name); | |||||
| public Tensor reshape(Tensor tensor, | public Tensor reshape(Tensor tensor, | ||||
| Tensor[] shape, | |||||
| string name = null) => gen_array_ops.reshape(tensor, shape, name); | |||||
| Tensor shape, | |||||
| string name = null) | |||||
| => gen_array_ops.reshape(tensor, shape, name); | |||||
| public Tensor reshape(Tensor tensor, | public Tensor reshape(Tensor tensor, | ||||
| Tensor shape, | |||||
| string name = null) => gen_array_ops.reshape(tensor, shape, name); | |||||
| object[] shape, | |||||
| string name = null) | |||||
| => gen_array_ops.reshape(tensor, shape, name); | |||||
| } | } | ||||
| } | } | ||||
| @@ -13,13 +13,22 @@ | |||||
| See the License for the specific language governing permissions and | See the License for the specific language governing permissions and | ||||
| limitations under the License. | limitations under the License. | ||||
| ******************************************************************************/ | ******************************************************************************/ | ||||
| using static Tensorflow.Binding; | |||||
| namespace Tensorflow | namespace Tensorflow | ||||
| { | { | ||||
| public partial class tensorflow | public partial class tensorflow | ||||
| { | { | ||||
| public Tensor tile<T>(Tensor input, | |||||
| T multiples, | |||||
| string name = null) => gen_array_ops.tile(input, multiples, name); | |||||
| public Tensor tile(Tensor input, Tensor multiples, string name = null) | |||||
| => gen_array_ops.tile(input, multiples, name); | |||||
| public Tensor tile(Tensor input, object[] multiples, string name = null) | |||||
| => gen_array_ops.tile(input, multiples, name); | |||||
| public Tensor tile(Tensor input, TensorShape multiples, string name = null) | |||||
| { | |||||
| var multiples_tensor = constant_op.constant(multiples); | |||||
| return gen_array_ops.tile(input, multiples_tensor, name); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -28,16 +28,27 @@ namespace Tensorflow.Contexts | |||||
| /// </summary> | /// </summary> | ||||
| public sealed partial class Context | public sealed partial class Context | ||||
| { | { | ||||
| // [DebuggerStepThrough] | |||||
| public T RunInAutoMode<T>(Func<T> graphAction, Func<T> eagerAction, params Tensor[] tensors) | |||||
| public T RunInAutoMode<T>(Func<T> graphAction, Func<T> eagerAction, params object[] args) | |||||
| { | { | ||||
| var shouldRunInEager = executing_eagerly() | |||||
| && tensors.Count(x => x.IsEagerTensor) == tensors.Length; | |||||
| if (shouldRunInEager) | |||||
| return eagerAction(); | |||||
| else | |||||
| if (tf.Context.has_graph_arg(args)) | |||||
| { | |||||
| return graphAction(); | return graphAction(); | ||||
| } | |||||
| else | |||||
| { | |||||
| try | |||||
| { | |||||
| return eagerAction(); | |||||
| } | |||||
| catch (InvalidArgumentError ex) | |||||
| { | |||||
| throw ex; | |||||
| } | |||||
| catch (Exception ex) | |||||
| { | |||||
| return graphAction(); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| // [DebuggerStepThrough] | // [DebuggerStepThrough] | ||||
| @@ -46,12 +57,7 @@ namespace Tensorflow.Contexts | |||||
| Action<Operation> recordGradient, | Action<Operation> recordGradient, | ||||
| Tensors tensors) | Tensors tensors) | ||||
| { | { | ||||
| var shouldRunInEager = executing_eagerly() | |||||
| && tensors.Count(x => x.IsEagerTensor) == tensors.Length; | |||||
| if (shouldRunInEager) | |||||
| return eagerAction(); | |||||
| else | |||||
| if (tf.Context.has_graph_arg(tensors)) | |||||
| { | { | ||||
| if (executing_eagerly()) | if (executing_eagerly()) | ||||
| { | { | ||||
| @@ -68,6 +74,10 @@ namespace Tensorflow.Contexts | |||||
| return result; | return result; | ||||
| } | } | ||||
| } | } | ||||
| else | |||||
| { | |||||
| return eagerAction(); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -20,6 +20,7 @@ using System.Linq; | |||||
| using Tensorflow.Eager; | using Tensorflow.Eager; | ||||
| using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
| using Google.Protobuf; | using Google.Protobuf; | ||||
| using Tensorflow.Util; | |||||
| namespace Tensorflow.Contexts | namespace Tensorflow.Contexts | ||||
| { | { | ||||
| @@ -103,6 +104,29 @@ namespace Tensorflow.Contexts | |||||
| public void eager_mode(bool isFunc = false) | public void eager_mode(bool isFunc = false) | ||||
| => context_switches.Push(true, isFunc); | => context_switches.Push(true, isFunc); | ||||
| public bool switched_to_graph(params object[] args) | |||||
| { | |||||
| var switching_to_graph = has_graph_arg(args) && tf.Context.executing_eagerly(); | |||||
| if (switching_to_graph) | |||||
| tf.Context.graph_mode(tf.Context.is_build_function()); | |||||
| return switching_to_graph; | |||||
| } | |||||
| public bool has_graph_arg(params object[] args) | |||||
| { | |||||
| var flatten_args = nest.flatten<object>(args); | |||||
| bool has_graph_arg = false; | |||||
| foreach (var el in flatten_args) | |||||
| { | |||||
| if (el is Tensor tensor && !tensor.IsEagerTensor) | |||||
| { | |||||
| has_graph_arg = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| return has_graph_arg; | |||||
| } | |||||
| public void restore_mode() | public void restore_mode() | ||||
| { | { | ||||
| context_switches.Pop(); | context_switches.Pop(); | ||||
| @@ -38,9 +38,9 @@ namespace Tensorflow.Eager | |||||
| } | } | ||||
| }*/ | }*/ | ||||
| } | } | ||||
| tf.Logger.Debug($"RecordGradient: should_record={should_record}, op_name={op_name}"); | |||||
| if (!should_record) return should_record; | if (!should_record) return should_record; | ||||
| tf.Logger.Debug($"RecordGradient: op_name={op_name}"); | |||||
| Tensor[] op_outputs; | Tensor[] op_outputs; | ||||
| #pragma warning disable CS0219 // Variable is assigned but its value is never used | #pragma warning disable CS0219 // Variable is assigned but its value is never used | ||||
| @@ -50,7 +50,7 @@ namespace Tensorflow.Eager | |||||
| var op_def = tf.get_default_graph().GetOpDef(opName); | var op_def = tf.get_default_graph().GetOpDef(opName); | ||||
| var flattened_attrs = new List<object>(op_def.InputArg.Count); | |||||
| var flattened_attrs = new List<object>(op_def.Attr.Count * 2); | |||||
| var flattened_inputs = new List<Tensor>(op_def.InputArg.Count); | var flattened_inputs = new List<Tensor>(op_def.InputArg.Count); | ||||
| // Set non-inferred attrs, including setting defaults if the attr is passed in | // Set non-inferred attrs, including setting defaults if the attr is passed in | ||||
| @@ -221,23 +221,9 @@ namespace Tensorflow.Eager | |||||
| SafeTensorHandleHandle input_handle; | SafeTensorHandleHandle input_handle; | ||||
| // ConvertToTensor(); | // ConvertToTensor(); | ||||
| switch (inputs) | |||||
| { | |||||
| case EagerTensor input: | |||||
| input_handle = input.EagerTensorHandle; | |||||
| flattened_inputs.Add(input); | |||||
| break; | |||||
| case ResourceVariable variable: | |||||
| var var_tensor = variable.AsTensor(); | |||||
| input_handle = var_tensor.EagerTensorHandle; | |||||
| flattened_inputs.Add(var_tensor); | |||||
| break; | |||||
| default: | |||||
| var tensor = tf.convert_to_tensor(inputs); | |||||
| input_handle = tensor.EagerTensorHandle; | |||||
| flattened_inputs.Add(tensor); | |||||
| break; | |||||
| } | |||||
| var tensor = tf.convert_to_tensor(inputs); | |||||
| input_handle = tensor.EagerTensorHandle; | |||||
| flattened_inputs.Add(tensor); | |||||
| if (add_type_attr && !string.IsNullOrEmpty(input_arg.TypeAttr)) | if (add_type_attr && !string.IsNullOrEmpty(input_arg.TypeAttr)) | ||||
| { | { | ||||
| @@ -2,6 +2,7 @@ | |||||
| using System; | using System; | ||||
| using System.Linq; | using System.Linq; | ||||
| using System.Text; | using System.Text; | ||||
| using static Tensorflow.Binding; | |||||
| namespace Tensorflow.Framework | namespace Tensorflow.Framework | ||||
| { | { | ||||
| @@ -65,5 +66,17 @@ namespace Tensorflow.Framework | |||||
| public static TensorShape as_shape(this Shape shape) | public static TensorShape as_shape(this Shape shape) | ||||
| => new TensorShape(shape.Dimensions); | => new TensorShape(shape.Dimensions); | ||||
| public static TensorShape most_specific_compatible_shape(this TensorShape self, TensorShape other) | |||||
| { | |||||
| var dims = range(self.rank).Select(x => -1).ToArray(); | |||||
| foreach(var (i, (d1, d2)) in enumerate(zip(self.dims, other.dims))) | |||||
| { | |||||
| if (d1 == d2) | |||||
| dims[i] = d1; | |||||
| } | |||||
| return new TensorShape(dims); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -134,7 +134,7 @@ namespace Tensorflow.Functions | |||||
| /// <param name="args"></param> | /// <param name="args"></param> | ||||
| /// <param name="captured_inputs"></param> | /// <param name="captured_inputs"></param> | ||||
| /// <returns></returns> | /// <returns></returns> | ||||
| public Tensor[] CallFlat(Tensor[] args, Tensor[] captured_inputs) | |||||
| public Tensors CallFlat(Tensor[] args, Tensor[] captured_inputs) | |||||
| { | { | ||||
| var executing_eagerly = tf.Context.executing_eagerly(); | var executing_eagerly = tf.Context.executing_eagerly(); | ||||
| var default_graph = ops.get_default_graph(); | var default_graph = ops.get_default_graph(); | ||||
| @@ -99,8 +99,18 @@ namespace Tensorflow.Functions | |||||
| if (input_index >= backward_function_inputs) | if (input_index >= backward_function_inputs) | ||||
| break; | break; | ||||
| } | } | ||||
| tf.Logger.Debug($"Invoke backward function: {backward.Name}"); | tf.Logger.Debug($"Invoke backward function: {backward.Name}"); | ||||
| return backward.CallFlat(processed_args, remapped_captures); | |||||
| var gradients = backward.CallFlat(processed_args, remapped_captures); | |||||
| foreach (var unneeded_gradient_index in unneeded_gradients) | |||||
| { | |||||
| var index = Convert.ToInt32(unneeded_gradient_index); | |||||
| if (gradients.Length <= index) | |||||
| gradients.Insert(index, null); | |||||
| } | |||||
| return gradients; | |||||
| }; | }; | ||||
| return (_backward_function_wrapper, recorded_outputs); | return (_backward_function_wrapper, recorded_outputs); | ||||
| @@ -151,6 +151,7 @@ namespace Tensorflow | |||||
| /// <returns></returns> | /// <returns></returns> | ||||
| public virtual Graph as_default() | public virtual Graph as_default() | ||||
| { | { | ||||
| tf.Context.graph_mode(isFunc: false); | |||||
| return ops.set_default_graph(this); | return ops.set_default_graph(this); | ||||
| } | } | ||||
| @@ -532,6 +533,7 @@ namespace Tensorflow | |||||
| public virtual void Exit() | public virtual void Exit() | ||||
| { | { | ||||
| tf.Context.restore_mode(); | |||||
| ops.pop_graph(); | ops.pop_graph(); | ||||
| } | } | ||||
| @@ -3,5 +3,6 @@ | |||||
| public class ReshapeArgs : LayerArgs | public class ReshapeArgs : LayerArgs | ||||
| { | { | ||||
| public TensorShape TargetShape { get; set; } | public TensorShape TargetShape { get; set; } | ||||
| public object[] TargetShapeObjects { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -132,7 +132,7 @@ namespace Tensorflow | |||||
| if (!input_arg.IsRef && dtype != DataType.DtInvalid) | if (!input_arg.IsRef && dtype != DataType.DtInvalid) | ||||
| dtype = dtype.as_base_dtype(); | dtype = dtype.as_base_dtype(); | ||||
| values = ops.internal_convert_n_to_tensor(values, | |||||
| values = ops.internal_convert_n_to_tensor(values as object[], | |||||
| name: input_arg.Name, | name: input_arg.Name, | ||||
| dtype: dtype.as_tf_dtype(), | dtype: dtype.as_tf_dtype(), | ||||
| preferred_dtype: default_dtype.as_tf_dtype(), | preferred_dtype: default_dtype.as_tf_dtype(), | ||||
| @@ -19,6 +19,7 @@ using System; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Linq; | using System.Linq; | ||||
| using Tensorflow.Contexts; | using Tensorflow.Contexts; | ||||
| using Tensorflow.Eager; | |||||
| using Tensorflow.Framework; | using Tensorflow.Framework; | ||||
| using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
| @@ -215,7 +216,7 @@ namespace Tensorflow | |||||
| } | } | ||||
| } | } | ||||
| public static Tensor _autopacking_conversion_function(object[] v, TF_DataType dtype = TF_DataType.DtInvalid, string name = null, bool as_ref = false) | |||||
| public static Tensor _autopacking_conversion_function(IEnumerable<object> v, TF_DataType dtype = TF_DataType.DtInvalid, string name = null, bool as_ref = false) | |||||
| { | { | ||||
| var inferred_dtype = _get_dtype_from_nested_lists(v); | var inferred_dtype = _get_dtype_from_nested_lists(v); | ||||
| if (dtype == TF_DataType.DtInvalid) | if (dtype == TF_DataType.DtInvalid) | ||||
| @@ -224,7 +225,7 @@ namespace Tensorflow | |||||
| return _autopacking_helper(v, dtype, name == null ? "packed" : name); | return _autopacking_helper(v, dtype, name == null ? "packed" : name); | ||||
| } | } | ||||
| private static TF_DataType _get_dtype_from_nested_lists(object[] list_or_tuple) | |||||
| private static TF_DataType _get_dtype_from_nested_lists(IEnumerable<object> list_or_tuple) | |||||
| { | { | ||||
| TF_DataType dtype = TF_DataType.DtInvalid; | TF_DataType dtype = TF_DataType.DtInvalid; | ||||
| @@ -251,11 +252,14 @@ namespace Tensorflow | |||||
| /// <param name="dtype"></param> | /// <param name="dtype"></param> | ||||
| /// <param name="name"></param> | /// <param name="name"></param> | ||||
| /// <returns>A `tf.Tensor` with value equivalent to `list_or_tuple`.</returns> | /// <returns>A `tf.Tensor` with value equivalent to `list_or_tuple`.</returns> | ||||
| public static Tensor _autopacking_helper(object[] list_or_tuple, TF_DataType dtype, string name) | |||||
| public static Tensor _autopacking_helper(IEnumerable<object> list_or_tuple, TF_DataType dtype, string name) | |||||
| { | { | ||||
| var must_pack = false; | var must_pack = false; | ||||
| var converted_elems = new List<object>(); | var converted_elems = new List<object>(); | ||||
| return tf_with(ops.name_scope(name), scope => | |||||
| bool switch_to_graph = tf.Context.switched_to_graph(list_or_tuple.ToArray()); | |||||
| var result = tf_with(ops.name_scope(name), scope => | |||||
| { | { | ||||
| foreach (var (i, elem) in enumerate(list_or_tuple)) | foreach (var (i, elem) in enumerate(list_or_tuple)) | ||||
| { | { | ||||
| @@ -268,8 +272,17 @@ namespace Tensorflow | |||||
| var elems_as_tensors = new List<Tensor>(); | var elems_as_tensors = new List<Tensor>(); | ||||
| foreach (var (i, elem) in enumerate(converted_elems)) | foreach (var (i, elem) in enumerate(converted_elems)) | ||||
| { | { | ||||
| if (elem is Tensor tensor) | |||||
| if (elem is EagerTensor eager_tensor) | |||||
| { | |||||
| if(switch_to_graph) | |||||
| elems_as_tensors.Add(constant_op.constant(eager_tensor.numpy(), dtype: dtype, name: i.ToString())); | |||||
| else | |||||
| elems_as_tensors.Add(eager_tensor); | |||||
| } | |||||
| else if (elem is Tensor tensor) | |||||
| { | |||||
| elems_as_tensors.Add(tensor); | elems_as_tensors.Add(tensor); | ||||
| } | |||||
| else | else | ||||
| { | { | ||||
| var elem_tensor = constant_op.constant(elem, dtype: dtype, name: i.ToString()); | var elem_tensor = constant_op.constant(elem, dtype: dtype, name: i.ToString()); | ||||
| @@ -284,6 +297,11 @@ namespace Tensorflow | |||||
| return tf.constant(np.array(new float[0])); | return tf.constant(np.array(new float[0])); | ||||
| } | } | ||||
| }); | }); | ||||
| if (switch_to_graph) | |||||
| tf.Context.restore_mode(); | |||||
| return result; | |||||
| } | } | ||||
| public static Tensor expand_dims(Tensor input, int axis = -1, string name = null, int dim = -1) | public static Tensor expand_dims(Tensor input, int axis = -1, string name = null, int dim = -1) | ||||
| @@ -351,8 +369,14 @@ namespace Tensorflow | |||||
| public static Tensor ones_like<T>(T tensor, TF_DataType dtype = TF_DataType.DtInvalid, string name = null, bool optimize = true) | public static Tensor ones_like<T>(T tensor, TF_DataType dtype = TF_DataType.DtInvalid, string name = null, bool optimize = true) | ||||
| => ones_like_impl(tensor, dtype, name, optimize); | => ones_like_impl(tensor, dtype, name, optimize); | ||||
| public static Tensor reshape<T2>(Tensor tensor, T2 shape, string name = null) | |||||
| => gen_array_ops.reshape(tensor, shape, null); | |||||
| public static Tensor reshape(Tensor tensor, Tensor shape, string name = null) | |||||
| => gen_array_ops.reshape(tensor, shape, name: name); | |||||
| public static Tensor reshape(Tensor tensor, TensorShape shape, string name = null) | |||||
| => gen_array_ops.reshape(tensor, shape, name: name); | |||||
| public static Tensor reshape(Tensor tensor, object[] shape, string name = null) | |||||
| => gen_array_ops.reshape(tensor, shape, name: name); | |||||
| private static Tensor ones_like_impl<T>(T tensor, TF_DataType dtype, string name, bool optimize = true) | private static Tensor ones_like_impl<T>(T tensor, TF_DataType dtype, string name, bool optimize = true) | ||||
| { | { | ||||
| @@ -22,7 +22,11 @@ namespace Tensorflow | |||||
| return results[0]; | return results[0]; | ||||
| } | } | ||||
| throw new NotImplementedException(""); | |||||
| var _op = tf.OpDefLib._apply_op_helper("TensorDataset", | |||||
| name: name, | |||||
| args: new { components, output_shapes }); | |||||
| return _op.output; | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -180,6 +184,28 @@ namespace Tensorflow | |||||
| throw new NotImplementedException(""); | throw new NotImplementedException(""); | ||||
| } | } | ||||
| public Tensor concatenate_dataset(Tensor input_dataset, Tensor another_dataset, | |||||
| TF_DataType[] output_types, TensorShape[] output_shapes, | |||||
| string name = null) | |||||
| { | |||||
| if (tf.Context.executing_eagerly()) | |||||
| { | |||||
| var results = tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
| "ConcatenateDataset", name, | |||||
| null, | |||||
| input_dataset, another_dataset, | |||||
| "output_types", output_types, | |||||
| "output_shapes", output_shapes); | |||||
| return results[0]; | |||||
| } | |||||
| var _op = tf.OpDefLib._apply_op_helper("ConcatenateDataset", | |||||
| name: name, | |||||
| args: new { input_dataset, another_dataset, output_types, output_shapes }); | |||||
| return _op.outputs[0]; | |||||
| } | |||||
| public Tensor cache_dataset_v2(Tensor input_dataset, Tensor filename, Tensor cache, | public Tensor cache_dataset_v2(Tensor input_dataset, Tensor filename, Tensor cache, | ||||
| TF_DataType[] output_types, TensorShape[] output_shapes, | TF_DataType[] output_types, TensorShape[] output_shapes, | ||||
| string name = null) | string name = null) | ||||
| @@ -202,20 +202,14 @@ namespace Tensorflow | |||||
| } | } | ||||
| public static Tensor pack(Tensor[] values, int axis = 0, string name = null) | public static Tensor pack(Tensor[] values, int axis = 0, string name = null) | ||||
| { | |||||
| if (tf.Context.executing_eagerly()) | |||||
| { | |||||
| var results = tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
| => tf.Context.RunInAutoMode(() | |||||
| => tf.OpDefLib._apply_op_helper("Pack", name, new { values, axis }).output, () | |||||
| => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
| "Pack", name, | "Pack", name, | ||||
| null, | null, | ||||
| values, | values, | ||||
| "axis", axis); | |||||
| return results[0]; | |||||
| } | |||||
| var _op = tf.OpDefLib._apply_op_helper("Pack", name: name, args: new { values, axis }); | |||||
| return _op.output; | |||||
| } | |||||
| "axis", axis).FirstOrDefault(), | |||||
| values, axis); | |||||
| /// <summary> | /// <summary> | ||||
| /// Return a tensor with the same shape and contents as the input tensor or value. | /// Return a tensor with the same shape and contents as the input tensor or value. | ||||
| @@ -338,12 +332,39 @@ namespace Tensorflow | |||||
| "Reshape", name, | "Reshape", name, | ||||
| null, | null, | ||||
| tensor, shape).FirstOrDefault(), | tensor, shape).FirstOrDefault(), | ||||
| tensor); | |||||
| tensor, shape); | |||||
| public static Tensor reshape(Tensor tensor, int[] shape, string name = null) | |||||
| public static Tensor reshape(Tensor tensor, object[] shape, string name = null) | |||||
| { | { | ||||
| var _op = tf.OpDefLib._apply_op_helper("Reshape", name, new { tensor, shape }); | |||||
| return _op.outputs[0]; | |||||
| try | |||||
| { | |||||
| return tf.Context.RunInAutoMode(() | |||||
| => tf.OpDefLib._apply_op_helper("Reshape", name, new { tensor, shape }).output, () | |||||
| => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
| "Reshape", name, | |||||
| null, | |||||
| tensor, shape).FirstOrDefault(), | |||||
| tensor, shape); | |||||
| } | |||||
| catch (InvalidArgumentError ex) | |||||
| { | |||||
| return reshape_eager_fallback(tensor, shape, name, tf.Context); | |||||
| } | |||||
| } | |||||
| private static Tensor reshape_eager_fallback(Tensor tensor, object[] shape, string name, Context ctx) | |||||
| { | |||||
| var (_attr_T, _input) = tf.Runner.ArgsToMatchingEager(ctx, args: new[] { tensor }); | |||||
| var (_attr_Tshape, _input_shape) = tf.Runner.ArgsToMatchingEager(ctx, args: new object[] { shape }, default_dtype: TF_DataType.TF_INT32); | |||||
| var _inputs_flat = new[] { _input[0], _input_shape[0] }; | |||||
| var _attrs = new object[] { "T", _attr_T, "Tshape", _attr_Tshape }; | |||||
| var results = tf.Runner.Execute(ctx, "Reshape", 1, _inputs_flat, _attrs, name: name); | |||||
| if (tf.Runner.MustRecordGradient()) | |||||
| { | |||||
| tf.Runner.RecordGradient("Reshape", _inputs_flat, _attrs, results); | |||||
| } | |||||
| return results[0]; | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -537,14 +558,23 @@ namespace Tensorflow | |||||
| return _op.outputs; | return _op.outputs; | ||||
| } | } | ||||
| public static Tensor tile<T>(Tensor input, T multiples, string name = null) | |||||
| public static Tensor tile(Tensor input, Tensor multiples, string name = null) | |||||
| => tf.Context.RunInAutoMode(() | => tf.Context.RunInAutoMode(() | ||||
| => tf.OpDefLib._apply_op_helper("Tile", name, new { input, multiples }).output, () | => tf.OpDefLib._apply_op_helper("Tile", name, new { input, multiples }).output, () | ||||
| => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | ||||
| "Tile", name, | "Tile", name, | ||||
| null, | null, | ||||
| input, multiples).FirstOrDefault(), | input, multiples).FirstOrDefault(), | ||||
| input); | |||||
| input, multiples); | |||||
| public static Tensor tile(Tensor input, object[] multiples, string name = null) | |||||
| => tf.Context.RunInAutoMode(() | |||||
| => tf.OpDefLib._apply_op_helper("Tile", name, new { input, multiples }).output, () | |||||
| => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
| "Tile", name, | |||||
| null, | |||||
| input, multiples).FirstOrDefault(), | |||||
| input, multiples); | |||||
| public static Tensor transpose<T1>(Tensor x, T1 perm, string name = null) | public static Tensor transpose<T1>(Tensor x, T1 perm, string name = null) | ||||
| { | { | ||||
| @@ -1874,7 +1874,7 @@ new_height, new_width"); | |||||
| { | { | ||||
| using (ops.name_scope("suppression_loop_body")) | using (ops.name_scope("suppression_loop_body")) | ||||
| { | { | ||||
| var num_tiles = Math.Floor((double)array_ops.shape(boxes).dims[1] / tile_size); | |||||
| var num_tiles = array_ops.shape(boxes).dims[1] / tile_size; | |||||
| var batch_size = array_ops.shape(boxes).dims[0]; | var batch_size = array_ops.shape(boxes).dims[0]; | ||||
| (Tensor, Tensor, Tensor, Tensor) cross_suppression_func(Tensor boxes, Tensor box_slice, Tensor iou_threshold, Tensor inner_idx, int tile_size) | (Tensor, Tensor, Tensor, Tensor) cross_suppression_func(Tensor boxes, Tensor box_slice, Tensor iou_threshold, Tensor inner_idx, int tile_size) | ||||
| @@ -5,7 +5,7 @@ | |||||
| <AssemblyName>TensorFlow.NET</AssemblyName> | <AssemblyName>TensorFlow.NET</AssemblyName> | ||||
| <RootNamespace>Tensorflow</RootNamespace> | <RootNamespace>Tensorflow</RootNamespace> | ||||
| <TargetTensorFlow>2.2.0</TargetTensorFlow> | <TargetTensorFlow>2.2.0</TargetTensorFlow> | ||||
| <Version>0.32.0</Version> | |||||
| <Version>0.33.0</Version> | |||||
| <LangVersion>8.0</LangVersion> | <LangVersion>8.0</LangVersion> | ||||
| <Authors>Haiping Chen, Meinrad Recheis, Eli Belash</Authors> | <Authors>Haiping Chen, Meinrad Recheis, Eli Belash</Authors> | ||||
| <Company>SciSharp STACK</Company> | <Company>SciSharp STACK</Company> | ||||
| @@ -19,7 +19,7 @@ | |||||
| <Description>Google's TensorFlow full binding in .NET Standard. | <Description>Google's TensorFlow full binding in .NET Standard. | ||||
| Building, training and infering deep learning models. | Building, training and infering deep learning models. | ||||
| https://tensorflownet.readthedocs.io</Description> | https://tensorflownet.readthedocs.io</Description> | ||||
| <AssemblyVersion>0.32.0.0</AssemblyVersion> | |||||
| <AssemblyVersion>0.33.0.0</AssemblyVersion> | |||||
| <PackageReleaseNotes>tf.net 0.20.x and above are based on tensorflow native 2.x. | <PackageReleaseNotes>tf.net 0.20.x and above are based on tensorflow native 2.x. | ||||
| * Eager Mode is added finally. | * Eager Mode is added finally. | ||||
| @@ -28,7 +28,7 @@ https://tensorflownet.readthedocs.io</Description> | |||||
| * autograph works partially. | * autograph works partially. | ||||
| TensorFlow .NET v0.3x is focused on making more Keras API works</PackageReleaseNotes> | TensorFlow .NET v0.3x is focused on making more Keras API works</PackageReleaseNotes> | ||||
| <FileVersion>0.32.0.0</FileVersion> | |||||
| <FileVersion>0.33.0.0</FileVersion> | |||||
| <PackageLicenseFile>LICENSE</PackageLicenseFile> | <PackageLicenseFile>LICENSE</PackageLicenseFile> | ||||
| <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | ||||
| <SignAssembly>true</SignAssembly> | <SignAssembly>true</SignAssembly> | ||||
| @@ -4,6 +4,12 @@ namespace Tensorflow | |||||
| { | { | ||||
| public partial class TensorShape | public partial class TensorShape | ||||
| { | { | ||||
| public void Deconstruct(out int h, out int w) | |||||
| { | |||||
| h = dims[0]; | |||||
| w = dims[1]; | |||||
| } | |||||
| public static implicit operator TensorShape(Shape shape) => new TensorShape((int[])shape.Dimensions.Clone()); | public static implicit operator TensorShape(Shape shape) => new TensorShape((int[])shape.Dimensions.Clone()); | ||||
| public static implicit operator Shape(TensorShape shape) => new Shape((int[])shape.dims.Clone()); | public static implicit operator Shape(TensorShape shape) => new Shape((int[])shape.dims.Clone()); | ||||
| @@ -60,6 +60,9 @@ namespace Tensorflow | |||||
| public void AddRange(Tensor[] tensors) | public void AddRange(Tensor[] tensors) | ||||
| => items.AddRange(tensors); | => items.AddRange(tensors); | ||||
| public void Insert(int index, Tensor tensor) | |||||
| => items.Insert(index, tensor); | |||||
| IEnumerator IEnumerable.GetEnumerator() | IEnumerator IEnumerable.GetEnumerator() | ||||
| { | { | ||||
| throw new NotImplementedException(); | throw new NotImplementedException(); | ||||
| @@ -156,8 +156,8 @@ namespace Tensorflow | |||||
| return val; | return val; | ||||
| case NDArray val: | case NDArray val: | ||||
| return new EagerTensor(val, ctx.DeviceName); | return new EagerTensor(val, ctx.DeviceName); | ||||
| //case TensorShape val: | |||||
| //return new EagerTensor(val.dims, ctx.DeviceName); | |||||
| case TensorShape val: | |||||
| return new EagerTensor(val.dims, ctx.DeviceName); | |||||
| case string val: | case string val: | ||||
| return new EagerTensor(val, ctx.DeviceName); | return new EagerTensor(val, ctx.DeviceName); | ||||
| case string[] val: | case string[] val: | ||||
| @@ -123,6 +123,17 @@ namespace Tensorflow | |||||
| { | { | ||||
| nparray = nd; | nparray = nd; | ||||
| } | } | ||||
| else if(values is string str) | |||||
| { | |||||
| // scalar string | |||||
| nparray = convert_to_numpy_ndarray(values); | |||||
| shape = new int[0]; | |||||
| } | |||||
| else if(values is string[] strings) | |||||
| { | |||||
| nparray = convert_to_numpy_ndarray(values); | |||||
| shape = new[] { strings.Length }; | |||||
| } | |||||
| else | else | ||||
| { | { | ||||
| if (values == null) | if (values == null) | ||||
| @@ -151,9 +162,14 @@ namespace Tensorflow | |||||
| { | { | ||||
| if (numpy_dtype == TF_DataType.TF_STRING) | if (numpy_dtype == TF_DataType.TF_STRING) | ||||
| { | { | ||||
| // scalar string | |||||
| shape = new int[0]; | |||||
| shape_size = 0; | |||||
| if (nparray.ndim == 0) | |||||
| { | |||||
| // scalar string | |||||
| shape = new int[0]; | |||||
| shape_size = 0; | |||||
| } | |||||
| else | |||||
| throw new NotImplementedException($"Not implemented for {nparray.ndim} dims string array."); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -428,6 +444,9 @@ would not be rank 1.", tensor.op.get_attr("axis"))); | |||||
| case NDArray val: | case NDArray val: | ||||
| nd = val; | nd = val; | ||||
| break; | break; | ||||
| case TensorShape val: | |||||
| nd = val.dims; | |||||
| break; | |||||
| case bool boolVal: | case bool boolVal: | ||||
| nd = boolVal; | nd = boolVal; | ||||
| break; | break; | ||||
| @@ -471,7 +490,7 @@ would not be rank 1.", tensor.op.get_attr("axis"))); | |||||
| nd = new NDArray(Encoding.ASCII.GetBytes(strVal)); | nd = new NDArray(Encoding.ASCII.GetBytes(strVal)); | ||||
| break; | break; | ||||
| case string[] strVals: | case string[] strVals: | ||||
| nd = strVals; | |||||
| nd = np.array(strVals); | |||||
| break; | break; | ||||
| case byte[] byteValues: | case byte[] byteValues: | ||||
| nd = byteValues; | nd = byteValues; | ||||
| @@ -150,7 +150,8 @@ namespace Tensorflow | |||||
| TensorShape ts => constant_op.constant(ts.dims, dtype: dtype, name: name), | TensorShape ts => constant_op.constant(ts.dims, dtype: dtype, name: name), | ||||
| int[] dims => constant_op.constant(dims, dtype: dtype, name: name), | int[] dims => constant_op.constant(dims, dtype: dtype, name: name), | ||||
| string str => constant_op.constant(str, dtype: tf.@string, name: name), | string str => constant_op.constant(str, dtype: tf.@string, name: name), | ||||
| object[] objects => array_ops._autopacking_conversion_function(objects, dtype: dtype, name: name), | |||||
| string[] str => constant_op.constant(str, dtype: tf.@string, name: name), | |||||
| IEnumerable<object> objects => array_ops._autopacking_conversion_function(objects, dtype: dtype, name: name), | |||||
| _ => constant_op.constant(value, dtype: dtype, name: name) | _ => constant_op.constant(value, dtype: dtype, name: name) | ||||
| }; | }; | ||||
| @@ -500,18 +501,16 @@ namespace Tensorflow | |||||
| return ret.ToArray(); | return ret.ToArray(); | ||||
| } | } | ||||
| public static Tensor[] internal_convert_n_to_tensor(object values, TF_DataType dtype = TF_DataType.DtInvalid, | |||||
| public static Tensor[] internal_convert_n_to_tensor(object[] values, TF_DataType dtype = TF_DataType.DtInvalid, | |||||
| string name = null, TF_DataType preferred_dtype = TF_DataType.DtInvalid, | string name = null, TF_DataType preferred_dtype = TF_DataType.DtInvalid, | ||||
| bool as_ref = false) | bool as_ref = false) | ||||
| { | { | ||||
| var ret = new List<Tensor>(); | var ret = new List<Tensor>(); | ||||
| foreach ((int i, object value) in enumerate(values as object[])) | |||||
| foreach ((int i, object value) in enumerate(values)) | |||||
| { | { | ||||
| string n = string.IsNullOrEmpty(name) ? "" : $"{name}_{i}"; | string n = string.IsNullOrEmpty(name) ? "" : $"{name}_{i}"; | ||||
| ret.Add(convert_to_tensor(value, dtype: dtype, name: n, as_ref: as_ref, preferred_dtype: preferred_dtype)); | ret.Add(convert_to_tensor(value, dtype: dtype, name: n, as_ref: as_ref, preferred_dtype: preferred_dtype)); | ||||
| } | } | ||||
| return ret.ToArray(); | return ret.ToArray(); | ||||
| } | } | ||||
| @@ -48,7 +48,7 @@ namespace Tensorflow | |||||
| public tensorflow() | public tensorflow() | ||||
| { | { | ||||
| Logger = new LoggerConfiguration() | Logger = new LoggerConfiguration() | ||||
| .MinimumLevel.Warning() | |||||
| .MinimumLevel.Error() | |||||
| .WriteTo.Console() | .WriteTo.Console() | ||||
| .CreateLogger(); | .CreateLogger(); | ||||