From 88d0e968ce6f061f9a3da6edf463fafc05d7d3ea Mon Sep 17 00:00:00 2001 From: Oceania2018 Date: Sat, 7 Mar 2020 23:36:43 -0600 Subject: [PATCH] TensorHandleDevices --- TensorFlow.NET.sln | 18 -------- src/TensorFlowNET.Core/APIs/tf.math.cs | 2 +- src/TensorFlowNET.Core/Binding.Util.cs | 13 ++++++ src/TensorFlowNET.Core/Device/c_api.device.cs | 24 ++++++++++- src/TensorFlowNET.Core/Eager/c_api.eager.cs | 22 ++++++++++ .../Eager/pywrap_tfe_src.cs | 11 ++++- .../Operations/gen_math_ops.cs | 39 ++++++++++++++--- src/TensorFlowNET.Core/Operations/math_ops.cs | 16 +++++++ .../Tensors/Tensor.Operators.cs | 2 +- src/TensorFlowNET.Core/ops.cs | 3 ++ test/TensorFlowNET.UnitTest/CApiTest.cs | 24 +++++++++++ .../Eager/CApi.Eager.Context.cs | 2 +- .../Eager/CApi.Eager.TensorHandleDevices.cs | 43 +++++++++++++++++++ .../Eager/CApi.Eager.cs | 25 +++++++++++ .../Tensorflow.UnitTest.csproj | 3 +- 15 files changed, 214 insertions(+), 33 deletions(-) create mode 100644 test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandleDevices.cs diff --git a/TensorFlow.NET.sln b/TensorFlow.NET.sln index f113418a..61f5cf6b 100644 --- a/TensorFlow.NET.sln +++ b/TensorFlow.NET.sln @@ -13,8 +13,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Keras", "src\Ten EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Keras.UnitTest", "test\Tensorflow.Keras.UnitTest\Tensorflow.Keras.UnitTest.csproj", "{EB92DD90-6346-41FB-B967-2B33A860AD98}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Hub", "src\TensorFlowNET.Hub\Tensorflow.Hub.csproj", "{95B077C1-E21B-486F-8BDD-1C902FE687AB}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -107,22 +105,6 @@ Global {EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|Any CPU.Build.0 = Release|Any CPU {EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|x64.ActiveCfg = Release|Any CPU {EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|x64.Build.0 = Release|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|x64.ActiveCfg = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|x64.Build.0 = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|x64.Build.0 = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|Any CPU.ActiveCfg = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|Any CPU.Build.0 = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|x64.ActiveCfg = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|x64.Build.0 = Debug|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|Any CPU.Build.0 = Release|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|x64.ActiveCfg = Release|Any CPU - {95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/TensorFlowNET.Core/APIs/tf.math.cs b/src/TensorFlowNET.Core/APIs/tf.math.cs index 958f4e27..24131a2d 100644 --- a/src/TensorFlowNET.Core/APIs/tf.math.cs +++ b/src/TensorFlowNET.Core/APIs/tf.math.cs @@ -261,7 +261,7 @@ namespace Tensorflow public Tensor divide(Tensor a, Tensor b) - => gen_math_ops.real_div(a, b); + => a / b; public Tensor sqrt(Tensor a, string name = null) => gen_math_ops.sqrt(a, name); diff --git a/src/TensorFlowNET.Core/Binding.Util.cs b/src/TensorFlowNET.Core/Binding.Util.cs index 3340e512..df818adb 100644 --- a/src/TensorFlowNET.Core/Binding.Util.cs +++ b/src/TensorFlowNET.Core/Binding.Util.cs @@ -77,6 +77,19 @@ namespace Tensorflow Console.WriteLine(_tostring(obj)); } + public static void print(string format, params object[] objects) + { + if (!format.Contains("{}")) + Console.WriteLine(format, string.Join(" ", objects.Select(x => x.ToString()))); + + foreach(var obj in objects) + { + + } + + Console.WriteLine(format); + } + public static int len(object a) { switch (a) diff --git a/src/TensorFlowNET.Core/Device/c_api.device.cs b/src/TensorFlowNET.Core/Device/c_api.device.cs index b7b88bee..f2289cee 100644 --- a/src/TensorFlowNET.Core/Device/c_api.device.cs +++ b/src/TensorFlowNET.Core/Device/c_api.device.cs @@ -37,6 +37,16 @@ namespace Tensorflow [DllImport(TensorFlowLibName)] public static extern int TF_DeviceListCount(IntPtr list); + /// + /// Retrieves the type of the device at the given index. + /// + /// TF_DeviceList* + /// int + /// TF_Status* + /// + [DllImport(TensorFlowLibName)] + public static extern IntPtr TF_DeviceListType(IntPtr list, int index, IntPtr status); + /// /// Deallocates the device list. /// @@ -44,6 +54,18 @@ namespace Tensorflow [DllImport(TensorFlowLibName)] public static extern void TF_DeleteDeviceList(IntPtr list); + /// + /// Create a new TFE_TensorHandle with the same contents as 'h' but placed + /// in the memory of the device name 'device_name'. + /// + /// TFE_TensorHandle* + /// TFE_Context* + /// char* + /// TF_Status* + /// TFE_TensorHandle* + [DllImport(TensorFlowLibName)] + public static extern IntPtr TFE_TensorHandleCopyToDevice(IntPtr h, IntPtr ctx, string device_name, IntPtr status); + /// /// Retrieves the full name of the device (e.g. /job:worker/replica:0/...) /// The return value will be a pointer to a null terminated string. The caller @@ -54,6 +76,6 @@ namespace Tensorflow /// /// TF_Status* [DllImport(TensorFlowLibName)] - public static extern string TF_DeviceListName(IntPtr list, int index, IntPtr status); + public static extern IntPtr TF_DeviceListName(IntPtr list, int index, IntPtr status); } } diff --git a/src/TensorFlowNET.Core/Eager/c_api.eager.cs b/src/TensorFlowNET.Core/Eager/c_api.eager.cs index e5af4157..7fd81af8 100644 --- a/src/TensorFlowNET.Core/Eager/c_api.eager.cs +++ b/src/TensorFlowNET.Core/Eager/c_api.eager.cs @@ -159,6 +159,28 @@ namespace Tensorflow [DllImport(TensorFlowLibName)] public static extern int TFE_TensorHandleNumDims(IntPtr h, IntPtr status); + /// + /// Returns the device of the operation that produced `h`. If `h` was produced by + /// a copy, returns the destination device of the copy. Note that the returned + /// device name is not always the device holding the tensor handle's memory. If + /// you want the latter, use TFE_TensorHandleBackingDeviceName. This function + /// will block till the operation that produces `h` has completed. + /// + /// TFE_TensorHandle* + /// TF_Status* + /// + [DllImport(TensorFlowLibName)] + public static extern IntPtr TFE_TensorHandleDeviceName(IntPtr h, IntPtr status); + + /// + /// Returns the name of the device in whose memory `h` resides. + /// + /// TFE_TensorHandle* + /// TF_Status* + /// + [DllImport(TensorFlowLibName)] + public static extern IntPtr TFE_TensorHandleBackingDeviceName(IntPtr h, IntPtr status); + /// /// /// diff --git a/src/TensorFlowNET.Core/Eager/pywrap_tfe_src.cs b/src/TensorFlowNET.Core/Eager/pywrap_tfe_src.cs index c0f9430c..0bcd5546 100644 --- a/src/TensorFlowNET.Core/Eager/pywrap_tfe_src.cs +++ b/src/TensorFlowNET.Core/Eager/pywrap_tfe_src.cs @@ -14,7 +14,7 @@ namespace Tensorflow.Eager string device_name, string opName, string name, - params Tensor[] inputs) + params object[] inputs) { IntPtr op = IntPtr.Zero; var attr_list_sizes = new Dictionary(); @@ -42,7 +42,14 @@ namespace Tensorflow.Eager else { // The item is a single item. - AddInputToOp(inputs[i], true, input_arg, op, status); + switch (inputs[i]) + { + case Tensor inputTensor: + AddInputToOp(inputTensor, true, input_arg, op, status); + break; + default: + throw new NotImplementedException(""); + } } } diff --git a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs index c6a931d0..8f622080 100644 --- a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs @@ -140,19 +140,14 @@ namespace Tensorflow return _op.outputs[0]; } - public static EagerTensor add(Tensor x, Tensor y, string name = null) + public static Tensor add(Tx x, Ty y, string name = null) { if (tf.context.executing_eagerly()) { - var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Add", name, new[] { x, y }); + var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Add", name, x, y); return _result; } - return null; - } - - public static Tensor add(Tx x, Ty y, string name = null) - { var _op = _op_def_lib._apply_op_helper("Add", name, args: new { x, y }); return _op.output; @@ -469,6 +464,12 @@ namespace Tensorflow public static Tensor cast(Tensor x, TF_DataType DstT, bool Truncate= false, string name= null) { + if (tf.context.executing_eagerly()) + { + var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Cast", name, x, "DstT", DstT, "Truncate", Truncate); + return _result; + } + var _op = _op_def_lib._apply_op_helper("Cast", name, args: new { x, DstT, Truncate }); return _op.outputs[0]; @@ -490,6 +491,12 @@ namespace Tensorflow public static Tensor sub(Tx x, Ty y, string name = null) { + if (tf.context.executing_eagerly()) + { + var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Sub", name, x, y); + return _result; + } + var _op = _op_def_lib._apply_op_helper("Sub", name, args: new { x, y }); return _op.outputs[0]; @@ -535,6 +542,12 @@ namespace Tensorflow public static Tensor mul(Tx x, Ty y, string name = null) { + if (tf.context.executing_eagerly()) + { + var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Mul", name, x, y); + return _result; + } + var _op = _op_def_lib._apply_op_helper("Mul", name, args: new { x, y }); return _op.outputs[0]; @@ -549,6 +562,12 @@ namespace Tensorflow public static Tensor real_div(Tensor x, Tensor y, string name = null) { + if (tf.context.executing_eagerly()) + { + var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "RealDiv", name, x, y); + return _result; + } + var _op = _op_def_lib._apply_op_helper("RealDiv", name, args: new { x, y }); return _op.outputs[0]; @@ -570,6 +589,12 @@ namespace Tensorflow public static Tensor floor_div(Tensor x, Tensor y, string name = null) { + if (tf.context.executing_eagerly()) + { + var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "FloorDiv", name, x, y); + return _result; + } + var _op = _op_def_lib._apply_op_helper("FloorDiv", name, args: new { x, y }); return _op.outputs[0]; diff --git a/src/TensorFlowNET.Core/Operations/math_ops.cs b/src/TensorFlowNET.Core/Operations/math_ops.cs index 34ab587f..8e147b41 100644 --- a/src/TensorFlowNET.Core/Operations/math_ops.cs +++ b/src/TensorFlowNET.Core/Operations/math_ops.cs @@ -712,6 +712,22 @@ namespace Tensorflow var x_dtype = x.dtype.as_base_dtype(); var y_dtype = y.dtype.as_base_dtype(); + if (x_dtype != y_dtype) + throw new TypeError($"x and y must have the same dtype, got {x_dtype} != {y_dtype}"); + + var dtype = x_dtype switch + { + TF_DataType.TF_UINT8 => TF_DataType.TF_FLOAT, + TF_DataType.TF_INT8 => TF_DataType.TF_FLOAT, + TF_DataType.TF_INT16 => TF_DataType.TF_FLOAT, + TF_DataType.TF_UINT16 => TF_DataType.TF_FLOAT, + TF_DataType.TF_INT32 => TF_DataType.TF_DOUBLE, + TF_DataType.TF_INT64 => TF_DataType.TF_DOUBLE, + _ => x_dtype + }; + x = cast(x, dtype); + y = cast(y, dtype); + return gen_math_ops.real_div(x, y, name: name); }); } diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Operators.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Operators.cs index 616a375f..e9ecb79a 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.Operators.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.Operators.cs @@ -130,7 +130,7 @@ namespace Tensorflow public static Tensor operator *(double lhs, Tensor rhs) => BinaryOpWrapper("mul", lhs, rhs); public static Tensor operator *(Tensor lhs, Complex rhs) => BinaryOpWrapper("mul", lhs, rhs); public static Tensor operator *(Complex lhs, Tensor rhs) => BinaryOpWrapper("mul", lhs, rhs); - public static Tensor operator /(Tensor lhs, Tensor rhs) => BinaryOpWrapper("div", lhs, rhs); + public static Tensor operator /(Tensor lhs, Tensor rhs) => BinaryOpWrapper("truediv", lhs, rhs); public static Tensor operator /(Tensor lhs, NDArray rhs) => BinaryOpWrapper("div", lhs, rhs); public static Tensor operator /(NDArray lhs, Tensor rhs) => BinaryOpWrapper("div", lhs, rhs); public static Tensor operator /(Tensor lhs, sbyte rhs) => BinaryOpWrapper("div", lhs, rhs); diff --git a/src/TensorFlowNET.Core/ops.cs b/src/TensorFlowNET.Core/ops.cs index 9ac0a042..15115d3f 100644 --- a/src/TensorFlowNET.Core/ops.cs +++ b/src/TensorFlowNET.Core/ops.cs @@ -97,6 +97,9 @@ namespace Tensorflow /// public static Tensor convert_to_tensor(object value, TF_DataType dtype = TF_DataType.DtInvalid, string name = null, TF_DataType preferred_dtype = TF_DataType.DtInvalid) { + if (value is Tensor tensor) + return tensor; + return convert_to_tensor_v2(value, dtype, preferred_dtype, name); } diff --git a/test/TensorFlowNET.UnitTest/CApiTest.cs b/test/TensorFlowNET.UnitTest/CApiTest.cs index 77596be2..45ac9b1b 100644 --- a/test/TensorFlowNET.UnitTest/CApiTest.cs +++ b/test/TensorFlowNET.UnitTest/CApiTest.cs @@ -103,6 +103,30 @@ namespace TensorFlowNET.UnitTest protected IntPtr TFE_TensorHandleResolve(IntPtr h, IntPtr status) => c_api.TFE_TensorHandleResolve(h, status); + protected string TFE_TensorHandleDeviceName(IntPtr h, IntPtr status) + => c_api.StringPiece(c_api.TFE_TensorHandleDeviceName(h, status)); + + protected string TFE_TensorHandleBackingDeviceName(IntPtr h, IntPtr status) + => c_api.StringPiece(c_api.TFE_TensorHandleBackingDeviceName(h, status)); + + protected IntPtr TFE_ContextListDevices(IntPtr ctx, IntPtr status) + => c_api.TFE_ContextListDevices(ctx, status); + + protected int TF_DeviceListCount(IntPtr list) + => c_api.TF_DeviceListCount(list); + + protected string TF_DeviceListType(IntPtr list, int index, IntPtr status) + => c_api.StringPiece(c_api.TF_DeviceListType(list, index, status)); + + protected string TF_DeviceListName(IntPtr list, int index, IntPtr status) + => c_api.StringPiece(c_api.TF_DeviceListName(list, index, status)); + + protected void TF_DeleteDeviceList(IntPtr list) + => c_api.TF_DeleteDeviceList(list); + + protected IntPtr TFE_TensorHandleCopyToDevice(IntPtr h, IntPtr ctx, string device_name, IntPtr status) + => c_api.TFE_TensorHandleCopyToDevice(h, ctx, device_name, status); + protected unsafe void memcpy(void * src, IntPtr dst, ulong size) { Buffer.MemoryCopy(src, dst.ToPointer(), size, size); diff --git a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Context.cs b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Context.cs index b966f0ea..05d34d20 100644 --- a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Context.cs +++ b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.Context.cs @@ -33,7 +33,7 @@ namespace TensorFlowNET.UnitTest.Eager EXPECT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); } - // c_api.TF_DeleteDeviceList(devices); + c_api.TF_DeleteDeviceList(devices); c_api.TF_DeleteStatus(status); } } diff --git a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandleDevices.cs b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandleDevices.cs new file mode 100644 index 00000000..eae59b08 --- /dev/null +++ b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.TensorHandleDevices.cs @@ -0,0 +1,43 @@ +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, TensorHandleDevices) + /// + [TestMethod] + public unsafe void TensorHandleDevices() + { + var status = c_api.TF_NewStatus(); + var opts = TFE_NewContextOptions(); + var ctx = TFE_NewContext(opts, status); + TFE_DeleteContextOptions(opts); + ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); + + var hcpu = TestMatrixTensorHandle(); + var device_name = TFE_TensorHandleDeviceName(hcpu, status); + ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); + ASSERT_TRUE(device_name.Contains("CPU:0")); + + var backing_device_name = TFE_TensorHandleBackingDeviceName(hcpu, status); + ASSERT_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); + ASSERT_TRUE(backing_device_name.Contains("CPU:0")); + + // Disable the test if no GPU is present. + string gpu_device_name = ""; + if(GetDeviceName(ctx, ref gpu_device_name, "GPU")) + { + var hgpu = TFE_TensorHandleCopyToDevice(hcpu, ctx, gpu_device_name, status); + ASSERT_TRUE(TF_GetCode(status) == TF_OK, TF_Message(status)); + + // shape_op = ShapeOp(ctx, hgpu); + } + } + } +} diff --git a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.cs b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.cs index 040a1141..f941c3c4 100644 --- a/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.cs +++ b/test/TensorFlowNET.UnitTest/Eager/CApi.Eager.cs @@ -42,5 +42,30 @@ namespace TensorFlowNET.UnitTest.Eager return op; } + + bool GetDeviceName(IntPtr ctx, ref string device_name, string device_type) + { + var status = TF_NewStatus(); + var devices = TFE_ContextListDevices(ctx, status); + CHECK_EQ(TF_OK, TF_GetCode(status), TF_Message(status)); + + int num_devices = TF_DeviceListCount(devices); + for (int i = 0; i < num_devices; ++i) + { + var dev_type = TF_DeviceListType(devices, i, status); + CHECK_EQ(TF_GetCode(status), TF_OK, TF_Message(status)); + var dev_name = TF_DeviceListName(devices, i, status); + CHECK_EQ(TF_GetCode(status), TF_OK, TF_Message(status)); + if (dev_type == device_type) + { + device_name = dev_name; + TF_DeleteDeviceList(devices); + return true; + } + } + + TF_DeleteDeviceList(devices); + return false; + } } } diff --git a/test/TensorFlowNET.UnitTest/Tensorflow.UnitTest.csproj b/test/TensorFlowNET.UnitTest/Tensorflow.UnitTest.csproj index e64571e9..a84ad93c 100644 --- a/test/TensorFlowNET.UnitTest/Tensorflow.UnitTest.csproj +++ b/test/TensorFlowNET.UnitTest/Tensorflow.UnitTest.csproj @@ -33,12 +33,11 @@ - + -