| @@ -146,7 +146,7 @@ namespace Tensorflow | |||||
| bytestream.Read(buf, 0, buf.Length); | 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) | if (one_hot) | ||||
| return DenseToOneHot(labels, num_classes); | return DenseToOneHot(labels, num_classes); | ||||
| @@ -1,8 +1,15 @@ | |||||
| namespace Tensorflow.Eager | |||||
| using Tensorflow.NumPy; | |||||
| namespace Tensorflow.Eager | |||||
| { | { | ||||
| public partial class EagerTensor | public partial class EagerTensor | ||||
| { | { | ||||
| public override string ToString() | 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}"; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -134,8 +134,8 @@ namespace Tensorflow.NumPy | |||||
| return array; | return array; | ||||
| } | } | ||||
| NDArray GetData(int[] indices, int axis = 0) | |||||
| unsafe NDArray GetData(int[] indices, int axis = 0) | |||||
| { | { | ||||
| if (shape.IsScalar) | if (shape.IsScalar) | ||||
| return GetScalar(); | return GetScalar(); | ||||
| @@ -148,19 +148,17 @@ namespace Tensorflow.NumPy | |||||
| var array = np.ndarray(dims, dtype: dtype); | var array = np.ndarray(dims, dtype: dtype); | ||||
| dims[0] = 1; | 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; | 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++); | 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; | return array; | ||||
| @@ -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 "<null>"; | |||||
| 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 "<unprintable>"; | |||||
| } | |||||
| else if (dtype == TF_DataType.TF_RESOURCE) | |||||
| { | |||||
| return "<unprintable>"; | |||||
| } | |||||
| else | |||||
| { | |||||
| return dtype switch | |||||
| { | |||||
| TF_DataType.TF_BOOL => Render(array.ToArray<bool>(), array.shape), | |||||
| TF_DataType.TF_INT8 => Render(array.ToArray<sbyte>(), array.shape), | |||||
| TF_DataType.TF_INT32 => Render(array.ToArray<int>(), array.shape), | |||||
| TF_DataType.TF_INT64 => Render(array.ToArray<long>(), array.shape), | |||||
| TF_DataType.TF_FLOAT => Render(array.ToArray<float>(), array.shape), | |||||
| TF_DataType.TF_DOUBLE => Render(array.ToArray<double>(), array.shape), | |||||
| _ => Render(array.ToArray<byte>(), array.shape) | |||||
| }; | |||||
| } | |||||
| } | |||||
| static string Render<T>(T[] array, Shape shape) | |||||
| { | |||||
| if (array == null) | |||||
| return "<null>"; | |||||
| if (array.Length == 0) | |||||
| return "<empty>"; | |||||
| 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; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -46,6 +46,6 @@ namespace Tensorflow.NumPy | |||||
| public byte[] ToByteArray() => BufferToArray(); | public byte[] ToByteArray() => BufferToArray(); | ||||
| public static string[] AsStringArray(NDArray arr) => throw new NotImplementedException(""); | 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); | |||||
| } | } | ||||
| } | } | ||||
| @@ -90,6 +90,9 @@ namespace Tensorflow | |||||
| case TF_DataType.TF_FLOAT: | case TF_DataType.TF_FLOAT: | ||||
| zeros = constant(0f); | zeros = constant(0f); | ||||
| break; | break; | ||||
| case TF_DataType.TF_INT8: | |||||
| zeros = constant((byte)0); | |||||
| break; | |||||
| default: | default: | ||||
| zeros = constant(0); | zeros = constant(0); | ||||
| break; | break; | ||||
| @@ -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"); | 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 "<null>"; | |||||
| 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 "<unprintable>"; | |||||
| } | |||||
| else if (dtype == TF_DataType.TF_RESOURCE) | |||||
| { | |||||
| return "<unprintable>"; | |||||
| } | |||||
| else | |||||
| { | |||||
| return dtype switch | |||||
| { | |||||
| TF_DataType.TF_BOOL => DisplayArrayAsString(tensor.ToArray<bool>(), tensor.shape), | |||||
| TF_DataType.TF_INT8 => DisplayArrayAsString(tensor.ToArray<sbyte>(), tensor.shape), | |||||
| TF_DataType.TF_INT32 => DisplayArrayAsString(tensor.ToArray<int>(), tensor.shape), | |||||
| TF_DataType.TF_INT64 => DisplayArrayAsString(tensor.ToArray<long>(), tensor.shape), | |||||
| TF_DataType.TF_FLOAT => DisplayArrayAsString(tensor.ToArray<float>(), tensor.shape), | |||||
| TF_DataType.TF_DOUBLE => DisplayArrayAsString(tensor.ToArray<double>(), tensor.shape), | |||||
| _ => DisplayArrayAsString(tensor.ToArray<byte>(), 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 "<null>"; | |||||
| 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 "<unprintable>"; | |||||
| } | |||||
| else if (dtype == TF_DataType.TF_RESOURCE) | |||||
| { | |||||
| return "<unprintable>"; | |||||
| } | |||||
| else | |||||
| { | |||||
| return dtype switch | |||||
| { | |||||
| TF_DataType.TF_BOOL => DisplayArrayAsString(tensor.ToArray<bool>(), tensor.shape), | |||||
| TF_DataType.TF_INT8 => DisplayArrayAsString(tensor.ToArray<sbyte>(), tensor.shape), | |||||
| TF_DataType.TF_INT32 => DisplayArrayAsString(tensor.ToArray<int>(), tensor.shape), | |||||
| TF_DataType.TF_INT64 => DisplayArrayAsString(tensor.ToArray<long>(), tensor.shape), | |||||
| TF_DataType.TF_FLOAT => DisplayArrayAsString(tensor.ToArray<float>(), tensor.shape), | |||||
| TF_DataType.TF_DOUBLE => DisplayArrayAsString(tensor.ToArray<double>(), tensor.shape), | |||||
| _ => DisplayArrayAsString(tensor.ToArray<byte>(), tensor.shape) | |||||
| }; | |||||
| } | |||||
| } | |||||
| static string DisplayArrayAsString<T>(T[] array, Shape shape) | |||||
| { | |||||
| if (array == null) | |||||
| return "<null>"; | |||||
| if (array.Length == 0) | |||||
| return "<empty>"; | |||||
| 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) | public static ParsedSliceArgs ParseSlices(Slice[] slices) | ||||
| { | { | ||||
| var begin = new List<int>(); | var begin = new List<int>(); | ||||
| @@ -222,7 +222,7 @@ namespace Tensorflow | |||||
| public override string ToString() | public override string ToString() | ||||
| { | { | ||||
| if (tf.Context.executing_eagerly()) | 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 | else | ||||
| return $"tf.Variable: '{Name}' shape={string.Join(",", shape)}, dtype={dtype.as_numpy_name()}"; | return $"tf.Variable: '{Name}' shape={string.Join(",", shape)}, dtype={dtype.as_numpy_name()}"; | ||||
| } | } | ||||
| @@ -94,9 +94,9 @@ namespace TensorFlowNET.UnitTest.NumPy | |||||
| public void to_numpy_string() | public void to_numpy_string() | ||||
| { | { | ||||
| var nd = np.arange(10 * 10 * 10 * 10).reshape((10, 10, 10, 10)); | 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)); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -27,5 +27,13 @@ namespace TensorFlowNET.UnitTest.NumPy | |||||
| Assert.AreEqual(p.shape, 2); | Assert.AreEqual(p.shape, 2); | ||||
| Assert.IsTrue(Equal(p.ToArray<double>(), new[] { 2.0, 12.0 })); | Assert.IsTrue(Equal(p.ToArray<double>(), 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); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||