@@ -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 | public enum TF_DataType | ||||
{ | { | ||||
DtInvalid = 0, | |||||
TF_FLOAT = 1, | TF_FLOAT = 1, | ||||
TF_DOUBLE = 2, | TF_DOUBLE = 2, | ||||
TF_INT32 = 3, // Int32 tensors are always in 'host' memory. | 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"></param> | ||||
/// <param name="deallocator_arg"></param> | /// <param name="deallocator_arg"></param> | ||||
/// <returns></returns> | /// <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> | /// <summary> | ||||
/// Return the number of dimensions that the tensor has. | /// 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 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) | public static unsafe Tensor add(Tensor a, Tensor b) | ||||
{ | { | ||||
return gen_math_ops.add(a, b); | return gen_math_ops.add(a, b); | ||||
@@ -13,50 +13,19 @@ namespace TensorFlowNET.UnitTest | |||||
public class TensorTest | public class TensorTest | ||||
{ | { | ||||
[TestMethod] | [TestMethod] | ||||
public unsafe void TF_NewTensor() | |||||
public unsafe void 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); | |||||
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.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(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)); | Assert.IsTrue(Enumerable.SequenceEqual(nd.Data<float>(), array)); | ||||
c_api.TF_DeleteTensor(handle); | |||||
Assert.AreEqual(*(bool *)deallocator_called, true); | |||||
} | } | ||||
} | } | ||||
} | } |