diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs
index 81c8006b..b90c4e69 100644
--- a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs
+++ b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs
@@ -1,5 +1,7 @@
/*****************************************************************************
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved.
+
+ Portions of this file have been adapted from TensorFlowSharp, authored by Miguel de Icaza (miguel@microsoft.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,6 +20,8 @@ using NumSharp;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Numerics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using static Tensorflow.c_api;
@@ -36,39 +40,246 @@ namespace Tensorflow
_handle = handle;
}
- public Tensor(NDArray nd, TF_DataType? tensorDType = null)
+#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)
{
- _handle = Allocate(nd, tensorDType: tensorDType);
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(#1)), new long[]{data.Length}, data, Marshal.SizeOf<#1>());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(#1[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(#1)), shape, data, Marshal.SizeOf<#1>());
+ }
+
+ %
+#else
+
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(sbyte[] data)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(sbyte)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(sbyte[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(sbyte)), shape, data, Marshal.SizeOf());
+ }
+
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(byte[] data)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(byte)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(byte[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(byte)), shape, data, Marshal.SizeOf());
+ }
+
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(short[] data)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(short)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(short[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(short)), shape, data, Marshal.SizeOf());
+ }
+
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(ushort[] data)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(ushort)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(ushort[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(ushort)), shape, data, Marshal.SizeOf());
+ }
+
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(int[] data)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(int)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(int[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(int)), shape, data, Marshal.SizeOf());
+ }
+
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(uint[] data)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(uint)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(uint[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(uint)), shape, data, Marshal.SizeOf());
}
- public unsafe Tensor(byte[] buffer)
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(long[] data)
{
- var size = c_api.TF_StringEncodedSize((UIntPtr)buffer.Length);
- _handle = TF_AllocateTensor(TF_DataType.TF_STRING, IntPtr.Zero, 0, (UIntPtr)((ulong)size + 8));
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(long)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
- IntPtr tensor = c_api.TF_TensorData(_handle);
- Marshal.WriteInt64(tensor, 0);
- fixed (byte* src = &buffer[0])
- c_api.TF_StringEncode(src, (UIntPtr)buffer.Length, (sbyte*)(tensor + sizeof(Int64)), size, status);
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(long[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(long)), shape, data, Marshal.SizeOf());
+ }
+
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(ulong[] data)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(ulong)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
- status.Check(true);
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(ulong[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(ulong)), shape, data, Marshal.SizeOf());
}
- private IntPtr Allocate(NDArray nd, TF_DataType? tensorDType = null)
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(float[] data)
{
- if (tensorDType == TF_DataType.TF_STRING &&
- nd.dtype.Name == "Byte")
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(float)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(float[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(float)), shape, data, Marshal.SizeOf());
+ }
+
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(double[] data)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(double)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(double[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(double)), shape, data, Marshal.SizeOf());
+ }
+
+
+ ///
+ /// Create a 1d Tensor from the given linear array and shape
+ ///
+ public Tensor(Complex[] data)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(Complex)), new long[]{data.Length}, data, Marshal.SizeOf());
+ }
+
+ ///
+ /// Create a N-dimensional Tensor from the given array
+ ///
+ public Tensor(Complex[] data, long[] shape)
+ {
+ _handle = CreateTensorWithoutCopying(dtypes.as_dtype(typeof(Complex)), shape, data, Marshal.SizeOf());
+ }
+#endif
+
+ public Tensor(NDArray nd, TF_DataType? tensorDType = null)
+ {
+ _handle = Allocate(nd, tensorDType: tensorDType);
+ }
+
+ private unsafe IntPtr Allocate(NDArray nd, TF_DataType? tensorDType = null)
+ {
+ if (tensorDType == TF_DataType.TF_STRING && nd.dtype.Name == "Byte")
{
- return new Tensor(nd.Data());
+ var buffer=nd.Data();
+ var size = c_api.TF_StringEncodedSize((UIntPtr)buffer.Length);
+ var handle = TF_AllocateTensor(TF_DataType.TF_STRING, IntPtr.Zero, 0, (UIntPtr)((ulong)size + 8));
+
+ IntPtr tensor = c_api.TF_TensorData(handle);
+ Marshal.WriteInt64(tensor, 0);
+ fixed (byte* src = &buffer[0])
+ c_api.TF_StringEncode(src, (UIntPtr)buffer.Length, (sbyte*)(tensor + sizeof(Int64)), size, status);
+
+ status.Check(true);
+ return handle;
}
IntPtr dotHandle = IntPtr.Zero;
- ulong size = 0;
+ int buffersize = 0;
if (nd.dtype.Name != "String")
{
- dotHandle = Marshal.AllocHGlobal(nd.dtypesize * nd.size);
- size = (ulong)(nd.size * nd.dtypesize);
+ buffersize = (nd.size * nd.dtypesize);
+ dotHandle = Marshal.AllocHGlobal(buffersize);
}
var dataType = ToTFDataType(nd.dtype);
@@ -116,7 +327,7 @@ namespace Tensorflow
dims,
dims.Length,
dotHandle,
- (UIntPtr)size,
+ (UIntPtr)buffersize,
deallocator,
ref deallocator_called);
@@ -130,5 +341,59 @@ namespace Tensorflow
_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.
+ ///
+ /// Represents the tensor shape.
+ /// The linear array of data, the data must fit in the tensor with the specified dimensions.
+ /// The number of bytes in memory of a single array element
+ ///
+ /// 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, Array data, int element_size)
+ {
+ return CreateTensorWithoutCopying(dt, shape, data, 0, data.Length, element_size);
+ }
+
+ ///
+ /// 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.
+ /// The offset into the provided data array where the data resides.
+ /// The number of elements to copy from data.
+ /// The number of bytes in memory of a single array element
+ ///
+ /// 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, Array data, int start, int count, int element_size)
+ {
+ if (start < 0 || start > data.Length - count)
+ throw new ArgumentException("start + count > Array size");
+
+ // get a handle to the pinned array which we will pass on to the tensor computation engine to use
+ var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
+
+ // Free the original buffer and set flag
+ Deallocator deallocator = (IntPtr values, IntPtr len, ref bool closure) =>
+ {
+ dataHandle.Free();
+ closure = true;
+ };
+
+ if (shape == null)
+ return TF_NewTensor(dt, null, 0, dataHandle.AddrOfPinnedObject() + start * element_size, (UIntPtr)(count * element_size), deallocator, ref deallocator_called);
+ else
+ return TF_NewTensor(dt, shape, shape.Length, dataHandle.AddrOfPinnedObject() + start * element_size, (UIntPtr)(count * element_size), deallocator, ref deallocator_called);
+ }
}
}
diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.cs b/src/TensorFlowNET.Core/Tensors/Tensor.cs
index 786daa5c..cc54c667 100644
--- a/src/TensorFlowNET.Core/Tensors/Tensor.cs
+++ b/src/TensorFlowNET.Core/Tensors/Tensor.cs
@@ -31,7 +31,7 @@ namespace Tensorflow
///
public partial class Tensor : IDisposable, ITensorOrOperation
{
- private readonly IntPtr _handle;
+ private IntPtr _handle;
private int _id;
private Operation _op;
@@ -351,6 +351,7 @@ namespace Tensorflow
public void Dispose()
{
c_api.TF_DeleteTensor(_handle);
+ _handle = IntPtr.Zero;
status.Dispose();
}
diff --git a/src/TensorFlowNET.Core/Tensors/dtypes.cs b/src/TensorFlowNET.Core/Tensors/dtypes.cs
index ebe6e283..5000401a 100644
--- a/src/TensorFlowNET.Core/Tensors/dtypes.cs
+++ b/src/TensorFlowNET.Core/Tensors/dtypes.cs
@@ -52,32 +52,51 @@ namespace Tensorflow
}
}
+ // "sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double", "Complex"
public static TF_DataType as_dtype(Type type)
{
TF_DataType dtype = TF_DataType.DtInvalid;
-
+
switch (type.Name)
{
- case "Boolean":
- dtype = TF_DataType.TF_BOOL;
+ case "SByte":
+ dtype = TF_DataType.TF_INT8;
+ break;
+ case "Byte":
+ dtype = TF_DataType.TF_UINT8;
+ break;
+ case "Int16":
+ dtype = TF_DataType.TF_INT16;
+ break;
+ case "UInt16":
+ dtype = TF_DataType.TF_UINT16;
break;
case "Int32":
dtype = TF_DataType.TF_INT32;
break;
+ case "UInt32":
+ dtype = TF_DataType.TF_UINT32;
+ break;
case "Int64":
dtype = TF_DataType.TF_INT64;
break;
+ case "UInt64":
+ dtype = TF_DataType.TF_UINT64;
+ break;
case "Single":
dtype = TF_DataType.TF_FLOAT;
break;
case "Double":
dtype = TF_DataType.TF_DOUBLE;
break;
+ case "Complex":
+ dtype = TF_DataType.TF_COMPLEX128;
+ break;
case "String":
dtype = TF_DataType.TF_STRING;
break;
- case "Byte":
- dtype = TF_DataType.TF_STRING;
+ case "Boolean":
+ dtype = TF_DataType.TF_BOOL;
break;
default:
throw new Exception("as_dtype Not Implemented");