| @@ -78,15 +78,15 @@ namespace Tensorflow | |||
| /// <param name="axis"></param> | |||
| /// <param name="name"></param> | |||
| /// <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 => | |||
| { | |||
| var tensor = ops.convert_to_tensor(axis, name: "concat_dim", dtype: dtypes.int32); | |||
| 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 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, | |||
| 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, | |||
| 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 | |||
| limitations under the License. | |||
| ******************************************************************************/ | |||
| using static Tensorflow.Binding; | |||
| namespace 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> | |||
| 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(); | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| return eagerAction(); | |||
| } | |||
| catch (InvalidArgumentError ex) | |||
| { | |||
| throw ex; | |||
| } | |||
| catch (Exception ex) | |||
| { | |||
| return graphAction(); | |||
| } | |||
| } | |||
| } | |||
| // [DebuggerStepThrough] | |||
| @@ -46,12 +57,7 @@ namespace Tensorflow.Contexts | |||
| Action<Operation> recordGradient, | |||
| 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()) | |||
| { | |||
| @@ -68,6 +74,10 @@ namespace Tensorflow.Contexts | |||
| return result; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| return eagerAction(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -20,6 +20,7 @@ using System.Linq; | |||
| using Tensorflow.Eager; | |||
| using static Tensorflow.Binding; | |||
| using Google.Protobuf; | |||
| using Tensorflow.Util; | |||
| namespace Tensorflow.Contexts | |||
| { | |||
| @@ -103,6 +104,29 @@ namespace Tensorflow.Contexts | |||
| public void eager_mode(bool isFunc = false) | |||
| => 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() | |||
| { | |||
| 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; | |||
| tf.Logger.Debug($"RecordGradient: op_name={op_name}"); | |||
| Tensor[] op_outputs; | |||
| #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 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); | |||
| // Set non-inferred attrs, including setting defaults if the attr is passed in | |||
| @@ -221,23 +221,9 @@ namespace Tensorflow.Eager | |||
| SafeTensorHandleHandle input_handle; | |||
| // 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)) | |||
| { | |||
| @@ -2,6 +2,7 @@ | |||
| using System; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using static Tensorflow.Binding; | |||
| namespace Tensorflow.Framework | |||
| { | |||
| @@ -65,5 +66,17 @@ namespace Tensorflow.Framework | |||
| public static TensorShape as_shape(this Shape shape) | |||
| => 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="captured_inputs"></param> | |||
| /// <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 default_graph = ops.get_default_graph(); | |||
| @@ -99,8 +99,18 @@ namespace Tensorflow.Functions | |||
| if (input_index >= backward_function_inputs) | |||
| break; | |||
| } | |||
| 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); | |||
| @@ -151,6 +151,7 @@ namespace Tensorflow | |||
| /// <returns></returns> | |||
| public virtual Graph as_default() | |||
| { | |||
| tf.Context.graph_mode(isFunc: false); | |||
| return ops.set_default_graph(this); | |||
| } | |||
| @@ -532,6 +533,7 @@ namespace Tensorflow | |||
| public virtual void Exit() | |||
| { | |||
| tf.Context.restore_mode(); | |||
| ops.pop_graph(); | |||
| } | |||
| @@ -3,5 +3,6 @@ | |||
| public class ReshapeArgs : LayerArgs | |||
| { | |||
| public TensorShape TargetShape { get; set; } | |||
| public object[] TargetShapeObjects { get; set; } | |||
| } | |||
| } | |||
| @@ -132,7 +132,7 @@ namespace Tensorflow | |||
| if (!input_arg.IsRef && dtype != DataType.DtInvalid) | |||
| 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, | |||
| dtype: dtype.as_tf_dtype(), | |||
| preferred_dtype: default_dtype.as_tf_dtype(), | |||
| @@ -19,6 +19,7 @@ using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using Tensorflow.Contexts; | |||
| using Tensorflow.Eager; | |||
| using Tensorflow.Framework; | |||
| 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); | |||
| if (dtype == TF_DataType.DtInvalid) | |||
| @@ -224,7 +225,7 @@ namespace Tensorflow | |||
| 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; | |||
| @@ -251,11 +252,14 @@ namespace Tensorflow | |||
| /// <param name="dtype"></param> | |||
| /// <param name="name"></param> | |||
| /// <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 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)) | |||
| { | |||
| @@ -268,8 +272,17 @@ namespace Tensorflow | |||
| var elems_as_tensors = new List<Tensor>(); | |||
| 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); | |||
| } | |||
| else | |||
| { | |||
| 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])); | |||
| } | |||
| }); | |||
| 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) | |||
| @@ -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) | |||
| => 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) | |||
| { | |||
| @@ -22,7 +22,11 @@ namespace Tensorflow | |||
| 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> | |||
| @@ -180,6 +184,28 @@ namespace Tensorflow | |||
| 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, | |||
| TF_DataType[] output_types, TensorShape[] output_shapes, | |||
| string name = null) | |||
| @@ -202,20 +202,14 @@ namespace Tensorflow | |||
| } | |||
| 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, | |||
| null, | |||
| 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> | |||
| /// Return a tensor with the same shape and contents as the input tensor or value. | |||
| @@ -338,12 +332,39 @@ namespace Tensorflow | |||
| "Reshape", name, | |||
| null, | |||
| 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> | |||
| @@ -537,14 +558,23 @@ namespace Tensorflow | |||
| 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.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); | |||
| 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) | |||
| { | |||
| @@ -1874,7 +1874,7 @@ new_height, new_width"); | |||
| { | |||
| 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]; | |||
| (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> | |||
| <RootNamespace>Tensorflow</RootNamespace> | |||
| <TargetTensorFlow>2.2.0</TargetTensorFlow> | |||
| <Version>0.32.0</Version> | |||
| <Version>0.33.0</Version> | |||
| <LangVersion>8.0</LangVersion> | |||
| <Authors>Haiping Chen, Meinrad Recheis, Eli Belash</Authors> | |||
| <Company>SciSharp STACK</Company> | |||
| @@ -19,7 +19,7 @@ | |||
| <Description>Google's TensorFlow full binding in .NET Standard. | |||
| Building, training and infering deep learning models. | |||
| 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. | |||
| * Eager Mode is added finally. | |||
| @@ -28,7 +28,7 @@ https://tensorflownet.readthedocs.io</Description> | |||
| * autograph works partially. | |||
| 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> | |||
| <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | |||
| <SignAssembly>true</SignAssembly> | |||
| @@ -4,6 +4,12 @@ namespace Tensorflow | |||
| { | |||
| 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 Shape(TensorShape shape) => new Shape((int[])shape.dims.Clone()); | |||
| @@ -60,6 +60,9 @@ namespace Tensorflow | |||
| public void AddRange(Tensor[] tensors) | |||
| => items.AddRange(tensors); | |||
| public void Insert(int index, Tensor tensor) | |||
| => items.Insert(index, tensor); | |||
| IEnumerator IEnumerable.GetEnumerator() | |||
| { | |||
| throw new NotImplementedException(); | |||
| @@ -156,8 +156,8 @@ namespace Tensorflow | |||
| return val; | |||
| case NDArray val: | |||
| 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: | |||
| return new EagerTensor(val, ctx.DeviceName); | |||
| case string[] val: | |||
| @@ -123,6 +123,17 @@ namespace Tensorflow | |||
| { | |||
| 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 | |||
| { | |||
| if (values == null) | |||
| @@ -151,9 +162,14 @@ namespace Tensorflow | |||
| { | |||
| 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 | |||
| { | |||
| @@ -428,6 +444,9 @@ would not be rank 1.", tensor.op.get_attr("axis"))); | |||
| case NDArray val: | |||
| nd = val; | |||
| break; | |||
| case TensorShape val: | |||
| nd = val.dims; | |||
| break; | |||
| case bool boolVal: | |||
| nd = boolVal; | |||
| break; | |||
| @@ -471,7 +490,7 @@ would not be rank 1.", tensor.op.get_attr("axis"))); | |||
| nd = new NDArray(Encoding.ASCII.GetBytes(strVal)); | |||
| break; | |||
| case string[] strVals: | |||
| nd = strVals; | |||
| nd = np.array(strVals); | |||
| break; | |||
| case byte[] byteValues: | |||
| nd = byteValues; | |||
| @@ -150,7 +150,8 @@ namespace Tensorflow | |||
| TensorShape ts => constant_op.constant(ts.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), | |||
| 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) | |||
| }; | |||
| @@ -500,18 +501,16 @@ namespace Tensorflow | |||
| 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, | |||
| bool as_ref = false) | |||
| { | |||
| 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}"; | |||
| ret.Add(convert_to_tensor(value, dtype: dtype, name: n, as_ref: as_ref, preferred_dtype: preferred_dtype)); | |||
| } | |||
| return ret.ToArray(); | |||
| } | |||
| @@ -48,7 +48,7 @@ namespace Tensorflow | |||
| public tensorflow() | |||
| { | |||
| Logger = new LoggerConfiguration() | |||
| .MinimumLevel.Warning() | |||
| .MinimumLevel.Error() | |||
| .WriteTo.Console() | |||
| .CreateLogger(); | |||