Browse Source

Finished Tensor class.

tags/v0.1.0-Tensor
Oceania2018 6 years ago
parent
commit
91befe9163
9 changed files with 160 additions and 107 deletions
  1. +0
    -66
      src/TensorFlowNET.Core/Tensor/Tensor.cs
  2. +1
    -0
      src/TensorFlowNET.Core/Tensors/TF_DataType.cs
  3. +139
    -0
      src/TensorFlowNET.Core/Tensors/Tensor.cs
  4. +0
    -0
      src/TensorFlowNET.Core/Tensors/TensorBuffer.cs
  5. +10
    -0
      src/TensorFlowNET.Core/Tensors/Variable.cs
  6. +0
    -0
      src/TensorFlowNET.Core/Tensors/tensor_util.cs
  7. +4
    -2
      src/TensorFlowNET.Core/c_api.cs
  8. +0
    -2
      src/TensorFlowNET.Core/tf.cs
  9. +6
    -37
      test/TensorFlowNET.UnitTest/TensorTest.cs

+ 0
- 66
src/TensorFlowNET.Core/Tensor/Tensor.cs View File

@@ -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;
}
}
}

src/TensorFlowNET.Core/Tensor/TF_DataType.cs → src/TensorFlowNET.Core/Tensors/TF_DataType.cs View File

@@ -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.

+ 139
- 0
src/TensorFlowNET.Core/Tensors/Tensor.cs View File

@@ -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;
}
}
}

src/TensorFlowNET.Core/Tensor/TensorBuffer.cs → src/TensorFlowNET.Core/Tensors/TensorBuffer.cs View File


+ 10
- 0
src/TensorFlowNET.Core/Tensors/Variable.cs View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Tensorflow
{
public class Variable
{
}
}

src/TensorFlowNET.Core/Tensor/tensor_util.cs → src/TensorFlowNET.Core/Tensors/tensor_util.cs View File


+ 4
- 2
src/TensorFlowNET.Core/c_api.cs View File

@@ -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.


+ 0
- 2
src/TensorFlowNET.Core/tf.cs View File

@@ -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);


+ 6
- 37
test/TensorFlowNET.UnitTest/TensorTest.cs View File

@@ -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);
}
}
}

Loading…
Cancel
Save