Browse Source

TEST(CAPI, AllocateTensor)

tags/v0.1.0-Tensor
Oceania2018 6 years ago
parent
commit
36272d6b26
13 changed files with 205 additions and 51 deletions
  1. +3
    -1
      README.md
  2. +11
    -1
      src/TensorFlowNET.Core/Graphs/Graph.cs
  3. +10
    -2
      src/TensorFlowNET.Core/Graphs/c_api.graph.cs
  4. +24
    -10
      src/TensorFlowNET.Core/Operations/Operation.cs
  5. +1
    -1
      src/TensorFlowNET.Core/Operations/TF_Output.cs
  6. +9
    -0
      src/TensorFlowNET.Core/Operations/c_api.ops.cs
  7. +13
    -2
      src/TensorFlowNET.Core/Tensors/Tensor.cs
  8. +11
    -8
      src/TensorFlowNET.Core/Tensors/c_api.tensor.cs
  9. +1
    -0
      src/TensorFlowNET.Core/c_api.cs
  10. +20
    -3
      test/TensorFlowNET.UnitTest/GraphTest.cs
  11. +5
    -1
      test/TensorFlowNET.UnitTest/OperationsTest.cs
  12. +72
    -21
      test/TensorFlowNET.UnitTest/TensorTest.cs
  13. +25
    -1
      test/TensorFlowNET.UnitTest/c_test_util.cs

+ 3
- 1
README.md View File

@@ -4,7 +4,7 @@ TensorFlow.NET provides .NET Standard binding for [TensorFlow](https://www.tenso
[![Join the chat at https://gitter.im/publiclab/publiclab](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/sci-sharp/community)
![Tensorflow.NET](https://ci.appveyor.com/api/projects/status/tensorflow-net-p7kmsjyo10ey?svg=true)

TensorFlow.NET is a member project of SciSharp stack.
TensorFlow.NET is a member project of [SciSharp](https://github.com/SciSharp) stack.

![tensors_flowing](docs/assets/tensors_flowing.gif)

@@ -45,3 +45,5 @@ using(var sess = tf.Session())
var o = sess.run(c, feed_dict);
}
```

Star me or raise issue on [Github](https://github.com/SciSharp/TensorFlow.NET) feel free.

+ 11
- 1
src/TensorFlowNET.Core/Graphs/Graph.cs View File

@@ -13,7 +13,7 @@ namespace Tensorflow
/// then create a TensorFlow session to run parts of the graph across a set of local and remote devices.
/// https://www.tensorflow.org/guide/graphs
/// </summary>
public class Graph
public class Graph : IDisposable
{
private IntPtr _handle;
private Dictionary<int, Operation> _nodes_by_id;
@@ -25,6 +25,11 @@ namespace Tensorflow

private string _name_stack;

public Graph()
{
_handle = c_api.TF_NewGraph();
}

public Graph(IntPtr graph)
{
_handle = graph;
@@ -171,6 +176,11 @@ namespace Tensorflow
return _nodes_by_name.Values.Select(x => x).ToArray();
}

public void Dispose()
{
c_api.TF_DeleteGraph(_handle);
}

public static implicit operator IntPtr(Graph graph)
{
return graph._handle;


+ 10
- 2
src/TensorFlowNET.Core/Graphs/c_api.graph.cs View File

@@ -7,6 +7,14 @@ namespace Tensorflow
{
public static partial class c_api
{
/// <summary>
/// Destroy an options object. Graph will be deleted once no more
/// TFSession's are referencing it.
/// </summary>
/// <param name="graph"></param>
[DllImport(TensorFlowLibName)]
public static extern void TF_DeleteGraph(IntPtr graph);

[DllImport(TensorFlowLibName)]
public static extern void TF_GraphGetOpDef(IntPtr graph, string op_name, IntPtr output_op_def, IntPtr status);

@@ -21,14 +29,14 @@ namespace Tensorflow
/// <param name="num_dims"></param>
/// <param name="status"></param>
[DllImport(TensorFlowLibName)]
public static extern void TF_GraphGetTensorShape(IntPtr graph, TF_Output output, int[] dims, int num_dims, IntPtr status);
public static extern void TF_GraphGetTensorShape(IntPtr graph, TF_Output output, long[] dims, int num_dims, IntPtr status);

/// <summary>
/// Sets the shape of the Tensor referenced by `output` in `graph` to
/// the shape described by `dims` and `num_dims`.
/// </summary>
[DllImport(TensorFlowLibName)]
public static extern void TF_GraphSetTensorShape(IntPtr graph, TF_Output output, int[] dims, int num_dims, IntPtr status);
public static extern void TF_GraphSetTensorShape(IntPtr graph, TF_Output output, long[] dims, int num_dims, IntPtr status);

/// <summary>
/// Returns the number of dimensions of the Tensor referenced by `output`


+ 24
- 10
src/TensorFlowNET.Core/Operations/Operation.cs View File

@@ -14,16 +14,16 @@ namespace Tensorflow

private Status status = new Status();

public string name => c_api.TF_OperationName(_handle);
public string optype => c_api.TF_OperationOpType(_handle);
public string device => c_api.TF_OperationDevice(_handle);
public int NumOutputs => c_api.TF_OperationNumOutputs(_handle);
public TF_DataType OutputType => c_api.TF_OperationOutputType(new TF_Output(_handle, 0));
public int OutputListLength => c_api.TF_OperationOutputListLength(_handle, "output", status);
public int NumInputs => c_api.TF_OperationNumInputs(_handle);
public int NumConsumers => c_api.TF_OperationOutputNumConsumers(new TF_Output(_handle, 0));
public int NumControlInputs => c_api.TF_OperationNumControlInputs(_handle);
public int NumControlOutputs => c_api.TF_OperationNumControlOutputs(_handle);
public string name { get; }
public string optype { get; }
public string device { get; }
public int NumOutputs { get; }
public TF_DataType OutputType { get; }
public int OutputListLength { get; }
public int NumInputs { get; }
public int NumConsumers { get; }
public int NumControlInputs { get; }
public int NumControlOutputs { get; }

private Tensor[] _outputs;
public Tensor[] outputs => _outputs;
@@ -31,7 +31,21 @@ namespace Tensorflow

public Operation(IntPtr handle)
{
if (handle == IntPtr.Zero)
return;

_handle = handle;

name = c_api.TF_OperationName(_handle);
optype = c_api.TF_OperationOpType(_handle);
device = "";// c_api.TF_OperationDevice(_handle);
NumOutputs = c_api.TF_OperationNumOutputs(_handle);
OutputType = c_api.TF_OperationOutputType(new TF_Output(_handle, 0));
OutputListLength = c_api.TF_OperationOutputListLength(_handle, "output", status);
NumInputs = c_api.TF_OperationNumInputs(_handle);
NumConsumers = c_api.TF_OperationOutputNumConsumers(new TF_Output(_handle, 0));
NumControlInputs = c_api.TF_OperationNumControlInputs(_handle);
NumControlOutputs = c_api.TF_OperationNumControlOutputs(_handle);
}

public Operation(Graph g, string opType, string oper_name)


+ 1
- 1
src/TensorFlowNET.Core/Operations/TF_Output.cs View File

@@ -14,7 +14,7 @@ namespace Tensorflow
this.index = index;
}

public IntPtr oper;
public unsafe IntPtr oper;
public int index;
}
}

+ 9
- 0
src/TensorFlowNET.Core/Operations/c_api.ops.cs View File

@@ -22,6 +22,15 @@ namespace Tensorflow
[DllImport(TensorFlowLibName)]
public static extern void TF_AddInput(IntPtr desc, TF_Output input);

/// <summary>
/// For inputs that take a list of tensors.
/// inputs must point to TF_Output[num_inputs].
/// </summary>
/// <param name="desc"></param>
/// <param name="inputs"></param>
[DllImport(TensorFlowLibName)]
public static extern void TF_AddInputList(IntPtr desc, TF_Output[] inputs, int num_inputs);

[DllImport(TensorFlowLibName)]
public static extern IntPtr TF_FinishOperation(IntPtr desc, IntPtr status);



+ 13
- 2
src/TensorFlowNET.Core/Tensors/Tensor.cs View File

@@ -11,7 +11,7 @@ namespace Tensorflow
/// 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 class Tensor : IDisposable
{
private readonly IntPtr _handle;

@@ -38,6 +38,7 @@ namespace Tensorflow
/// n n-Tensor (you get the idea)
/// </summary>
public int rank;
public int NDims => rank;

/// <summary>
/// if original buffer is free.
@@ -96,7 +97,7 @@ namespace Tensorflow
nd.shape.Select(x => (long)x).ToArray(), // shape
nd.ndim,
dotHandle,
(UIntPtr)(nd.size * nd.dtypesize),
(ulong)(nd.size * nd.dtypesize),
(IntPtr values, IntPtr len, ref bool closure) =>
{
// Free the original buffer and set flag
@@ -160,9 +161,19 @@ namespace Tensorflow
return TF_DataType.DtInvalid;
}

public void Dispose()
{
c_api.TF_DeleteTensor(_handle);
}

public static implicit operator IntPtr(Tensor tensor)
{
return tensor._handle;
}

public static implicit operator Tensor(IntPtr handle)
{
return new Tensor(handle);
}
}
}

+ 11
- 8
src/TensorFlowNET.Core/Tensors/c_api.tensor.cs View File

@@ -7,20 +7,23 @@ namespace Tensorflow
{
public static partial class c_api
{
[DllImport(TensorFlowLibName)]
public static extern IntPtr TF_AllocateTensor(TF_DataType dtype, long[] dims, int num_dims, ulong len);

/// <summary>
/// returns the sizeof() for the underlying type corresponding to the given TF_DataType enum value.
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
[DllImport(TensorFlowLibName)]
public static unsafe extern ulong TF_DataTypeSize(TF_DataType dt);
public static extern ulong TF_DataTypeSize(TF_DataType dt);

/// <summary>
/// Destroy a tensor.
/// </summary>
/// <param name="tensor"></param>
[DllImport(TensorFlowLibName)]
public static unsafe extern void TF_DeleteTensor(IntPtr tensor);
public static extern void TF_DeleteTensor(IntPtr tensor);

/// <summary>
/// Return the length of the tensor in the "dim_index" dimension.
@@ -30,7 +33,7 @@ namespace Tensorflow
/// <param name="dim_index"></param>
/// <returns></returns>
[DllImport(TensorFlowLibName)]
public static extern unsafe long TF_Dim(IntPtr tensor, int dim_index);
public static extern long TF_Dim(IntPtr tensor, int dim_index);

/// <summary>
/// Return a new tensor that holds the bytes data[0,len-1]
@@ -44,7 +47,7 @@ namespace Tensorflow
/// <param name="deallocator_arg"></param>
/// <returns></returns>
[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 static extern IntPtr TF_NewTensor(TF_DataType dataType, long[] dims, int num_dims, IntPtr data, ulong len, Deallocator deallocator, ref bool deallocator_arg);

/// <summary>
/// Return the number of dimensions that the tensor has.
@@ -52,7 +55,7 @@ namespace Tensorflow
/// <param name="tensor"></param>
/// <returns></returns>
[DllImport(TensorFlowLibName)]
public static extern unsafe int TF_NumDims(IntPtr tensor);
public static extern int TF_NumDims(IntPtr tensor);

/// <summary>
/// Return the size of the underlying data in bytes.
@@ -60,7 +63,7 @@ namespace Tensorflow
/// <param name="tensor"></param>
/// <returns></returns>
[DllImport(TensorFlowLibName)]
public static extern unsafe ulong TF_TensorByteSize(IntPtr tensor);
public static extern ulong TF_TensorByteSize(IntPtr tensor);

/// <summary>
/// Return a pointer to the underlying data buffer.
@@ -68,7 +71,7 @@ namespace Tensorflow
/// <param name="tensor"></param>
/// <returns></returns>
[DllImport(TensorFlowLibName)]
public static extern unsafe IntPtr TF_TensorData(IntPtr tensor);
public static extern IntPtr TF_TensorData(IntPtr tensor);

/// <summary>
/// Return the type of a tensor element.
@@ -76,6 +79,6 @@ namespace Tensorflow
/// <param name="tensor"></param>
/// <returns></returns>
[DllImport(TensorFlowLibName)]
public static extern unsafe TF_DataType TF_TensorType(IntPtr tensor);
public static extern TF_DataType TF_TensorType(IntPtr tensor);
}
}

+ 1
- 0
src/TensorFlowNET.Core/c_api.cs View File

@@ -7,6 +7,7 @@ namespace Tensorflow
{
/// <summary>
/// C API for TensorFlow.
/// Port from tensorflow\c\c_api.h
///
/// The API leans towards simplicity and uniformity instead of convenience
/// since most usage will be by language specific wrappers.


+ 20
- 3
test/TensorFlowNET.UnitTest/GraphTest.cs View File

@@ -9,17 +9,21 @@ namespace TensorFlowNET.UnitTest
[TestClass]
public class GraphTest
{
/// <summary>
/// Port from c_api_test.cc
/// `TEST(CAPI, Graph)`
/// </summary>
[TestMethod]
public void Graph()
public void c_api_Graph()
{
var s = new Status();
var graph = tf.get_default_graph();
var graph = new Graph();

// Make a placeholder operation.
var feed = c_test_util.Placeholder(graph, s);
Assert.AreEqual("feed", feed.name);
Assert.AreEqual("Placeholder", feed.optype);
//Assert.AreEqual("", feed.device);
Assert.AreEqual("", feed.device);
Assert.AreEqual(1, feed.NumOutputs);
Assert.AreEqual(TF_DataType.TF_INT32, feed.OutputType);
Assert.AreEqual(1, feed.OutputListLength);
@@ -30,6 +34,19 @@ namespace TensorFlowNET.UnitTest

AttrValue attr_value = null;
c_test_util.GetAttrValue(feed, "dtype", ref attr_value, s);
Assert.AreEqual(attr_value.Type, DataType.DtInt32);

// Test not found errors in TF_Operation*() query functions.
// Assert.AreEqual(-1, c_api.TF_OperationOutputListLength(feed, "bogus", s));
// Assert.AreEqual(TF_Code.TF_INVALID_ARGUMENT, s.Code);
// Assert.IsFalse(c_test_util.GetAttrValue(feed, "missing", ref attr_value, s));
// Assert.AreEqual("Operation 'feed' has no attr named 'missing'.", s.Message);

// Make a constant oper with the scalar "3".
var three = c_test_util.ScalarConst(3, graph, s);

// Add oper.
var add = c_test_util.Add(feed, three, graph, s);
}
}
}

+ 5
- 1
test/TensorFlowNET.UnitTest/OperationsTest.cs View File

@@ -10,8 +10,12 @@ namespace TensorFlowNET.UnitTest
[TestClass]
public class OperationsTest
{
/// <summary>
/// Port from tensorflow\c\c_api_test.cc
/// `TEST(CAPI, GetAllOpList)`
/// </summary>
[TestMethod]
public void GetAllOpList()
public void c_api_GetAllOpList()
{
var handle = c_api.TF_GetAllOpList();
var buffer = new Buffer(handle);


+ 72
- 21
test/TensorFlowNET.UnitTest/TensorTest.cs View File

@@ -12,8 +12,29 @@ namespace TensorFlowNET.UnitTest
[TestClass]
public class TensorTest
{
/// <summary>
/// Port from c_api_test.cc
/// `TEST(CAPI, AllocateTensor)`
/// </summary>
[TestMethod]
public void c_api_AllocateTensor()
{
ulong num_bytes = 6 * sizeof(float);
long[] dims = { 2, 3 };
Tensor t = c_api.TF_AllocateTensor(TF_DataType.TF_FLOAT, dims, 2, num_bytes);
Assert.AreEqual(TF_DataType.TF_FLOAT, t.dtype);
Assert.AreEqual(2, t.NDims);
Assert.IsTrue(Enumerable.SequenceEqual(dims, t.shape));
Assert.AreEqual(num_bytes, t.bytesize);
t.Dispose();
}

/// <summary>
/// Port from c_api_test.cc
/// `TEST(CAPI, Tensor)`
/// </summary>
[TestMethod]
public void NewTensor()
public void c_api_Tensor()
{
var nd = np.array(1f, 2f, 3f, 4f, 5f, 6f).reshape(2, 3);

@@ -30,46 +51,38 @@ namespace TensorFlowNET.UnitTest

/// <summary>
/// Port from tensorflow\c\c_api_test.cc
/// `TEST(CAPI, SetShape)`
/// </summary>
[TestMethod]
public void SetShape()
public void c_api_SetShape()
{
var s = new Status();
var graph = tf.get_default_graph();
var graph = new Graph();

var desc = c_api.TF_NewOperation(graph, "Placeholder", "");
c_api.TF_SetAttrType(desc, "dtype", TF_DataType.TF_FLOAT);
//if (!dims.empty())
{
//TF_SetAttrShape(desc, "shape", dims.data(), dims.size());
}
var op = c_api.TF_FinishOperation(desc, s);

Assert.IsTrue(s.Code == TF_Code.TF_OK);
Assert.IsNotNull(op);
var feed = c_test_util.Placeholder(graph, s);
var feed_out_0 = new TF_Output(feed, 0);

// Fetch the shape, it should be completely unknown.
var feed_out_0 = new TF_Output { oper = op, index = 0 };
int num_dims = c_api.TF_GraphGetTensorNumDims(graph, feed_out_0, s);

Assert.IsTrue(s.Code == TF_Code.TF_OK);
Assert.AreEqual(-1, num_dims);

// Set the shape to be unknown, expect no change.
c_api.TF_GraphSetTensorShape(graph, feed_out_0, new int[0], -1, s);
c_api.TF_GraphSetTensorShape(graph, feed_out_0, null, -1, s);
Assert.IsTrue(s.Code == TF_Code.TF_OK);
num_dims = c_api.TF_GraphGetTensorNumDims(graph, feed_out_0, s);
Assert.AreEqual(-1, num_dims);

// Set the shape to be 2 x Unknown
var dims = new int[] { 2, -1 };
long[] dims = { 2, -1 };
c_api.TF_GraphSetTensorShape(graph, feed_out_0, dims, dims.Length, s);
Assert.IsTrue(s.Code == TF_Code.TF_OK);
num_dims = c_api.TF_GraphGetTensorNumDims(graph, feed_out_0, s);
Assert.AreEqual(2, num_dims);

// Get the dimension vector appropriately.
var returned_dims = new int[dims.Length];
var returned_dims = new long[dims.Length];
c_api.TF_GraphGetTensorShape(graph, feed_out_0, returned_dims, num_dims, s);
Assert.IsTrue(s.Code == TF_Code.TF_OK);
Assert.IsTrue(Enumerable.SequenceEqual(dims, returned_dims));
@@ -77,19 +90,57 @@ namespace TensorFlowNET.UnitTest
// Set to a new valid shape: [2, 3]
dims[1] = 3;
c_api.TF_GraphSetTensorShape(graph, feed_out_0, dims, dims.Length, s);
//Assert.IsTrue(s.Code == TF_Code.TF_OK);
Assert.IsTrue(s.Code == TF_Code.TF_OK);

// Fetch and see that the new value is returned.
c_api.TF_GraphGetTensorShape(graph, feed_out_0, returned_dims, num_dims, s);
//Assert.IsTrue(s.Code == TF_Code.TF_OK);
//Assert.IsTrue(Enumerable.SequenceEqual(dims, returned_dims));
Assert.IsTrue(s.Code == TF_Code.TF_OK);
Assert.IsTrue(Enumerable.SequenceEqual(dims, returned_dims));

// Try to set 'unknown' with unknown rank on the shape and see that
// it doesn't change.
c_api.TF_GraphSetTensorShape(graph, feed_out_0, null, -1, s);
Assert.IsTrue(s.Code == TF_Code.TF_OK);
c_api.TF_GraphGetTensorShape(graph, feed_out_0, returned_dims, num_dims, s);
Assert.IsTrue(s.Code == TF_Code.TF_OK);
Assert.AreEqual(2, num_dims);
Assert.AreEqual(2, returned_dims[0]);
Assert.AreEqual(3, returned_dims[1]);

// Try to set 'unknown' with same rank on the shape and see that
// it doesn't change.
dims[0] = -1;
dims[1] = -1;
c_api.TF_GraphSetTensorShape(graph, feed_out_0, dims, 2, s);
Assert.IsTrue(s.Code == TF_Code.TF_OK);
c_api.TF_GraphGetTensorShape(graph, feed_out_0, returned_dims, num_dims, s);
Assert.IsTrue(s.Code == TF_Code.TF_OK);
Assert.AreEqual(2, num_dims);
Assert.AreEqual(2, returned_dims[0]);
Assert.AreEqual(3, returned_dims[1]);

// Try to fetch a shape with the wrong num_dims
c_api.TF_GraphGetTensorShape(graph, feed_out_0, returned_dims, 5, s);
Assert.IsTrue(s.Code == TF_Code.TF_INVALID_ARGUMENT);

// Try to set an invalid shape (cannot change 2x3 to a 2x5).
dims[1] = 5;
c_api.TF_GraphSetTensorShape(graph, feed_out_0, dims, 2, s);
Assert.IsTrue(s.Code == TF_Code.TF_INVALID_ARGUMENT);

// Test for a scalar.
var three = c_test_util.ScalarConst(3, graph, s);
Assert.IsTrue(s.Code == TF_Code.TF_OK);
var three_out_0 = new TF_Output { oper = three };
var three_out_0 = new TF_Output(three, 0);

num_dims = c_api.TF_GraphGetTensorNumDims(graph, three_out_0, s);
Assert.IsTrue(s.Code == TF_Code.TF_OK);
Assert.AreEqual(0, num_dims);
c_api.TF_GraphGetTensorShape(graph, feed_out_0, null, num_dims, s);
//Assert.IsTrue(s.Code == TF_Code.TF_OK);

graph.Dispose();
s.Dispose();
}
}
}

+ 25
- 1
test/TensorFlowNET.UnitTest/c_test_util.cs View File

@@ -7,8 +7,32 @@ using Buffer = Tensorflow.Buffer;

namespace TensorFlowNET.UnitTest
{
/// <summary>
/// Port from `tensorflow\c\c_test_util.cc`
/// </summary>
public static class c_test_util
{
public static Operation Add(Operation l, Operation r, Graph graph, Status s, string name = "add")
{
Operation op = null;
AddOpHelper(l, r, graph, s, name, ref op, true);
return op;
}

public static void AddOpHelper(Operation l, Operation r, Graph graph, Status s, string name, ref Operation op, bool check)
{
var desc = c_api.TF_NewOperation(graph, "AddN", name);

c_api.TF_AddInputList(desc, new TF_Output[]
{
new TF_Output(l, 0),
new TF_Output(r, 0),
}, 2);

op = c_api.TF_FinishOperation(desc, s);
s.Check();
}

public static bool GetAttrValue(Operation oper, string attr_name, ref AttrValue attr_value, Status s)
{
var buffer = new Buffer();
@@ -58,7 +82,7 @@ namespace TensorFlowNET.UnitTest
return op;
}

public static Operation ScalarConst(int v, Graph graph, Status s, string name = "Const")
public static Operation ScalarConst(int v, Graph graph, Status s, string name = "scalar")
{
return Const(new Tensor(v), graph, s, name);
}


Loading…
Cancel
Save