From ed8ccecc1498c347e88e352122cc15ebb157c812 Mon Sep 17 00:00:00 2001 From: Yaohui Liu Date: Tue, 25 Apr 2023 13:59:20 +0800 Subject: [PATCH 1/2] Fix the mapping from dtype to numpy descr of byte. --- src/TensorFlowNET.Core/NumPy/Persistence/NpyFormat.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TensorFlowNET.Core/NumPy/Persistence/NpyFormat.cs b/src/TensorFlowNET.Core/NumPy/Persistence/NpyFormat.cs index 1886e4b4e..10de0e7d2 100644 --- a/src/TensorFlowNET.Core/NumPy/Persistence/NpyFormat.cs +++ b/src/TensorFlowNET.Core/NumPy/Persistence/NpyFormat.cs @@ -70,7 +70,7 @@ private static string GetDtypeName(NDArray array, out Type type, out int bytes) if (type == typeof(bool)) return "|b1"; else if (type == typeof(byte)) - return "|i1"; + return "|u1"; else if (type == typeof(short)) return " Date: Fri, 28 Apr 2023 02:18:16 +0800 Subject: [PATCH 2/2] Add the constructor of ndarray which reuse memory. --- .../Numpy/NDArray.Creation.cs | 15 ++++++++++++++ .../Operations/array_ops.cs | 2 +- .../Tensors/c_api.tensor.cs | 11 +++++++++- src/TensorFlowNET.Core/Tensors/tensor_util.cs | 20 +++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/TensorFlowNET.Core/Numpy/NDArray.Creation.cs b/src/TensorFlowNET.Core/Numpy/NDArray.Creation.cs index d9743eada..af7e94c85 100644 --- a/src/TensorFlowNET.Core/Numpy/NDArray.Creation.cs +++ b/src/TensorFlowNET.Core/Numpy/NDArray.Creation.cs @@ -8,6 +8,7 @@ namespace Tensorflow.NumPy { public partial class NDArray { + protected NDArray() { } public NDArray(bool value) : base(value) => NewEagerTensorHandle(); public NDArray(byte value) : base(value) => NewEagerTensorHandle(); public NDArray(short value) : base(value) => NewEagerTensorHandle(); @@ -57,6 +58,20 @@ public static NDArray Scalar(T value) where T : unmanaged _ => throw new NotImplementedException("") }; + /// + /// Reuse the existing memory instead of copying it. + /// + /// + /// + /// + /// + protected void InitWithExistingMemory(IntPtr data_ptr, Shape shape, TF_DataType dtype, c_api.DeallocatorV2 deallocator) + { + _handle = c_api.TF_NewTensor(TF_DataType.TF_STRING, shape.dims, shape.ndim, data_ptr, (ulong)(shape.size * dtype.get_datatype_size()), deallocator, IntPtr.Zero); + tensor_util.DangerousManuallySetTensorDType(_handle, dtype); + NewEagerTensorHandle(); + } + void NewEagerTensorHandle() { if (_handle is not null) diff --git a/src/TensorFlowNET.Core/Operations/array_ops.cs b/src/TensorFlowNET.Core/Operations/array_ops.cs index 0e888a0ab..2767e8219 100644 --- a/src/TensorFlowNET.Core/Operations/array_ops.cs +++ b/src/TensorFlowNET.Core/Operations/array_ops.cs @@ -417,7 +417,7 @@ public static Tensor ones(Shape shape, TF_DataType dtype = TF_DataType.TF_FLOAT, { TF_DataType.TF_DOUBLE => constant(1.0d), TF_DataType.TF_FLOAT => constant(1.0f), - _ => constant(1) + _ => constant(1, dtype) }; if (shape.ndim == 0) diff --git a/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs b/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs index 2e7edc66d..3779ddcfd 100644 --- a/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs +++ b/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs @@ -71,7 +71,7 @@ public partial class c_api /// /// [DllImport(TensorFlowLibName)] - public static extern SafeTensorHandle TF_NewTensor(TF_DataType dataType, long[] dims, int num_dims, IntPtr data, ulong len, Deallocator deallocator, IntPtr deallocator_arg); + public static extern SafeTensorHandle TF_NewTensor(TF_DataType dataType, long[] dims, int num_dims, IntPtr data, ulong len, DeallocatorV2 deallocator, IntPtr deallocator_arg); public static unsafe SafeTensorHandle TF_NewTensor(byte[] data, Shape shape, TF_DataType dtype) { @@ -147,6 +147,15 @@ public static unsafe SafeTensorHandle TF_NewTensor(T value) [DllImport(TensorFlowLibName)] public static extern TF_DataType TF_TensorType(SafeTensorHandle tensor); + /// + /// Set a new shape for the Tensor. Note that this API only works after tf2.11. + /// + /// + /// + /// + [DllImport(TensorFlowLibName)] + public static extern void TF_SetShape(SafeTensorHandle tensor, long[] dims, int num_dims); + /// /// Return the size in bytes required to encode a string `len` bytes long into a /// TF_STRING tensor. diff --git a/src/TensorFlowNET.Core/Tensors/tensor_util.cs b/src/TensorFlowNET.Core/Tensors/tensor_util.cs index 25bb88826..e65c4850d 100644 --- a/src/TensorFlowNET.Core/Tensors/tensor_util.cs +++ b/src/TensorFlowNET.Core/Tensors/tensor_util.cs @@ -22,6 +22,7 @@ limitations under the License. using Tensorflow.Eager; using Tensorflow.Graphs; using static Tensorflow.Binding; +using System.Diagnostics; namespace Tensorflow { @@ -649,5 +650,24 @@ public static ParsedSliceArgs ParseSlices(Tensor start, Tensor stop = null, Tens NewAxisMask = new_axis_mask }; } + + /// + /// Warning: this method is an extremely dangerous method. It directly changes the dtype inside the tensor + /// and security is not guaranteed at all. Currently this method is only used for some conditions to reuse + /// the existing memory. Any other usage should be prevented. If you are sure you want to use it when + /// developing tensorflow.net, please ask @Oceanic2018 or @AsakusaRinne first. + /// + /// + /// + internal static unsafe void DangerousManuallySetTensorDType(SafeTensorHandle handle, TF_DataType dtype) + { + long tf_tensor_address = handle.DangerousGetHandle().ToInt64(); + long interface_address = *(long*)(tf_tensor_address); + long tensor_shape_address = interface_address + 8; + long tensor_dtype_address = tensor_shape_address + 13; + byte* dtype_pointer = (byte*)tensor_dtype_address; + *dtype_pointer = (byte)dtype; + Debug.Assert(c_api.TF_TensorType(handle) == dtype); + } } }