| @@ -1,66 +0,0 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Runtime.InteropServices; | |||
| using System.Text; | |||
| namespace Tensorflow | |||
| { | |||
| public class Tensor | |||
| { | |||
| public Operation op { get; } | |||
| public int value_index { get; } | |||
| public TF_DataType dtype { get; } | |||
| public Graph graph => op.graph; | |||
| public string name; | |||
| public IntPtr handle { get; } | |||
| public int ndim { get; } | |||
| public ulong bytesize { get; } | |||
| public ulong dataTypeSize { get;} | |||
| public ulong size => bytesize / dataTypeSize; | |||
| public IntPtr buffer { get; } | |||
| public Tensor(IntPtr handle) | |||
| { | |||
| this.handle = handle; | |||
| dtype = c_api.TF_TensorType(handle); | |||
| ndim = c_api.TF_NumDims(handle); | |||
| bytesize = c_api.TF_TensorByteSize(handle); | |||
| buffer = c_api.TF_TensorData(handle); | |||
| dataTypeSize = c_api.TF_DataTypeSize(dtype); | |||
| } | |||
| public Tensor(Operation op, int value_index, TF_DataType dtype) | |||
| { | |||
| this.op = op; | |||
| this.value_index = value_index; | |||
| this.dtype = dtype; | |||
| } | |||
| public TF_Output _as_tf_output() | |||
| { | |||
| return c_api_util.tf_output(op._c_op, value_index); | |||
| } | |||
| public T[] Data<T>() | |||
| { | |||
| var data = new T[size]; | |||
| for (ulong i = 0; i < size; i++) | |||
| { | |||
| data[i] = Marshal.PtrToStructure<T>(buffer + (int)(i * dataTypeSize)); | |||
| } | |||
| return data; | |||
| } | |||
| public byte[] Data() | |||
| { | |||
| var data = new byte[bytesize]; | |||
| Marshal.Copy(buffer, data, 0, (int)bytesize); | |||
| return data; | |||
| } | |||
| } | |||
| } | |||
| @@ -6,6 +6,7 @@ namespace Tensorflow | |||
| { | |||
| public enum TF_DataType | |||
| { | |||
| DtInvalid = 0, | |||
| TF_FLOAT = 1, | |||
| TF_DOUBLE = 2, | |||
| TF_INT32 = 3, // Int32 tensors are always in 'host' memory. | |||
| @@ -0,0 +1,139 @@ | |||
| using NumSharp.Core; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Runtime.InteropServices; | |||
| using System.Text; | |||
| namespace Tensorflow | |||
| { | |||
| /// <summary> | |||
| /// A tensor is a generalization of vectors and matrices to potentially higher dimensions. | |||
| /// Internally, TensorFlow represents tensors as n-dimensional arrays of base datatypes. | |||
| /// </summary> | |||
| public class Tensor | |||
| { | |||
| public Operation op { get; } | |||
| public int value_index { get; } | |||
| public Graph graph => op.graph; | |||
| public string name; | |||
| public TF_DataType dtype { get; } | |||
| public IntPtr handle { get; } | |||
| public ulong bytesize { get; } | |||
| public ulong dataTypeSize { get;} | |||
| public ulong size => bytesize / dataTypeSize; | |||
| public IntPtr buffer { get; } | |||
| public long[] shape { get; } | |||
| /// <summary> | |||
| /// number of dimensions | |||
| /// 0 Scalar (magnitude only) | |||
| /// 1 Vector (magnitude and direction) | |||
| /// 2 Matrix (table of numbers) | |||
| /// 3 3-Tensor (cube of numbers) | |||
| /// n n-Tensor (you get the idea) | |||
| /// </summary> | |||
| public int rank; | |||
| /// <summary> | |||
| /// if original buffer is free. | |||
| /// </summary> | |||
| private bool deallocator_called; | |||
| public Tensor(IntPtr handle) | |||
| { | |||
| this.handle = handle; | |||
| dtype = c_api.TF_TensorType(handle); | |||
| rank = c_api.TF_NumDims(handle); | |||
| bytesize = c_api.TF_TensorByteSize(handle); | |||
| buffer = c_api.TF_TensorData(handle); | |||
| dataTypeSize = c_api.TF_DataTypeSize(dtype); | |||
| shape = new long[rank]; | |||
| for (int i = 0; i < rank; i++) | |||
| shape[i] = c_api.TF_Dim(handle, i); | |||
| } | |||
| public Tensor(NDArray nd) | |||
| { | |||
| var data = Marshal.AllocHGlobal(sizeof(float) * nd.size); | |||
| Marshal.Copy(nd.Data<float>(), 0, data, nd.size); | |||
| var dataType = ToTFDataType(nd.dtype); | |||
| var handle = c_api.TF_NewTensor(dataType, | |||
| nd.shape.Select(x => (long)x).ToArray(), // shape | |||
| nd.ndim, | |||
| data, | |||
| (UIntPtr)(nd.size * sizeof(float)), | |||
| (IntPtr values, IntPtr len, ref bool closure) => | |||
| { | |||
| // Free the original buffer and set flag | |||
| Marshal.FreeHGlobal(data); | |||
| closure = true; | |||
| }, | |||
| ref deallocator_called); | |||
| this.handle = handle; | |||
| dtype = c_api.TF_TensorType(handle); | |||
| rank = c_api.TF_NumDims(handle); | |||
| bytesize = c_api.TF_TensorByteSize(handle); | |||
| buffer = c_api.TF_TensorData(handle); | |||
| dataTypeSize = c_api.TF_DataTypeSize(dtype); | |||
| shape = new long[rank]; | |||
| for (int i = 0; i < rank; i++) | |||
| shape[i] = c_api.TF_Dim(handle, i); | |||
| } | |||
| public Tensor(Operation op, int value_index, TF_DataType dtype) | |||
| { | |||
| this.op = op; | |||
| this.value_index = value_index; | |||
| this.dtype = dtype; | |||
| } | |||
| public TF_Output _as_tf_output() | |||
| { | |||
| return c_api_util.tf_output(op._c_op, value_index); | |||
| } | |||
| public T[] Data<T>() | |||
| { | |||
| // Column major order | |||
| // https://en.wikipedia.org/wiki/File:Row_and_column_major_order.svg | |||
| // matrix:[[1, 2, 3], [4, 5, 6]] | |||
| // index: 0 2 4 1 3 5 | |||
| // result: 1 4 2 5 3 6 | |||
| var data = new T[size]; | |||
| for (ulong i = 0; i < size; i++) | |||
| { | |||
| data[i] = Marshal.PtrToStructure<T>(buffer + (int)(i * dataTypeSize)); | |||
| } | |||
| return data; | |||
| } | |||
| public byte[] Data() | |||
| { | |||
| var data = new byte[bytesize]; | |||
| Marshal.Copy(buffer, data, 0, (int)bytesize); | |||
| return data; | |||
| } | |||
| public TF_DataType ToTFDataType(Type type) | |||
| { | |||
| switch (type.Name) | |||
| { | |||
| case "Single": | |||
| return TF_DataType.TF_FLOAT; | |||
| } | |||
| return TF_DataType.DtInvalid; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Text; | |||
| namespace Tensorflow | |||
| { | |||
| public class Variable | |||
| { | |||
| } | |||
| } | |||
| @@ -73,8 +73,10 @@ namespace Tensorflow | |||
| /// <param name="deallocator"></param> | |||
| /// <param name="deallocator_arg"></param> | |||
| /// <returns></returns> | |||
| [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); | |||
| [DllImport(TensorFlowLibName)] | |||
| public static extern unsafe IntPtr TF_NewTensor(TF_DataType dataType, long[] dims, int num_dims, IntPtr data, UIntPtr len, Deallocator deallocator, ref bool deallocator_arg); | |||
| public delegate void Deallocator(IntPtr data, IntPtr size, ref bool deallocatorData); | |||
| /// <summary> | |||
| /// Return the number of dimensions that the tensor has. | |||
| @@ -16,8 +16,6 @@ namespace Tensorflow | |||
| public static Graph g = new Graph(c_api.TF_NewGraph()); | |||
| public delegate void Deallocator(IntPtr data, IntPtr size, IntPtr deallocatorData); | |||
| public static unsafe Tensor add(Tensor a, Tensor b) | |||
| { | |||
| return gen_math_ops.add(a, b); | |||
| @@ -13,50 +13,19 @@ namespace TensorFlowNET.UnitTest | |||
| public class TensorTest | |||
| { | |||
| [TestMethod] | |||
| public unsafe void TF_NewTensor() | |||
| public unsafe void NewTensor() | |||
| { | |||
| var nd = np.array(1f, 2f, 3f, 4f, 5f, 6f).reshape(2, 3); | |||
| var data = Marshal.AllocHGlobal(sizeof(float) * 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, | |||
| nd.shape.Select(x => (long)x).ToArray(), // shape | |||
| nd.ndim, | |||
| data, | |||
| (UIntPtr)(nd.size * sizeof(float)), | |||
| (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); | |||
| var tensor = new Tensor(handle); | |||
| var tensor = new Tensor(nd); | |||
| var array = tensor.Data<float>(); | |||
| Assert.AreEqual(tensor.dtype, TF_DataType.TF_FLOAT); | |||
| Assert.AreEqual(tensor.ndim, nd.ndim); | |||
| Assert.AreEqual(nd.shape[0], c_api.TF_Dim(handle, 0)); | |||
| Assert.AreEqual(nd.shape[1], c_api.TF_Dim(handle, 1)); | |||
| Assert.AreEqual(tensor.rank, nd.ndim); | |||
| Assert.AreEqual(tensor.shape[0], nd.shape[0]); | |||
| Assert.AreEqual(tensor.shape[1], nd.shape[1]); | |||
| Assert.AreEqual(tensor.bytesize, (uint)nd.size * sizeof(float)); | |||
| Assert.AreEqual(*(bool*)deallocator_called, true); | |||
| // Column major order | |||
| // https://en.wikipedia.org/wiki/File:Row_and_column_major_order.svg | |||
| // matrix:[[1, 2, 3], [4, 5, 6]] | |||
| // index: 0 2 4 1 3 5 | |||
| // result: 1 4 2 5 3 6 | |||
| var array = tensor.Data<float>(); | |||
| Assert.IsTrue(Enumerable.SequenceEqual(nd.Data<float>(), array)); | |||
| c_api.TF_DeleteTensor(handle); | |||
| Assert.AreEqual(*(bool *)deallocator_called, true); | |||
| } | |||
| } | |||
| } | |||