| @@ -334,3 +334,4 @@ ASALocalRun/ | |||||
| /tensorflowlib/linux/native/libtensorflow_framework.so | /tensorflowlib/linux/native/libtensorflow_framework.so | ||||
| /tensorflowlib/linux/native/libtensorflow.so | /tensorflowlib/linux/native/libtensorflow.so | ||||
| /src/TensorFlowNET.Core/libtensorflow.dll | /src/TensorFlowNET.Core/libtensorflow.dll | ||||
| /src/TensorFlowNET.Core/tensorflow.dll | |||||
| @@ -3,7 +3,7 @@ using System.Collections.Generic; | |||||
| using System.Linq; | using System.Linq; | ||||
| using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
| using System.Text; | using System.Text; | ||||
| using Tensorflow; | |||||
| using TF_DataType = Tensorflow.DataType; | using TF_DataType = Tensorflow.DataType; | ||||
| namespace TensorFlowNET.Core | namespace TensorFlowNET.Core | ||||
| @@ -19,6 +19,7 @@ namespace TensorFlowNET.Core | |||||
| public IntPtr handle; | public IntPtr handle; | ||||
| private Dictionary<int, Operation> _nodes_by_id; | private Dictionary<int, Operation> _nodes_by_id; | ||||
| private Dictionary<string, Operation> _nodes_by_name; | private Dictionary<string, Operation> _nodes_by_name; | ||||
| private Dictionary<string, int> _names_in_use; | |||||
| public int _version; | public int _version; | ||||
| private int _next_id_counter; | private int _next_id_counter; | ||||
| @@ -27,17 +28,20 @@ namespace TensorFlowNET.Core | |||||
| this.handle = graph; | this.handle = graph; | ||||
| _nodes_by_id = new Dictionary<int, Operation>(); | _nodes_by_id = new Dictionary<int, Operation>(); | ||||
| _nodes_by_name = new Dictionary<string, Operation>(); | _nodes_by_name = new Dictionary<string, Operation>(); | ||||
| _names_in_use = new Dictionary<string, int>(); | |||||
| } | } | ||||
| public unsafe Operation create_op(string op_type, object inputs, TF_DataType[] dtypes, TF_DataType[] input_types = null, string name = "") | |||||
| public unsafe Operation create_op(string op_type, object inputs, TF_DataType[] dtypes, TF_DataType[] input_types = null, Dictionary<string, AttrValue> attrs = null, string name = "Const") | |||||
| { | { | ||||
| if (String.IsNullOrEmpty(name)) | if (String.IsNullOrEmpty(name)) | ||||
| { | { | ||||
| op_type = name; | |||||
| name = op_type; | |||||
| } | } | ||||
| var op = new Operation(this, inputs); | |||||
| op.name = name; | |||||
| name = unique_name(name); | |||||
| var node_def = ops._NodeDef(op_type, name, device: "", attrs: attrs); | |||||
| var op = new Operation(node_def, this, inputs, dtypes); | |||||
| return op; | return op; | ||||
| } | } | ||||
| @@ -54,6 +58,22 @@ namespace TensorFlowNET.Core | |||||
| return ++_next_id_counter; | return ++_next_id_counter; | ||||
| } | } | ||||
| public string unique_name(string name) | |||||
| { | |||||
| var name_key = name.ToLower(); | |||||
| if (_names_in_use.ContainsKey(name_key)) | |||||
| { | |||||
| _names_in_use[name_key]++; | |||||
| } | |||||
| else | |||||
| { | |||||
| _names_in_use[name_key] = 1; | |||||
| } | |||||
| return $"{name}_{_names_in_use[name_key]}"; | |||||
| } | |||||
| public Operation[] get_operations() | public Operation[] get_operations() | ||||
| { | { | ||||
| return _nodes_by_name.Values.Select(x => x).ToArray(); | return _nodes_by_name.Values.Select(x => x).ToArray(); | ||||
| @@ -1,6 +1,8 @@ | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Text; | using System.Text; | ||||
| using Tensorflow; | |||||
| using TF_DataType = Tensorflow.DataType; | |||||
| namespace TensorFlowNET.Core | namespace TensorFlowNET.Core | ||||
| { | { | ||||
| @@ -11,13 +13,23 @@ namespace TensorFlowNET.Core | |||||
| public int _id => _id_value; | public int _id => _id_value; | ||||
| private int _id_value; | private int _id_value; | ||||
| public string name; | public string name; | ||||
| private Tensor[] _outputs; | |||||
| public Tensor[] outputs => _outputs; | |||||
| public Operation(Graph g, object inputs) | |||||
| public Operation(NodeDef node_def, Graph g, object inputs = null, TF_DataType[] output_types = null, object control_inputs = null, TF_DataType[] input_types = null, string original_op = "", string op_def = "") | |||||
| { | { | ||||
| _graph = g; | _graph = g; | ||||
| _id_value = _graph._next_id(); | _id_value = _graph._next_id(); | ||||
| _c_op = ops._create_c_op(g, inputs); | |||||
| _c_op = ops._create_c_op(g, node_def, inputs); | |||||
| var num_outputs = c_api.TF_OperationNumOutputs(_c_op); | |||||
| _outputs = new Tensor[num_outputs]; | |||||
| for (int i = 0; i < num_outputs; i++) | |||||
| { | |||||
| _outputs[i] = new Tensor(this, i, TF_DataType.DtDouble); | |||||
| } | |||||
| _graph._add_op(this); | _graph._add_op(this); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,10 +1,21 @@ | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Text; | using System.Text; | ||||
| using Tensorflow; | |||||
| namespace TensorFlowNET.Core | namespace TensorFlowNET.Core | ||||
| { | { | ||||
| public class Tensor | public class Tensor | ||||
| { | { | ||||
| private Operation _op; | |||||
| private int _value_index; | |||||
| private DataType _dtype; | |||||
| public Tensor(Operation op, int value_index, DataType dtype) | |||||
| { | |||||
| _op = op; | |||||
| _value_index = value_index; | |||||
| _dtype = dtype; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -9,6 +9,10 @@ | |||||
| <DefineConstants>DEBUG;TRACE</DefineConstants> | <DefineConstants>DEBUG;TRACE</DefineConstants> | ||||
| </PropertyGroup> | </PropertyGroup> | ||||
| <ItemGroup> | |||||
| <None Remove="Tensorflow\README.md" /> | |||||
| </ItemGroup> | |||||
| <ItemGroup> | <ItemGroup> | ||||
| <PackageReference Include="Google.Protobuf" Version="3.6.1" /> | <PackageReference Include="Google.Protobuf" Version="3.6.1" /> | ||||
| </ItemGroup> | </ItemGroup> | ||||
| @@ -0,0 +1,31 @@ | |||||
| using Google.Protobuf.Collections; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Text; | |||||
| using Tensorflow; | |||||
| using tensor_shape_pb2 = Tensorflow; | |||||
| namespace TensorFlowNET.Core | |||||
| { | |||||
| public class TensorShape | |||||
| { | |||||
| private int[] _dims; | |||||
| public TensorShape() | |||||
| { | |||||
| } | |||||
| public TensorShape as_shape() | |||||
| { | |||||
| return this; | |||||
| } | |||||
| public TensorShapeProto as_proto() | |||||
| { | |||||
| TensorShapeProto dim = new TensorShapeProto(); | |||||
| return new TensorShapeProto(dim); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -3,6 +3,8 @@ using System.Collections.Generic; | |||||
| using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
| using System.Text; | using System.Text; | ||||
| using TF_DataType = Tensorflow.DataType; | using TF_DataType = Tensorflow.DataType; | ||||
| using attr_value_pb2 = Tensorflow; | |||||
| using Tensorflow; | |||||
| namespace TensorFlowNET.Core | namespace TensorFlowNET.Core | ||||
| { | { | ||||
| @@ -13,9 +15,20 @@ namespace TensorFlowNET.Core | |||||
| public static unsafe Tensor constant(object value) | public static unsafe Tensor constant(object value) | ||||
| { | { | ||||
| var g = ops.get_default_graph(); | var g = ops.get_default_graph(); | ||||
| g.create_op("Const", value, new TF_DataType[] { TF_DataType.DtDouble }); | |||||
| return new Tensor(); | |||||
| var tensor_value = new attr_value_pb2.AttrValue(); | |||||
| var tensor_pb = tensor_util.make_tensor_proto(value); | |||||
| tensor_value.Tensor = tensor_pb; | |||||
| var dtype_value = new attr_value_pb2.AttrValue | |||||
| { | |||||
| Type = tensor_value.Tensor.Dtype, | |||||
| }; | |||||
| var attrs = new Dictionary<string, AttrValue>(); | |||||
| attrs["dtype"] = dtype_value; | |||||
| attrs["value"] = tensor_value; | |||||
| var const_tensor = g.create_op("Const", null, new TF_DataType[] { dtype_value.Type }, attrs: attrs).outputs[0]; | |||||
| return const_tensor; | |||||
| } | } | ||||
| public static Deallocator FreeTensorDataDelegate = FreeTensorData; | public static Deallocator FreeTensorDataDelegate = FreeTensorData; | ||||
| @@ -18,7 +18,7 @@ namespace TensorFlowNET.Core | |||||
| { | { | ||||
| public static class c_api | public static class c_api | ||||
| { | { | ||||
| public const string TensorFlowLibName = "libtensorflow"; | |||||
| public const string TensorFlowLibName = "tensorflow"; | |||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static unsafe extern TF_Operation TF_FinishOperation(TF_OperationDescription desc, TF_Status status); | public static unsafe extern TF_Operation TF_FinishOperation(TF_OperationDescription desc, TF_Status status); | ||||
| @@ -35,6 +35,12 @@ namespace TensorFlowNET.Core | |||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static extern unsafe TF_Tensor TF_NewTensor(TF_DataType dataType, Int64 dims, int num_dims, IntPtr data, size_t len, Deallocator deallocator, IntPtr deallocator_arg); | public static extern unsafe TF_Tensor TF_NewTensor(TF_DataType dataType, Int64 dims, int num_dims, IntPtr data, size_t len, Deallocator deallocator, IntPtr deallocator_arg); | ||||
| [DllImport(TensorFlowLibName)] | |||||
| public static extern unsafe int TF_OperationNumOutputs(TF_Operation oper); | |||||
| [DllImport(TensorFlowLibName)] | |||||
| public static extern unsafe void TF_SetAttrValueProto(TF_OperationDescription desc, string attr_name, void* proto, size_t proto_len, TF_Status status); | |||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static extern unsafe void TF_SetAttrTensor(TF_OperationDescription desc, string attr_name, TF_Tensor value, TF_Status status); | public static extern unsafe void TF_SetAttrTensor(TF_OperationDescription desc, string attr_name, TF_Tensor value, TF_Status status); | ||||
| @@ -3,8 +3,10 @@ using System.Collections.Generic; | |||||
| using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Threading; | using System.Threading; | ||||
| using Tensorflow; | |||||
| using tf = TensorFlowNET.Core.Tensorflow; | using tf = TensorFlowNET.Core.Tensorflow; | ||||
| using TF_DataType = Tensorflow.DataType; | using TF_DataType = Tensorflow.DataType; | ||||
| using node_def_pb2 = Tensorflow; | |||||
| namespace TensorFlowNET.Core | namespace TensorFlowNET.Core | ||||
| { | { | ||||
| @@ -15,28 +17,73 @@ namespace TensorFlowNET.Core | |||||
| return tf.Graph(); | return tf.Graph(); | ||||
| } | } | ||||
| public static unsafe IntPtr _create_c_op(Graph graph, object inputs) | |||||
| public static unsafe IntPtr _create_c_op(Graph graph, NodeDef node_def, object inputs) | |||||
| { | { | ||||
| var op_desc = c_api.TF_NewOperation(graph.handle, "Const", "Const0"); | |||||
| var op_desc = c_api.TF_NewOperation(graph.handle, node_def.Op, node_def.Name); | |||||
| var status = c_api.TF_NewStatus(); | var status = c_api.TF_NewStatus(); | ||||
| IntPtr tensor = IntPtr.Zero; | |||||
| // Doesn't work | |||||
| /*foreach(var attr in node_def.Attr) | |||||
| { | |||||
| if (attr.Value.Tensor != null) | |||||
| { | |||||
| switch (attr.Value.Tensor.Dtype) | |||||
| { | |||||
| case DataType.DtDouble: | |||||
| var proto = (double*)Marshal.AllocHGlobal(sizeof(double)); | |||||
| *proto = attr.Value.Tensor.DoubleVal[0]; | |||||
| c_api.TF_SetAttrValueProto(op_desc, attr.Key, proto, proto_len: (UIntPtr)sizeof(double), status: status); | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| //c_api.TF_SetAttrValueProto(op_desc, attr.Key, null, proto_len: UIntPtr.Zero, status: status); | |||||
| } | |||||
| } */ | |||||
| switch (inputs) | |||||
| foreach (var attr in node_def.Attr) | |||||
| { | { | ||||
| case double value: | |||||
| var v = (double*)Marshal.AllocHGlobal(sizeof(double)); | |||||
| *v = value; | |||||
| tensor = c_api.TF_NewTensor(TF_DataType.DtDouble, 0, 0, data: (IntPtr)v, len: (UIntPtr)sizeof(double), deallocator: Tensorflow.FreeTensorDataDelegate, deallocator_arg: IntPtr.Zero); | |||||
| c_api.TF_SetAttrType(op_desc, "dtype", TF_DataType.DtDouble); | |||||
| break; | |||||
| if (attr.Value.Tensor == null) continue; | |||||
| switch (attr.Value.Tensor.Dtype) | |||||
| { | |||||
| case DataType.DtDouble: | |||||
| var v = (double*)Marshal.AllocHGlobal(sizeof(double)); | |||||
| *v = attr.Value.Tensor.DoubleVal[0]; | |||||
| var tensor = c_api.TF_NewTensor(TF_DataType.DtDouble, 0, 0, data: (IntPtr)v, len: (UIntPtr)sizeof(double), deallocator: Tensorflow.FreeTensorDataDelegate, deallocator_arg: IntPtr.Zero); | |||||
| c_api.TF_SetAttrTensor(op_desc, "value", tensor, status); | |||||
| c_api.TF_SetAttrType(op_desc, "dtype", TF_DataType.DtDouble); | |||||
| break; | |||||
| case DataType.DtString: | |||||
| var proto = Marshal.StringToHGlobalAnsi(attr.Value.Tensor.StringVal[0].ToStringUtf8()); | |||||
| c_api.TF_SetAttrValueProto(op_desc, attr.Key, proto.ToPointer(), proto_len: (UIntPtr)32, status: status); | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| c_api.TF_SetAttrTensor(op_desc, "value", tensor, status); | |||||
| var c_op = c_api.TF_FinishOperation(op_desc, status); | var c_op = c_api.TF_FinishOperation(op_desc, status); | ||||
| return c_op; | return c_op; | ||||
| } | } | ||||
| public static NodeDef _NodeDef(string op_type, string name, string device = "", Dictionary<string, AttrValue> attrs = null) | |||||
| { | |||||
| var node_def = new node_def_pb2.NodeDef(); | |||||
| node_def.Op = op_type; | |||||
| node_def.Name = name; | |||||
| foreach (var attr in attrs) | |||||
| { | |||||
| node_def.Attr.Add(attr.Key, attr.Value); | |||||
| } | |||||
| return node_def; | |||||
| } | |||||
| public static int uid() | |||||
| { | |||||
| return 1; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,45 @@ | |||||
| using System; | |||||
| using NumSharp.Core; | |||||
| using System; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Text; | using System.Text; | ||||
| using Tensorflow; | |||||
| using np = NumSharp.Core.NumPy; | using np = NumSharp.Core.NumPy; | ||||
| using tensor_pb2 = Tensorflow; | |||||
| namespace TensorFlowNET.Core | namespace TensorFlowNET.Core | ||||
| { | { | ||||
| public static class tensor_util | public static class tensor_util | ||||
| { | { | ||||
| public static void make_tensor_proto(object values, Type dtype = null) | |||||
| public static TensorProto make_tensor_proto(object values, Type dtype = null) | |||||
| { | { | ||||
| var nparray = np.array(values as Array, dtype); | |||||
| NDArray nparray; | |||||
| TensorProto tensor_proto = null; | |||||
| TensorShape tensor_shape = new TensorShape(); | |||||
| switch (values) | |||||
| { | |||||
| case double val: | |||||
| nparray = np.array(new double[] { val }, np.float64); | |||||
| tensor_proto = new tensor_pb2.TensorProto | |||||
| { | |||||
| Dtype = DataType.DtDouble, | |||||
| TensorShape = tensor_shape.as_shape().as_proto() | |||||
| }; | |||||
| tensor_proto.DoubleVal.Add(val); | |||||
| break; | |||||
| case string val: | |||||
| nparray = np.array(new string[] { val }, np.chars); | |||||
| tensor_proto = new tensor_pb2.TensorProto | |||||
| { | |||||
| Dtype = DataType.DtString, | |||||
| TensorShape = tensor_shape.as_shape().as_proto() | |||||
| }; | |||||
| tensor_proto.StringVal.Add(Google.Protobuf.ByteString.CopyFrom(val, Encoding.UTF8)); | |||||
| break; | |||||
| } | |||||
| return tensor_proto; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -19,8 +19,7 @@ namespace TensorFlowNET.Examples | |||||
| The value returned by the constructor represents the output | The value returned by the constructor represents the output | ||||
| of the Constant op.*/ | of the Constant op.*/ | ||||
| var graph = tf.get_default_graph(); | var graph = tf.get_default_graph(); | ||||
| var hello = tf.constant(4.0); | |||||
| //var hello = tf.constant("Hello, TensorFlow!"); | |||||
| var hello = tf.constant("Hello, TensorFlow!"); | |||||
| // Start tf session | // Start tf session | ||||
| // var sess = tf.Session(); | // var sess = tf.Session(); | ||||