| @@ -85,7 +85,7 @@ namespace Tensorflow | |||||
| /// <param name="num_dims">const int</param> | /// <param name="num_dims">const int</param> | ||||
| /// <param name="out_status">TF_Status*</param> | /// <param name="out_status">TF_Status*</param> | ||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static extern void TFE_OpSetAttrShape(IntPtr op, string attr_name, long[] dims, int num_dims, Status out_status); | |||||
| public static extern void TFE_OpSetAttrShape(IntPtr op, string attr_name, long[] dims, int num_dims, IntPtr out_status); | |||||
| /// <summary> | /// <summary> | ||||
| /// | /// | ||||
| @@ -52,6 +52,9 @@ namespace TensorFlowNET.UnitTest | |||||
| protected TF_DataType TFE_TensorHandleDataType(IntPtr h) | protected TF_DataType TFE_TensorHandleDataType(IntPtr h) | ||||
| => c_api.TFE_TensorHandleDataType(h); | => c_api.TFE_TensorHandleDataType(h); | ||||
| protected int TFE_TensorHandleNumDims(IntPtr h, IntPtr status) | |||||
| => c_api.TFE_TensorHandleNumDims(h, status); | |||||
| protected TF_Code TF_GetCode(Status s) | protected TF_Code TF_GetCode(Status s) | ||||
| => s.Code; | => s.Code; | ||||
| @@ -79,9 +82,18 @@ namespace TensorFlowNET.UnitTest | |||||
| protected void TFE_OpSetAttrType(IntPtr op, string attr_name, TF_DataType value) | protected void TFE_OpSetAttrType(IntPtr op, string attr_name, TF_DataType value) | ||||
| => c_api.TFE_OpSetAttrType(op, attr_name, value); | => c_api.TFE_OpSetAttrType(op, attr_name, value); | ||||
| protected void TFE_OpSetAttrShape(IntPtr op, string attr_name, long[] dims, int num_dims, IntPtr out_status) | |||||
| => c_api.TFE_OpSetAttrShape(op, attr_name, dims, num_dims, out_status); | |||||
| protected void TFE_OpSetAttrString(IntPtr op, string attr_name, string value, uint length) | |||||
| => c_api.TFE_OpSetAttrString(op, attr_name, value, length); | |||||
| protected IntPtr TFE_NewOp(IntPtr ctx, string op_or_function_name, IntPtr status) | protected IntPtr TFE_NewOp(IntPtr ctx, string op_or_function_name, IntPtr status) | ||||
| => c_api.TFE_NewOp(ctx, op_or_function_name, status); | => c_api.TFE_NewOp(ctx, op_or_function_name, status); | ||||
| protected void TFE_Execute(IntPtr op, IntPtr[] retvals, ref int num_retvals, IntPtr status) | |||||
| => c_api.TFE_Execute(op, retvals, ref num_retvals, status); | |||||
| protected IntPtr TFE_NewContextOptions() | protected IntPtr TFE_NewContextOptions() | ||||
| => c_api.TFE_NewContextOptions(); | => c_api.TFE_NewContextOptions(); | ||||
| @@ -139,37 +151,49 @@ namespace TensorFlowNET.UnitTest | |||||
| protected void TFE_OpSetDevice(IntPtr op, string device_name, IntPtr status) | protected void TFE_OpSetDevice(IntPtr op, string device_name, IntPtr status) | ||||
| => c_api.TFE_OpSetDevice(op, device_name, status); | => c_api.TFE_OpSetDevice(op, device_name, status); | ||||
| protected unsafe void memcpy(void * src, IntPtr dst, ulong size) | |||||
| protected unsafe void memcpy<T>(T* dst, void* src, ulong size) | |||||
| where T : unmanaged | |||||
| { | { | ||||
| Buffer.MemoryCopy(src, dst.ToPointer(), size, size); | |||||
| Buffer.MemoryCopy(src, dst, size, size); | |||||
| } | } | ||||
| protected unsafe void memcpy<T>(T[] src, IntPtr dst, ulong size) | |||||
| protected unsafe void memcpy<T>(void* dst, T* src, ulong size) | |||||
| where T : unmanaged | where T : unmanaged | ||||
| { | { | ||||
| fixed (void* p = &src[0]) | |||||
| Buffer.MemoryCopy(p, dst.ToPointer(), size, size); | |||||
| Buffer.MemoryCopy(src, dst, size, size); | |||||
| } | } | ||||
| protected unsafe void memcpy<T>(T[] src, IntPtr dst, long size) | |||||
| where T : unmanaged | |||||
| protected unsafe void memcpy(void * dst, IntPtr src, ulong size) | |||||
| { | { | ||||
| fixed (void* p = &src[0]) | |||||
| Buffer.MemoryCopy(p, dst.ToPointer(), size, size); | |||||
| Buffer.MemoryCopy(src.ToPointer(), dst, size, size); | |||||
| } | } | ||||
| protected unsafe void memcpy<T>(IntPtr src, T[] dst, ulong size) | |||||
| protected unsafe void memcpy<T>(T[] dst, IntPtr src, ulong size) | |||||
| where T : unmanaged | where T : unmanaged | ||||
| { | { | ||||
| fixed (void* p = &dst[0]) | fixed (void* p = &dst[0]) | ||||
| Buffer.MemoryCopy(src.ToPointer(), p, size, size); | Buffer.MemoryCopy(src.ToPointer(), p, size, size); | ||||
| } | } | ||||
| protected unsafe void memcpy<T>(IntPtr src, T[] dst, long size) | |||||
| where T: unmanaged | |||||
| protected unsafe void memcpy<T>(T[] dst, IntPtr src, long size) | |||||
| where T : unmanaged | |||||
| { | { | ||||
| fixed (void* p = &dst[0]) | fixed (void* p = &dst[0]) | ||||
| Buffer.MemoryCopy(src.ToPointer(), p, size, size); | Buffer.MemoryCopy(src.ToPointer(), p, size, size); | ||||
| } | } | ||||
| protected unsafe void memcpy<T>(IntPtr dst, T[] src, ulong size) | |||||
| where T : unmanaged | |||||
| { | |||||
| fixed (void* p = &src[0]) | |||||
| Buffer.MemoryCopy(p, dst.ToPointer(), size, size); | |||||
| } | |||||
| protected unsafe void memcpy<T>(IntPtr dst, T[] src, long size) | |||||
| where T: unmanaged | |||||
| { | |||||
| fixed (void* p = &src[0]) | |||||
| Buffer.MemoryCopy(p, dst.ToPointer(), size, size); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -43,7 +43,7 @@ namespace TensorFlowNET.UnitTest.Eager | |||||
| ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | ||||
| var product = new float[4]; | var product = new float[4]; | ||||
| EXPECT_EQ(product.Length * sizeof(float), (int)TF_TensorByteSize(t)); | EXPECT_EQ(product.Length * sizeof(float), (int)TF_TensorByteSize(t)); | ||||
| memcpy(TF_TensorData(t), product, TF_TensorByteSize(t)); | |||||
| memcpy(product, TF_TensorData(t), TF_TensorByteSize(t)); | |||||
| c_api.TF_DeleteTensor(t); | c_api.TF_DeleteTensor(t); | ||||
| EXPECT_EQ(7f, product[0]); | EXPECT_EQ(7f, product[0]); | ||||
| @@ -22,7 +22,7 @@ namespace TensorFlowNET.UnitTest.Eager | |||||
| ASSERT_EQ(16ul, c_api.TF_TensorByteSize(t)); | ASSERT_EQ(16ul, c_api.TF_TensorByteSize(t)); | ||||
| var data = new float[] { 0f, 0f, 0f, 0f }; | var data = new float[] { 0f, 0f, 0f, 0f }; | ||||
| memcpy(c_api.TF_TensorData(t), data, data.Length * sizeof(float)); | |||||
| memcpy(data, c_api.TF_TensorData(t), data.Length * sizeof(float)); | |||||
| EXPECT_EQ(1.0f, data[0]); | EXPECT_EQ(1.0f, data[0]); | ||||
| EXPECT_EQ(2.0f, data[1]); | EXPECT_EQ(2.0f, data[1]); | ||||
| @@ -61,10 +61,10 @@ namespace TensorFlowNET.UnitTest.Eager | |||||
| TFE_DeleteTensorHandle(hcpu); | TFE_DeleteTensorHandle(hcpu); | ||||
| // not export api | // not export api | ||||
| /*var executor = TFE_ContextGetExecutorForThread(ctx); | |||||
| var executor = TFE_ContextGetExecutorForThread(ctx); | |||||
| TFE_ExecutorWaitForAllPendingNodes(executor, status); | TFE_ExecutorWaitForAllPendingNodes(executor, status); | ||||
| ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | ||||
| TFE_DeleteExecutor(executor);*/ | |||||
| TFE_DeleteExecutor(executor); | |||||
| TFE_DeleteContext(ctx); | TFE_DeleteContext(ctx); | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,56 @@ | |||||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
| using System; | |||||
| using Tensorflow; | |||||
| using Tensorflow.Eager; | |||||
| using Buffer = System.Buffer; | |||||
| namespace TensorFlowNET.UnitTest.Eager | |||||
| { | |||||
| public partial class CApiEagerTest | |||||
| { | |||||
| /// <summary> | |||||
| /// TEST(CAPI, Variables) | |||||
| /// </summary> | |||||
| [TestMethod] | |||||
| public unsafe void Variables() | |||||
| { | |||||
| var status = c_api.TF_NewStatus(); | |||||
| var opts = TFE_NewContextOptions(); | |||||
| var ctx = TFE_NewContext(opts, status); | |||||
| ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | |||||
| TFE_DeleteContextOptions(opts); | |||||
| var var_handle = CreateVariable(ctx, 12.0f, status); | |||||
| ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | |||||
| var op = TFE_NewOp(ctx, "ReadVariableOp", status); | |||||
| ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | |||||
| TFE_OpSetAttrType(op, "dtype", TF_FLOAT); | |||||
| TFE_OpAddInput(op, var_handle, status); | |||||
| ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | |||||
| int num_retvals = 1; | |||||
| var value_handle = new[] { IntPtr.Zero }; | |||||
| TFE_Execute(op, value_handle, ref num_retvals, status); | |||||
| TFE_DeleteOp(op); | |||||
| ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | |||||
| ASSERT_EQ(1, num_retvals); | |||||
| EXPECT_EQ(TF_FLOAT, TFE_TensorHandleDataType(value_handle[0])); | |||||
| EXPECT_EQ(0, TFE_TensorHandleNumDims(value_handle[0], status)); | |||||
| ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | |||||
| var value = 0f; // new float[1]; | |||||
| var t = TFE_TensorHandleResolve(value_handle[0], status); | |||||
| ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | |||||
| ASSERT_EQ(sizeof(float), (int)TF_TensorByteSize(t)); | |||||
| memcpy(&value, TF_TensorData(t).ToPointer(), sizeof(float)); | |||||
| c_api.TF_DeleteTensor(t); | |||||
| EXPECT_EQ(12.0f, value); | |||||
| TFE_DeleteTensorHandle(var_handle); | |||||
| TFE_DeleteTensorHandle(value_handle[0]); | |||||
| TFE_DeleteContext(ctx); | |||||
| CHECK_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); | |||||
| TF_DeleteStatus(status); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -15,7 +15,7 @@ namespace TensorFlowNET.UnitTest.Eager | |||||
| var dims = new long[] { 2, 2 }; | var dims = new long[] { 2, 2 }; | ||||
| var data = new float[] { 1.0f, 2.0f, 3.0f, 4.0f }; | var data = new float[] { 1.0f, 2.0f, 3.0f, 4.0f }; | ||||
| var t = c_api.TF_AllocateTensor(TF_FLOAT, dims, dims.Length, (ulong)data.Length * sizeof(float)); | var t = c_api.TF_AllocateTensor(TF_FLOAT, dims, dims.Length, (ulong)data.Length * sizeof(float)); | ||||
| memcpy(data, c_api.TF_TensorData(t), data.Length * sizeof(float)); | |||||
| memcpy(c_api.TF_TensorData(t), data, data.Length * sizeof(float)); | |||||
| var status = c_api.TF_NewStatus(); | var status = c_api.TF_NewStatus(); | ||||
| var th = c_api.TFE_NewTensorHandle(t, status); | var th = c_api.TFE_NewTensorHandle(t, status); | ||||
| @@ -79,5 +79,46 @@ namespace TensorFlowNET.UnitTest.Eager | |||||
| return op; | return op; | ||||
| } | } | ||||
| unsafe IntPtr CreateVariable(IntPtr ctx, float value, IntPtr status) | |||||
| { | |||||
| var op = TFE_NewOp(ctx, "VarHandleOp", status); | |||||
| if (TF_GetCode(status) != TF_OK) return IntPtr.Zero; | |||||
| TFE_OpSetAttrType(op, "dtype", TF_FLOAT); | |||||
| TFE_OpSetAttrShape(op, "shape", new long[0], 0, status); | |||||
| TFE_OpSetAttrString(op, "container", "", 0); | |||||
| TFE_OpSetAttrString(op, "shared_name", "", 0); | |||||
| if (TF_GetCode(status) != TF_OK) return IntPtr.Zero; | |||||
| var var_handle = new IntPtr[1]; | |||||
| int num_retvals = 1; | |||||
| TFE_Execute(op, var_handle, ref num_retvals, status); | |||||
| TFE_DeleteOp(op); | |||||
| if (TF_GetCode(status) != TF_OK) return IntPtr.Zero; | |||||
| CHECK_EQ(1, num_retvals); | |||||
| // Assign 'value' to it. | |||||
| op = TFE_NewOp(ctx, "AssignVariableOp", status); | |||||
| if (TF_GetCode(status) != TF_OK) return IntPtr.Zero; | |||||
| TFE_OpSetAttrType(op, "dtype", TF_FLOAT); | |||||
| TFE_OpAddInput(op, var_handle[0], status); | |||||
| // Convert 'value' to a TF_Tensor then a TFE_TensorHandle. | |||||
| var t = c_api.TF_AllocateTensor(TF_DataType.TF_FLOAT, new long[0], 0, sizeof(float)); | |||||
| memcpy(TF_TensorData(t).ToPointer(), &value, TF_TensorByteSize(t)); | |||||
| var value_handle = c_api.TFE_NewTensorHandle(t, status); | |||||
| if (TF_GetCode(status) != TF_OK) return IntPtr.Zero; | |||||
| TFE_OpAddInput(op, value_handle, status); | |||||
| if (TF_GetCode(status) != TF_OK) return IntPtr.Zero; | |||||
| num_retvals = 0; | |||||
| c_api.TFE_Execute(op, null, ref num_retvals, status); | |||||
| TFE_DeleteOp(op); | |||||
| if (TF_GetCode(status) != TF_OK) return IntPtr.Zero; | |||||
| CHECK_EQ(0, num_retvals); | |||||
| return var_handle[0]; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||