| @@ -448,6 +448,17 @@ namespace Tensorflow | |||||
| public Tensor reduce_prod(Tensor input_tensor, int[] axis = null, bool keepdims = false, string name = null) | 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); | => math_ops.reduce_prod(input_tensor, axis: axis, keepdims: keepdims, name: name); | ||||
| /// <summary> | |||||
| /// Computes the sum of elements across dimensions of a tensor. | |||||
| /// </summary> | |||||
| /// <param name="input_tensors"></param> | |||||
| /// <param name="axis"></param> | |||||
| /// <param name="keepdims"></param> | |||||
| /// <param name="name"></param> | |||||
| /// <returns></returns> | |||||
| 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); | |||||
| /// <summary> | /// <summary> | ||||
| /// Computes the sum of elements across dimensions of a tensor. | /// Computes the sum of elements across dimensions of a tensor. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -9,6 +9,7 @@ namespace Tensorflow.Eager | |||||
| public int default_execution_mode; | public int default_execution_mode; | ||||
| public string device_name = ""; | public string device_name = ""; | ||||
| bool _initialized = false; | |||||
| public Context(ContextOptions opts, Status status) | public Context(ContextOptions opts, Status status) | ||||
| { | { | ||||
| @@ -16,6 +17,13 @@ namespace Tensorflow.Eager | |||||
| status.Check(true); | status.Check(true); | ||||
| } | } | ||||
| public void ensure_initialized() | |||||
| { | |||||
| if (_initialized) | |||||
| return; | |||||
| _initialized = true; | |||||
| } | |||||
| /// <summary> | /// <summary> | ||||
| /// Dispose any unmanaged resources related to given <paramref name="handle"/>. | /// Dispose any unmanaged resources related to given <paramref name="handle"/>. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -27,5 +35,8 @@ namespace Tensorflow.Eager | |||||
| public static implicit operator IntPtr(Context ctx) | public static implicit operator IntPtr(Context ctx) | ||||
| => ctx._handle; | => ctx._handle; | ||||
| public static implicit operator TFE_Context(Context ctx) | |||||
| => new TFE_Context(ctx._handle); | |||||
| } | } | ||||
| } | } | ||||
| @@ -17,6 +17,10 @@ namespace Tensorflow.Eager | |||||
| public static implicit operator IntPtr(ContextOptions opts) | public static implicit operator IntPtr(ContextOptions opts) | ||||
| => opts._handle; | => opts._handle; | ||||
| public static implicit operator TFE_ContextOptions(ContextOptions opts) | |||||
| => new TFE_ContextOptions(opts._handle); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,12 +1,67 @@ | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System; | |||||
| using System.Linq; | |||||
| namespace Tensorflow.Eager | namespace Tensorflow.Eager | ||||
| { | { | ||||
| public class Execute | public class Execute | ||||
| { | { | ||||
| /// <summary> | |||||
| /// Execute a TensorFlow operation. | |||||
| /// </summary> | |||||
| /// <param name="op_name"> | |||||
| /// Name of the TensorFlow operation (see REGISTER_OP in C++ code) to | |||||
| /// execute. | |||||
| /// </param> | |||||
| /// <param name="num_outputs"> | |||||
| /// The number of outputs of the operation to fetch. | |||||
| /// </param> | |||||
| /// <param name="inputs"> | |||||
| /// 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. | |||||
| /// </param> | |||||
| /// <param name="attrs"> | |||||
| /// A tuple with alternating string attr names and attr values for this | |||||
| /// operation. | |||||
| /// </param> | |||||
| /// <param name="ctx">The value of context.context().</param> | |||||
| /// <param name="name">Customized name for the operation.</param> | |||||
| /// <returns>List of output Tensor objects. The list is empty if there are no outputs</returns> | |||||
| 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<string, object> attrs, Tensor[] results, string name = null) | public void record_gradient(string op_name, InputList inputs, Dictionary<string, object> 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); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -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}"; | |||||
| } | |||||
| } | |||||
| @@ -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}"; | |||||
| } | |||||
| } | |||||
| @@ -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}"; | |||||
| } | |||||
| } | |||||
| @@ -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}"; | |||||
| } | |||||
| } | |||||
| @@ -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}"; | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,6 @@ | |||||
| using System; | using System; | ||||
| using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
| using Tensorflow.Eager; | |||||
| using TFE_Executor = System.IntPtr; | using TFE_Executor = System.IntPtr; | ||||
| namespace Tensorflow | namespace Tensorflow | ||||
| @@ -11,7 +12,7 @@ namespace Tensorflow | |||||
| /// </summary> | /// </summary> | ||||
| /// <returns>TFE_ContextOptions*</returns> | /// <returns>TFE_ContextOptions*</returns> | ||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static extern IntPtr TFE_NewContextOptions(); | |||||
| public static extern TFE_ContextOptions TFE_NewContextOptions(); | |||||
| /// <summary> | /// <summary> | ||||
| /// Destroy an options object. | /// Destroy an options object. | ||||
| @@ -70,7 +71,7 @@ namespace Tensorflow | |||||
| /// <param name="status">TF_Status*</param> | /// <param name="status">TF_Status*</param> | ||||
| /// <returns>TFE_Context*</returns> | /// <returns>TFE_Context*</returns> | ||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static extern IntPtr TFE_NewContext(IntPtr opts, IntPtr status); | |||||
| public static extern TFE_Context TFE_NewContext(IntPtr opts, IntPtr status); | |||||
| /// <summary> | /// <summary> | ||||
| /// | /// | ||||
| @@ -88,7 +89,7 @@ namespace Tensorflow | |||||
| /// <param name="num_retvals">int*</param> | /// <param name="num_retvals">int*</param> | ||||
| /// <param name="status">TF_Status*</param> | /// <param name="status">TF_Status*</param> | ||||
| [DllImport(TensorFlowLibName)] | [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); | |||||
| /// <summary> | /// <summary> | ||||
| /// | /// | ||||
| @@ -98,7 +99,7 @@ namespace Tensorflow | |||||
| /// <param name="status">TF_Status*</param> | /// <param name="status">TF_Status*</param> | ||||
| /// <returns></returns> | /// <returns></returns> | ||||
| [DllImport(TensorFlowLibName)] | [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); | |||||
| /// <summary> | /// <summary> | ||||
| /// | /// | ||||
| @@ -150,7 +151,7 @@ namespace Tensorflow | |||||
| /// <param name="device_name"></param> | /// <param name="device_name"></param> | ||||
| /// <param name="status"></param> | /// <param name="status"></param> | ||||
| [DllImport(TensorFlowLibName)] | [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); | |||||
| /// <summary> | /// <summary> | ||||
| /// | /// | ||||
| @@ -167,7 +168,7 @@ namespace Tensorflow | |||||
| /// <param name="t">const tensorflow::Tensor&</param> | /// <param name="t">const tensorflow::Tensor&</param> | ||||
| /// <returns>TFE_TensorHandle*</returns> | /// <returns>TFE_TensorHandle*</returns> | ||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static extern IntPtr TFE_NewTensorHandle(IntPtr t, IntPtr status); | |||||
| public static extern TFE_TensorHandle TFE_NewTensorHandle(IntPtr t, IntPtr status); | |||||
| /// <summary> | /// <summary> | ||||
| /// Sets the default execution mode (sync/async). Note that this can be | /// Sets the default execution mode (sync/async). Note that this can be | ||||
| @@ -195,7 +196,7 @@ namespace Tensorflow | |||||
| /// <param name="status">TF_Status*</param> | /// <param name="status">TF_Status*</param> | ||||
| /// <returns></returns> | /// <returns></returns> | ||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static extern IntPtr TFE_TensorHandleResolve(IntPtr h, IntPtr status); | |||||
| public static extern TF_Tensor TFE_TensorHandleResolve(IntPtr h, IntPtr status); | |||||
| /// <summary> | /// <summary> | ||||
| /// This function will block till the operation that produces `h` has completed. | /// This function will block till the operation that produces `h` has completed. | ||||
| @@ -252,7 +253,7 @@ namespace Tensorflow | |||||
| /// <param name="is_async"></param> | /// <param name="is_async"></param> | ||||
| /// <returns>TFE_Executor*</returns> | /// <returns>TFE_Executor*</returns> | ||||
| [DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
| public static extern IntPtr TFE_NewExecutor(bool is_async); | |||||
| public static extern TFE_Executor TFE_NewExecutor(bool is_async); | |||||
| /// <summary> | /// <summary> | ||||
| /// Deletes the eager Executor without waiting for enqueued nodes. Please call | /// Deletes the eager Executor without waiting for enqueued nodes. Please call | ||||
| @@ -0,0 +1,33 @@ | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System; | |||||
| using static Tensorflow.OpDef.Types; | |||||
| namespace Tensorflow.Eager | |||||
| { | |||||
| /// <summary> | |||||
| /// python\eager\pywrap_tfe_src.cc | |||||
| /// </summary> | |||||
| public partial class wrap_tfe_src | |||||
| { | |||||
| public static void RecordGradient(string op_name, Tensor[] inputs, Dictionary<string, object> 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; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,53 @@ | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System; | |||||
| using static Tensorflow.OpDef.Types; | |||||
| namespace Tensorflow.Eager | |||||
| { | |||||
| /// <summary> | |||||
| /// python\eager\pywrap_tfe_src.cc | |||||
| /// </summary> | |||||
| 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; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -8,7 +8,7 @@ namespace Tensorflow.Eager | |||||
| /// <summary> | /// <summary> | ||||
| /// python\eager\pywrap_tfe_src.cc | /// python\eager\pywrap_tfe_src.cc | ||||
| /// </summary> | /// </summary> | ||||
| public class pywrap_tfe_src | |||||
| public partial class wrap_tfe_src | |||||
| { | { | ||||
| static int kFastPathExecuteInputStartIndex = 0; | static int kFastPathExecuteInputStartIndex = 0; | ||||
| public static EagerTensor TFE_Py_FastPathExecute(Context ctx, | public static EagerTensor TFE_Py_FastPathExecute(Context ctx, | ||||
| @@ -19,11 +19,10 @@ namespace Tensorflow.Eager | |||||
| params object[] args) | params object[] args) | ||||
| { | { | ||||
| int args_size = args.Length; | int args_size = args.Length; | ||||
| IntPtr op = IntPtr.Zero; | |||||
| var attr_list_sizes = new Dictionary<string, long>(); | var attr_list_sizes = new Dictionary<string, long>(); | ||||
| using (var status = new Status()) | 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); | var op_def = Graph.TFE_GetOpDef(opName); | ||||
| @@ -52,9 +51,9 @@ namespace Tensorflow.Eager | |||||
| for (int i = 0; i < op_def.InputArg.Count; i++) | for (int i = 0; i < op_def.InputArg.Count; i++) | ||||
| { | { | ||||
| var input_arg = op_def.InputArg[i]; | var input_arg = op_def.InputArg[i]; | ||||
| int len = (args[kFastPathExecuteInputStartIndex + i] as object[]).Length; | |||||
| if (!string.IsNullOrEmpty(input_arg.NumberAttr)) | if (!string.IsNullOrEmpty(input_arg.NumberAttr)) | ||||
| { | { | ||||
| int len = (args[kFastPathExecuteInputStartIndex + i] as object[]).Length; | |||||
| c_api.TFE_OpSetAttrInt(op, input_arg.NumberAttr, len); | c_api.TFE_OpSetAttrInt(op, input_arg.NumberAttr, len); | ||||
| attr_list_sizes[input_arg.NumberAttr] = len; | attr_list_sizes[input_arg.NumberAttr] = len; | ||||
| @@ -125,13 +124,16 @@ namespace Tensorflow.Eager | |||||
| IntPtr op, | IntPtr op, | ||||
| Status status) | Status status) | ||||
| { | { | ||||
| IntPtr input_handle = IntPtr.Zero; | |||||
| TFE_TensorHandle input_handle; | |||||
| switch (inputs) | switch (inputs) | ||||
| { | { | ||||
| case Tensor input: | case Tensor input: | ||||
| input_handle = c_api.TFE_NewTensorHandle(input, status); | input_handle = c_api.TFE_NewTensorHandle(input, status); | ||||
| break; | break; | ||||
| case Tensor[] input_list: | |||||
| input_handle = c_api.TFE_NewTensorHandle(input_list[0], status); | |||||
| break; | |||||
| default: | default: | ||||
| throw new NotImplementedException(""); | throw new NotImplementedException(""); | ||||
| } | } | ||||
| @@ -148,6 +150,25 @@ namespace Tensorflow.Eager | |||||
| return true; | 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); | |||||
| } | |||||
| } | |||||
| /// <summary> | /// <summary> | ||||
| /// This function will set the op attrs required. If an attr has the value of | /// 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 | /// 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<string, long> attr_list_sizes, | |||||
| Status status) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| private static bool SetOpAttrScalar(Context ctx, IntPtr op, | private static bool SetOpAttrScalar(Context ctx, IntPtr op, | ||||
| string key, object value, TF_AttrType type, | string key, object value, TF_AttrType type, | ||||
| Dictionary<string, long> attr_list_sizes, | Dictionary<string, long> attr_list_sizes, | ||||
| @@ -213,25 +242,5 @@ namespace Tensorflow.Eager | |||||
| return true; | return true; | ||||
| } | } | ||||
| public static void RecordGradient(string op_name, Tensor[] inputs, Dictionary<string, object> 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; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -125,7 +125,7 @@ namespace Tensorflow | |||||
| { | { | ||||
| if(tf.context.executing_eagerly()) | 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; | return _result; | ||||
| } | } | ||||
| @@ -14,6 +14,7 @@ | |||||
| limitations under the License. | limitations under the License. | ||||
| ******************************************************************************/ | ******************************************************************************/ | ||||
| using System; | |||||
| using Tensorflow.Eager; | using Tensorflow.Eager; | ||||
| using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
| @@ -22,6 +23,7 @@ namespace Tensorflow | |||||
| public static class gen_math_ops | public static class gen_math_ops | ||||
| { | { | ||||
| public static OpDefLibrary _op_def_lib = new OpDefLibrary(); | 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) | public static Tensor _all(Tensor input, Tensor axis, bool keep_dims = false, string name = null) | ||||
| { | { | ||||
| @@ -114,11 +116,36 @@ namespace Tensorflow | |||||
| /// <returns> A `Tensor`. Has the same type as `input`.</returns> | /// <returns> A `Tensor`. Has the same type as `input`.</returns> | ||||
| public static Tensor mean<T1, T2>(T1 input, T2 axis, bool keep_dims= false, string name = null) | public static Tensor mean<T1, T2>(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 }); | var _op = _op_def_lib._apply_op_helper("Mean", name, args: new { input, reduction_indices = axis, keep_dims = keep_dims }); | ||||
| return _op.output; | 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, T2>(T1 input, T2 axis, bool keep_dims = false, string name = null) | public static Tensor prod<T1, T2>(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 }); | 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()) | 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; | return _result; | ||||
| } | } | ||||
| @@ -466,7 +493,7 @@ namespace Tensorflow | |||||
| { | { | ||||
| if (tf.context.executing_eagerly()) | 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; | return _result; | ||||
| } | } | ||||
| @@ -493,7 +520,7 @@ namespace Tensorflow | |||||
| { | { | ||||
| if (tf.context.executing_eagerly()) | 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; | return _result; | ||||
| } | } | ||||
| @@ -544,7 +571,7 @@ namespace Tensorflow | |||||
| { | { | ||||
| if (tf.context.executing_eagerly()) | 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; | return _result; | ||||
| } | } | ||||
| @@ -564,7 +591,7 @@ namespace Tensorflow | |||||
| { | { | ||||
| if (tf.context.executing_eagerly()) | 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; | return _result; | ||||
| } | } | ||||
| @@ -591,7 +618,7 @@ namespace Tensorflow | |||||
| { | { | ||||
| if (tf.context.executing_eagerly()) | 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; | return _result; | ||||
| } | } | ||||
| @@ -709,6 +736,14 @@ namespace Tensorflow | |||||
| public static Tensor _sum<Tx, Ty>(Tx input, Ty axis = default, bool keep_dims = false, string name = null) | public static Tensor _sum<Tx, Ty>(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 }); | var _op = _op_def_lib._apply_op_helper("Sum", name, args: new { input, reduction_indices = axis, keep_dims }); | ||||
| return _op.outputs[0]; | return _op.outputs[0]; | ||||
| @@ -724,6 +759,12 @@ namespace Tensorflow | |||||
| /// <returns></returns> | /// <returns></returns> | ||||
| public static Tensor range(Tensor start, Tensor limit, Tensor delta, string name = null) | 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 }); | var _op = _op_def_lib._apply_op_helper("Range", name, new { start, limit, delta }); | ||||
| return _op.outputs[0]; | return _op.outputs[0]; | ||||
| @@ -480,6 +480,13 @@ namespace Tensorflow | |||||
| throw new NotImplementedException(); | 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) | public static Tensor reduce_sum(Tensor input_tensor, Tensor axis = null, bool keepdims = false, string name = null) | ||||
| { | { | ||||
| var r = _ReductionDims(input_tensor, axis); | var r = _ReductionDims(input_tensor, axis); | ||||
| @@ -47,6 +47,8 @@ namespace Tensorflow | |||||
| TF_SetStatus(_handle, code, msg); | TF_SetStatus(_handle, code, msg); | ||||
| } | } | ||||
| public bool ok() => Code == TF_Code.TF_OK; | |||||
| /// <summary> | /// <summary> | ||||
| /// Check status | /// Check status | ||||
| /// Throw exception with error message if code != TF_OK | /// Throw exception with error message if code != TF_OK | ||||
| @@ -3,11 +3,20 @@ using System.Runtime.InteropServices; | |||||
| namespace Tensorflow | namespace Tensorflow | ||||
| { | { | ||||
| [StructLayout(LayoutKind.Sequential)] | |||||
| public struct TF_Tensor | 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}"; | |||||
| } | } | ||||
| } | } | ||||
| @@ -2,6 +2,7 @@ | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Text; | using System.Text; | ||||
| using Tensorflow.Eager; | |||||
| namespace Tensorflow | namespace Tensorflow | ||||
| { | { | ||||
| @@ -15,13 +16,12 @@ namespace Tensorflow | |||||
| } | } | ||||
| public static implicit operator Operation(Tensor tensor) | 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) | public static implicit operator Tensor(IntPtr handle) | ||||
| { | |||||
| return new Tensor(handle); | |||||
| } | |||||
| => new Tensor(handle); | |||||
| } | } | ||||
| } | } | ||||
| @@ -157,7 +157,15 @@ namespace Tensorflow | |||||
| } | } | ||||
| else | 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<int>(); | |||||
| default: | |||||
| return BufferToArray(); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -23,6 +23,7 @@ using System.Threading; | |||||
| using NumSharp; | using NumSharp; | ||||
| using Tensorflow.Util; | using Tensorflow.Util; | ||||
| using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
| using Tensorflow.Eager; | |||||
| namespace Tensorflow | namespace Tensorflow | ||||
| { | { | ||||
| @@ -95,15 +96,19 @@ namespace Tensorflow | |||||
| /// <param name="dtype"></param> | /// <param name="dtype"></param> | ||||
| /// <param name="name"></param> | /// <param name="name"></param> | ||||
| /// <returns></returns> | /// <returns></returns> | ||||
| 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) | public static Tensor convert_to_tensor_or_composite(Tensor value, TF_DataType dtype = TF_DataType.DtInvalid, string name = null) | ||||
| { | { | ||||