From 2192f4d875935d2e9d31096a9c17e16fc0e09fec Mon Sep 17 00:00:00 2001 From: Oceania2018 Date: Sat, 10 Jul 2021 10:30:22 -0500 Subject: [PATCH] fix placeholder feeds value issue. --- src/TensorFlowNET.Console/MemoryMonitor.cs | 1 + src/TensorFlowNET.Core/Binding.Util.cs | 35 ++ src/TensorFlowNET.Core/Numpy/NDArray.cs | 3 +- .../Operations/image_ops_impl.cs | 2 +- .../Sessions/BaseSession.cs | 27 +- .../Tensors/Tensor.Creation.cs | 506 ++---------------- .../Tensors/TensorConverter.cs | 2 +- .../Tensors/c_api.tensor.cs | 9 + src/TensorFlowNET.Core/Tensors/constant_op.cs | 8 +- src/TensorFlowNET.Core/Tensors/dtypes.cs | 3 + src/TensorFlowNET.Core/Tensors/tensor_util.cs | 41 +- .../Gradients/GradientsTest.cs | 2 +- 12 files changed, 132 insertions(+), 507 deletions(-) diff --git a/src/TensorFlowNET.Console/MemoryMonitor.cs b/src/TensorFlowNET.Console/MemoryMonitor.cs index 8916cac6..e2964b01 100644 --- a/src/TensorFlowNET.Console/MemoryMonitor.cs +++ b/src/TensorFlowNET.Console/MemoryMonitor.cs @@ -15,6 +15,7 @@ namespace Tensorflow while (true) { var ones = np.ones((128, 128)); + Thread.Sleep(1); } TensorShape shape = (1, 32, 32, 3); diff --git a/src/TensorFlowNET.Core/Binding.Util.cs b/src/TensorFlowNET.Core/Binding.Util.cs index e6069023..018c171f 100644 --- a/src/TensorFlowNET.Core/Binding.Util.cs +++ b/src/TensorFlowNET.Core/Binding.Util.cs @@ -505,5 +505,40 @@ namespace Tensorflow return defaultValue; } + + public static Shape GetShape(this object data) + { + if (!data.GetType().IsArray) + return Shape.Scalar; + + switch (data) + { + case Array array: + var dims = range(array.Rank).Select(x => (long)array.GetLength(x)).ToArray(); + return new Shape(dims); + default: + throw new NotImplementedException(""); + } + } + + public static unsafe byte[] ToByteArray(Array array) + { + /*var size = array.GetShape().size; + byte[]? bytes = null; + switch (array) + { + case float[] arr: + var len = new byte[size * sizeof(float)]; + fixed (void* addr = &arr[0]) + System.Buffer.MemoryCopy(addr, dst, bytesize, bytesize); + tensor_proto.TensorContent = Google.Protobuf.ByteString.CopyFrom(array.ToArray()); + break; + default: + throw new NotImplementedException(""); + } + + return bytes;*/ + throw new NotImplementedException(""); + } } } diff --git a/src/TensorFlowNET.Core/Numpy/NDArray.cs b/src/TensorFlowNET.Core/Numpy/NDArray.cs index 38123d7a..0a0d53fb 100644 --- a/src/TensorFlowNET.Core/Numpy/NDArray.cs +++ b/src/TensorFlowNET.Core/Numpy/NDArray.cs @@ -14,7 +14,8 @@ namespace Tensorflow.NumPy public ulong dtypesize => _tensor.itemsize; public int ndim => _tensor.NDims; public long[] dims => _tensor.dims.Select(x => Convert.ToInt64(x)).ToArray(); - public Shape shape => _tensor.shape; + public Shape shape => _tensor.shape; + public IntPtr data => _tensor.TensorDataPointer; public NDArray(bool value) { diff --git a/src/TensorFlowNET.Core/Operations/image_ops_impl.cs b/src/TensorFlowNET.Core/Operations/image_ops_impl.cs index 60b9b25c..d319b3c9 100644 --- a/src/TensorFlowNET.Core/Operations/image_ops_impl.cs +++ b/src/TensorFlowNET.Core/Operations/image_ops_impl.cs @@ -923,7 +923,7 @@ new_height, new_width"); int p_height = (int)max_(0, math_ops.cast(f_padding_height, dtype: dtypes.int32)); int p_width = (int)max_(0, math_ops.cast(f_padding_width, dtype: dtypes.int32)); - var resized = resize_fn(image, new Tensor(new[] { resized_height, resized_width })); + var resized = resize_fn(image, array_ops.concat(new[] { resized_height, resized_width }, 0)); var padded = pad_to_bounding_box(resized, p_height, p_width, target_height, target_width); diff --git a/src/TensorFlowNET.Core/Sessions/BaseSession.cs b/src/TensorFlowNET.Core/Sessions/BaseSession.cs index 33f2a705..b7403c56 100644 --- a/src/TensorFlowNET.Core/Sessions/BaseSession.cs +++ b/src/TensorFlowNET.Core/Sessions/BaseSession.cs @@ -176,14 +176,35 @@ namespace Tensorflow var tensor = new Tensor(v); if (tensor.dtype != key.dtype) throw new ValueError($"Tensor {v} does not match the expected dtype {key.dtype}, actual dtype: {tensor.dtype}"); - feeds[i++] = new KeyValuePair(key._as_tf_output(), tensor); break; - default: - feeds[i++] = new KeyValuePair(key._as_tf_output(), constant_op.constant(x.Value)); + case bool v: + feeds[i++] = new KeyValuePair(key._as_tf_output(), new Tensor(v)); + break; + case byte v: + feeds[i++] = new KeyValuePair(key._as_tf_output(), new Tensor(v)); + break; + case int v: + feeds[i++] = new KeyValuePair(key._as_tf_output(), new Tensor(v)); + break; + case long v: + feeds[i++] = new KeyValuePair(key._as_tf_output(), new Tensor(v)); break; + case float v: + feeds[i++] = new KeyValuePair(key._as_tf_output(), new Tensor(v)); + break; + case double v: + feeds[i++] = new KeyValuePair(key._as_tf_output(), new Tensor(v)); + break; + case Array v: + feeds[i++] = new KeyValuePair(key._as_tf_output(), new Tensor(v, v.GetShape())); + break; + default: + throw new NotImplementedException(""); } } + else + throw new NotImplementedException(""); } var fetches = fetch_list.Select(x => x._as_tf_output()).ToArray(); diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs index 790b4fff..dda4a291 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs @@ -22,7 +22,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using static Tensorflow.Binding; using static Tensorflow.c_api; namespace Tensorflow @@ -65,11 +64,12 @@ namespace Tensorflow #endif } - internal Tensor(Array array, Shape shape) + internal Tensor(Array array, Shape? shape = null) => InitTensor(array, shape); - unsafe void InitTensor(Array array, Shape shape) + unsafe void InitTensor(Array array, Shape? shape = null) { + shape = shape ?? array.GetShape(); var dtype = array.GetType().GetElementType().as_tf_dtype(); var length = (ulong)(array.Length * dtype.get_datatype_size()); @@ -112,14 +112,6 @@ namespace Tensorflow } } - public Tensor(int value) - { - unsafe - { - _handle = TF_NewTensor(tf.int32, dims: null, num_dims: 0, data: &value, len: sizeof(int)); - } - } - /// /// 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 @@ -138,329 +130,36 @@ namespace Tensorflow } } - /// - /// 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! - /// - /// Pointer to unmanaged, fixed or pinned memory which the caller owns - /// Tensor shape - /// TF data type - /// Size of the tensor in memory - public unsafe Tensor(void* data_ptr, long[] shape, TF_DataType dType, int num_bytes) - { - _handle = TF_NewTensor(dType, dims: shape, num_dims: shape.Length, data: data_ptr, len: (ulong)num_bytes); - AllocationType = TF_TensorData(_handle).ToPointer() == data_ptr ? AllocationType.FromPointer : AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(sbyte[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(sbyte)), new long[] { data.Length }, data, sizeof(sbyte)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(sbyte[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(sbyte)), shape, data, sizeof(sbyte)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(sbyte value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(sbyte)), dims: new long[0], num_dims: 0, len: sizeof(sbyte)); - *(sbyte*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(bool[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(bool)), new long[] { data.Length }, data, sizeof(bool)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(bool[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(bool)), shape, data, sizeof(bool)); - } - - internal Tensor(float[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(bool)), shape, data, sizeof(bool)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(bool value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(bool)), dims: new long[0], num_dims: 0, len: sizeof(bool)); - *(bool*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(byte[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(byte)), new long[] { data.Length }, data, sizeof(byte)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(byte[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(byte)), shape, data, sizeof(byte)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(byte value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(byte)), dims: new long[0], num_dims: 0, len: sizeof(byte)); - *(byte*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(short[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(short)), new long[] { data.Length }, data, sizeof(short)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(short[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(short)), shape, data, sizeof(short)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(short value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(short)), dims: new long[0], num_dims: 0, len: sizeof(short)); - *(short*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(ushort[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(ushort)), new long[] { data.Length }, data, sizeof(ushort)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(ushort[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(ushort)), shape, data, sizeof(ushort)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(ushort value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(ushort)), dims: new long[0], num_dims: 0, len: sizeof(ushort)); - *(ushort*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(int[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(int)), new long[] { data.Length }, data, sizeof(int)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(int[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(int)), shape, data, sizeof(int)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(int value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(int)), dims: new long[0], num_dims: 0, len: sizeof(int)); - *(int*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(uint[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(uint)), new long[] { data.Length }, data, sizeof(uint)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(uint[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(uint)), shape, data, sizeof(uint)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(uint value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(uint)), dims: new long[0], num_dims: 0, len: sizeof(uint)); - *(uint*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(long[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(long)), new long[] { data.Length }, data, sizeof(long)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(long[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(long)), shape, data, sizeof(long)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(long value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(long)), dims: new long[0], num_dims: 0, len: sizeof(long)); - *(long*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(ulong[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(ulong)), new long[] { data.Length }, data, sizeof(ulong)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(ulong[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(ulong)), shape, data, sizeof(ulong)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(ulong value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(ulong)), dims: new long[0], num_dims: 0, len: sizeof(ulong)); - *(ulong*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(float[] data) - { - _handle = CreateTensorFromArray(TF_DataType.TF_FLOAT, new long[] { data.Length }, data, sizeof(float)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(float value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(float)), dims: new long[0], num_dims: 0, len: sizeof(float)); - *(float*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(double[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(double)), new long[] { data.Length }, data, sizeof(double)); - } - - /// - /// Create a N-dimensional Tensor from the given array - /// - public Tensor(double[] data, long[] shape, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(double)), shape, data, sizeof(double)); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(double value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(double)), dims: new long[0], num_dims: 0, len: sizeof(double)); - *(double*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } - - /// - /// Create a 1d Tensor from the given linear array and shape - /// - public Tensor(Complex[] data, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_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, TF_DataType? dType = null) - { - _handle = CreateTensorFromArray(dType ?? dtypes.as_tf_dtype(typeof(Complex)), shape, data, Marshal.SizeOf()); - } - - /// - /// Create a scalar Tensor from the given value - /// - public unsafe Tensor(Complex value, TF_DataType? dType = null) - { - _handle = TF_AllocateTensor(dType ?? dtypes.as_tf_dtype(typeof(Complex)), dims: new long[0], num_dims: 0, len: (ulong)sizeof(Complex)); - *(Complex*)TF_TensorData(_handle) = value; - AllocationType = AllocationType.Tensorflow; - } + public unsafe Tensor(NDArray nd) + => _handle = TF_NewTensor(nd.shape, nd.dtype.as_tf_dtype(), nd.data.ToPointer(), nd.size * nd.dtypesize); + + #region scala + public Tensor(bool value) => _handle = TF_NewTensor(value); + public Tensor(byte value) => _handle = TF_NewTensor(value); + public Tensor(sbyte value) => _handle = TF_NewTensor(value); + public Tensor(short value) => _handle = TF_NewTensor(value); + public Tensor(int value) => _handle = TF_NewTensor(value); + public Tensor(uint value) => _handle = TF_NewTensor(value); + public Tensor(long value) => _handle = TF_NewTensor(value); + public Tensor(ulong value) => _handle = TF_NewTensor(value); + public Tensor(float value) => _handle = TF_NewTensor(value); + public Tensor(double value) => _handle = TF_NewTensor(value); + #endregion + + #region 1d array + public Tensor(bool[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(sbyte[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(byte[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(short[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(ushort[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(int[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(uint[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(long[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(ulong[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(float[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(double[] data, Shape? shape = null) => InitTensor(data, shape); + public Tensor(Complex[] data, Shape? shape = null) => InitTensor(data, shape); + #endregion /// /// Create a string Tensor from the given string @@ -481,77 +180,6 @@ namespace Tensorflow #endif } - public unsafe Tensor(NDArray nd, TF_DataType? tensorDType = null) - { - if (tensorDType == null) - tensorDType = nd.dtype.as_tf_dtype(); - - // todo: handle nd of type "String" here too - /*if (tensorDType == TF_DataType.TF_STRING && nd.typecode == NPTypeCode.Byte) - { - if (nd.Unsafe.Storage.Shape.IsContiguous) - { - var bytesLength = (ulong)nd.size; - var size = bytesLength + 1; - var handle = TF_AllocateTensor(TF_DataType.TF_STRING, null, 0, size + 8); - AllocationType = AllocationType.Tensorflow; - - IntPtr tensor = c_api.TF_TensorData(handle); - Marshal.WriteInt64(tensor, 0); - - c_api.TF_StringEncode((byte*)nd.Unsafe.Address, bytesLength, (byte*)(tensor + sizeof(long)), size, tf.Status.Handle); - tf.Status.Check(true); - _handle = handle; - } - else - { - var buffer = nd.ToArray(); - var size = (ulong)buffer.Length + 1; - var handle = TF_AllocateTensor(TF_DataType.TF_STRING, null, 0, size + 8); - AllocationType = AllocationType.Tensorflow; - - IntPtr tensor = c_api.TF_TensorData(handle); - Marshal.WriteInt64(tensor, 0); - - fixed (byte* src = buffer) - c_api.TF_StringEncode(src, (ulong)buffer.Length, (byte*)(tensor + sizeof(Int64)), size, tf.Status.Handle); - - tf.Status.Check(true); - _handle = handle; - } - - return; - }*/ - - CreateTensorFromNDArray(nd, tensorDType); -#if TRACK_TENSOR_LIFE - print($"New Tensor 0x{_handle.ToString("x16")} {AllocationType} Data: 0x{TensorDataPointer.ToString("x16")}"); -#endif - } - - private unsafe void CreateTensorFromNDArray(NDArray nd, TF_DataType? given_dtype) - { - if (nd.dtype == NumpyDType.String) - throw new NotImplementedException("Support for NDArray of type string not implemented yet"); - - throw new NotImplementedException(""); - /*_handle = TF_NewTensor( - given_dtype ?? nd.dtype.as_tf_dtype(), - dims: nd.dims.Select(i => (long)i).ToArray(), - num_dims: nd.ndim, - data: nd.Address, - len: nd.size * nd.dtypesize); - - // if TF decided not to perform copy, hold reference for given NDArray. - if (TensorDataPointer == nd.Address) - { - AllocationType = AllocationType.FromPointer; - AllocationHandle = nd; - } - else - AllocationType = AllocationType.Tensorflow;*/ - } - public Tensor(Operation op, int value_index, TF_DataType dtype) { _op = op; @@ -559,73 +187,5 @@ namespace Tensorflow _override_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)] - [SuppressMessage("ReSharper", "LocalVariableHidesMember")] - protected IntPtr CreateTensorFromArray(TF_DataType dt, long[] shape, Array data, int element_size) - { - if (dt == TF_DataType.TF_STRING && data is byte[] buffer) - return StringTensor(new byte[][] { buffer }, TensorShape.Scalar); - return CreateTensorFromArray(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 CreateTensorFromArray(TF_DataType dt, long[] shape, Array data, int start, int count, int element_size) - { - if (start < 0 || start > data.Length - count) - throw new ArgumentException($"Array length {data.Length} does not match the given shape {new Shape(shape.ToArray())}"); - - // get a handle to the pinned array which we will pass on to the tensor computation engine to use - var gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned); - var pinnedAddr = gcHandle.AddrOfPinnedObject(); - - //call NewTensor - IntPtr handle; - if (shape == null || shape.Length == 0) - handle = TF_NewTensor(dt, new long[0], 0, pinnedAddr + start * element_size, (ulong)(count * element_size)); - else - handle = TF_NewTensor(dt, shape, shape.Length, pinnedAddr + start * element_size, (ulong)(count * element_size)); - - //Figure if TF decided to clone or not. - if (c_api.TF_TensorData(handle) == pinnedAddr) - { - AllocationType = AllocationType.GCHandle; - AllocationHandle = gcHandle; - } - else - { - AllocationType = AllocationType.Tensorflow; - gcHandle.Free(); - } - - return handle; - } } } \ No newline at end of file diff --git a/src/TensorFlowNET.Core/Tensors/TensorConverter.cs b/src/TensorFlowNET.Core/Tensors/TensorConverter.cs index 43ba4eb4..8521f8eb 100644 --- a/src/TensorFlowNET.Core/Tensors/TensorConverter.cs +++ b/src/TensorFlowNET.Core/Tensors/TensorConverter.cs @@ -64,7 +64,7 @@ namespace Tensorflow //is multidim or jagged, if so - use NDArrays constructor as it records shape. if (array.Rank != 1 || array.GetType().GetElementType().IsArray) - return new Tensor(new NDArray(array)); + return new Tensor(array, array.GetShape()); switch (arrtype.GetTypeCode()) { diff --git a/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs b/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs index fbf966e6..4347ace2 100644 --- a/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs +++ b/src/TensorFlowNET.Core/Tensors/c_api.tensor.cs @@ -112,6 +112,15 @@ namespace Tensorflow return handle; } + public static unsafe IntPtr TF_NewTensor(T value) + where T : unmanaged + { + var dtype = value.GetType().as_tf_dtype(); + var handle = TF_AllocateTensor(dtype, new long[0], 0, (ulong)dtype.get_datatype_size()); + *(T*)TF_TensorData(handle) = value; + return handle; + } + /// /// Return a new tensor that holds the bytes data[0,len-1] /// diff --git a/src/TensorFlowNET.Core/Tensors/constant_op.cs b/src/TensorFlowNET.Core/Tensors/constant_op.cs index 1dc1a493..e7fdabf0 100644 --- a/src/TensorFlowNET.Core/Tensors/constant_op.cs +++ b/src/TensorFlowNET.Core/Tensors/constant_op.cs @@ -182,18 +182,12 @@ namespace Tensorflow case double val: return new EagerTensor(new[] { val }, Shape.Scalar); case Array val: - return new EagerTensor(val, GetArrayDims(val)); + return new EagerTensor(val, val.GetShape()); default: throw new NotImplementedException($"convert_to_eager_tensor {value.GetType()}"); } } - static Shape GetArrayDims(Array array) - { - var dims = range(array.Rank).Select(x => (long)array.GetLength(x)).ToArray(); - return new Shape(dims); - } - /// /// Function to convert TensorShape to Tensor. /// diff --git a/src/TensorFlowNET.Core/Tensors/dtypes.cs b/src/TensorFlowNET.Core/Tensors/dtypes.cs index 5d9c026e..1037eff2 100644 --- a/src/TensorFlowNET.Core/Tensors/dtypes.cs +++ b/src/TensorFlowNET.Core/Tensors/dtypes.cs @@ -128,6 +128,9 @@ namespace Tensorflow /// When has no equivalent public static TF_DataType as_tf_dtype(this Type type, TF_DataType? dtype = null) { + while (type.IsArray) + type = type.GetElementType(); + switch (type.Name) { case "Char": diff --git a/src/TensorFlowNET.Core/Tensors/tensor_util.cs b/src/TensorFlowNET.Core/Tensors/tensor_util.cs index 056a5f37..453606f4 100644 --- a/src/TensorFlowNET.Core/Tensors/tensor_util.cs +++ b/src/TensorFlowNET.Core/Tensors/tensor_util.cs @@ -27,13 +27,6 @@ namespace Tensorflow { public static class tensor_util { - public static TF_DataType[] _TENSOR_CONTENT_TYPES = - { - TF_DataType.TF_FLOAT, TF_DataType.TF_DOUBLE, TF_DataType.TF_INT32, TF_DataType.TF_UINT8, TF_DataType.TF_INT16, - TF_DataType.TF_INT8, TF_DataType.TF_INT64, TF_DataType.TF_QINT8, TF_DataType.TF_QUINT8, TF_DataType.TF_QINT16, - TF_DataType.TF_QUINT16, TF_DataType.TF_QINT32, TF_DataType.TF_UINT32, TF_DataType.TF_UINT64 - }; - /// /// Returns the constant value of the given tensor, if efficiently calculable. /// @@ -119,13 +112,12 @@ namespace Tensorflow var tensor_proto = new TensorProto { Dtype = dtype.as_datatype_enum(), + TensorShape = values.GetShape().as_shape_proto() }; // scalar if (!values.GetType().IsArray) { - tensor_proto.TensorShape = tensor_util.as_shape(new int[0]); - switch (values) { case bool val: @@ -157,7 +149,6 @@ namespace Tensorflow if (values is string str) { tensor_proto.StringVal.Add(Google.Protobuf.ByteString.CopyFromUtf8(str)); - tensor_proto.TensorShape = tensor_util.as_shape(new int[0]); } else if (values is string[] str_values) tensor_proto.StringVal.AddRange(str_values.Select(x => Google.Protobuf.ByteString.CopyFromUtf8(x))); @@ -166,18 +157,12 @@ namespace Tensorflow return tensor_proto; } - else + else if(values is Array array) { - tensor_proto.TensorShape = tensor_util.as_shape(shape); - // array - if (_TENSOR_CONTENT_TYPES.Contains(dtype)) - { - throw new NotImplementedException(""); - /*byte[] bytes = nparray.ToByteArray(); - tensor_proto.TensorContent = Google.Protobuf.ByteString.CopyFrom(bytes.ToArray()); - return tensor_proto;*/ - } + /*byte[] bytes = array.ToByteArray(); + tensor_proto.TensorContent = Google.Protobuf.ByteString.CopyFrom(bytes.ToArray()); + return tensor_proto;*/ } return tensor_proto; @@ -417,6 +402,22 @@ would not be rank 1.", tensor.op.get_attr("axis"))); return new TensorShape(shape.dims); } + public static TensorShapeProto as_shape_proto(this Shape tshape) + { + TensorShapeProto shape = new TensorShapeProto(); + + for (int i = 0; i < tshape.ndim; i++) + { + var dim = new TensorShapeProto.Types.Dim(); + dim.Size = tshape.dims[i]; + //dim.Name = $"dim_{i}"; + + shape.Dim.Add(dim); + } + + return shape; + } + public static TensorShape reshape(this Shape shape, int[] dims) { return new TensorShape(dims); diff --git a/test/TensorFlowNET.Native.UnitTest/Gradients/GradientsTest.cs b/test/TensorFlowNET.Native.UnitTest/Gradients/GradientsTest.cs index 7a9f909e..2cdd5019 100644 --- a/test/TensorFlowNET.Native.UnitTest/Gradients/GradientsTest.cs +++ b/test/TensorFlowNET.Native.UnitTest/Gradients/GradientsTest.cs @@ -226,7 +226,7 @@ namespace Tensorflow.Native.UnitTest //long[] dims = { 2, 2 }; //Tensor t = c_api.TF_AllocateTensor(TF_FLOAT, dims, 2, sizeof(float) * 4); //Marshal.Copy(values, 0, t, 4); - Tensor t = new Tensor(new NDArray(values).reshape((2, 2))); + Tensor t = np.array(values).reshape((2, 2)); return t; }