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