| @@ -1,5 +1,5 @@ | |||||
| # The Definitive Guide to Tensorflow.NET | |||||
| # Tensorflow.NET 权威指南 | |||||
| # The Definitive Guide to TensorFlow.NET | |||||
| # TensorFlow.NET 权威指南 | |||||
| @@ -14,9 +14,9 @@ | |||||
| Why do I start the Tensorflow.NET project? | |||||
| Why do I start the TensorFlow.NET project? | |||||
| 我为什么会写Tensorflow.NET? | |||||
| 我为什么会写TensorFlow.NET? | |||||
| 再过几天就是2018年圣诞节,看着孩子一天天长大并懂事,感慨时间过得太快。IT技术更新换代比以往任何时候都更快,各种前后端技术纷纷涌现。大数据,人工智能和区块链,容器技术和微服务,分布式计算和无服务器技术,让人眼花缭乱。Amazon AI服务接口宣称不需要具有任何机器学习经验的工程师就能使用,让像我这样刚静下心来学习了两年并打算将来转行做AI架构的想法泼了一桶凉水。 | 再过几天就是2018年圣诞节,看着孩子一天天长大并懂事,感慨时间过得太快。IT技术更新换代比以往任何时候都更快,各种前后端技术纷纷涌现。大数据,人工智能和区块链,容器技术和微服务,分布式计算和无服务器技术,让人眼花缭乱。Amazon AI服务接口宣称不需要具有任何机器学习经验的工程师就能使用,让像我这样刚静下心来学习了两年并打算将来转行做AI架构的想法泼了一桶凉水。 | ||||
| @@ -9,12 +9,7 @@ namespace Tensorflow | |||||
| { | { | ||||
| public static Tensor constant(NDArray nd, string name = "Const", bool verify_shape = false) | public static Tensor constant(NDArray nd, string name = "Const", bool verify_shape = false) | ||||
| { | { | ||||
| var t = constant_op.Create(nd, name, verify_shape); | |||||
| /*var graph = tf.get_default_graph(); | |||||
| var tensor = new Tensor(nd); | |||||
| var op = graph.NewOperation("Const", name, tensor);*/ | |||||
| return t; | |||||
| return constant_op.Create(nd, name, verify_shape); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -59,7 +59,7 @@ namespace Tensorflow | |||||
| if (!String.IsNullOrEmpty(input_arg.TypeAttr)) | if (!String.IsNullOrEmpty(input_arg.TypeAttr)) | ||||
| { | { | ||||
| attrs[input_arg.TypeAttr] = DataType.DtFloat; | |||||
| attrs[input_arg.TypeAttr] = (keywords[input_name] as Tensor).dtype; | |||||
| } | } | ||||
| if (input_arg.IsRef) | if (input_arg.IsRef) | ||||
| @@ -92,7 +92,7 @@ namespace Tensorflow | |||||
| switch (attr_def.Type) | switch (attr_def.Type) | ||||
| { | { | ||||
| case "type": | case "type": | ||||
| attr_value.Type = _MakeType(value, attr_def); | |||||
| attr_value.Type = _MakeType((TF_DataType)value, attr_def); | |||||
| break; | break; | ||||
| case "shape": | case "shape": | ||||
| attr_value.Shape = new TensorShapeProto(); | attr_value.Shape = new TensorShapeProto(); | ||||
| @@ -127,9 +127,9 @@ namespace Tensorflow | |||||
| return op; | return op; | ||||
| } | } | ||||
| public DataType _MakeType(Object v, AttrDef attr_def) | |||||
| public DataType _MakeType(TF_DataType v, AttrDef attr_def) | |||||
| { | { | ||||
| return DataType.DtFloat; | |||||
| return v.as_datatype_enum(); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -37,7 +37,6 @@ namespace Tensorflow | |||||
| private static OpDefLibrary _InitOpDefLibrary() | private static OpDefLibrary _InitOpDefLibrary() | ||||
| { | { | ||||
| // c_api.TF_GraphGetOpDef(g.Handle, op_type_name, buffer.Handle, status.Handle); | |||||
| var bytes = File.ReadAllBytes("Operations/op_list_proto_array.bin"); | var bytes = File.ReadAllBytes("Operations/op_list_proto_array.bin"); | ||||
| var op_list = OpList.Parser.ParseFrom(bytes); | var op_list = OpList.Parser.ParseFrom(bytes); | ||||
| var op_def_lib = new OpDefLibrary(); | var op_def_lib = new OpDefLibrary(); | ||||
| @@ -17,9 +17,7 @@ namespace Tensorflow | |||||
| var _op = _op_def_lib._apply_op_helper("Add", name: "add", keywords: keywords); | var _op = _op_def_lib._apply_op_helper("Add", name: "add", keywords: keywords); | ||||
| var tensor = new Tensor(_op, 0, TF_DataType.TF_FLOAT); | |||||
| return tensor; | |||||
| return new Tensor(_op, 0, _op.OutputType(0)); | |||||
| } | } | ||||
| private static OpDefLibrary _InitOpDefLibrary() | private static OpDefLibrary _InitOpDefLibrary() | ||||
| @@ -28,14 +28,20 @@ namespace Tensorflow | |||||
| var op_desc = graph.NewOperation(node_def.Op, node_def.Name); | var op_desc = graph.NewOperation(node_def.Op, node_def.Name); | ||||
| // Add inputs | // Add inputs | ||||
| if(inputs != null && inputs.Count > 0) | |||||
| if(inputs != null) | |||||
| { | { | ||||
| /*foreach (var op_input in inputs) | |||||
| foreach (var op_input in inputs) | |||||
| { | { | ||||
| c_api.TF_AddInput(op_desc, op_input._as_tf_output()); | |||||
| }*/ | |||||
| c_api.TF_AddInputList(op_desc, inputs.Select(x => x._as_tf_output()).ToArray(), inputs.Count); | |||||
| bool isList = false; | |||||
| if (!isList) | |||||
| { | |||||
| c_api.TF_AddInput(op_desc, op_input._as_tf_output()); | |||||
| } | |||||
| else | |||||
| { | |||||
| c_api.TF_AddInputList(op_desc, inputs.Select(x => x._as_tf_output()).ToArray(), inputs.Count); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| var status = new Status(); | var status = new Status(); | ||||
| @@ -131,6 +131,9 @@ namespace Tensorflow | |||||
| case TF_DataType.TF_FLOAT: | case TF_DataType.TF_FLOAT: | ||||
| result[i] = *(float*)c_api.TF_TensorData(output_values[i]); | result[i] = *(float*)c_api.TF_TensorData(output_values[i]); | ||||
| break; | break; | ||||
| case TF_DataType.TF_INT32: | |||||
| result[i] = *(int*)c_api.TF_TensorData(output_values[i]); | |||||
| break; | |||||
| default: | default: | ||||
| throw new NotImplementedException("can't get output"); | throw new NotImplementedException("can't get output"); | ||||
| break; | break; | ||||
| @@ -18,6 +18,7 @@ | |||||
| Docs: https://tensorflownet.readthedocs.io</Description> | Docs: https://tensorflownet.readthedocs.io</Description> | ||||
| <AssemblyVersion>0.0.2.0</AssemblyVersion> | <AssemblyVersion>0.0.2.0</AssemblyVersion> | ||||
| <PackageReleaseNotes></PackageReleaseNotes> | <PackageReleaseNotes></PackageReleaseNotes> | ||||
| <LangVersion>7.2</LangVersion> | |||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | ||||
| @@ -0,0 +1,14 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| namespace Tensorflow | |||||
| { | |||||
| public partial class Tensor | |||||
| { | |||||
| public static Tensor operator +(Tensor t1, Tensor t2) | |||||
| { | |||||
| return gen_math_ops.add(t1, t2); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -11,7 +11,7 @@ namespace Tensorflow | |||||
| /// A tensor is a generalization of vectors and matrices to potentially higher dimensions. | /// A tensor is a generalization of vectors and matrices to potentially higher dimensions. | ||||
| /// Internally, TensorFlow represents tensors as n-dimensional arrays of base datatypes. | /// Internally, TensorFlow represents tensors as n-dimensional arrays of base datatypes. | ||||
| /// </summary> | /// </summary> | ||||
| public class Tensor : IDisposable | |||||
| public partial class Tensor : IDisposable | |||||
| { | { | ||||
| private readonly IntPtr _handle; | private readonly IntPtr _handle; | ||||
| @@ -22,7 +22,8 @@ namespace Tensorflow | |||||
| public object value; | public object value; | ||||
| public int value_index { get; } | public int value_index { get; } | ||||
| public TF_DataType dtype => _handle == IntPtr.Zero ? TF_DataType.DtInvalid : c_api.TF_TensorType(_handle); | |||||
| private TF_DataType _dtype = TF_DataType.DtInvalid; | |||||
| public TF_DataType dtype => _handle == IntPtr.Zero ? _dtype : c_api.TF_TensorType(_handle); | |||||
| public ulong bytesize => _handle == IntPtr.Zero ? 0 : c_api.TF_TensorByteSize(_handle); | public ulong bytesize => _handle == IntPtr.Zero ? 0 : c_api.TF_TensorByteSize(_handle); | ||||
| public ulong dataTypeSize => _handle == IntPtr.Zero ? 0 : c_api.TF_DataTypeSize(dtype); | public ulong dataTypeSize => _handle == IntPtr.Zero ? 0 : c_api.TF_DataTypeSize(dtype); | ||||
| public ulong size => _handle == IntPtr.Zero ? 0 : bytesize / dataTypeSize; | public ulong size => _handle == IntPtr.Zero ? 0 : bytesize / dataTypeSize; | ||||
| @@ -118,6 +119,7 @@ namespace Tensorflow | |||||
| { | { | ||||
| this.op = op; | this.op = op; | ||||
| this.value_index = value_index; | this.value_index = value_index; | ||||
| this._dtype = dtype; | |||||
| } | } | ||||
| public TF_Output _as_tf_output() | public TF_Output _as_tf_output() | ||||
| @@ -0,0 +1,31 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| using Tensorflow; | |||||
| namespace TensorFlowNET.Examples | |||||
| { | |||||
| /// <summary> | |||||
| /// Basic Operations example using TensorFlow library. | |||||
| /// https://github.com/aymericdamien/TensorFlow-Examples/blob/master/examples/1_Introduction/basic_operations.py | |||||
| /// </summary> | |||||
| public class BasicOperations : IExample | |||||
| { | |||||
| public void Run() | |||||
| { | |||||
| // Basic constant operations | |||||
| // The value returned by the constructor represents the output | |||||
| // of the Constant op. | |||||
| var a = tf.constant(2); | |||||
| var b = tf.constant(3); | |||||
| // Launch the default graph. | |||||
| using (var sess = tf.Session()) | |||||
| { | |||||
| Console.WriteLine("a=2, b=3"); | |||||
| Console.WriteLine($"Addition with constants: {sess.run(a + b)}"); | |||||
| //Console.WriteLine($"Multiplication with constants: {sess.run(a * b)}"); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -11,6 +11,9 @@ namespace TensorFlowNET.Examples | |||||
| var assembly = Assembly.GetEntryAssembly(); | var assembly = Assembly.GetEntryAssembly(); | ||||
| foreach(Type type in assembly.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IExample)))) | foreach(Type type in assembly.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IExample)))) | ||||
| { | { | ||||
| if (args.Length > 0 && !args.Contains(type.Name)) | |||||
| continue; | |||||
| var example = (IExample)Activator.CreateInstance(type); | var example = (IExample)Activator.CreateInstance(type); | ||||
| try | try | ||||
| @@ -22,6 +25,8 @@ namespace TensorFlowNET.Examples | |||||
| Console.WriteLine(ex); | Console.WriteLine(ex); | ||||
| } | } | ||||
| } | } | ||||
| Console.ReadLine(); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||