diff --git a/src/TensorFlowNET.Core/APIs/tf.math.cs b/src/TensorFlowNET.Core/APIs/tf.math.cs index 24131a2d..8c6248e3 100644 --- a/src/TensorFlowNET.Core/APIs/tf.math.cs +++ b/src/TensorFlowNET.Core/APIs/tf.math.cs @@ -448,6 +448,17 @@ namespace Tensorflow public Tensor reduce_prod(Tensor input_tensor, int[] axis = null, bool keepdims = false, string name = null) => math_ops.reduce_prod(input_tensor, axis: axis, keepdims: keepdims, name: name); + /// + /// Computes the sum of elements across dimensions of a tensor. + /// + /// + /// + /// + /// + /// + public Tensor reduce_sum(Tensor[] input_tensors, int? axis = null, bool keepdims = false, string name = null) + => math_ops.reduce_sum(input_tensors, axis: axis, keepdims: keepdims, name: name); + /// /// Computes the sum of elements across dimensions of a tensor. /// diff --git a/src/TensorFlowNET.Core/Eager/Context.cs b/src/TensorFlowNET.Core/Eager/Context.cs index b2909327..7f428229 100644 --- a/src/TensorFlowNET.Core/Eager/Context.cs +++ b/src/TensorFlowNET.Core/Eager/Context.cs @@ -9,6 +9,7 @@ namespace Tensorflow.Eager public int default_execution_mode; public string device_name = ""; + bool _initialized = false; public Context(ContextOptions opts, Status status) { @@ -16,6 +17,13 @@ namespace Tensorflow.Eager status.Check(true); } + public void ensure_initialized() + { + if (_initialized) + return; + _initialized = true; + } + /// /// Dispose any unmanaged resources related to given . /// @@ -27,5 +35,8 @@ namespace Tensorflow.Eager public static implicit operator IntPtr(Context ctx) => ctx._handle; + + public static implicit operator TFE_Context(Context ctx) + => new TFE_Context(ctx._handle); } } diff --git a/src/TensorFlowNET.Core/Eager/ContextOptions.cs b/src/TensorFlowNET.Core/Eager/ContextOptions.cs index 12c4cdfc..8659b6ce 100644 --- a/src/TensorFlowNET.Core/Eager/ContextOptions.cs +++ b/src/TensorFlowNET.Core/Eager/ContextOptions.cs @@ -17,6 +17,10 @@ namespace Tensorflow.Eager public static implicit operator IntPtr(ContextOptions opts) => opts._handle; + + public static implicit operator TFE_ContextOptions(ContextOptions opts) + => new TFE_ContextOptions(opts._handle); + } } diff --git a/src/TensorFlowNET.Core/Eager/Execute.cs b/src/TensorFlowNET.Core/Eager/Execute.cs index e5a2db2f..aece7aab 100644 --- a/src/TensorFlowNET.Core/Eager/Execute.cs +++ b/src/TensorFlowNET.Core/Eager/Execute.cs @@ -1,12 +1,67 @@ using System.Collections.Generic; +using System; +using System.Linq; namespace Tensorflow.Eager { public class Execute { + /// + /// Execute a TensorFlow operation. + /// + /// + /// Name of the TensorFlow operation (see REGISTER_OP in C++ code) to + /// execute. + /// + /// + /// The number of outputs of the operation to fetch. + /// + /// + /// A list of inputs to the operation. Each entry should be a Tensor, or + /// a value which can be passed to the Tensor constructor to create one. + /// + /// + /// A tuple with alternating string attr names and attr values for this + /// operation. + /// + /// The value of context.context(). + /// Customized name for the operation. + /// List of output Tensor objects. The list is empty if there are no outputs + public Tensor execute(Context ctx, string op_name, Tensor[] inputs, object[] attrs, string name = null) + { + ctx.ensure_initialized(); + using (var status = new Status()) + { + var retVals = wrap_tfe_src.TFE_Py_Execute(ctx, ctx.device_name, op_name, inputs, attrs, 1, status); + + var t = c_api.TFE_TensorHandleResolve(retVals[0], status); + status.Check(true); + + return new EagerTensor(t); + } + } + + public (TF_DataType, Tensor) args_to_matching_eager(Tensor[] l, Context ctx, TF_DataType default_dtype = TF_DataType.DtInvalid) + { + var dtype = default_dtype; + if(dtype == TF_DataType.DtInvalid) + { + var tensor = ops.convert_to_tensor(l, dtype, preferred_dtype: default_dtype, ctx: ctx); + + if (dtype == TF_DataType.DtInvalid) + dtype = tensor.dtype; + + return (dtype, tensor); + } + else + { + return (dtype, l[0]); + } + } + public void record_gradient(string op_name, InputList inputs, Dictionary attrs, Tensor[] results, string name = null) { - pywrap_tfe_src.RecordGradient(op_name, inputs._inputs, attrs, results, name); + wrap_tfe_src.RecordGradient(op_name, inputs._inputs, attrs, results, name); } } } diff --git a/src/TensorFlowNET.Core/Eager/TFE_Context.cs b/src/TensorFlowNET.Core/Eager/TFE_Context.cs new file mode 100644 index 00000000..dc16909d --- /dev/null +++ b/src/TensorFlowNET.Core/Eager/TFE_Context.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tensorflow.Eager +{ + public struct TFE_Context + { + IntPtr _handle; + + public TFE_Context(IntPtr handle) + => _handle = handle; + + public static implicit operator TFE_Context(IntPtr handle) + => new TFE_Context(handle); + + public static implicit operator IntPtr(TFE_Context tensor) + => tensor._handle; + + public override string ToString() + => $"TFE_Context {_handle}"; + } +} diff --git a/src/TensorFlowNET.Core/Eager/TFE_ContextOptions.cs b/src/TensorFlowNET.Core/Eager/TFE_ContextOptions.cs new file mode 100644 index 00000000..f43d97f8 --- /dev/null +++ b/src/TensorFlowNET.Core/Eager/TFE_ContextOptions.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tensorflow.Eager +{ + public struct TFE_ContextOptions + { + IntPtr _handle; + + public TFE_ContextOptions(IntPtr handle) + => _handle = handle; + + public static implicit operator TFE_ContextOptions(IntPtr handle) + => new TFE_ContextOptions(handle); + + public static implicit operator IntPtr(TFE_ContextOptions tensor) + => tensor._handle; + + public override string ToString() + => $"TFE_ContextOptions {_handle}"; + } +} diff --git a/src/TensorFlowNET.Core/Eager/TFE_Executor.cs b/src/TensorFlowNET.Core/Eager/TFE_Executor.cs new file mode 100644 index 00000000..ed88dd30 --- /dev/null +++ b/src/TensorFlowNET.Core/Eager/TFE_Executor.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tensorflow.Eager +{ + public struct TFE_Executor + { + IntPtr _handle; + + public TFE_Executor(IntPtr handle) + => _handle = handle; + + public static implicit operator TFE_Executor(IntPtr handle) + => new TFE_Executor(handle); + + public static implicit operator IntPtr(TFE_Executor tensor) + => tensor._handle; + + public override string ToString() + => $"TFE_Executor {_handle}"; + } +} diff --git a/src/TensorFlowNET.Core/Eager/TFE_Op.cs b/src/TensorFlowNET.Core/Eager/TFE_Op.cs new file mode 100644 index 00000000..538ada78 --- /dev/null +++ b/src/TensorFlowNET.Core/Eager/TFE_Op.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tensorflow.Eager +{ + public struct TFE_Op + { + IntPtr _handle; + + public TFE_Op(IntPtr handle) + => _handle = handle; + + public static implicit operator TFE_Op(IntPtr handle) + => new TFE_Op(handle); + + public static implicit operator IntPtr(TFE_Op tensor) + => tensor._handle; + + public override string ToString() + => $"TFE_Op {_handle}"; + } +} diff --git a/src/TensorFlowNET.Core/Eager/TFE_TensorHandle.cs b/src/TensorFlowNET.Core/Eager/TFE_TensorHandle.cs new file mode 100644 index 00000000..a0c59259 --- /dev/null +++ b/src/TensorFlowNET.Core/Eager/TFE_TensorHandle.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tensorflow.Eager +{ + public struct TFE_TensorHandle + { + IntPtr _handle; + + public TFE_TensorHandle(IntPtr handle) + => _handle = handle; + + public static implicit operator TFE_TensorHandle(IntPtr handle) + => new TFE_TensorHandle(handle); + + public static implicit operator IntPtr(TFE_TensorHandle tensor) + => tensor._handle; + + public override string ToString() + => $"TFE_TensorHandle {_handle}"; + } +} diff --git a/src/TensorFlowNET.Core/Eager/c_api.eager.cs b/src/TensorFlowNET.Core/Eager/c_api.eager.cs index 2cd3a68c..a241ee0f 100644 --- a/src/TensorFlowNET.Core/Eager/c_api.eager.cs +++ b/src/TensorFlowNET.Core/Eager/c_api.eager.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using Tensorflow.Eager; using TFE_Executor = System.IntPtr; namespace Tensorflow @@ -11,7 +12,7 @@ namespace Tensorflow /// /// TFE_ContextOptions* [DllImport(TensorFlowLibName)] - public static extern IntPtr TFE_NewContextOptions(); + public static extern TFE_ContextOptions TFE_NewContextOptions(); /// /// Destroy an options object. @@ -70,7 +71,7 @@ namespace Tensorflow /// TF_Status* /// TFE_Context* [DllImport(TensorFlowLibName)] - public static extern IntPtr TFE_NewContext(IntPtr opts, IntPtr status); + public static extern TFE_Context TFE_NewContext(IntPtr opts, IntPtr status); /// /// @@ -88,7 +89,7 @@ namespace Tensorflow /// int* /// TF_Status* [DllImport(TensorFlowLibName)] - public static extern void TFE_Execute(IntPtr op, IntPtr[] retvals, ref int num_retvals, IntPtr status); + public static extern void TFE_Execute(TFE_Op op, IntPtr[] retvals, ref int num_retvals, IntPtr status); /// /// @@ -98,7 +99,7 @@ namespace Tensorflow /// TF_Status* /// [DllImport(TensorFlowLibName)] - public static extern IntPtr TFE_NewOp(IntPtr ctx, string op_or_function_name, IntPtr status); + public static extern TFE_Op TFE_NewOp(IntPtr ctx, string op_or_function_name, IntPtr status); /// /// @@ -150,7 +151,7 @@ namespace Tensorflow /// /// [DllImport(TensorFlowLibName)] - public static extern void TFE_OpSetDevice(IntPtr op, string device_name, IntPtr status); + public static extern void TFE_OpSetDevice(TFE_Op op, string device_name, IntPtr status); /// /// @@ -167,7 +168,7 @@ namespace Tensorflow /// const tensorflow::Tensor& /// TFE_TensorHandle* [DllImport(TensorFlowLibName)] - public static extern IntPtr TFE_NewTensorHandle(IntPtr t, IntPtr status); + public static extern TFE_TensorHandle TFE_NewTensorHandle(IntPtr t, IntPtr status); /// /// Sets the default execution mode (sync/async). Note that this can be @@ -195,7 +196,7 @@ namespace Tensorflow /// TF_Status* /// [DllImport(TensorFlowLibName)] - public static extern IntPtr TFE_TensorHandleResolve(IntPtr h, IntPtr status); + public static extern TF_Tensor TFE_TensorHandleResolve(IntPtr h, IntPtr status); /// /// This function will block till the operation that produces `h` has completed. @@ -252,7 +253,7 @@ namespace Tensorflow /// /// TFE_Executor* [DllImport(TensorFlowLibName)] - public static extern IntPtr TFE_NewExecutor(bool is_async); + public static extern TFE_Executor TFE_NewExecutor(bool is_async); /// /// Deletes the eager Executor without waiting for enqueued nodes. Please call diff --git a/src/TensorFlowNET.Core/Eager/wrap_tfe_src.RecordGradient.cs b/src/TensorFlowNET.Core/Eager/wrap_tfe_src.RecordGradient.cs new file mode 100644 index 00000000..88e8ef88 --- /dev/null +++ b/src/TensorFlowNET.Core/Eager/wrap_tfe_src.RecordGradient.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; +using System; +using static Tensorflow.OpDef.Types; + +namespace Tensorflow.Eager +{ + /// + /// python\eager\pywrap_tfe_src.cc + /// + public partial class wrap_tfe_src + { + public static void RecordGradient(string op_name, Tensor[] inputs, Dictionary attrs, Tensor[] results, string name = null) + { + var input_ids = inputs.Select(x => x.Id).ToArray(); + var input_dtypes = inputs.Select(x => x.dtype).ToArray(); + + bool should_record = false; + foreach (var input_dtype in input_dtypes) + { + if (Tape.IsDtypeTrainable(input_dtype.as_datatype_enum())) + { + should_record = true; + break; + } + } + if (!should_record) return; + + var op_outputs = results; + var op_inputs = inputs; + } + } +} diff --git a/src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_Execute.cs b/src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_Execute.cs new file mode 100644 index 00000000..0271250e --- /dev/null +++ b/src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_Execute.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.Linq; +using System; +using static Tensorflow.OpDef.Types; + +namespace Tensorflow.Eager +{ + /// + /// python\eager\pywrap_tfe_src.cc + /// + public partial class wrap_tfe_src + { + public static IntPtr[] TFE_Py_Execute(Context ctx, + string device_name, + string op_name, + Tensor[] inputs, + object[] attrs, + int num_outputs, + Status status) + => TFE_Py_ExecuteCancelable(ctx, device_name, op_name, inputs, attrs, num_outputs, status); + + public static IntPtr[] TFE_Py_ExecuteCancelable(Context ctx, + string device_name, + string op_name, + Tensor[] inputs, + object[] attrs, + int num_outputs, + Status status) + { + var op = c_api.TFE_NewOp(ctx, op_name, status); + status.Check(true); + c_api.TFE_OpSetDevice(op, device_name, status); + if(status.ok()) + { + for (int i = 0; i < inputs.Length; ++i) + { + var tensor_handle = c_api.TFE_NewTensorHandle(inputs[i], status); + c_api.TFE_OpAddInput(op, tensor_handle, status); + } + } + if (status.ok()) + SetOpAttrs(ctx, op, attrs, 0, status); + + var outputs = new IntPtr[num_outputs]; + if (status.ok()) + { + c_api.TFE_Execute(op, outputs, ref num_outputs, status); + status.Check(true); + } + return outputs; + } + } +} diff --git a/src/TensorFlowNET.Core/Eager/pywrap_tfe_src.cs b/src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_FastPathExecute.cs similarity index 85% rename from src/TensorFlowNET.Core/Eager/pywrap_tfe_src.cs rename to src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_FastPathExecute.cs index 792e945d..25ed69f5 100644 --- a/src/TensorFlowNET.Core/Eager/pywrap_tfe_src.cs +++ b/src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_FastPathExecute.cs @@ -8,7 +8,7 @@ namespace Tensorflow.Eager /// /// python\eager\pywrap_tfe_src.cc /// - public class pywrap_tfe_src + public partial class wrap_tfe_src { static int kFastPathExecuteInputStartIndex = 0; public static EagerTensor TFE_Py_FastPathExecute(Context ctx, @@ -19,11 +19,10 @@ namespace Tensorflow.Eager params object[] args) { int args_size = args.Length; - IntPtr op = IntPtr.Zero; var attr_list_sizes = new Dictionary(); using (var status = new Status()) { - op = c_api.TFE_NewOp(ctx, opName, status); + var op = c_api.TFE_NewOp(ctx, opName, status); var op_def = Graph.TFE_GetOpDef(opName); @@ -52,9 +51,9 @@ namespace Tensorflow.Eager for (int i = 0; i < op_def.InputArg.Count; i++) { var input_arg = op_def.InputArg[i]; - int len = (args[kFastPathExecuteInputStartIndex + i] as object[]).Length; if (!string.IsNullOrEmpty(input_arg.NumberAttr)) { + int len = (args[kFastPathExecuteInputStartIndex + i] as object[]).Length; c_api.TFE_OpSetAttrInt(op, input_arg.NumberAttr, len); attr_list_sizes[input_arg.NumberAttr] = len; @@ -125,13 +124,16 @@ namespace Tensorflow.Eager IntPtr op, Status status) { - IntPtr input_handle = IntPtr.Zero; + TFE_TensorHandle input_handle; switch (inputs) { case Tensor input: input_handle = c_api.TFE_NewTensorHandle(input, status); break; + case Tensor[] input_list: + input_handle = c_api.TFE_NewTensorHandle(input_list[0], status); + break; default: throw new NotImplementedException(""); } @@ -148,6 +150,25 @@ namespace Tensorflow.Eager return true; } + private static void SetOpAttrs(Context ctx, TFE_Op op, object[] attrs, int start_index, Status out_status) + { + var len = attrs.Length; + for (int i = 0; i < len; i += 2) + { + var key = attrs[start_index + i].ToString(); + var value = attrs[start_index + i + 1]; + + byte is_list = 0; + var type = c_api.TFE_OpGetAttrType(op, key, ref is_list, out_status); + if (!out_status.ok()) return; + if (is_list != 0) + SetOpAttrList(ctx, op, key, value, type, null, out_status); + else + SetOpAttrScalar(ctx, op, key, value, type, null, out_status); + out_status.Check(true); + } + } + /// /// This function will set the op attrs required. If an attr has the value of /// None, then it will read the AttrDef to get the default value and set that @@ -188,6 +209,14 @@ namespace Tensorflow.Eager } } + private static bool SetOpAttrList(Context ctx, IntPtr op, + string key, object value, TF_AttrType type, + Dictionary attr_list_sizes, + Status status) + { + return false; + } + private static bool SetOpAttrScalar(Context ctx, IntPtr op, string key, object value, TF_AttrType type, Dictionary attr_list_sizes, @@ -213,25 +242,5 @@ namespace Tensorflow.Eager return true; } - - public static void RecordGradient(string op_name, Tensor[] inputs, Dictionary attrs, Tensor[] results, string name = null) - { - var input_ids = inputs.Select(x => x.Id).ToArray(); - var input_dtypes = inputs.Select(x => x.dtype).ToArray(); - - bool should_record = false; - foreach (var input_dtype in input_dtypes) - { - if (Tape.IsDtypeTrainable(input_dtype.as_datatype_enum())) - { - should_record = true; - break; - } - } - if (!should_record) return; - - var op_outputs = results; - var op_inputs = inputs; - } } } diff --git a/src/TensorFlowNET.Core/Operations/gen_array_ops.cs b/src/TensorFlowNET.Core/Operations/gen_array_ops.cs index ad7013dd..eea1f1a1 100644 --- a/src/TensorFlowNET.Core/Operations/gen_array_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_array_ops.cs @@ -125,7 +125,7 @@ namespace Tensorflow { if(tf.context.executing_eagerly()) { - var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, tf.context.device_name, "Pack", name, null, values, "axis", axis); + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, tf.context.device_name, "Pack", name, null, values, "axis", axis); return _result; } diff --git a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs index b08e4f0c..aa0a6785 100644 --- a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs @@ -14,6 +14,7 @@ limitations under the License. ******************************************************************************/ +using System; using Tensorflow.Eager; using static Tensorflow.Binding; @@ -22,6 +23,7 @@ namespace Tensorflow public static class gen_math_ops { public static OpDefLibrary _op_def_lib = new OpDefLibrary(); + public static Execute _execute = new Execute(); public static Tensor _all(Tensor input, Tensor axis, bool keep_dims = false, string name = null) { @@ -114,11 +116,36 @@ namespace Tensorflow /// A `Tensor`. Has the same type as `input`. public static Tensor mean(T1 input, T2 axis, bool keep_dims= false, string name = null) { + if (tf.context.executing_eagerly()) + { + try + { + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, tf.context.device_name, "Mean", name, null, input, axis, "keep_dims", keep_dims); + return _result; + } + catch (Exception ex) + { + return mean_eager_fallback(input as Tensor[], axis as Tensor, keep_dims: keep_dims, name: name, ctx: tf.context); + } + } + var _op = _op_def_lib._apply_op_helper("Mean", name, args: new { input, reduction_indices = axis, keep_dims = keep_dims }); return _op.output; } + private static Tensor mean_eager_fallback(Tensor[] inputs, Tensor axis, bool keep_dims = false, string name = null, Context ctx = null) + { + var (_attr_T, input) = _execute.args_to_matching_eager(inputs, ctx); + var (_attr_Tidx, axis1) = _execute.args_to_matching_eager(new[] { axis }, ctx, TF_DataType.TF_INT32); + var _inputs_flat = new Tensor[] { input, axis1 }; + + var _attrs = new object[] { "keep_dims", keep_dims, "T", _attr_T, "Tidx", _attr_Tidx }; + + var _result = _execute.execute(ctx, "Mean", _inputs_flat, _attrs, name: name); + return _result; + } + public static Tensor prod(T1 input, T2 axis, bool keep_dims = false, string name = null) { var _op = _op_def_lib._apply_op_helper("Prod", name, args: new { input, reduction_indices = axis, keep_dims }); @@ -144,7 +171,7 @@ namespace Tensorflow { if (tf.context.executing_eagerly()) { - var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Add", name, null, x, y); + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Add", name, null, x, y); return _result; } @@ -466,7 +493,7 @@ namespace Tensorflow { if (tf.context.executing_eagerly()) { - var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Cast", name, null, x, "DstT", DstT, "Truncate", Truncate); + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Cast", name, null, x, "DstT", DstT, "Truncate", Truncate); return _result; } @@ -493,7 +520,7 @@ namespace Tensorflow { if (tf.context.executing_eagerly()) { - var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Sub", name, null, x, y); + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Sub", name, null, x, y); return _result; } @@ -544,7 +571,7 @@ namespace Tensorflow { if (tf.context.executing_eagerly()) { - var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Mul", name, null, x, y); + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "Mul", name, null, x, y); return _result; } @@ -564,7 +591,7 @@ namespace Tensorflow { if (tf.context.executing_eagerly()) { - var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "RealDiv", name, null, x, y); + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "RealDiv", name, null, x, y); return _result; } @@ -591,7 +618,7 @@ namespace Tensorflow { if (tf.context.executing_eagerly()) { - var _result = pywrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "FloorDiv", name, null, x, y); + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, "", "FloorDiv", name, null, x, y); return _result; } @@ -709,6 +736,14 @@ namespace Tensorflow public static Tensor _sum(Tx input, Ty axis = default, bool keep_dims = false, string name = null) { + if (tf.context.executing_eagerly()) + { + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, tf.context.device_name, + "Sum", name, null, + input, axis, "keep_dims", keep_dims); + return _result; + } + var _op = _op_def_lib._apply_op_helper("Sum", name, args: new { input, reduction_indices = axis, keep_dims }); return _op.outputs[0]; @@ -724,6 +759,12 @@ namespace Tensorflow /// public static Tensor range(Tensor start, Tensor limit, Tensor delta, string name = null) { + if (tf.context.executing_eagerly()) + { + var _result = wrap_tfe_src.TFE_Py_FastPathExecute(tf.context, tf.context.device_name, "Range", name, null, start, limit, delta); + return _result; + } + var _op = _op_def_lib._apply_op_helper("Range", name, new { start, limit, delta }); return _op.outputs[0]; diff --git a/src/TensorFlowNET.Core/Operations/math_ops.cs b/src/TensorFlowNET.Core/Operations/math_ops.cs index 8e147b41..de9d761c 100644 --- a/src/TensorFlowNET.Core/Operations/math_ops.cs +++ b/src/TensorFlowNET.Core/Operations/math_ops.cs @@ -480,6 +480,13 @@ namespace Tensorflow throw new NotImplementedException(); } + public static Tensor reduce_sum(Tensor[] input_tensors, int? axis = null, bool keepdims = false, string name = null) + { + var dims = _ReductionDims(input_tensors, axis); + var m = gen_math_ops._sum(input_tensors, dims, keep_dims: keepdims, name: name); + return _may_reduce_to_scalar(keepdims, axis, m); + } + public static Tensor reduce_sum(Tensor input_tensor, Tensor axis = null, bool keepdims = false, string name = null) { var r = _ReductionDims(input_tensor, axis); diff --git a/src/TensorFlowNET.Core/Status/Status.cs b/src/TensorFlowNET.Core/Status/Status.cs index 928f39f2..1e2e222c 100644 --- a/src/TensorFlowNET.Core/Status/Status.cs +++ b/src/TensorFlowNET.Core/Status/Status.cs @@ -47,6 +47,8 @@ namespace Tensorflow TF_SetStatus(_handle, code, msg); } + public bool ok() => Code == TF_Code.TF_OK; + /// /// Check status /// Throw exception with error message if code != TF_OK diff --git a/src/TensorFlowNET.Core/Tensors/TF_Tensor.cs b/src/TensorFlowNET.Core/Tensors/TF_Tensor.cs index ea80f073..210501f5 100644 --- a/src/TensorFlowNET.Core/Tensors/TF_Tensor.cs +++ b/src/TensorFlowNET.Core/Tensors/TF_Tensor.cs @@ -3,11 +3,20 @@ using System.Runtime.InteropServices; namespace Tensorflow { - [StructLayout(LayoutKind.Sequential)] public struct TF_Tensor { - public TF_DataType dtype; - public IntPtr shape; - public IntPtr buffer; + IntPtr _handle; + + public TF_Tensor(IntPtr handle) + => _handle = handle; + + public static implicit operator TF_Tensor(IntPtr handle) + => new TF_Tensor(handle); + + public static implicit operator IntPtr(TF_Tensor tensor) + => tensor._handle; + + public override string ToString() + => $"TF_Tensor {_handle}"; } } diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Implicit.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Implicit.cs index b5fdde48..94d95eba 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.Implicit.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.Implicit.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Text; +using Tensorflow.Eager; namespace Tensorflow { @@ -15,13 +16,12 @@ namespace Tensorflow } public static implicit operator Operation(Tensor tensor) - { - return tensor.op; - } + => tensor.op; + + public static implicit operator TF_Tensor(Tensor tensor) + => new TF_Tensor(tensor._handle); public static implicit operator Tensor(IntPtr handle) - { - return new Tensor(handle); - } + => new Tensor(handle); } } diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Value.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Value.cs index c4251e28..0b51bec5 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.Value.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.Value.cs @@ -157,7 +157,15 @@ namespace Tensorflow } else { - throw new NotImplementedException("numpy not implemented when ndim > 0"); + switch (dtype) + { + case TF_DataType.TF_STRING: + return StringData(); + case TF_DataType.TF_INT32: + return ToArray(); + default: + return BufferToArray(); + } } } diff --git a/src/TensorFlowNET.Core/ops.cs b/src/TensorFlowNET.Core/ops.cs index 9ac0a042..2fe5ef4e 100644 --- a/src/TensorFlowNET.Core/ops.cs +++ b/src/TensorFlowNET.Core/ops.cs @@ -23,6 +23,7 @@ using System.Threading; using NumSharp; using Tensorflow.Util; using static Tensorflow.Binding; +using Tensorflow.Eager; namespace Tensorflow { @@ -95,15 +96,19 @@ namespace Tensorflow /// /// /// - public static Tensor convert_to_tensor(object value, TF_DataType dtype = TF_DataType.DtInvalid, string name = null, TF_DataType preferred_dtype = TF_DataType.DtInvalid) + public static Tensor convert_to_tensor(object value, + TF_DataType dtype = TF_DataType.DtInvalid, + string name = null, + TF_DataType preferred_dtype = TF_DataType.DtInvalid, + Context ctx = null) { - return convert_to_tensor_v2(value, dtype, preferred_dtype, name); + return internal_convert_to_tensor(value, + dtype: dtype, + name: name, + preferred_dtype: preferred_dtype, + as_ref: false); } - public static Tensor convert_to_tensor_v2(object value, TF_DataType dtype = TF_DataType.DtInvalid, TF_DataType dtype_hint = TF_DataType.DtInvalid, string name = null) - { - return internal_convert_to_tensor(value, dtype: dtype, name: name, preferred_dtype: dtype_hint, as_ref: false); - } public static Tensor convert_to_tensor_or_composite(Tensor value, TF_DataType dtype = TF_DataType.DtInvalid, string name = null) {