diff --git a/src/TensorFlowNET.Core/Data/MnistModelLoader.cs b/src/TensorFlowNET.Core/Data/MnistModelLoader.cs index 4625a7f8..0aaeb32a 100644 --- a/src/TensorFlowNET.Core/Data/MnistModelLoader.cs +++ b/src/TensorFlowNET.Core/Data/MnistModelLoader.cs @@ -146,7 +146,7 @@ namespace Tensorflow bytestream.Read(buf, 0, buf.Length); - var labels = np.frombuffer(buf, new Shape(num_items), np.uint8); + var labels = np.frombuffer(buf, new Shape(num_items), np.@byte); if (one_hot) return DenseToOneHot(labels, num_classes); diff --git a/src/TensorFlowNET.Core/Eager/EagerTensor.ToString.cs b/src/TensorFlowNET.Core/Eager/EagerTensor.ToString.cs index e503c3ca..ce3c983b 100644 --- a/src/TensorFlowNET.Core/Eager/EagerTensor.ToString.cs +++ b/src/TensorFlowNET.Core/Eager/EagerTensor.ToString.cs @@ -1,8 +1,15 @@ -namespace Tensorflow.Eager +using Tensorflow.NumPy; + +namespace Tensorflow.Eager { public partial class EagerTensor { public override string ToString() - => $"tf.Tensor: shape={shape}, dtype={dtype.as_numpy_name()}, numpy={tensor_util.to_numpy_string(this)}"; + { + var nd = new NDArray(this); + var str = NDArrayRender.ToString(nd); + return $"tf.Tensor: shape={shape}, dtype={dtype.as_numpy_name()}, numpy={str}"; + } + } } diff --git a/src/TensorFlowNET.Core/NumPy/NDArray.Index.cs b/src/TensorFlowNET.Core/NumPy/NDArray.Index.cs index 58cbb4ce..5e36c48c 100644 --- a/src/TensorFlowNET.Core/NumPy/NDArray.Index.cs +++ b/src/TensorFlowNET.Core/NumPy/NDArray.Index.cs @@ -134,8 +134,8 @@ namespace Tensorflow.NumPy return array; } - - NDArray GetData(int[] indices, int axis = 0) + + unsafe NDArray GetData(int[] indices, int axis = 0) { if (shape.IsScalar) return GetScalar(); @@ -148,19 +148,17 @@ namespace Tensorflow.NumPy var array = np.ndarray(dims, dtype: dtype); dims[0] = 1; - var bytesize = new Shape(dims).size * dtype.get_datatype_size(); + var len = new Shape(dims).size * dtype.get_datatype_size(); int dst_index = 0; - foreach (var index in indices) + foreach (var pos in indices) { - var src_offset = (ulong)ShapeHelper.GetOffset(shape, index); + var src_offset = (ulong)ShapeHelper.GetOffset(shape, pos); var dst_offset = (ulong)ShapeHelper.GetOffset(array.shape, dst_index++); - unsafe - { - var src = (byte*)data + src_offset * dtypesize; - var dst = (byte*)array.data.ToPointer() + dst_offset * dtypesize; - System.Buffer.MemoryCopy(src, dst, bytesize, bytesize); - } + + var src = (byte*)data + src_offset * dtypesize; + var dst = (byte*)array.data + dst_offset * dtypesize; + System.Buffer.MemoryCopy(src, dst, len, len); } return array; diff --git a/src/TensorFlowNET.Core/NumPy/NDArrayRender.cs b/src/TensorFlowNET.Core/NumPy/NDArrayRender.cs new file mode 100644 index 00000000..22b4d6ab --- /dev/null +++ b/src/TensorFlowNET.Core/NumPy/NDArrayRender.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; + +namespace Tensorflow.NumPy +{ + public class NDArrayRender + { + public static string ToString(NDArray array) + { + Shape shape = array.shape; + if (shape.IsScalar) + return Render(array); + + var s = new StringBuilder(); + s.Append("array("); + Build(s, array); + s.Append(")"); + return s.ToString(); + } + + static void Build(StringBuilder s, NDArray array) + { + var shape = array.shape; + + if (shape.Length == 1) + { + s.Append("["); + s.Append(Render(array)); + s.Append("]"); + return; + } + + var len = shape[0]; + s.Append("["); + + if (len <= 10) + { + for (int i = 0; i < len; i++) + { + Build(s, array[i]); + if (i < len - 1) + { + s.Append(", "); + s.AppendLine(); + } + } + } + else + { + for (int i = 0; i < 5; i++) + { + Build(s, array[i]); + if (i < len - 1) + { + s.Append(", "); + s.AppendLine(); + } + } + + s.Append(" ... "); + s.AppendLine(); + + for (int i = (int)len - 5; i < len; i++) + { + Build(s, array[i]); + if (i < len - 1) + { + s.Append(", "); + s.AppendLine(); + } + } + } + + s.Append("]"); + } + + static string Render(NDArray array) + { + if (array.buffer == IntPtr.Zero) + return ""; + + var dtype = array.dtype; + var shape = array.shape; + + if (dtype == TF_DataType.TF_STRING) + { + if (array.rank == 0) + return "'" + string.Join(string.Empty, array.StringBytes()[0] + .Take(25) + .Select(x => x < 32 || x > 127 ? "\\x" + x.ToString("x") : Convert.ToChar(x).ToString())) + "'"; + else + return $"['{string.Join("', '", array.StringData().Take(25))}']"; + } + else if (dtype == TF_DataType.TF_VARIANT) + { + return ""; + } + else if (dtype == TF_DataType.TF_RESOURCE) + { + return ""; + } + else + { + return dtype switch + { + TF_DataType.TF_BOOL => Render(array.ToArray(), array.shape), + TF_DataType.TF_INT8 => Render(array.ToArray(), array.shape), + TF_DataType.TF_INT32 => Render(array.ToArray(), array.shape), + TF_DataType.TF_INT64 => Render(array.ToArray(), array.shape), + TF_DataType.TF_FLOAT => Render(array.ToArray(), array.shape), + TF_DataType.TF_DOUBLE => Render(array.ToArray(), array.shape), + _ => Render(array.ToArray(), array.shape) + }; + } + } + + static string Render(T[] array, Shape shape) + { + if (array == null) + return ""; + + if (array.Length == 0) + return ""; + + if (shape.IsScalar) + return array[0].ToString(); + + var display = ""; + if (array.Length <= 10) + display += string.Join(", ", array); + else + display += string.Join(", ", array.Take(5)) + ", ..., " + string.Join(", ", array.Skip(array.Length - 5)); + return display; + } + } +} diff --git a/src/TensorFlowNET.Core/Numpy/NDArray.cs b/src/TensorFlowNET.Core/Numpy/NDArray.cs index bbe8fda3..9455ddc8 100644 --- a/src/TensorFlowNET.Core/Numpy/NDArray.cs +++ b/src/TensorFlowNET.Core/Numpy/NDArray.cs @@ -46,6 +46,6 @@ namespace Tensorflow.NumPy public byte[] ToByteArray() => BufferToArray(); public static string[] AsStringArray(NDArray arr) => throw new NotImplementedException(""); - public override string ToString() => tensor_util.to_numpy_string(this); + public override string ToString() => NDArrayRender.ToString(this); } } diff --git a/src/TensorFlowNET.Core/Operations/array_ops.cs b/src/TensorFlowNET.Core/Operations/array_ops.cs index 230eba3c..287bc37a 100644 --- a/src/TensorFlowNET.Core/Operations/array_ops.cs +++ b/src/TensorFlowNET.Core/Operations/array_ops.cs @@ -90,6 +90,9 @@ namespace Tensorflow case TF_DataType.TF_FLOAT: zeros = constant(0f); break; + case TF_DataType.TF_INT8: + zeros = constant((byte)0); + break; default: zeros = constant(0); break; diff --git a/src/TensorFlowNET.Core/Tensors/tensor_util.cs b/src/TensorFlowNET.Core/Tensors/tensor_util.cs index b86fa4fe..4fa4d773 100644 --- a/src/TensorFlowNET.Core/Tensors/tensor_util.cs +++ b/src/TensorFlowNET.Core/Tensors/tensor_util.cs @@ -470,246 +470,6 @@ would not be rank 1.", tensor.op.get_attr("axis"))); return ops.convert_to_tensor(shape, dtype: TF_DataType.TF_INT32, name: "shape"); } - public static string to_numpy_string(NDArray array) - { - Shape shape = array.shape; - if (shape.ndim == 0) - return array[0].ToString(); - - var s = new StringBuilder(); - s.Append("array("); - PrettyPrint(s, array); - s.Append(")"); - return s.ToString(); - } - - static void PrettyPrint(StringBuilder s, NDArray array) - { - var shape = array.shape; - - if (shape.Length == 1) - { - s.Append("["); - s.Append(Render(array)); - s.Append("]"); - return; - } - - var len = shape[0]; - s.Append("["); - - if (len <= 10) - { - for (int i = 0; i < len; i++) - { - PrettyPrint(s, array[i]); - if (i < len - 1) - { - s.Append(", "); - s.AppendLine(); - } - } - } - else - { - for (int i = 0; i < 5; i++) - { - PrettyPrint(s, array[i]); - if (i < len - 1) - { - s.Append(", "); - s.AppendLine(); - } - } - - s.Append(" ... "); - s.AppendLine(); - - for (int i = (int)len - 5; i < len; i++) - { - PrettyPrint(s, array[i]); - if (i < len - 1) - { - s.Append(", "); - s.AppendLine(); - } - } - } - - s.Append("]"); - } - - static string Render(NDArray tensor) - { - if (tensor.buffer == IntPtr.Zero) - return ""; - - var dtype = tensor.dtype; - var shape = tensor.shape; - - if (dtype == TF_DataType.TF_STRING) - { - if (tensor.rank == 0) - return "'" + string.Join(string.Empty, tensor.StringBytes()[0] - .Take(25) - .Select(x => x < 32 || x > 127 ? "\\x" + x.ToString("x") : Convert.ToChar(x).ToString())) + "'"; - else - return $"['{string.Join("', '", tensor.StringData().Take(25))}']"; - } - else if (dtype == TF_DataType.TF_VARIANT) - { - return ""; - } - else if (dtype == TF_DataType.TF_RESOURCE) - { - return ""; - } - else - { - return dtype switch - { - TF_DataType.TF_BOOL => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_INT8 => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_INT32 => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_INT64 => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_FLOAT => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_DOUBLE => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - _ => DisplayArrayAsString(tensor.ToArray(), tensor.shape) - }; - } - } - - public static string to_numpy_string(Tensor array) - { - Shape shape = array.shape; - if (shape.ndim == 0) - return array[0].ToString(); - - var s = new StringBuilder(); - s.Append("array("); - PrettyPrint(s, array); - s.Append(")"); - return s.ToString(); - } - - static string Render(Tensor tensor) - { - if (tensor.buffer == IntPtr.Zero) - return ""; - - var dtype = tensor.dtype; - var shape = tensor.shape; - - if (dtype == TF_DataType.TF_STRING) - { - if (tensor.rank == 0) - return "'" + string.Join(string.Empty, tensor.StringBytes()[0] - .Take(25) - .Select(x => x < 32 || x > 127 ? "\\x" + x.ToString("x") : Convert.ToChar(x).ToString())) + "'"; - else - return $"['{string.Join("', '", tensor.StringData().Take(25))}']"; - } - else if (dtype == TF_DataType.TF_VARIANT) - { - return ""; - } - else if (dtype == TF_DataType.TF_RESOURCE) - { - return ""; - } - else - { - return dtype switch - { - TF_DataType.TF_BOOL => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_INT8 => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_INT32 => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_INT64 => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_FLOAT => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - TF_DataType.TF_DOUBLE => DisplayArrayAsString(tensor.ToArray(), tensor.shape), - _ => DisplayArrayAsString(tensor.ToArray(), tensor.shape) - }; - } - } - - static string DisplayArrayAsString(T[] array, Shape shape) - { - if (array == null) - return ""; - - if (array.Length == 0) - return ""; - - if (shape.ndim == 0) - return array[0].ToString(); - - var display = ""; - if (array.Length <= 10) - display += string.Join(", ", array); - else - display += string.Join(", ", array.Take(5)) + ", ..., " + string.Join(", ", array.Skip(array.Length - 5)); - return display; - } - - static void PrettyPrint(StringBuilder s, Tensor array, bool flat = false) - { - var shape = array.shape; - - if (shape.Length == 1) - { - s.Append("["); - s.Append(Render(array)); - s.Append("]"); - return; - } - - var len = shape[0]; - s.Append("["); - - if (len <= 10) - { - for (int i = 0; i < len; i++) - { - PrettyPrint(s, array[i], flat); - if (i < len - 1) - { - s.Append(", "); - if (!flat) - s.AppendLine(); - } - } - } - else - { - for (int i = 0; i < 5; i++) - { - PrettyPrint(s, array[i], flat); - if (i < len - 1) - { - s.Append(", "); - if (!flat) - s.AppendLine(); - } - } - - s.Append(" ... "); - s.AppendLine(); - - for (int i = (int)len - 5; i < len; i++) - { - PrettyPrint(s, array[i], flat); - if (i < len - 1) - { - s.Append(", "); - if (!flat) - s.AppendLine(); - } - } - } - - s.Append("]"); - } - public static ParsedSliceArgs ParseSlices(Slice[] slices) { var begin = new List(); diff --git a/src/TensorFlowNET.Core/Variables/BaseResourceVariable.cs b/src/TensorFlowNET.Core/Variables/BaseResourceVariable.cs index 9bebc652..46268e51 100644 --- a/src/TensorFlowNET.Core/Variables/BaseResourceVariable.cs +++ b/src/TensorFlowNET.Core/Variables/BaseResourceVariable.cs @@ -222,7 +222,7 @@ namespace Tensorflow public override string ToString() { if (tf.Context.executing_eagerly()) - return $"tf.Variable: '{Name}' shape={string.Join(",", shape)}, dtype={dtype.as_numpy_name()}, numpy={tensor_util.to_numpy_string(read_value())}"; + return $"tf.Variable: '{Name}' shape={string.Join(",", shape)}, dtype={dtype.as_numpy_name()}, numpy={read_value()}"; else return $"tf.Variable: '{Name}' shape={string.Join(",", shape)}, dtype={dtype.as_numpy_name()}"; } diff --git a/test/TensorFlowNET.UnitTest/Numpy/Array.Creation.Test.cs b/test/TensorFlowNET.UnitTest/Numpy/Array.Creation.Test.cs index 0e024fd1..aa0652f2 100644 --- a/test/TensorFlowNET.UnitTest/Numpy/Array.Creation.Test.cs +++ b/test/TensorFlowNET.UnitTest/Numpy/Array.Creation.Test.cs @@ -94,9 +94,9 @@ namespace TensorFlowNET.UnitTest.NumPy public void to_numpy_string() { var nd = np.arange(10 * 10 * 10 * 10).reshape((10, 10, 10, 10)); - var str = tensor_util.to_numpy_string(nd); - Assert.AreEqual("array([[[[0, 1, 2, ..., 7, 8, 9],", str.Substring(0, 33)); - Assert.AreEqual("[9990, 9991, 9992, ..., 9997, 9998, 9999]]]])", str.Substring(str.Length - 45)); + var str = NDArrayRender.ToString(nd); + Assert.AreEqual("array([[[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],", str.Substring(0, 40)); + Assert.AreEqual("[9990, 9991, 9992, 9993, 9994, 9995, 9996, 9997, 9998, 9999]]]])", str.Substring(str.Length - 64)); } } } diff --git a/test/TensorFlowNET.UnitTest/Numpy/Math.Test.cs b/test/TensorFlowNET.UnitTest/Numpy/Math.Test.cs index d08253cb..a3306f88 100644 --- a/test/TensorFlowNET.UnitTest/Numpy/Math.Test.cs +++ b/test/TensorFlowNET.UnitTest/Numpy/Math.Test.cs @@ -27,5 +27,13 @@ namespace TensorFlowNET.UnitTest.NumPy Assert.AreEqual(p.shape, 2); Assert.IsTrue(Equal(p.ToArray(), new[] { 2.0, 12.0 })); } + + [TestMethod] + public void astype() + { + var x = np.array(new byte[] { 1, 100, 200 }); + var x1 = x.astype(np.float32); + Assert.AreEqual(x1[2], 200f); + } } }