From 7cb17461a93b0f2b7dfb7fd1c6401abd4e77410f Mon Sep 17 00:00:00 2001 From: Meinrad Recheis Date: Thu, 18 Jul 2019 15:08:22 +0200 Subject: [PATCH] Tensor: added a constructor to create a Tensor from a fixed memory pointer that is owned by the caller --- TensorFlow.NET.sln | 6 +- .../Tensors/Tensor.Creation.cs | 285 +++++++----------- src/TensorFlowNet.Benchmarks/Program.cs | 9 +- .../TensorBenchmark.cs | 13 +- .../TensorFlowBenchmark.csproj | 31 ++ .../TensorFlowNet.Benchmark.csproj | 20 -- test/TensorFlowNET.UnitTest/TensorTest.cs | 27 +- 7 files changed, 179 insertions(+), 212 deletions(-) create mode 100644 src/TensorFlowNet.Benchmarks/TensorFlowBenchmark.csproj delete mode 100644 src/TensorFlowNet.Benchmarks/TensorFlowNet.Benchmark.csproj diff --git a/TensorFlow.NET.sln b/TensorFlow.NET.sln index fd92608d..e6775ce4 100644 --- a/TensorFlow.NET.sln +++ b/TensorFlow.NET.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29102.190 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.645 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TensorFlowNET.UnitTest", "test\TensorFlowNET.UnitTest\TensorFlowNET.UnitTest.csproj", "{029A8CF1-CF95-4DCB-98AA-9D3D96A83B3E}" EndProject @@ -17,7 +17,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keras.UnitTest", "test\Kera EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TensorFlowNET.Examples.FSharp", "test\TensorFlowNET.Examples.FSharp\TensorFlowNET.Examples.FSharp.fsproj", "{62BC3801-F0D3-44A9-A0AC-712F40C8F961}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TensorFlowNET.Benchmark", "src\TensorFlowNet.Benchmarks\TensorFlowNET.Benchmark.csproj", "{68861442-971A-4196-876E-C9330F0B3C54}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TensorFlowBenchmark", "src\TensorFlowNet.Benchmarks\TensorFlowBenchmark.csproj", "{68861442-971A-4196-876E-C9330F0B3C54}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs index 077a65e1..7ee4edd3 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs @@ -38,6 +38,12 @@ namespace Tensorflow /// private bool _isPinnedArray => _deallocatorArgs.gc_handle != IntPtr.Zero; + /// + /// True only if the Tensor object was created in a way that the Tensor object itself allocated memory or pinned a managed object. + /// False if the Tensor was created from a pointer + /// + public bool IsMemoryOwner { get; private set; } + /// /// This holds values that are used by the unmanaged deallocator callback /// @@ -46,30 +52,44 @@ namespace Tensorflow // note: they must be assigned to a static variable in order to work as unmanaged callbacks static Deallocator _hGlobalDeallocator = FreeHGlobalMemory; static Deallocator _gcHandleDeallocator = FreeGCHandle; + private static Deallocator _nothingDeallocator = FreeNothing; + /// + /// Create a Tensor object from an existing TF handle + /// + /// public Tensor(IntPtr handle) { _handle = handle; - } - -#if _REGEN - %types=["sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double", "Complex"] - %foreach types% - + IsMemoryOwner = false; + } + /// - /// Create a N-dimensional Tensor from the given span + /// Create a new Tensor from the given unmanaged memory pointer (which must be allocated, fixed or pinned by the caller) + /// Note: the caller is responsible for freeing the memory. Calling Dispose on this object will dispose the TensorFlow tensor + /// but not the memory itself! /// - public Tensor(Span<#1> data, long[] shape, TF_DataType? dType = null) + /// Pointer to unmanaged, fixed or pinned memory which the caller owns + /// Tensor shape + /// TF data type + /// Size of the tensor in memory + public Tensor(IntPtr ptr, long[] shape, TF_DataType dType, int num_bytes) { - _handle = CreateTensorWithoutCopying<#1>(dType ?? dtypes.as_dtype(typeof(#1)), shape, data); + _handle = TF_NewTensor(dType, dims: shape, num_dims: shape.Length, data: ptr, len: (UIntPtr)num_bytes, deallocator: _nothingDeallocator, ref _deallocatorArgs); + IsMemoryOwner = false; } +#if _REGEN + %types=["sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double", "Complex"] + %foreach types% + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(#1[] data, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(#1)), new long[]{data.Length}, data, Marshal.SizeOf<#1>()); + IsMemoryOwner=true; } /// @@ -78,6 +98,7 @@ namespace Tensorflow public Tensor(#1[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(#1)), shape, data, Marshal.SizeOf<#1>()); + IsMemoryOwner=true; } /// @@ -88,28 +109,19 @@ namespace Tensorflow var v = (#1*)Marshal.AllocHGlobal(sizeof(#1)); *v = value; _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(#1)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(#1), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } % #else - - - - - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(sbyte)), shape, data); - } + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(sbyte[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(sbyte)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(sbyte)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -118,6 +130,7 @@ namespace Tensorflow public Tensor(sbyte[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(sbyte)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -127,23 +140,17 @@ namespace Tensorflow { var v = (sbyte*)Marshal.AllocHGlobal(sizeof(sbyte)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(sbyte)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(sbyte), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(byte)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(sbyte)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(sbyte), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(byte[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(byte)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(byte)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -152,6 +159,7 @@ namespace Tensorflow public Tensor(byte[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(byte)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -161,23 +169,17 @@ namespace Tensorflow { var v = (byte*)Marshal.AllocHGlobal(sizeof(byte)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(byte)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(byte), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(short)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(byte)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(byte), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(short[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(short)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(short)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -186,6 +188,7 @@ namespace Tensorflow public Tensor(short[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(short)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -195,23 +198,17 @@ namespace Tensorflow { var v = (short*)Marshal.AllocHGlobal(sizeof(short)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(short)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(short), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ushort)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(short)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(short), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(ushort[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ushort)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ushort)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -220,6 +217,7 @@ namespace Tensorflow public Tensor(ushort[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ushort)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -229,23 +227,17 @@ namespace Tensorflow { var v = (ushort*)Marshal.AllocHGlobal(sizeof(ushort)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(ushort)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(ushort), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(int)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(ushort)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(ushort), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(int[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(int)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(int)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -254,6 +246,7 @@ namespace Tensorflow public Tensor(int[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(int)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -263,23 +256,17 @@ namespace Tensorflow { var v = (int*)Marshal.AllocHGlobal(sizeof(int)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(int)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(int), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(uint)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(int)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(int), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(uint[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(uint)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(uint)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -288,6 +275,7 @@ namespace Tensorflow public Tensor(uint[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(uint)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -297,23 +285,17 @@ namespace Tensorflow { var v = (uint*)Marshal.AllocHGlobal(sizeof(uint)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(uint)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(uint), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(long)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(uint)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(uint), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(long[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(long)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(long)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -322,6 +304,7 @@ namespace Tensorflow public Tensor(long[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(long)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -331,23 +314,17 @@ namespace Tensorflow { var v = (long*)Marshal.AllocHGlobal(sizeof(long)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(long)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(long), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ulong)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(long)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(long), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(ulong[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ulong)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ulong)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -356,6 +333,7 @@ namespace Tensorflow public Tensor(ulong[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ulong)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -365,23 +343,17 @@ namespace Tensorflow { var v = (ulong*)Marshal.AllocHGlobal(sizeof(ulong)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(ulong)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(ulong), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(float)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(ulong)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(ulong), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(float[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(float)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(float)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -390,6 +362,7 @@ namespace Tensorflow public Tensor(float[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(float)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -399,23 +372,17 @@ namespace Tensorflow { var v = (float*)Marshal.AllocHGlobal(sizeof(float)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(float)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(float), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(double)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(float)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(float), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(double[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(double)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(double)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -424,6 +391,7 @@ namespace Tensorflow public Tensor(double[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(double)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -433,23 +401,17 @@ namespace Tensorflow { var v = (double*)Marshal.AllocHGlobal(sizeof(double)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(double)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(double), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); - } - - /// - /// Create a N-dimensional Tensor from the given span - /// - public Tensor(Span data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(Complex)), shape, data); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(double)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(double), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } - + /// /// Create a 1d Tensor from the given linear array and shape /// public Tensor(Complex[] data, TF_DataType? dType = null) { - _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(Complex)), new long[] { data.Length }, data, Marshal.SizeOf()); + _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(Complex)), new long[]{data.Length}, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -458,6 +420,7 @@ namespace Tensorflow public Tensor(Complex[] data, long[] shape, TF_DataType? dType = null) { _handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(Complex)), shape, data, Marshal.SizeOf()); + IsMemoryOwner=true; } /// @@ -467,7 +430,8 @@ namespace Tensorflow { var v = (Complex*)Marshal.AllocHGlobal(sizeof(Complex)); *v = value; - _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(Complex)), dims: new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(Complex), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + _handle = TF_NewTensor(dType ?? dtypes.as_dtype(typeof(Complex)), dims:new long[0], num_dims: 0, data: (IntPtr)v, len: (UIntPtr)sizeof(Complex), deallocator: _hGlobalDeallocator, ref _deallocatorArgs); + IsMemoryOwner=true; } #endif @@ -488,12 +452,7 @@ namespace Tensorflow status.Check(true); } - public Tensor(NDArray nd, TF_DataType? tensorDType = null) - { - _handle = Allocate(nd, tensorDType: tensorDType); - } - - private unsafe IntPtr Allocate(NDArray nd, TF_DataType? tensorDType = null) + public unsafe Tensor(NDArray nd, TF_DataType? tensorDType = null) { if (tensorDType == TF_DataType.TF_STRING && nd.dtype.Name == "Byte") { @@ -507,9 +466,16 @@ namespace Tensorflow c_api.TF_StringEncode(src, (UIntPtr)buffer.Length, (sbyte*)(tensor + sizeof(Int64)), size, status); status.Check(true); - return handle; + _handle=handle; + IsMemoryOwner = false; + return; } + _handle = Allocate(nd, tensorDType: tensorDType); + IsMemoryOwner = true; + } + private unsafe IntPtr Allocate(NDArray nd, TF_DataType? tensorDType = null) + { IntPtr dotHandle = IntPtr.Zero; int buffersize = 0; @@ -569,9 +535,9 @@ namespace Tensorflow _value_index = value_index; _dtype = dtype; _id = ops.uid(); - } - - + } + + /// /// Creates a new tensor from the given array without copying memory. The array is pinned down and the pointer passed on. /// @@ -633,31 +599,6 @@ namespace Tensorflow return TF_NewTensor(dt, shape, shape.Length, gcHandle.AddrOfPinnedObject() + start * element_size, (UIntPtr)(count * element_size), _gcHandleDeallocator, ref _deallocatorArgs); } - /// - /// Creates a new tensor from a subsection of the given array without copying memory. The array is pinned down and the pointer passed on. - /// - /// Represents the tensor shape. - /// The linear array of data, the data must fit in the tensor with the specified dimensions. - /// - /// Use the FromBuffer method to create a tensor that has the specified dimensions - /// and is initialized with data from the data array. The data is copied starting - /// at the start offset, for count bytes and is laid out into the tensor following the - /// specified dimensions. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected IntPtr CreateTensorWithoutCopying(TF_DataType dt, long[] shape, Span data) - { - var element_size = Marshal.SizeOf(); - var count = data.Length; - // get a handle to the pinned array which we will pass on to the tensor computation engine to use - var gcHandle = GCHandle.Alloc(data.GetPinnableReference(), GCHandleType.Pinned); - _deallocatorArgs = new DeallocatorArgs() { gc_handle = GCHandle.ToIntPtr(gcHandle) }; - if (shape == null || shape.Length == 0) - return TF_NewTensor(dt, new long[0], 0, gcHandle.AddrOfPinnedObject(), (UIntPtr)(count * element_size), _gcHandleDeallocator, ref _deallocatorArgs); - else - return TF_NewTensor(dt, shape, shape.Length, gcHandle.AddrOfPinnedObject(), (UIntPtr)(count * element_size), _gcHandleDeallocator, ref _deallocatorArgs); - } - [MonoPInvokeCallback(typeof(Deallocator))] internal static void FreeHGlobalMemory(IntPtr dataPtr, IntPtr len, ref DeallocatorArgs args) { @@ -676,6 +617,13 @@ namespace Tensorflow GCHandle.FromIntPtr(args.gc_handle).Free(); args.deallocator_called = true; } + + [MonoPInvokeCallback(typeof(Deallocator))] + internal static void FreeNothing(IntPtr dataPtr, IntPtr len, ref DeallocatorArgs args) + { + args.deallocator_called = true; + } + } /// @@ -697,4 +645,5 @@ namespace Tensorflow /// T. public MonoPInvokeCallbackAttribute(Type t) { } } + } diff --git a/src/TensorFlowNet.Benchmarks/Program.cs b/src/TensorFlowNet.Benchmarks/Program.cs index 4ba08cf1..e17a1d68 100644 --- a/src/TensorFlowNet.Benchmarks/Program.cs +++ b/src/TensorFlowNet.Benchmarks/Program.cs @@ -3,15 +3,10 @@ using System.Reflection; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Running; -namespace TensorFlowNet.Benchmark +namespace TensorFlowBenchmark { class Program { - /// - /// dotnet NumSharp.Benchmark.dll (Benchmark Class Name) - /// dotnet NumSharp.Benchmark.dll nparange - /// - /// static void Main(string[] args) { #if DEBUG @@ -24,7 +19,7 @@ namespace TensorFlowNet.Benchmark { for (int i = 0; i < args.Length; i++) { - string name = $"TensorFlowNet.Benchmark.{args[i]}"; + string name = $"TensorFlowBenchmark.{args[i]}"; var type = Type.GetType(name); BenchmarkRunner.Run(type, config); } diff --git a/src/TensorFlowNet.Benchmarks/TensorBenchmark.cs b/src/TensorFlowNet.Benchmarks/TensorBenchmark.cs index c90c35c2..3a0eeb65 100644 --- a/src/TensorFlowNet.Benchmarks/TensorBenchmark.cs +++ b/src/TensorFlowNet.Benchmarks/TensorBenchmark.cs @@ -1,11 +1,9 @@ using System; -using System.Linq; using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Engines; using NumSharp; using Tensorflow; -namespace TensorFlowNet.Benchmark +namespace TensorFlowBenchmark { [SimpleJob(launchCount: 1, warmupCount: 2, targetCount: 10)] [MinColumn, MaxColumn, MeanColumn, MedianColumn] @@ -33,15 +31,16 @@ namespace TensorFlowNet.Benchmark } [Benchmark] - public void TensorFromSpan() + public unsafe void TensorFromFixedPtr() { var g = new Graph(); - var span = new Span(data); for (int i = 0; i < 100; i++) { - using (var tensor = new Tensor(span, new long[] { data.Length })) + fixed (double* ptr = &data[0]) { - + using (var t = new Tensor((IntPtr)ptr, new long[] { data.Length }, tf.float64, 8 * data.Length)) + { + } } } } diff --git a/src/TensorFlowNet.Benchmarks/TensorFlowBenchmark.csproj b/src/TensorFlowNet.Benchmarks/TensorFlowBenchmark.csproj new file mode 100644 index 00000000..04680df3 --- /dev/null +++ b/src/TensorFlowNet.Benchmarks/TensorFlowBenchmark.csproj @@ -0,0 +1,31 @@ + + + + Exe + netcoreapp2.2 + true + TensorFlowBenchmark + TensorFlowBenchmark + + + + true + + + + true + + + + + + + + + + + + + + + diff --git a/src/TensorFlowNet.Benchmarks/TensorFlowNet.Benchmark.csproj b/src/TensorFlowNet.Benchmarks/TensorFlowNet.Benchmark.csproj deleted file mode 100644 index a0af6db4..00000000 --- a/src/TensorFlowNet.Benchmarks/TensorFlowNet.Benchmark.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - Exe - netcoreapp2.2 - - - - - - - - - - - - - - - diff --git a/test/TensorFlowNET.UnitTest/TensorTest.cs b/test/TensorFlowNET.UnitTest/TensorTest.cs index eea13e08..1713772e 100644 --- a/test/TensorFlowNET.UnitTest/TensorTest.cs +++ b/test/TensorFlowNET.UnitTest/TensorTest.cs @@ -53,14 +53,27 @@ namespace TensorFlowNET.UnitTest } [TestMethod] - public void TensorFromSpan() - { - var array = new int[1000]; - var span = new Span(array, 100, 500); - using (var t = new Tensor(span, new long[] { span.Length })) + public unsafe void TensorFromFixed() + { + var array = new float[1000]; + var span = new Span(array, 100, 500); + fixed (float* ptr=&MemoryMarshal.GetReference(span)) + { + using (var t = new Tensor((IntPtr)ptr, new long[] {span.Length}, tf.float32, 4*span.Length)) + { + Assert.IsFalse(t.IsDisposed); + Assert.IsFalse(t.IsMemoryOwner); + Assert.AreEqual(2000, (int) t.bytesize); + } + } + fixed (float* ptr = &array[0]) { - Assert.IsFalse(t.IsDisposed); - Assert.AreEqual(2000, (int)t.bytesize); + using (var t = new Tensor((IntPtr)ptr, new long[] { array.Length }, tf.float32, 4 * array.Length)) + { + Assert.IsFalse(t.IsDisposed); + Assert.IsFalse(t.IsMemoryOwner); + Assert.AreEqual(4000, (int)t.bytesize); + } } }