| @@ -10,6 +10,16 @@ | |||||
| ##### Tensor 是什么? | ##### Tensor 是什么? | ||||
| Tensor holds a multi-dimensional array of elements of a single data type which is very similar with numpy's ndarray. | |||||
| Tensor是一个具有单一数据类型的多维数组容器,非常类似于numpy里的ndarray。如果你对numpy非常熟悉的话,那么对Tensor的理解会相当容易。 | |||||
| ##### How to create a Tensor? | |||||
| ##### 如何创建一个Tensor? | |||||
| @@ -26,6 +36,6 @@ var nd = np.array(1f, 2f, 3f, 4f, 5f, 6f).reshape(2, 3); | |||||
|  | |||||
|  | |||||
|  | |||||
|  | |||||
| @@ -0,0 +1,9 @@ | |||||
| # Foreword 前言 | |||||
| One of the most nerve-wracking periods when releasing the first version of an open source project occurs when the gitter community is created. You are all alone, eagerly hoping and wishing for the first user to come along. I still vividly remember those days. | |||||
| 当我开始写这个项目的时候,我同时也在整理编码过程时候的想法,Tensorflow是个巨大最复杂的工程,很容易超出个人能力范围,所以想尽可能地把当时的思路记录下来,也想趁着记录整理的过程把思路理清。 | |||||
| When I started writing this project, I was also sorting out the idea of the coding process. Tensorflow is a huge and complicated project, and it is easy to go beyond the scope of personal ability. Therefore, I want to record the thoughts at the time as much as possible. The process of recording and sorting clears the way of thinking. | |||||
| @@ -1,5 +1,7 @@ | |||||
| # Preface 序 | |||||
| @@ -0,0 +1,18 @@ | |||||
| # Table of Contents | |||||
| ### Foreword...........................................................................................xxi | |||||
| ### Preface..............................................................................................xxiii | |||||
| ## Part I. Getting Started | |||||
| ##### 1. You Know, for Machine Learning............................................................................................ 3 | |||||
| Installing Tensorflow.NET | |||||
| Running Tensorflow.NET | |||||
| Talking to Tensorflow.NET | |||||
| ## Part II. Tensorflow.NET in Depth | |||||
| ## Part III. Dealing with Human Language | |||||
| @@ -28,6 +28,13 @@ namespace Tensorflow | |||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static unsafe extern void TF_DeleteSessionOptions(IntPtr opts); | public static unsafe extern void TF_DeleteSessionOptions(IntPtr opts); | ||||
| /// <summary> | |||||
| /// Destroy a tensor. | |||||
| /// </summary> | |||||
| /// <param name="tensor"></param> | |||||
| [DllImport(TensorFlowLibName)] | |||||
| public static unsafe extern void TF_DeleteTensor(IntPtr tensor); | |||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static extern unsafe long TF_Dim(IntPtr tensor, int dim_index); | public static extern unsafe long TF_Dim(IntPtr tensor, int dim_index); | ||||
| @@ -66,7 +73,7 @@ namespace Tensorflow | |||||
| /// <param name="deallocator"></param> | /// <param name="deallocator"></param> | ||||
| /// <param name="deallocator_arg"></param> | /// <param name="deallocator_arg"></param> | ||||
| /// <returns></returns> | /// <returns></returns> | ||||
| [DllImport(TensorFlowLibName)] | |||||
| [DllImport(TensorFlowLibName, CallingConvention = CallingConvention.StdCall)] | |||||
| public static extern unsafe IntPtr TF_NewTensor(TF_DataType dataType, long[] dims, int num_dims, IntPtr data, UIntPtr len, tf.Deallocator deallocator, IntPtr deallocator_arg); | public static extern unsafe IntPtr TF_NewTensor(TF_DataType dataType, long[] dims, int num_dims, IntPtr data, UIntPtr len, tf.Deallocator deallocator, IntPtr deallocator_arg); | ||||
| /// <summary> | /// <summary> | ||||
| @@ -52,14 +52,6 @@ namespace Tensorflow | |||||
| context.default_execution_mode = Context.EAGER_MODE; | context.default_execution_mode = Context.EAGER_MODE; | ||||
| } | } | ||||
| public static Deallocator FreeTensorDataDelegate = FreeTensorData; | |||||
| [MonoPInvokeCallback(typeof(Deallocator))] | |||||
| public static void FreeTensorData(IntPtr data, IntPtr len, IntPtr closure) | |||||
| { | |||||
| Marshal.FreeHGlobal(data); | |||||
| } | |||||
| public static string VERSION => Marshal.PtrToStringAnsi(c_api.TF_Version()); | public static string VERSION => Marshal.PtrToStringAnsi(c_api.TF_Version()); | ||||
| public static Graph get_default_graph() | public static Graph get_default_graph() | ||||
| @@ -13,20 +13,28 @@ namespace TensorFlowNET.UnitTest | |||||
| public class TensorTest | public class TensorTest | ||||
| { | { | ||||
| [TestMethod] | [TestMethod] | ||||
| public void TF_NewTensor() | |||||
| public unsafe void TF_NewTensor() | |||||
| { | { | ||||
| var nd = np.array(1f, 2f, 3f, 4f, 5f, 6f).reshape(2, 3); | var nd = np.array(1f, 2f, 3f, 4f, 5f, 6f).reshape(2, 3); | ||||
| var data = Marshal.AllocHGlobal(sizeof(float) * nd.size); | var data = Marshal.AllocHGlobal(sizeof(float) * nd.size); | ||||
| Marshal.Copy(nd.Data<float>(), 0, data, nd.size); | Marshal.Copy(nd.Data<float>(), 0, data, nd.size); | ||||
| var deallocator_called = Marshal.AllocHGlobal(sizeof(bool)); | |||||
| Assert.AreEqual(*(bool*)deallocator_called, false); | |||||
| var handle = c_api.TF_NewTensor(TF_DataType.TF_FLOAT, | var handle = c_api.TF_NewTensor(TF_DataType.TF_FLOAT, | ||||
| nd.shape.Select(x => (long)x).ToArray(), // shape | nd.shape.Select(x => (long)x).ToArray(), // shape | ||||
| nd.ndim, | nd.ndim, | ||||
| data, | data, | ||||
| (UIntPtr)(nd.size * sizeof(float)), | (UIntPtr)(nd.size * sizeof(float)), | ||||
| tf.FreeTensorData, | |||||
| IntPtr.Zero); | |||||
| (IntPtr values, IntPtr len, IntPtr closure) => | |||||
| { | |||||
| // Free the original buffer and set flag | |||||
| Marshal.FreeHGlobal(data); | |||||
| *(bool*)closure = true; | |||||
| }, | |||||
| deallocator_called); | |||||
| Assert.AreNotEqual(handle, IntPtr.Zero); | Assert.AreNotEqual(handle, IntPtr.Zero); | ||||
| @@ -37,6 +45,7 @@ namespace TensorFlowNET.UnitTest | |||||
| Assert.AreEqual(nd.shape[0], c_api.TF_Dim(handle, 0)); | Assert.AreEqual(nd.shape[0], c_api.TF_Dim(handle, 0)); | ||||
| Assert.AreEqual(nd.shape[1], c_api.TF_Dim(handle, 1)); | Assert.AreEqual(nd.shape[1], c_api.TF_Dim(handle, 1)); | ||||
| Assert.AreEqual(tensor.bytesize, (uint)nd.size * sizeof(float)); | Assert.AreEqual(tensor.bytesize, (uint)nd.size * sizeof(float)); | ||||
| Assert.AreEqual(*(bool*)deallocator_called, true); | |||||
| // Column major order | // Column major order | ||||
| // https://en.wikipedia.org/wiki/File:Row_and_column_major_order.svg | // https://en.wikipedia.org/wiki/File:Row_and_column_major_order.svg | ||||
| @@ -45,6 +54,9 @@ namespace TensorFlowNET.UnitTest | |||||
| // result: 1 4 2 5 3 6 | // result: 1 4 2 5 3 6 | ||||
| var array = tensor.Data<float>(); | var array = tensor.Data<float>(); | ||||
| Assert.IsTrue(Enumerable.SequenceEqual(nd.Data<float>(), array)); | Assert.IsTrue(Enumerable.SequenceEqual(nd.Data<float>(), array)); | ||||
| c_api.TF_DeleteTensor(handle); | |||||
| Assert.AreEqual(*(bool *)deallocator_called, true); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||