@@ -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 static Tensorflow.Binding; | |||
using Google.Protobuf; | |||
using System.Collections.Generic; | |||
namespace Tensorflow.Contexts | |||
{ | |||
@@ -57,14 +58,39 @@ namespace Tensorflow.Contexts | |||
} | |||
} | |||
} | |||
// [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()) | |||
{ | |||
@@ -77,7 +103,28 @@ namespace Tensorflow.Contexts | |||
{ | |||
var result = graphAction(); | |||
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; | |||
} | |||
} | |||
@@ -18,6 +18,21 @@ namespace Tensorflow.Eager | |||
int kFastPathExecuteInputStartIndex = 0; | |||
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, | |||
string device_name, | |||
string opName, | |||
@@ -16,6 +16,14 @@ namespace Tensorflow.Eager | |||
TF_DataType default_dtype = TF_DataType.DtInvalid, | |||
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, | |||
string device_name, | |||
string opName, | |||
@@ -737,44 +737,35 @@ namespace Tensorflow | |||
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 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, | |||
begin, | |||
end, | |||
strides, | |||
dy, | |||
dy | |||
}, | |||
OpAttrs = new | |||
{ | |||
begin_mask, | |||
end_mask, | |||
ellipsis_mask, | |||
new_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> | |||
/// 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); | |||
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") | |||
{ | |||
@@ -240,30 +240,16 @@ namespace Tensorflow | |||
public static Tensor resize_nearest_neighbor_grad(Tensor grads, Tensor size, bool align_corners = false, | |||
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> | |||
/// <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) | |||
=> 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) | |||
{ | |||
@@ -356,21 +344,10 @@ namespace Tensorflow | |||
/// <c>dy</c> is the corresponding input gradient. | |||
/// </remarks> | |||
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") | |||
{ | |||
@@ -806,21 +783,10 @@ namespace Tensorflow | |||
} | |||
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) | |||
{ | |||
@@ -45,21 +45,10 @@ namespace Tensorflow | |||
=> gen_math_ops.add(x, y, name); | |||
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) | |||
=> gen_math_ops.add_v2(x, y, name); | |||
@@ -272,41 +261,19 @@ namespace Tensorflow | |||
/// <param name="name"></param> | |||
/// <returns></returns> | |||
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) | |||
=> gen_math_ops.sqrt(x, name: name); | |||
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) | |||
=> gen_math_ops.mul(x, y, name: name); | |||