@@ -0,0 +1,13 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace Tensorflow | |||||
{ | |||||
public class AutoModeArgs | |||||
{ | |||||
public Func<Operation, object> GetGradientAttrs { get; set; } | |||||
public object OpInputArgs { get; set; } | |||||
public object OpAttrs { get; set; } | |||||
} | |||||
} |
@@ -20,6 +20,7 @@ using System.Linq; | |||||
using Tensorflow.Eager; | using Tensorflow.Eager; | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
using Google.Protobuf; | using Google.Protobuf; | ||||
using System.Collections.Generic; | |||||
namespace Tensorflow.Contexts | namespace Tensorflow.Contexts | ||||
{ | { | ||||
@@ -57,14 +58,39 @@ namespace Tensorflow.Contexts | |||||
} | } | ||||
} | } | ||||
} | } | ||||
// [DebuggerStepThrough] | // [DebuggerStepThrough] | ||||
public Tensors RunInAutoMode2(Func<Tensors> graphAction, | |||||
Func<Tensors> eagerAction, | |||||
Action<Operation> recordGradient, | |||||
Tensors tensors) | |||||
public Tensors RunInAutoMode2(string OpType, string Name, AutoModeArgs args) | |||||
{ | { | ||||
if (tf.Context.has_graph_arg(tensors)) | |||||
var inputArgs = ConvertToDict(args.OpInputArgs); | |||||
var attrDict = ConvertToDict(args.OpAttrs); | |||||
Func<Tensor> graphAction = () => | |||||
{ | |||||
foreach (var attr in attrDict) | |||||
inputArgs[attr.Key] = attr.Value; | |||||
return tf.OpDefLib._apply_op_helper(OpType, Name, inputArgs).output; | |||||
}; | |||||
Func<Tensor> eagerAction = () => | |||||
{ | |||||
var attrs = new object[attrDict.Count() * 2]; | |||||
int i = 0; | |||||
foreach(var arg in attrDict) | |||||
{ | |||||
attrs[i]= arg.Key; | |||||
attrs[i + 1] = arg.Value; | |||||
i += 2; | |||||
} | |||||
return tf.Runner.TFE_FastPathExecute2(tf.Context, tf.Context.DeviceName, | |||||
OpType, Name, | |||||
null, | |||||
inputArgs.Values.ToArray(), | |||||
attrs).FirstOrDefault(); | |||||
}; | |||||
if (tf.Context.has_graph_arg(inputArgs.Values)) | |||||
{ | { | ||||
if (executing_eagerly()) | if (executing_eagerly()) | ||||
{ | { | ||||
@@ -77,7 +103,28 @@ namespace Tensorflow.Contexts | |||||
{ | { | ||||
var result = graphAction(); | var result = graphAction(); | ||||
if (tf.Runner.MustRecordGradient()) | if (tf.Runner.MustRecordGradient()) | ||||
recordGradient(result[0].op); | |||||
{ | |||||
var op = result[0].op; | |||||
Dictionary<string, object> attrs; | |||||
if (args.GetGradientAttrs == null) | |||||
{ | |||||
attrs = new Dictionary<string, object>(); | |||||
attrs["T"] = op.get_attr<TF_DataType>("T"); | |||||
} | |||||
else | |||||
{ | |||||
attrs = ConvertToDict(args.GetGradientAttrs(op)); | |||||
} | |||||
var args1 = new object[attrs.Count() * 2]; | |||||
int i = 0; | |||||
foreach (var arg in attrs) | |||||
{ | |||||
args1[i] = arg.Key; | |||||
args1[i + 1] = arg.Value; | |||||
i += 2; | |||||
} | |||||
tf.Runner.RecordGradient(OpType, op.inputs, args1, op.outputs); | |||||
} | |||||
return result; | return result; | ||||
} | } | ||||
} | } | ||||
@@ -18,6 +18,21 @@ namespace Tensorflow.Eager | |||||
int kFastPathExecuteInputStartIndex = 0; | int kFastPathExecuteInputStartIndex = 0; | ||||
UnorderedMap<Context, SafeOpHandle> thread_local_eager_operation_map = new UnorderedMap<Context, SafeOpHandle>(); | UnorderedMap<Context, SafeOpHandle> thread_local_eager_operation_map = new UnorderedMap<Context, SafeOpHandle>(); | ||||
public Tensor[] TFE_FastPathExecute2(Context ctx, | |||||
string device_name, | |||||
string opName, | |||||
string name, | |||||
Action callbacks, | |||||
object[] inputArgs, | |||||
object[] attrs) | |||||
{ | |||||
var args = new List<object>(); | |||||
args.AddRange(inputArgs); | |||||
if (attrs != null) | |||||
args.AddRange(attrs); | |||||
return TFE_FastPathExecute(ctx, device_name, opName, name, callbacks, args.ToArray()); | |||||
} | |||||
public Tensor[] TFE_FastPathExecute(Context ctx, | public Tensor[] TFE_FastPathExecute(Context ctx, | ||||
string device_name, | string device_name, | ||||
string opName, | string opName, | ||||
@@ -16,6 +16,14 @@ namespace Tensorflow.Eager | |||||
TF_DataType default_dtype = TF_DataType.DtInvalid, | TF_DataType default_dtype = TF_DataType.DtInvalid, | ||||
object[] args = null); | object[] args = null); | ||||
Tensor[] TFE_FastPathExecute2(Context ctx, | |||||
string device_name, | |||||
string opName, | |||||
string name, | |||||
Action callbacks, | |||||
object[] inputArgs, | |||||
object[] attrs); | |||||
Tensor[] TFE_FastPathExecute(Context ctx, | Tensor[] TFE_FastPathExecute(Context ctx, | ||||
string device_name, | string device_name, | ||||
string opName, | string opName, | ||||
@@ -737,44 +737,35 @@ namespace Tensorflow | |||||
public static Tensor strided_slice_grad(Tensor shape, Tensor begin, Tensor end, Tensor strides, Tensor dy, | public static Tensor strided_slice_grad(Tensor shape, Tensor begin, Tensor end, Tensor strides, Tensor dy, | ||||
long begin_mask = 0, long end_mask = 0, long ellipsis_mask = 0, long new_axis_mask = 0, | long begin_mask = 0, long end_mask = 0, long ellipsis_mask = 0, long new_axis_mask = 0, | ||||
long shrink_axis_mask = 0, string name = null) | long shrink_axis_mask = 0, string name = null) | ||||
=> tf.Context.RunInAutoMode2( | |||||
() => tf.OpDefLib._apply_op_helper("StridedSliceGrad", name, new | |||||
=> tf.Context.RunInAutoMode2("StridedSliceGrad", name, new AutoModeArgs | |||||
{ | |||||
OpInputArgs = new | |||||
{ | { | ||||
shape, | shape, | ||||
begin, | begin, | ||||
end, | end, | ||||
strides, | strides, | ||||
dy, | |||||
dy | |||||
}, | |||||
OpAttrs = new | |||||
{ | |||||
begin_mask, | begin_mask, | ||||
end_mask, | end_mask, | ||||
ellipsis_mask, | ellipsis_mask, | ||||
new_axis_mask, | new_axis_mask, | ||||
shrink_axis_mask | shrink_axis_mask | ||||
}).output, | |||||
() => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
"StridedSliceGrad", name, | |||||
null, | |||||
shape, begin, end, strides, dy, | |||||
"begin_mask", begin_mask, | |||||
"end_mask", end_mask, | |||||
"ellipsis_mask", ellipsis_mask, | |||||
"new_axis_mask", new_axis_mask, | |||||
"shrink_axis_mask", shrink_axis_mask).FirstOrDefault(), | |||||
(op) => | |||||
{ | |||||
var attrs = new object[] | |||||
{ | |||||
"T", op.get_attr<TF_DataType>("T"), | |||||
"Index", op.get_attr<TF_DataType>("Index"), | |||||
"begin_mask", op.get_attr<long>("begin_mask"), | |||||
"end_mask", op.get_attr<long>("end_mask"), | |||||
"ellipsis_mask", op.get_attr<long>("ellipsis_mask"), | |||||
"new_axis_mask", op.get_attr<long>("new_axis_mask"), | |||||
"shrink_axis_mask", op.get_attr<long>("shrink_axis_mask") | |||||
}; | |||||
tf.Runner.RecordGradient("StridedSliceGrad", op.inputs, attrs, op.outputs); | |||||
}, | }, | ||||
new Tensors(shape, begin, end, strides, dy)); | |||||
GetGradientAttrs = (op) => new | |||||
{ | |||||
T = op.get_attr<TF_DataType>("T"), | |||||
Index = op.get_attr<TF_DataType>("Index"), | |||||
begin_mask = op.get_attr<long>("begin_mask"), | |||||
end_mask = op.get_attr<long>("end_mask"), | |||||
ellipsis_mask = op.get_attr<long>("ellipsis_mask"), | |||||
new_axis_mask = op.get_attr<long>("new_axis_mask"), | |||||
shrink_axis_mask = op.get_attr<long>("shrink_axis_mask") | |||||
} | |||||
}); | |||||
/// <summary> | /// <summary> | ||||
/// Removes dimensions of size 1 from the shape of a tensor. | /// Removes dimensions of size 1 from the shape of a tensor. | ||||
@@ -969,27 +960,15 @@ namespace Tensorflow | |||||
=> gen_array_ops.slice(input, begin, size, name: name); | => gen_array_ops.slice(input, begin, size, name: name); | ||||
public static Tensor slice(Tensor input, Tensor begin, Tensor size, string name = null) | public static Tensor slice(Tensor input, Tensor begin, Tensor size, string name = null) | ||||
=> tf.Context.RunInAutoMode2( | |||||
() => tf.OpDefLib._apply_op_helper("Slice", name, new | |||||
{ | |||||
input, | |||||
begin, | |||||
size | |||||
}).output, | |||||
() => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
"Slice", name, | |||||
null, | |||||
input, begin, size).FirstOrDefault(), | |||||
(op) => | |||||
=> tf.Context.RunInAutoMode2("Slice", name, new AutoModeArgs | |||||
{ | |||||
OpInputArgs = new { input, begin, size }, | |||||
GetGradientAttrs = (op) => new | |||||
{ | { | ||||
var attrs = new object[] | |||||
{ | |||||
"T", op.get_attr<TF_DataType>("T"), | |||||
"Index", op.get_attr<int>("Index") | |||||
}; | |||||
tf.Runner.RecordGradient("Slice", op.inputs, attrs, op.outputs); | |||||
}, | |||||
new Tensors(input, begin, size)); | |||||
T = op.get_attr<TF_DataType>("T"), | |||||
Index = op.get_attr<int>("Index") | |||||
} | |||||
}); | |||||
public static Tensor stack(object values, int axis = 0, string name = "stack") | public static Tensor stack(object values, int axis = 0, string name = "stack") | ||||
{ | { | ||||
@@ -240,30 +240,16 @@ namespace Tensorflow | |||||
public static Tensor resize_nearest_neighbor_grad(Tensor grads, Tensor size, bool align_corners = false, | public static Tensor resize_nearest_neighbor_grad(Tensor grads, Tensor size, bool align_corners = false, | ||||
bool half_pixel_centers = false, string name = null) | bool half_pixel_centers = false, string name = null) | ||||
=> tf.Context.RunInAutoMode2( | |||||
() => tf.OpDefLib._apply_op_helper("ResizeNearestNeighborGrad", name, new | |||||
=> tf.Context.RunInAutoMode2("ResizeNearestNeighborGrad", name, new AutoModeArgs | |||||
{ | { | ||||
grads, | |||||
size, | |||||
align_corners, | |||||
half_pixel_centers | |||||
}).output, | |||||
() => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
"ResizeNearestNeighborGrad", name, | |||||
null, | |||||
grads, size, | |||||
"align_corners", align_corners, | |||||
"half_pixel_centers", half_pixel_centers).FirstOrDefault(), | |||||
(op) => | |||||
{ | |||||
var attrs = new object[] | |||||
OpInputArgs = new { grads, size }, | |||||
OpAttrs = new { align_corners, half_pixel_centers }, | |||||
GetGradientAttrs = (op) => new | |||||
{ | { | ||||
"T", op.get_attr<TF_DataType>("T"), | |||||
"align_corners", op.get_attr<bool>("align_corners"), | |||||
"half_pixel_centers", op.get_attr<bool>("half_pixel_centers") | |||||
}; | |||||
tf.Runner.RecordGradient("ResizeNearestNeighborGrad", op.inputs, attrs, op.outputs); | |||||
}, | |||||
new Tensors(grads, size)); | |||||
T = op.get_attr<TF_DataType>("T"), | |||||
align_corners = op.get_attr<bool>("align_corners"), | |||||
half_pixel_centers = op.get_attr<bool>("half_pixel_centers") | |||||
} | |||||
}); | |||||
} | } | ||||
} | } |
@@ -141,29 +141,17 @@ namespace Tensorflow | |||||
/// <param name="name"> A name for the operation (optional).</param> | /// <param name="name"> A name for the operation (optional).</param> | ||||
/// <returns> A `Tensor`. Has the same type as `input`.</returns> | /// <returns> A `Tensor`. Has the same type as `input`.</returns> | ||||
public static Tensor mean(Tensor input, Tensor axis, bool keep_dims = false, string name = null) | public static Tensor mean(Tensor input, Tensor axis, bool keep_dims = false, string name = null) | ||||
=> tf.Context.RunInAutoMode2( | |||||
() => tf.OpDefLib._apply_op_helper("Mean", name, new | |||||
{ | |||||
input, | |||||
reduction_indices = axis, | |||||
keep_dims = keep_dims | |||||
}).output, | |||||
() => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
"Mean", name, | |||||
null, | |||||
input, axis, | |||||
"keep_dims", keep_dims).FirstOrDefault(), | |||||
(op) => | |||||
=> tf.Context.RunInAutoMode2("Mean", name, new AutoModeArgs | |||||
{ | |||||
OpInputArgs = new { input, axis }, | |||||
OpAttrs = new { keep_dims, reduction_indices = axis }, | |||||
GetGradientAttrs = (op) => new | |||||
{ | { | ||||
var attrs = new object[] | |||||
{ | |||||
"T", op.get_attr<TF_DataType>("T"), | |||||
"Tidx", op.get_attr<TF_DataType>("Tidx"), | |||||
"keep_dims", op.get_attr<bool>("keep_dims") | |||||
}; | |||||
tf.Runner.RecordGradient("Mean", op.inputs, attrs, op.outputs); | |||||
}, | |||||
new Tensors(input, axis)); | |||||
T = op.get_attr<TF_DataType>("T"), | |||||
Tidx = op.get_attr<TF_DataType>("Tidx"), | |||||
keep_dims = op.get_attr<bool>("keep_dims") | |||||
} | |||||
}); | |||||
public static Tensor mean(Tensor[] inputs, Tensor axis, bool keep_dims = false, string name = null) | public static Tensor mean(Tensor[] inputs, Tensor axis, bool keep_dims = false, string name = null) | ||||
{ | { | ||||
@@ -356,21 +344,10 @@ namespace Tensorflow | |||||
/// <c>dy</c> is the corresponding input gradient. | /// <c>dy</c> is the corresponding input gradient. | ||||
/// </remarks> | /// </remarks> | ||||
public static Tensor sigmoid_grad(Tensor y, Tensor dy, string name = "SigmoidGrad") | public static Tensor sigmoid_grad(Tensor y, Tensor dy, string name = "SigmoidGrad") | ||||
=> tf.Context.RunInAutoMode2( | |||||
() => tf.OpDefLib._apply_op_helper("SigmoidGrad", name, new { y, dy }).output, | |||||
() => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
"SigmoidGrad", name, | |||||
null, | |||||
y, dy).FirstOrDefault(), | |||||
(op) => | |||||
{ | |||||
var attrs = new object[] | |||||
{ | |||||
"T", op.get_attr<TF_DataType>("T") | |||||
}; | |||||
tf.Runner.RecordGradient("SigmoidGrad", op.inputs, attrs, op.outputs); | |||||
}, | |||||
new Tensors(y, dy)); | |||||
=> tf.Context.RunInAutoMode2("SigmoidGrad", name, new AutoModeArgs | |||||
{ | |||||
OpInputArgs = new { y, dy } | |||||
}); | |||||
public static Tensor sign<T>(T x, string name = "Sign") | public static Tensor sign<T>(T x, string name = "Sign") | ||||
{ | { | ||||
@@ -806,21 +783,10 @@ namespace Tensorflow | |||||
} | } | ||||
public static Tensor sub(Tensor x, Tensor y, string name = null) | public static Tensor sub(Tensor x, Tensor y, string name = null) | ||||
=> tf.Context.RunInAutoMode2( | |||||
() => tf.OpDefLib._apply_op_helper("Sub", name, new { x, y }).output, | |||||
() => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
"Sub", name, | |||||
null, | |||||
x, y).FirstOrDefault(), | |||||
(op) => | |||||
{ | |||||
var attrs = new object[] | |||||
{ | |||||
"T", op.get_attr<TF_DataType>("T") | |||||
}; | |||||
tf.Runner.RecordGradient("Sub", op.inputs, attrs, op.outputs); | |||||
}, | |||||
new Tensors(x, y)); | |||||
=> tf.Context.RunInAutoMode2("Sub", name, new AutoModeArgs | |||||
{ | |||||
OpInputArgs = new { x, y } | |||||
}); | |||||
public static Tensor sub<Tx, Ty>(Tx x, Ty y, string name = null) | public static Tensor sub<Tx, Ty>(Tx x, Ty y, string name = null) | ||||
{ | { | ||||
@@ -45,21 +45,10 @@ namespace Tensorflow | |||||
=> gen_math_ops.add(x, y, name); | => gen_math_ops.add(x, y, name); | ||||
public static Tensor add_v2(Tensor x, Tensor y, string name = null) | public static Tensor add_v2(Tensor x, Tensor y, string name = null) | ||||
=> tf.Context.RunInAutoMode2( | |||||
() => tf.OpDefLib._apply_op_helper("AddV2", name, new { x, y }).output, | |||||
() => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
"AddV2", name, | |||||
null, | |||||
x, y).FirstOrDefault(), | |||||
(op) => | |||||
{ | |||||
var attrs = new object[] | |||||
{ | |||||
"T", op.get_attr<TF_DataType>("T") | |||||
}; | |||||
tf.Runner.RecordGradient("AddV2", op.inputs, attrs, op.outputs); | |||||
}, | |||||
new Tensors(x, y)); | |||||
=> tf.Context.RunInAutoMode2("AddV2", name, new AutoModeArgs | |||||
{ | |||||
OpInputArgs = new { x, y } | |||||
}); | |||||
public static Tensor add_v2<Tx, Ty>(Tx x, Ty y, string name = null) | public static Tensor add_v2<Tx, Ty>(Tx x, Ty y, string name = null) | ||||
=> gen_math_ops.add_v2(x, y, name); | => gen_math_ops.add_v2(x, y, name); | ||||
@@ -272,41 +261,19 @@ namespace Tensorflow | |||||
/// <param name="name"></param> | /// <param name="name"></param> | ||||
/// <returns></returns> | /// <returns></returns> | ||||
public static Tensor erf(Tensor x, string name = null) | public static Tensor erf(Tensor x, string name = null) | ||||
=> tf.Context.RunInAutoMode2( | |||||
() => tf.OpDefLib._apply_op_helper("Erf", name, new { x }).output, | |||||
() => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
"Erf", name, | |||||
null, | |||||
x).FirstOrDefault(), | |||||
(op) => | |||||
{ | |||||
var attrs = new object[] | |||||
{ | |||||
"T", op.get_attr<TF_DataType>("T") | |||||
}; | |||||
tf.Runner.RecordGradient("Erf", op.inputs, attrs, op.outputs); | |||||
}, | |||||
new Tensors(x)); | |||||
=> tf.Context.RunInAutoMode2("Erf", name, new AutoModeArgs | |||||
{ | |||||
OpInputArgs = new { x } | |||||
}); | |||||
public static Tensor sqrt(Tensor x, string name = null) | public static Tensor sqrt(Tensor x, string name = null) | ||||
=> gen_math_ops.sqrt(x, name: name); | => gen_math_ops.sqrt(x, name: name); | ||||
public static Tensor multiply(Tensor x, Tensor y, string name = null) | public static Tensor multiply(Tensor x, Tensor y, string name = null) | ||||
=> tf.Context.RunInAutoMode2( | |||||
() => tf.OpDefLib._apply_op_helper("Mul", name, new { x, y }).output, | |||||
() => tf.Runner.TFE_FastPathExecute(tf.Context, tf.Context.DeviceName, | |||||
"Mul", name, | |||||
null, | |||||
x, y).FirstOrDefault(), | |||||
(op) => | |||||
{ | |||||
var attrs = new object[] | |||||
{ | |||||
"T", op.get_attr<TF_DataType>("T") | |||||
}; | |||||
tf.Runner.RecordGradient("Mul", op.inputs, attrs, op.outputs); | |||||
}, | |||||
new Tensors(x, y)); | |||||
=> tf.Context.RunInAutoMode2("Mul", name, new AutoModeArgs | |||||
{ | |||||
OpInputArgs = new { x, y } | |||||
}); | |||||
public static Tensor multiply<Tx, Ty>(Tx x, Ty y, string name = null) | public static Tensor multiply<Tx, Ty>(Tx x, Ty y, string name = null) | ||||
=> gen_math_ops.mul(x, y, name: name); | => gen_math_ops.mul(x, y, name: name); | ||||