Browse Source

Tensor: added a constructor to create a Tensor from a fixed memory pointer that is owned by the caller

tags/v0.10
Meinrad Recheis 6 years ago
parent
commit
7cb17461a9
7 changed files with 179 additions and 212 deletions
  1. +3
    -3
      TensorFlow.NET.sln
  2. +117
    -168
      src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs
  3. +2
    -7
      src/TensorFlowNet.Benchmarks/Program.cs
  4. +6
    -7
      src/TensorFlowNet.Benchmarks/TensorBenchmark.cs
  5. +31
    -0
      src/TensorFlowNet.Benchmarks/TensorFlowBenchmark.csproj
  6. +0
    -20
      src/TensorFlowNet.Benchmarks/TensorFlowNet.Benchmark.csproj
  7. +20
    -7
      test/TensorFlowNET.UnitTest/TensorTest.cs

+ 3
- 3
TensorFlow.NET.sln View File

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


+ 117
- 168
src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs View File

@@ -38,6 +38,12 @@ namespace Tensorflow
/// </summary>
private bool _isPinnedArray => _deallocatorArgs.gc_handle != IntPtr.Zero;

/// <summary>
/// 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
/// </summary>
public bool IsMemoryOwner { get; private set; }

/// <summary>
/// This holds values that are used by the unmanaged deallocator callback
/// </summary>
@@ -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;

/// <summary>
/// Create a Tensor object from an existing TF handle
/// </summary>
/// <param name="handle"></param>
public Tensor(IntPtr handle)
{
_handle = handle;
}
#if _REGEN
%types=["sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double", "Complex"]
%foreach types%
IsMemoryOwner = false;
}

/// <summary>
/// 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!
/// </summary>
public Tensor(Span<#1> data, long[] shape, TF_DataType? dType = null)
/// <param name="ptr">Pointer to unmanaged, fixed or pinned memory which the caller owns</param>
/// <param name="shape">Tensor shape</param>
/// <param name="dType">TF data type</param>
/// <param name="num_bytes">Size of the tensor in memory</param>
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%
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
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;
}

/// <summary>
@@ -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;
}

/// <summary>
@@ -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
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<sbyte> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<sbyte>(dType ?? dtypes.as_dtype(typeof(sbyte)), shape, data);
}

/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(sbyte[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(sbyte)), new long[] { data.Length }, data, Marshal.SizeOf<sbyte>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(sbyte)), new long[]{data.Length}, data, Marshal.SizeOf<sbyte>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<sbyte>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<byte> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<byte>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(byte[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(byte)), new long[] { data.Length }, data, Marshal.SizeOf<byte>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(byte)), new long[]{data.Length}, data, Marshal.SizeOf<byte>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<byte>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<short> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<short>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(short[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(short)), new long[] { data.Length }, data, Marshal.SizeOf<short>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(short)), new long[]{data.Length}, data, Marshal.SizeOf<short>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<short>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<ushort> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<ushort>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(ushort[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ushort)), new long[] { data.Length }, data, Marshal.SizeOf<ushort>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ushort)), new long[]{data.Length}, data, Marshal.SizeOf<ushort>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<ushort>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<int> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<int>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(int[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(int)), new long[] { data.Length }, data, Marshal.SizeOf<int>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(int)), new long[]{data.Length}, data, Marshal.SizeOf<int>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<int>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<uint> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<uint>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(uint[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(uint)), new long[] { data.Length }, data, Marshal.SizeOf<uint>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(uint)), new long[]{data.Length}, data, Marshal.SizeOf<uint>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<uint>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<long> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<long>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(long[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(long)), new long[] { data.Length }, data, Marshal.SizeOf<long>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(long)), new long[]{data.Length}, data, Marshal.SizeOf<long>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<long>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<ulong> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<ulong>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(ulong[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ulong)), new long[] { data.Length }, data, Marshal.SizeOf<ulong>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(ulong)), new long[]{data.Length}, data, Marshal.SizeOf<ulong>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<ulong>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<float> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<float>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(float[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(float)), new long[] { data.Length }, data, Marshal.SizeOf<float>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(float)), new long[]{data.Length}, data, Marshal.SizeOf<float>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<float>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<double> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<double>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(double[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(double)), new long[] { data.Length }, data, Marshal.SizeOf<double>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(double)), new long[]{data.Length}, data, Marshal.SizeOf<double>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<double>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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);
}
/// <summary>
/// Create a N-dimensional Tensor from the given span
/// </summary>
public Tensor(Span<Complex> data, long[] shape, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying<Complex>(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;
}
/// <summary>
/// Create a 1d Tensor from the given linear array and shape
/// </summary>
public Tensor(Complex[] data, TF_DataType? dType = null)
{
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(Complex)), new long[] { data.Length }, data, Marshal.SizeOf<Complex>());
_handle = CreateTensorWithoutCopying(dType ?? dtypes.as_dtype(typeof(Complex)), new long[]{data.Length}, data, Marshal.SizeOf<Complex>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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<Complex>());
IsMemoryOwner=true;
}

/// <summary>
@@ -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();
}
}
/// <summary>
/// Creates a new tensor from the given array without copying memory. The array is pinned down and the pointer passed on.
/// </summary>
@@ -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);
}

/// <summary>
/// Creates a new tensor from a subsection of the given array without copying memory. The array is pinned down and the pointer passed on.
/// </summary>
/// <param name="shape">Represents the tensor shape.</param>
/// <param name="data">The linear array of data, the data must fit in the tensor with the specified dimensions.</param>
/// <remarks>
/// 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.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected IntPtr CreateTensorWithoutCopying<T>(TF_DataType dt, long[] shape, Span<T> data)
{
var element_size = Marshal.SizeOf<T>();
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;
}
}

/// <summary>
@@ -697,4 +645,5 @@ namespace Tensorflow
/// <param name="t">T.</param>
public MonoPInvokeCallbackAttribute(Type t) { }
}

}

+ 2
- 7
src/TensorFlowNet.Benchmarks/Program.cs View File

@@ -3,15 +3,10 @@ using System.Reflection;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
namespace TensorFlowNet.Benchmark
namespace TensorFlowBenchmark
{
class Program
{
/// <summary>
/// dotnet NumSharp.Benchmark.dll (Benchmark Class Name)
/// dotnet NumSharp.Benchmark.dll nparange
/// </summary>
/// <param name="args"></param>
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);
}


+ 6
- 7
src/TensorFlowNet.Benchmarks/TensorBenchmark.cs View File

@@ -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<double>(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))
{
}
}
}
}


+ 31
- 0
src/TensorFlowNet.Benchmarks/TensorFlowBenchmark.csproj View File

@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<NoWin32Manifest>true</NoWin32Manifest>
<AssemblyName>TensorFlowBenchmark</AssemblyName>
<RootNamespace>TensorFlowBenchmark</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<None Remove="tensorflow.dll" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TensorFlowNET.Core\TensorFlowNET.Core.csproj" />
</ItemGroup>
</Project>

+ 0
- 20
src/TensorFlowNet.Benchmarks/TensorFlowNet.Benchmark.csproj View File

@@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Remove="tensorflow.dll" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TensorFlowNET.Core\TensorFlowNET.Core.csproj" />
</ItemGroup>
</Project>

+ 20
- 7
test/TensorFlowNET.UnitTest/TensorTest.cs View File

@@ -53,14 +53,27 @@ namespace TensorFlowNET.UnitTest
}

[TestMethod]
public void TensorFromSpan()
{
var array = new int[1000];
var span = new Span<int>(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<float>(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);
}
}
}



Loading…
Cancel
Save