From 7426fd0af0922057b269c25c833b4fb7314aab19 Mon Sep 17 00:00:00 2001 From: Oceania2018 Date: Wed, 30 Jan 2019 21:56:35 -0600 Subject: [PATCH] Add FeedItem to hold feed session dictionary. --- docs/source/Attribute.md | 2 ++ docs/source/EagerMode.md | 2 ++ docs/source/Gradient.md | 2 ++ docs/source/Placeholder.md | 18 ++++++++++ docs/source/index.rst | 5 ++- src/TensorFlowNET.Core/APIs/c_api.cs | 4 +-- .../Sessions/BaseSession.cs | 18 +++++++--- src/TensorFlowNET.Core/Sessions/FeedItem.cs | 22 ++++++++++++ src/TensorFlowNET.Core/Tensors/Tensor.cs | 2 +- .../Tensors/c_api.tensor.cs | 36 +++++++++++++++++++ src/TensorFlowNET.Core/Train/Optimizer.cs | 15 +++++--- .../Variables/RefVariable.cs | 2 +- src/TensorFlowNET.Core/ops.py.cs | 2 +- src/TensorFlowNET.Core/tf.cs | 1 + .../TensorFlowNET.Examples/BasicOperations.cs | 15 ++++---- test/TensorFlowNET.UnitTest/ConstantTest.cs | 15 ++++++++ test/TensorFlowNET.UnitTest/OperationsTest.cs | 10 +++--- .../TensorFlowNET.UnitTest/PlaceholderTest.cs | 12 ++++++- 18 files changed, 156 insertions(+), 27 deletions(-) create mode 100644 docs/source/Attribute.md create mode 100644 docs/source/EagerMode.md create mode 100644 docs/source/Gradient.md create mode 100644 src/TensorFlowNET.Core/Sessions/FeedItem.cs diff --git a/docs/source/Attribute.md b/docs/source/Attribute.md new file mode 100644 index 00000000..713fc989 --- /dev/null +++ b/docs/source/Attribute.md @@ -0,0 +1,2 @@ +# Chapter. Attribute + diff --git a/docs/source/EagerMode.md b/docs/source/EagerMode.md new file mode 100644 index 00000000..cbb0ea02 --- /dev/null +++ b/docs/source/EagerMode.md @@ -0,0 +1,2 @@ +# Chapter. Eager Mode + diff --git a/docs/source/Gradient.md b/docs/source/Gradient.md new file mode 100644 index 00000000..1c63a1c0 --- /dev/null +++ b/docs/source/Gradient.md @@ -0,0 +1,2 @@ +# Chapter. Gradient + diff --git a/docs/source/Placeholder.md b/docs/source/Placeholder.md index 469c1c9e..2407bfca 100644 --- a/docs/source/Placeholder.md +++ b/docs/source/Placeholder.md @@ -1,2 +1,20 @@ # Chapter. Placeholder +In this chapter we will talk about another common data type in TensorFlow: Placeholder. It is a simplified variable that can be passed to the required value by the session when the graph is run, that is, when you build the graph, you don't need to specify the value of that variable, but delay the session to the beginning. In TensorFlow terminology, we then feed data into the graph through these placeholders. The difference between placeholders and constants is that placeholders can specify coefficient values more flexibly without modifying the code that builds the graph. For example, mathematical constants are suitable for Constant, and some model smoothing values can be specified with Placeholder. + +这章我们讲一下TensorFlow里的另一种常用数据类型:占位符。它是一种简化的变量,可以在图运行的时候由会话传入所需要的值,就是说你在构建图的时候,不需要具体指定那个变量的值,而是延迟到会话开始的时候以参数的方式从外部传入初始值。占位符和常量的区别是占位符可以更灵活的指定系数值,而不需要修改构建图的代码。比如数学常量就适合用Constant, 有些模型平滑值可以用Placeholder来指定。 + +```csharp +var x = tf.placeholder(tf.int32); +var y = x * 3; + +Python.with(tf.Session(), sess => +{ + var result = sess.run(y, feed_dict: new FeedItem[] + { + new FeedItem(x, 2) + }); + // (int)result should be 6; +}); +``` + diff --git a/docs/source/index.rst b/docs/source/index.rst index e17c0d9e..87d2668d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -19,6 +19,9 @@ Welcome to TensorFlow.NET's documentation! Constant Placeholder Variable + Attribute Operation Graph - Session \ No newline at end of file + Session + Gradient + EagerMode \ No newline at end of file diff --git a/src/TensorFlowNET.Core/APIs/c_api.cs b/src/TensorFlowNET.Core/APIs/c_api.cs index 898afe34..93d93959 100644 --- a/src/TensorFlowNET.Core/APIs/c_api.cs +++ b/src/TensorFlowNET.Core/APIs/c_api.cs @@ -21,8 +21,8 @@ namespace Tensorflow /// const char* => string /// int32_t => int /// int64_t* => long[] - /// size_t* => unlong[] - /// size_t* => ref uint + /// size_t* => ulong[] + /// size_t* => ref ulong /// void* => IntPtr /// string => IntPtr c_api.StringPiece(IntPtr) /// unsigned char => byte diff --git a/src/TensorFlowNET.Core/Sessions/BaseSession.cs b/src/TensorFlowNET.Core/Sessions/BaseSession.cs index 212ff3a3..55105eb8 100644 --- a/src/TensorFlowNET.Core/Sessions/BaseSession.cs +++ b/src/TensorFlowNET.Core/Sessions/BaseSession.cs @@ -35,14 +35,24 @@ namespace Tensorflow c_api.TF_DeleteSessionOptions(opts); } - public virtual NDArray run(Tensor fetches, Dictionary feed_dict = null) + public virtual NDArray run(Tensor fetches, FeedItem[] feed_dict = null) { - return _run(fetches, feed_dict); + var feed = new Dictionary(); + + if (feed_dict != null) + feed_dict.ToList().ForEach(x => feed.Add(x.Key, x.Value)); + + return _run(fetches, feed); } - public virtual NDArray run(Operation fetches, Dictionary feed_dict = null) + public virtual NDArray run(Operation fetches, FeedItem[] feed_dict = null) { - return _run(fetches, feed_dict); + var feed = new Dictionary(); + + if (feed_dict != null) + feed_dict.ToList().ForEach(x => feed.Add(x.Key, x.Value)); + + return _run(fetches, feed); } private NDArray _run(T fetches, Dictionary feed_dict = null) diff --git a/src/TensorFlowNET.Core/Sessions/FeedItem.cs b/src/TensorFlowNET.Core/Sessions/FeedItem.cs new file mode 100644 index 00000000..06060d03 --- /dev/null +++ b/src/TensorFlowNET.Core/Sessions/FeedItem.cs @@ -0,0 +1,22 @@ +using NumSharp.Core; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tensorflow +{ + /// + /// Feed dictionary item + /// + public class FeedItem + { + public Tensor Key { get; } + public NDArray Value { get; } + + public FeedItem(Tensor tensor, NDArray nd) + { + Key = tensor; + Value = nd; + } + } +} diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.cs b/src/TensorFlowNET.Core/Tensors/Tensor.cs index f350bc8c..77f23f93 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.cs @@ -213,7 +213,7 @@ namespace Tensorflow /// A dictionary that maps `Tensor` objects to feed values. /// The `Session` to be used to evaluate this tensor. /// - public NDArray eval(Dictionary feed_dict = null, Session session = null) + public NDArray eval(FeedItem[] feed_dict = null, Session session = null) { return ops._eval_using_default_session(this, feed_dict, Graph, session); } diff --git a/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs b/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs index ec4cb488..a06af129 100644 --- a/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs +++ b/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs @@ -97,5 +97,41 @@ namespace Tensorflow /// [DllImport(TensorFlowLibName)] public static extern TF_DataType TF_TensorType(IntPtr tensor); + + /// + /// Return the size in bytes required to encode a string `len` bytes long into a + /// TF_STRING tensor. + /// + /// size_t + /// + [DllImport(TensorFlowLibName)] + public static extern ulong TF_StringEncodedSize(ulong len); + + /// + /// Encode the string `src` (`src_len` bytes long) into `dst` in the format + /// required by TF_STRING tensors. Does not write to memory more than `dst_len` + /// bytes beyond `*dst`. `dst_len` should be at least + /// TF_StringEncodedSize(src_len). + /// + /// const char* + /// size_t + /// char* + /// size_t + /// TF_Status* + /// On success returns the size in bytes of the encoded string. + [DllImport(TensorFlowLibName)] + public static extern ulong TF_StringEncode(string src, ulong src_len, string dst, ulong dst_len, IntPtr status); + + /// + /// Decode a string encoded using TF_StringEncode. + /// + /// const char* + /// size_t + /// const char** + /// size_t* + /// TF_Status* + /// + [DllImport(TensorFlowLibName)] + public static extern ulong TF_StringDecode(string src, ulong src_len, IntPtr dst, ref ulong dst_len, IntPtr status); } } diff --git a/src/TensorFlowNET.Core/Train/Optimizer.cs b/src/TensorFlowNET.Core/Train/Optimizer.cs index 7385a927..e000fb51 100644 --- a/src/TensorFlowNET.Core/Train/Optimizer.cs +++ b/src/TensorFlowNET.Core/Train/Optimizer.cs @@ -39,16 +39,19 @@ namespace Tensorflow /// Add operations to minimize `loss` by updating `var_list` /// /// - /// - public Optimizer minimize(Tensor loss, + /// + /// An Operation that updates the variables in `var_list`. If `global_step` + /// was not `None`, that operation also increments `global_step`. + /// + public Operation minimize(Tensor loss, GateGradientType gate_gradients = GateGradientType.GATE_OP, bool colocate_gradients_with_ops = false) { - compute_gradients(loss, + var grads_and_vars = compute_gradients(loss, gate_gradients: gate_gradients, colocate_gradients_with_ops: colocate_gradients_with_ops); - return this; + return null; } /// @@ -56,6 +59,10 @@ namespace Tensorflow /// /// /// + /// + /// A list of (gradient, variable) pairs. Variable is always present, but + /// gradient can be `None`. + /// public List> compute_gradients(Tensor loss, List var_list = null, int? aggregation_method = null, diff --git a/src/TensorFlowNET.Core/Variables/RefVariable.cs b/src/TensorFlowNET.Core/Variables/RefVariable.cs index 6777eddd..4065686e 100644 --- a/src/TensorFlowNET.Core/Variables/RefVariable.cs +++ b/src/TensorFlowNET.Core/Variables/RefVariable.cs @@ -78,7 +78,7 @@ namespace Tensorflow var shape = _initial_value.shape; dtype = _initial_value.dtype; - _variable = gen_state_ops.variable_v2(shape, dtype.as_base_dtype(), name); + _variable = gen_state_ops.variable_v2(shape, dtype.as_base_dtype(), scope); } // Manually overrides the variable's shape with the initial value's. diff --git a/src/TensorFlowNET.Core/ops.py.cs b/src/TensorFlowNET.Core/ops.py.cs index 0b2a0e91..dc4eaec5 100644 --- a/src/TensorFlowNET.Core/ops.py.cs +++ b/src/TensorFlowNET.Core/ops.py.cs @@ -240,7 +240,7 @@ namespace Tensorflow /// of numpy ndarrays that each correspond to the respective element in /// "tensors". /// - public static NDArray _eval_using_default_session(Tensor tensor, Dictionary feed_dict, Graph graph, Session session = null) + public static NDArray _eval_using_default_session(Tensor tensor, FeedItem[] feed_dict, Graph graph, Session session = null) { if (session == null) { diff --git a/src/TensorFlowNET.Core/tf.cs b/src/TensorFlowNET.Core/tf.cs index 4e28589c..8edc70f5 100644 --- a/src/TensorFlowNET.Core/tf.cs +++ b/src/TensorFlowNET.Core/tf.cs @@ -8,6 +8,7 @@ namespace Tensorflow public static partial class tf { public static TF_DataType int16 = TF_DataType.TF_INT16; + public static TF_DataType int32 = TF_DataType.TF_INT32; public static TF_DataType float16 = TF_DataType.TF_HALF; public static TF_DataType float32 = TF_DataType.TF_FLOAT; public static TF_DataType float64 = TF_DataType.TF_DOUBLE; diff --git a/test/TensorFlowNET.Examples/BasicOperations.cs b/test/TensorFlowNET.Examples/BasicOperations.cs index c2758565..c18904e0 100644 --- a/test/TensorFlowNET.Examples/BasicOperations.cs +++ b/test/TensorFlowNET.Examples/BasicOperations.cs @@ -44,9 +44,11 @@ namespace TensorFlowNET.Examples // Launch the default graph. using(sess = tf.Session()) { - var feed_dict = new Dictionary(); - feed_dict.Add(a, (short)2); - feed_dict.Add(b, (short)3); + var feed_dict = new FeedItem[] + { + new FeedItem(a, (short)2), + new FeedItem(b, (short)3) + }; // Run every operation with variable input Console.WriteLine($"Addition with variables: {sess.run(add, feed_dict)}"); Console.WriteLine($"Multiplication with variables: {sess.run(mul, feed_dict)}"); @@ -87,12 +89,11 @@ namespace TensorFlowNET.Examples using (sess = tf.Session()) { var result = sess.run(product); - Console.WriteLine(result.ToString()); - if(result.Data()[0] != 12) + Console.WriteLine(result.ToString()); // ==> [[ 12.]] + if (result.Data()[0] != 12) { - throw new Exception("BasicOperations error"); + throw new ValueError("BasicOperations"); } - // ==> [[ 12.]] } } } diff --git a/test/TensorFlowNET.UnitTest/ConstantTest.cs b/test/TensorFlowNET.UnitTest/ConstantTest.cs index 111f3f18..588e10d1 100644 --- a/test/TensorFlowNET.UnitTest/ConstantTest.cs +++ b/test/TensorFlowNET.UnitTest/ConstantTest.cs @@ -11,6 +11,8 @@ namespace TensorFlowNET.UnitTest [TestClass] public class ConstantTest { + Status status = new Status(); + [TestMethod] public void ScalarConst() { @@ -94,5 +96,18 @@ namespace TensorFlowNET.UnitTest Assert.AreEqual(6.0, result); } + + [TestMethod] + public void StringEncode() + { + string str = "Hello, TensorFlow.NET!"; + ulong dst_len = c_api.TF_StringEncodedSize((ulong)str.Length); + Assert.AreEqual(dst_len, (ulong)23); + string dst = ""; + c_api.TF_StringEncode(str, (ulong)str.Length, dst, dst_len, status); + Assert.AreEqual(status.Code, TF_Code.TF_OK); + + //c_api.TF_StringDecode(str, (ulong)str.Length, IntPtr.Zero, ref dst_len, status); + } } } diff --git a/test/TensorFlowNET.UnitTest/OperationsTest.cs b/test/TensorFlowNET.UnitTest/OperationsTest.cs index 69f93ecc..36c7b1f9 100644 --- a/test/TensorFlowNET.UnitTest/OperationsTest.cs +++ b/test/TensorFlowNET.UnitTest/OperationsTest.cs @@ -32,11 +32,11 @@ namespace TensorFlowNET.UnitTest using(var sess = tf.Session()) { - var feed_dict = new Dictionary(); - feed_dict.Add(a, 3.0f); - feed_dict.Add(b, 2.0f); - - var o = sess.run(c, feed_dict); + var o = sess.run(c, feed_dict: new FeedItem[] + { + new FeedItem(a, 3.0f), + new FeedItem(b, 2.0f) + }); Assert.AreEqual((float)o, 5.0f); } } diff --git a/test/TensorFlowNET.UnitTest/PlaceholderTest.cs b/test/TensorFlowNET.UnitTest/PlaceholderTest.cs index d5413e8d..f4ba9856 100644 --- a/test/TensorFlowNET.UnitTest/PlaceholderTest.cs +++ b/test/TensorFlowNET.UnitTest/PlaceholderTest.cs @@ -12,7 +12,17 @@ namespace TensorFlowNET.UnitTest [TestMethod] public void placeholder() { - var x = tf.placeholder(tf.float32); + var x = tf.placeholder(tf.int32); + var y = x * 3; + + Python.with(tf.Session(), sess => + { + var result = sess.run(y, feed_dict: new FeedItem[] + { + new FeedItem(x, 2) + }); + Assert.AreEqual((int)result, 6); + }); } } }