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);
+ }
}
}