diff --git a/src/TensorFlowNET.Core/Operations/OpDefLibrary.cs b/src/TensorFlowNET.Core/Operations/OpDefLibrary.cs index 2ceeb043..3b30a12b 100644 --- a/src/TensorFlowNET.Core/Operations/OpDefLibrary.cs +++ b/src/TensorFlowNET.Core/Operations/OpDefLibrary.cs @@ -51,7 +51,7 @@ namespace Tensorflow var input_name = input_arg.Name; if (keywords[input_name] is double int_value) { - keywords[input_name] = constant_op.Constant(int_value, input_name); + keywords[input_name] = constant_op.constant(int_value, input_name); } if (keywords[input_name] is Tensor value) diff --git a/src/TensorFlowNET.Core/Operations/array_ops.py.cs b/src/TensorFlowNET.Core/Operations/array_ops.py.cs index db51e21b..14594755 100644 --- a/src/TensorFlowNET.Core/Operations/array_ops.py.cs +++ b/src/TensorFlowNET.Core/Operations/array_ops.py.cs @@ -43,12 +43,12 @@ namespace Tensorflow var nd = np.zeros(shape); if (shape.Size < 1000) { - return constant_op.Constant(nd, name); + return constant_op.constant(nd, name); } else { tShape = constant_op._tensor_shape_tensor_conversion_function(shape.as_shape()); - var c = constant_op.Constant(0); + var c = constant_op.constant(0); return gen_array_ops.fill(tShape, c, name); } } diff --git a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs index 8ffb28a3..c8e19d91 100644 --- a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs @@ -38,9 +38,18 @@ namespace Tensorflow return _op.outputs[0]; } - public static Tensor mat_mul(Tensor a, Tensor b, bool transpose_a = false, bool transpose_b = false) + /// + /// Multiply the matrix "a" by the matrix "b". + /// + /// + /// + /// + /// + /// + /// + public static Tensor mat_mul(Tensor a, Tensor b, bool transpose_a = false, bool transpose_b = false, string name = "") { - var _op = _op_def_lib._apply_op_helper("MatMul", args: new { a, b, transpose_a, transpose_b }); + var _op = _op_def_lib._apply_op_helper("MatMul", name, args: new { a, b, transpose_a, transpose_b }); return _op.outputs[0]; } diff --git a/src/TensorFlowNET.Core/Operations/math_ops.py.cs b/src/TensorFlowNET.Core/Operations/math_ops.py.cs new file mode 100644 index 00000000..078de45c --- /dev/null +++ b/src/TensorFlowNET.Core/Operations/math_ops.py.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tensorflow +{ + public class math_ops + { + public static Tensor matmul(Tensor a, Tensor b, + bool transpose_a = false, bool transpose_b = false, + bool adjoint_a = false, bool adjoint_b = false, + bool a_is_sparse = false, bool b_is_sparse = false, + string name = "") + { + Tensor result = null; + + Python.with(new ops.name_scope(name, "MatMul", new Tensor[] { a, b }), scope => + { + name = scope; + + if (transpose_a && adjoint_a) + throw new ValueError("Only one of transpose_a and adjoint_a can be True."); + if (transpose_b && adjoint_b) + throw new ValueError("Only one of transpose_b and adjoint_b can be True."); + + a = ops.convert_to_tensor(a, name: "a"); + b = ops.convert_to_tensor(b, name: "b"); + + result = gen_math_ops.mat_mul(a, b, transpose_a, transpose_b, name); + }); + + return result; + } + } +} diff --git a/src/TensorFlowNET.Core/Sessions/Session.cs b/src/TensorFlowNET.Core/Sessions/Session.cs index 182d0fe3..413dbd41 100644 --- a/src/TensorFlowNET.Core/Sessions/Session.cs +++ b/src/TensorFlowNET.Core/Sessions/Session.cs @@ -7,16 +7,17 @@ namespace Tensorflow public class Session : BaseSession, IPython { private IntPtr _handle; - public Status Status { get; } + public Status Status = new Status(); public SessionOptions Options { get; } + public Graph graph; public Session(string target = "", Graph graph = null) { - Status = new Status(); if(graph == null) { graph = tf.get_default_graph(); } + this.graph = graph; Options = new SessionOptions(); _handle = c_api.TF_NewSession(graph, Options, Status); Status.Check(); @@ -27,9 +28,12 @@ namespace Tensorflow _handle = handle; } - public Session(Graph graph, SessionOptions opts, Status s) + public Session(Graph graph, SessionOptions opts, Status s = null) { + if (s == null) + s = Status; _handle = c_api.TF_NewSession(graph, opts, s); + Status.Check(true); } public static implicit operator IntPtr(Session session) => session._handle; diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Implicit.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Implicit.cs index a68f28c1..ada0c89a 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.Implicit.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.Implicit.cs @@ -8,12 +8,12 @@ namespace Tensorflow { public static implicit operator Tensor(double scalar) { - return constant_op.Constant(scalar); + return constant_op.constant(scalar); } public static implicit operator Tensor(int scalar) { - return constant_op.Constant(scalar); + return constant_op.constant(scalar); } public static implicit operator int(Tensor tensor) diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.cs b/src/TensorFlowNET.Core/Tensors/Tensor.cs index c4261a19..1b88b55d 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.cs @@ -213,9 +213,9 @@ namespace Tensorflow /// A dictionary that maps `Tensor` objects to feed values. /// The `Session` to be used to evaluate this tensor. /// - public NDArray eval(dynamic feed_dict = null, Session session = null) + public NDArray eval(Dictionary feed_dict = null, Session session = null) { - return ops._eval_using_default_session(new Tensor[] { this }, feed_dict, Graph, session)[0]; + return ops._eval_using_default_session(this, feed_dict, Graph, session); } public TF_DataType ToTFDataType(Type type) diff --git a/src/TensorFlowNET.Core/Tensors/constant_op.cs b/src/TensorFlowNET.Core/Tensors/constant_op.cs index b98150ae..1e331c0b 100644 --- a/src/TensorFlowNET.Core/Tensors/constant_op.cs +++ b/src/TensorFlowNET.Core/Tensors/constant_op.cs @@ -19,7 +19,7 @@ namespace Tensorflow /// Optional name for the tensor. /// Boolean that enables verification of a shape of values. /// - 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) { Graph g = ops.get_default_graph(); var tensor_pb = tensor_util.make_tensor_proto(nd, verify_shape); @@ -76,7 +76,7 @@ namespace Tensorflow if (string.IsNullOrEmpty(name)) name = "shape_as_tensor"; - return constant_op.Constant(s_list, name); + return constant_op.constant(s_list, name); } } } diff --git a/src/TensorFlowNET.Core/Tensors/tf.constant.cs b/src/TensorFlowNET.Core/Tensors/tf.constant.cs index e2a7bedd..26711316 100644 --- a/src/TensorFlowNET.Core/Tensors/tf.constant.cs +++ b/src/TensorFlowNET.Core/Tensors/tf.constant.cs @@ -9,7 +9,7 @@ namespace Tensorflow { public static Tensor constant(NDArray nd, string name = "Const", bool verify_shape = false) { - return constant_op.Constant(nd, name, verify_shape); + return constant_op.constant(nd, name, verify_shape); } public static Tensor zeros(Shape shape, TF_DataType dtype = TF_DataType.TF_FLOAT, string name = "") diff --git a/src/TensorFlowNET.Core/ops.py.cs b/src/TensorFlowNET.Core/ops.py.cs index 483461c1..0b2a0e91 100644 --- a/src/TensorFlowNET.Core/ops.py.cs +++ b/src/TensorFlowNET.Core/ops.py.cs @@ -75,7 +75,7 @@ namespace Tensorflow return val; default: var nd = tensor_util.convert_to_numpy_ndarray(value); - return constant_op.Constant(nd, name); + return constant_op.constant(nd, name); } } @@ -240,12 +240,34 @@ namespace Tensorflow /// of numpy ndarrays that each correspond to the respective element in /// "tensors". /// - public static NDArray[] _eval_using_default_session(Tensor[] tensors, dynamic feed_dict, Graph graph, Session session = null) + public static NDArray _eval_using_default_session(Tensor tensor, Dictionary feed_dict, Graph graph, Session session = null) { if (session == null) + { session = get_default_session(); - return null; + if (session == null) + throw new ValueError("Cannot evaluate tensor using `eval()`: No default " + + "session is registered. Use `with " + + "sess.as_default()` or pass an explicit session to " + + "`eval(session=sess)`"); + + if (session.graph != graph) + throw new ValueError("Cannot use the default session to evaluate tensor: " + + "the tensor's graph is different from the session's " + + "graph. Pass an explicit session to " + + "`eval(session=sess)`."); + } + else + { + if (session.graph != graph) + throw new ValueError("Cannot use the default session to evaluate tensor: " + + "the tensor's graph is different from the session's " + + "graph. Pass an explicit session to " + + "`eval(session=sess)`."); + } + + return session.run(tensor, feed_dict); } /// @@ -254,7 +276,7 @@ namespace Tensorflow /// The default `Session` being used in the current thread. public static Session get_default_session() { - return null; + return tf.Session(); } } } diff --git a/test/TensorFlowNET.UnitTest/SessionTest.cs b/test/TensorFlowNET.UnitTest/SessionTest.cs index 3d79d747..d187b856 100644 --- a/test/TensorFlowNET.UnitTest/SessionTest.cs +++ b/test/TensorFlowNET.UnitTest/SessionTest.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using NumSharp.Core; using System; using System.Collections.Generic; using System.Text; @@ -74,5 +75,18 @@ namespace TensorFlowNET.UnitTest graph.Dispose(); s.Dispose(); } + + [TestMethod] + public void EvalTensor() + { + var a = constant_op.constant(np.array(3.0).reshape(1, 1)); + var b = constant_op.constant(np.array(2.0).reshape(1, 1)); + var c = math_ops.matmul(a, b, name: "matmul"); + Python.with(tf.Session(), delegate + { + var result = c.eval(); + Assert.AreEqual(6, result.Data()[0]); + }); + } } }