From 4076cd113767672bd1152abdb1a8067e4777f0da Mon Sep 17 00:00:00 2001 From: Oceania2018 Date: Sun, 8 Mar 2020 18:10:33 -0500 Subject: [PATCH] Eager.Variables. --- src/TensorFlowNET.Core/Eager/c_api.eager.cs | 2 +- test/TensorFlowNET.UnitTest/CApiTest.cs | 48 ++++++++++++---- .../Eager/CApi.Eager.Execute_MatMul_CPU.cs | 2 +- .../Eager/CApi.Eager.TensorHandle.cs | 2 +- .../Eager/CApi.Eager.TensorHandleDevices.cs | 4 +- .../Eager/CApi.Eager.Variables.cs | 56 +++++++++++++++++++ .../Eager/CApi.Eager.cs | 43 +++++++++++++- 7 files changed, 139 insertions(+), 18 deletions(-) create mode 100644 test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Variables.cs diff --git a/src/TensorFlowNET.Core/Eager/c_api.eager.cs b/src/TensorFlowNET.Core/Eager/c_api.eager.cs index 7da0a7e3..16456ecd 100644 --- a/src/TensorFlowNET.Core/Eager/c_api.eager.cs +++ b/src/TensorFlowNET.Core/Eager/c_api.eager.cs @@ -85,7 +85,7 @@ namespace Tensorflow /// const int /// TF_Status* [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); /// /// diff --git a/test/TensorFlowNET.UnitTest/CApiTest.cs b/test/TensorFlowNET.UnitTest/CApiTest.cs index fc5121ad..2ae410da 100644 --- a/test/TensorFlowNET.UnitTest/CApiTest.cs +++ b/test/TensorFlowNET.UnitTest/CApiTest.cs @@ -52,6 +52,9 @@ namespace TensorFlowNET.UnitTest protected TF_DataType TFE_TensorHandleDataType(IntPtr 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) => s.Code; @@ -79,9 +82,18 @@ namespace TensorFlowNET.UnitTest protected void TFE_OpSetAttrType(IntPtr op, string attr_name, TF_DataType 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) => 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() => c_api.TFE_NewContextOptions(); @@ -139,37 +151,49 @@ namespace TensorFlowNET.UnitTest protected void TFE_OpSetDevice(IntPtr op, string device_name, IntPtr status) => c_api.TFE_OpSetDevice(op, device_name, status); - protected unsafe void memcpy(void * src, IntPtr dst, ulong size) + protected unsafe void memcpy(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[] src, IntPtr dst, ulong size) + protected unsafe void memcpy(void* dst, T* src, ulong size) 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[] 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(IntPtr src, T[] dst, ulong size) + protected unsafe void memcpy(T[] dst, IntPtr src, ulong size) where T : unmanaged { fixed (void* p = &dst[0]) Buffer.MemoryCopy(src.ToPointer(), p, size, size); } - protected unsafe void memcpy(IntPtr src, T[] dst, long size) - where T: unmanaged + protected unsafe void memcpy(T[] dst, IntPtr src, long size) + where T : unmanaged { fixed (void* p = &dst[0]) Buffer.MemoryCopy(src.ToPointer(), p, size, size); } + + protected unsafe void memcpy(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(IntPtr dst, T[] src, long size) + where T: unmanaged + { + fixed (void* p = &src[0]) + Buffer.MemoryCopy(p, dst.ToPointer(), size, size); + } } } diff --git a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Execute_MatMul_CPU.cs b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Execute_MatMul_CPU.cs index bce7f7c4..a7274582 100644 --- a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Execute_MatMul_CPU.cs +++ b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Execute_MatMul_CPU.cs @@ -43,7 +43,7 @@ namespace TensorFlowNET.UnitTest.Eager ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); var product = new float[4]; 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); EXPECT_EQ(7f, product[0]); diff --git a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandle.cs b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandle.cs index a61863f8..eaecdca8 100644 --- a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandle.cs +++ b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandle.cs @@ -22,7 +22,7 @@ namespace TensorFlowNET.UnitTest.Eager ASSERT_EQ(16ul, c_api.TF_TensorByteSize(t)); 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(2.0f, data[1]); diff --git a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandleDevices.cs b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandleDevices.cs index 2f0b9dc3..5239dff3 100644 --- a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandleDevices.cs +++ b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandleDevices.cs @@ -61,10 +61,10 @@ namespace TensorFlowNET.UnitTest.Eager TFE_DeleteTensorHandle(hcpu); // not export api - /*var executor = TFE_ContextGetExecutorForThread(ctx); + var executor = TFE_ContextGetExecutorForThread(ctx); TFE_ExecutorWaitForAllPendingNodes(executor, status); ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); - TFE_DeleteExecutor(executor);*/ + TFE_DeleteExecutor(executor); TFE_DeleteContext(ctx); } } diff --git a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Variables.cs b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Variables.cs new file mode 100644 index 00000000..f5300088 --- /dev/null +++ b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Variables.cs @@ -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 + { + /// + /// TEST(CAPI, Variables) + /// + [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); + } + } +} diff --git a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.cs b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.cs index 0a9db179..80150600 100644 --- a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.cs +++ b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.cs @@ -15,7 +15,7 @@ namespace TensorFlowNET.UnitTest.Eager var dims = new long[] { 2, 2 }; 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)); - 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 th = c_api.TFE_NewTensorHandle(t, status); @@ -79,5 +79,46 @@ namespace TensorFlowNET.UnitTest.Eager 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]; + } } }