From b3497f31f294ded8e3cafc54c6449b2ff09f719a Mon Sep 17 00:00:00 2001 From: haiping008 Date: Mon, 28 Jan 2019 17:02:48 -0600 Subject: [PATCH] finished tf.zeros #143 --- .../Operations/OpDefLibrary.cs | 43 +++++++---- .../Operations/array_ops.py.cs | 6 +- .../Operations/gen_array_ops.cs | 33 +++------ .../Operations/gen_control_flow_ops.py.cs | 2 +- .../Operations/gen_math_ops.cs | 52 +++----------- src/TensorFlowNET.Core/Python.cs | 20 ++++++ .../Sessions/BaseSession.cs | 72 ++++++++----------- src/TensorFlowNET.Core/Sessions/Session.cs | 12 +++- .../Variables/RefVariable.cs | 6 +- .../Variables/gen_state_ops.py.cs | 16 +---- test/TensorFlowNET.UnitTest/ConstantTest.cs | 36 ++++++++-- 11 files changed, 146 insertions(+), 152 deletions(-) diff --git a/src/TensorFlowNET.Core/Operations/OpDefLibrary.cs b/src/TensorFlowNET.Core/Operations/OpDefLibrary.cs index 642cbb13..2ceeb043 100644 --- a/src/TensorFlowNET.Core/Operations/OpDefLibrary.cs +++ b/src/TensorFlowNET.Core/Operations/OpDefLibrary.cs @@ -1,6 +1,7 @@ -using NumSharp.Core; -using System; +using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Dynamic; using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -10,8 +11,9 @@ namespace Tensorflow { public class OpDefLibrary { - public Operation _apply_op_helper(string op_type_name, string name = "", Dictionary keywords = null) + public Operation _apply_op_helper(string op_type_name, string name = "", dynamic args = null) { + var keywords = ConvertToDict(args); var g = ops.get_default_graph(); var op_def = g.GetOpDef(op_type_name); @@ -20,9 +22,9 @@ namespace Tensorflow name = op_type_name; // Check for deprecation - if(op_def.Deprecation != null && op_def.Deprecation.Version > 0) + if (op_def.Deprecation != null && op_def.Deprecation.Version > 0) { - + } var default_type_attr_map = new Dictionary(); @@ -30,7 +32,7 @@ namespace Tensorflow { if (attr_def.Type != "type") continue; var key = attr_def.Name; - if(attr_def.DefaultValue != null) + if (attr_def.DefaultValue != null) { default_type_attr_map[key] = attr_def.DefaultValue.Type; } @@ -40,11 +42,9 @@ namespace Tensorflow var inputs = new List(); var input_types = new List(); - string scope = ""; - using (var namescope = new ops.name_scope(name)) + Operation op = null; + Python.with(new ops.name_scope(name), scope => { - scope = namescope; - // Perform input type inference foreach (var input_arg in op_def.InputArg) { @@ -73,7 +73,7 @@ namespace Tensorflow else { var base_type = value.dtype.as_base_dtype(); - + input_types.Add(base_type); } } @@ -135,19 +135,34 @@ namespace Tensorflow } // Add Op to graph - var op = g.create_op(op_type_name, inputs, output_types.ToArray(), + op = g.create_op(op_type_name, inputs, output_types.ToArray(), name: scope, input_types: input_types.ToArray(), attrs: attr_protos, op_def: op_def); + }); - return op; - } + return op; } public DataType _MakeType(TF_DataType v, AttrDef attr_def) { return v.as_base_dtype().as_datatype_enum(); } + + private Dictionary ConvertToDict(dynamic dyn) + { + var dictionary = new Dictionary(); + foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(dyn)) + { + object obj = propertyDescriptor.GetValue(dyn); + string name = propertyDescriptor.Name; + // avoid .net keyword + if (name == "_ref_") + name = "ref"; + dictionary.Add(name, obj); + } + return dictionary; + } } } diff --git a/src/TensorFlowNET.Core/Operations/array_ops.py.cs b/src/TensorFlowNET.Core/Operations/array_ops.py.cs index 7f0b0e92..db51e21b 100644 --- a/src/TensorFlowNET.Core/Operations/array_ops.py.cs +++ b/src/TensorFlowNET.Core/Operations/array_ops.py.cs @@ -47,9 +47,9 @@ namespace Tensorflow } else { - tShape = constant_op._tensor_shape_tensor_conversion_function(shape.as_shape(), dtype, name); - var c = constant_op.Constant(nd, name); - return gen_array_ops.fill(shape, value, name); + tShape = constant_op._tensor_shape_tensor_conversion_function(shape.as_shape()); + var c = constant_op.Constant(0); + return gen_array_ops.fill(tShape, c, name); } } } diff --git a/src/TensorFlowNET.Core/Operations/gen_array_ops.cs b/src/TensorFlowNET.Core/Operations/gen_array_ops.cs index 0ff134cc..8c28c58b 100644 --- a/src/TensorFlowNET.Core/Operations/gen_array_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_array_ops.cs @@ -14,11 +14,7 @@ namespace Tensorflow public static Tensor placeholder(TF_DataType dtype, TensorShape shape = null, string name = "") { - var keywords = new Dictionary(); - keywords.Add("dtype", dtype); - keywords.Add("shape", shape); - - var _op = _op_def_lib._apply_op_helper("Placeholder", keywords: keywords); + var _op = _op_def_lib._apply_op_helper("Placeholder", args: new { dtype, shape }); var _result = _op.outputs; var _inputs_flat = _op.inputs; @@ -38,20 +34,14 @@ namespace Tensorflow /// public static Tensor identity(Tensor input, string name = "") { - var keywords = new Dictionary(); - keywords.Add("input", input); - - var _op = _op_def_lib._apply_op_helper("Identity", name, keywords); + var _op = _op_def_lib._apply_op_helper("Identity", name, new { input }); return _op.outputs[0]; } public static Tensor rank(Tensor input, string name = "") { - var keywords = new Dictionary(); - keywords.Add("input", input); - - var _op = _op_def_lib._apply_op_helper("Rank", name: name, keywords: keywords); + var _op = _op_def_lib._apply_op_helper("Rank", name: name, args: new { input }); return _op.outputs[0]; } @@ -59,18 +49,13 @@ namespace Tensorflow /// /// Creates a tensor filled with a scalar value. /// - /// - /// - /// - /// - /// - public static Tensor fill(int[] dims, T value, string name = "") + /// A `Tensor`. + /// A `Tensor`. + /// A name for the operation (optional). + /// A `Tensor`. Has the same type as `value`. + public static Tensor fill(Tensor dims, Tensor value, string name = "") { - var keywords = new Dictionary(); - keywords.Add("dims", dims); - keywords.Add("value", value); - - var _op = _op_def_lib._apply_op_helper("Fill", name); + var _op = _op_def_lib._apply_op_helper("Fill", name, new { dims, value }); return _op.outputs[0]; } diff --git a/src/TensorFlowNET.Core/Operations/gen_control_flow_ops.py.cs b/src/TensorFlowNET.Core/Operations/gen_control_flow_ops.py.cs index c17753dd..f8ba6563 100644 --- a/src/TensorFlowNET.Core/Operations/gen_control_flow_ops.py.cs +++ b/src/TensorFlowNET.Core/Operations/gen_control_flow_ops.py.cs @@ -10,7 +10,7 @@ namespace Tensorflow public static Operation no_op(string name = "") { - var _op = _op_def_lib._apply_op_helper("NoOp", name); + var _op = _op_def_lib._apply_op_helper("NoOp", name, null); return _op; } diff --git a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs index b5e68ae2..8ffb28a3 100644 --- a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs @@ -12,80 +12,49 @@ namespace Tensorflow public static Tensor add(Tensor x, Tensor y) { - var keywords = new Dictionary(); - keywords.Add("x", x); - keywords.Add("y", y); - - var _op = _op_def_lib._apply_op_helper("Add", keywords: keywords); + var _op = _op_def_lib._apply_op_helper("Add", args: new { x, y }); return _op.outputs[0]; } public static Tensor sub(Tensor x, Tensor y) { - var keywords = new Dictionary(); - keywords.Add("x", x); - keywords.Add("y", y); - - var _op = _op_def_lib._apply_op_helper("Sub", name: "sub", keywords: keywords); + var _op = _op_def_lib._apply_op_helper("Sub", name: "sub", args: new { x, y }); return _op.outputs[0]; } public static Tensor mul(Tensor x, Tensor y) { - var keywords = new Dictionary(); - keywords.Add("x", x); - keywords.Add("y", y); - - var _op = _op_def_lib._apply_op_helper("Mul", keywords: keywords); + var _op = _op_def_lib._apply_op_helper("Mul", args: new { x, y }); return _op.outputs[0]; } public static Tensor real_div(Tensor x, Tensor y) { - var keywords = new Dictionary(); - keywords.Add("x", x); - keywords.Add("y", y); - - var _op = _op_def_lib._apply_op_helper("RealDiv", name: "truediv", keywords: keywords); + var _op = _op_def_lib._apply_op_helper("RealDiv", name: "truediv", args: new { x, y }); return _op.outputs[0]; } public static Tensor mat_mul(Tensor a, Tensor b, bool transpose_a = false, bool transpose_b = false) { - var keywords = new Dictionary(); - keywords.Add("a", a); - keywords.Add("b", b); - keywords.Add("transpose_a", transpose_a); - keywords.Add("transpose_b", transpose_b); - - var _op = _op_def_lib._apply_op_helper("MatMul", keywords: keywords); + var _op = _op_def_lib._apply_op_helper("MatMul", args: new { a, b, transpose_a, transpose_b }); return _op.outputs[0]; } public static Tensor pow(Tensor x, double y) { - var keywords = new Dictionary(); - keywords.Add("x", x); - keywords.Add("y", y); - - var _op = _op_def_lib._apply_op_helper("Pow", keywords: keywords); + var _op = _op_def_lib._apply_op_helper("Pow", args: new { x, y }); return _op.outputs[0]; } public static Tensor sum(Tensor input, Tensor axis = null) { - var keywords = new Dictionary(); - keywords.Add("input", input); - keywords.Add("reduction_indices", axis); - keywords.Add("keep_dims", false); - - var _op = _op_def_lib._apply_op_helper("Sum", keywords: keywords); + var _op = _op_def_lib._apply_op_helper("Sum", args: new { input, reduction_indices = axis, keep_dims = false }); return _op.outputs[0]; } @@ -100,12 +69,7 @@ namespace Tensorflow /// public static Tensor range(Tensor start, Tensor limit, Tensor delta, string name = "") { - var keywords = new Dictionary(); - keywords.Add("start", start); - keywords.Add("limit", limit); - keywords.Add("delta", delta); - - var _op = _op_def_lib._apply_op_helper("Range", name, keywords); + var _op = _op_def_lib._apply_op_helper("Range", name, new { start, limit, delta }); return _op.outputs[0]; } diff --git a/src/TensorFlowNET.Core/Python.cs b/src/TensorFlowNET.Core/Python.cs index 78ba4786..6f5d304f 100644 --- a/src/TensorFlowNET.Core/Python.cs +++ b/src/TensorFlowNET.Core/Python.cs @@ -23,6 +23,26 @@ namespace Tensorflow } catch (Exception ex) { + Console.WriteLine(ex.ToString()); + throw ex; + } + finally + { + py.__exit__(); + py.Dispose(); + } + } + + public static void with(IPython py, Action action) where T : IPython + { + try + { + py.__enter__(); + action((T)py); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); throw ex; } finally diff --git a/src/TensorFlowNET.Core/Sessions/BaseSession.cs b/src/TensorFlowNET.Core/Sessions/BaseSession.cs index 2bd71e49..1bdbb257 100644 --- a/src/TensorFlowNET.Core/Sessions/BaseSession.cs +++ b/src/TensorFlowNET.Core/Sessions/BaseSession.cs @@ -125,57 +125,47 @@ namespace Tensorflow for (int i = 0; i < fetch_list.Length; i++) { - var tensor = new Tensor(output_values[i]); - - switch (tensor.dtype) - { - case TF_DataType.TF_STRING: - { - // wired, don't know why we have to start from offset 9. - var bytes = tensor.Data(); - var output = UTF8Encoding.Default.GetString(bytes, 9, bytes.Length - 9); - result[i] = fetchValue(tensor, output); - } - break; - case TF_DataType.TF_FLOAT: - { - var output = *(float*)c_api.TF_TensorData(output_values[i]); - result[i] = fetchValue(tensor, output); - } - break; - case TF_DataType.TF_INT16: - { - var output = *(short*)c_api.TF_TensorData(output_values[i]); - result[i] = fetchValue(tensor, output); - } - break; - case TF_DataType.TF_INT32: - { - var output = *(int*)c_api.TF_TensorData(output_values[i]); - result[i] = fetchValue(tensor, output); - } - break; - default: - throw new NotImplementedException("can't get output"); - } + result[i] = fetchValue(output_values[i]); } return result; } - private NDArray fetchValue(Tensor tensor, T output) + private unsafe NDArray fetchValue(IntPtr output) { - NDArray nd; + var tensor = new Tensor(output); + NDArray nd = null; Type type = tensor.dtype.as_numpy_datatype(); var ndims = tensor.shape.Select(x => (int)x).ToArray(); - if (tensor.NDims == 0) - { - nd = np.array(output).reshape(); - } - else + switch (tensor.dtype) { - nd = np.array(output).reshape(ndims); + case TF_DataType.TF_STRING: + var bytes = tensor.Data(); + // wired, don't know why we have to start from offset 9. + var str = UTF8Encoding.Default.GetString(bytes, 9, bytes.Length - 9); + nd = np.array(str).reshape(); + break; + case TF_DataType.TF_INT32: + var ints = new int[tensor.size]; + for (ulong i = 0; i < tensor.size; i++) + ints[i] = *(int*)(c_api.TF_TensorData(output) + (int)(tensor.dataTypeSize * i)); + nd = np.array(ints).reshape(ndims); + break; + case TF_DataType.TF_FLOAT: + var floats = new float[tensor.size]; + for (ulong i = 0; i < tensor.size; i++) + floats[i] = *(float*)(c_api.TF_TensorData(output) + (int)(tensor.dataTypeSize * i)); + nd = np.array(floats).reshape(ndims); + break; + case TF_DataType.TF_DOUBLE: + var doubles = new double[tensor.size]; + for (ulong i = 0; i < tensor.size; i++) + doubles[i] = *(double*)(c_api.TF_TensorData(output) + (int)(tensor.dataTypeSize * i)); + nd = np.array(doubles).reshape(ndims); + break; + default: + throw new NotImplementedException("can't fetch output"); } return nd; diff --git a/src/TensorFlowNET.Core/Sessions/Session.cs b/src/TensorFlowNET.Core/Sessions/Session.cs index 8cf84c52..5c416b09 100644 --- a/src/TensorFlowNET.Core/Sessions/Session.cs +++ b/src/TensorFlowNET.Core/Sessions/Session.cs @@ -4,7 +4,7 @@ using System.Text; namespace Tensorflow { - public class Session : BaseSession, IDisposable + public class Session : BaseSession, IPython { private IntPtr _handle; public Status Status { get; } @@ -41,5 +41,15 @@ namespace Tensorflow Status.Dispose(); c_api.TF_DeleteSession(_handle, Status); } + + public void __enter__() + { + + } + + public void __exit__() + { + + } } } diff --git a/src/TensorFlowNET.Core/Variables/RefVariable.cs b/src/TensorFlowNET.Core/Variables/RefVariable.cs index 69a1f55b..6777eddd 100644 --- a/src/TensorFlowNET.Core/Variables/RefVariable.cs +++ b/src/TensorFlowNET.Core/Variables/RefVariable.cs @@ -65,10 +65,8 @@ namespace Tensorflow ops.init_scope(); var values = init_from_fn ? new List() : new List { initial_value }; - using (var namescope = new ops.name_scope(name, "Variable", values)) + Python.with(new ops.name_scope(name, "Variable", values), scope => { - name = namescope; - if (init_from_fn) { @@ -108,7 +106,7 @@ namespace Tensorflow } ops.add_to_collections(collections, this); - } + }); } public Tensor _ref() diff --git a/src/TensorFlowNET.Core/Variables/gen_state_ops.py.cs b/src/TensorFlowNET.Core/Variables/gen_state_ops.py.cs index 35e0d1c5..f6904407 100644 --- a/src/TensorFlowNET.Core/Variables/gen_state_ops.py.cs +++ b/src/TensorFlowNET.Core/Variables/gen_state_ops.py.cs @@ -23,13 +23,7 @@ namespace Tensorflow /// public static Tensor variable_v2(long[] shape, TF_DataType dtype, string name = "", string container = "", string shared_name = "") { - var keywords = new Dictionary(); - keywords.Add("dtype", dtype); - keywords.Add("shape", shape); - keywords.Add("container", container); - keywords.Add("shared_name", shared_name); - - var _op = _op_def_lib._apply_op_helper("VariableV2", name: name, keywords: keywords); + var _op = _op_def_lib._apply_op_helper("VariableV2", name: name, args: new { dtype, shape, container, shared_name }); var _result = _op.outputs; var _inputs_flat = _op.inputs; @@ -58,13 +52,7 @@ namespace Tensorflow bool use_locking = true, string name = "") { - var keywords = new Dictionary(); - keywords.Add("ref", tensor); - keywords.Add("value", value); - keywords.Add("validate_shape", validate_shape); - keywords.Add("use_locking", use_locking); - - var _op = _op_def_lib._apply_op_helper("Assign", name: name, keywords: keywords); + var _op = _op_def_lib._apply_op_helper("Assign", name: name, args: new { _ref_ = tensor, value, validate_shape, use_locking }); var _result = _op.outputs; var _inputs_flat = _op.inputs; diff --git a/test/TensorFlowNET.UnitTest/ConstantTest.cs b/test/TensorFlowNET.UnitTest/ConstantTest.cs index caba1f59..89a65a20 100644 --- a/test/TensorFlowNET.UnitTest/ConstantTest.cs +++ b/test/TensorFlowNET.UnitTest/ConstantTest.cs @@ -24,18 +24,42 @@ namespace TensorFlowNET.UnitTest [TestMethod] public void StringConst() { - tensor = tf.constant("Elephant"); + string str = "Hello, TensorFlow.NET!"; + tensor = tf.constant(str); + Python.with(tf.Session(), sess => + { + var result = sess.run(tensor); + Assert.IsTrue(result.Data()[0] == str); + }); } [TestMethod] public void ZerosConst() { - tensor = tf.zeros(new Shape(3, 2), TF_DataType.TF_INT32, "x"); - Assert.AreEqual(tensor.shape[0], 3); - Assert.AreEqual(tensor.shape[0], 2); - Assert.IsTrue(Enumerable.SequenceEqual(new int[] { 0, 0, 0, 0, 0, 0 }, tensor.Data())); + // small size + tensor = tf.zeros(new Shape(3, 2), TF_DataType.TF_INT32, "small"); + Python.with(tf.Session(), sess => + { + var result = sess.run(tensor); + + Assert.AreEqual(result.shape[0], 3); + Assert.AreEqual(result.shape[1], 2); + Assert.IsTrue(Enumerable.SequenceEqual(new int[] { 0, 0, 0, 0, 0, 0 }, result.Data())); + }); - tensor = tf.zeros(new Shape(200, 300), TF_DataType.TF_INT32, "x"); + // big size + tensor = tf.zeros(new Shape(200, 100), TF_DataType.TF_INT32, "big"); + Python.with(tf.Session(), sess => + { + var result = sess.run(tensor); + + Assert.AreEqual(result.shape[0], 200); + Assert.AreEqual(result.shape[1], 100); + + var data = result.Data(); + Assert.AreEqual(0, data[0]); + Assert.AreEqual(0, data[result.size - 1]); + }); } [TestMethod]