@@ -390,7 +390,7 @@ namespace Tensorflow | |||||
=> x / ops.convert_to_tensor(y, dtype: x.dtype.as_base_dtype(), name: "y"); | => x / ops.convert_to_tensor(y, dtype: x.dtype.as_base_dtype(), name: "y"); | ||||
public Tensor pow<T1, T2>(T1 x, T2 y, string name = "pow") | public Tensor pow<T1, T2>(T1 x, T2 y, string name = "pow") | ||||
=> gen_math_ops.pow(x, y, name: name); | |||||
=> math_ops.pow(x, y, name: name); | |||||
/// <summary> | /// <summary> | ||||
/// Divides `x / y` elementwise, rounding toward the most negative integer. | /// Divides `x / y` elementwise, rounding toward the most negative integer. | ||||
@@ -53,6 +53,9 @@ namespace Tensorflow.Eager | |||||
public static string GetFormattedString(TF_DataType dtype, NDArray nd) | public static string GetFormattedString(TF_DataType dtype, NDArray nd) | ||||
{ | { | ||||
if (nd.size == 0) | |||||
return "[]"; | |||||
switch (dtype) | switch (dtype) | ||||
{ | { | ||||
case TF_DataType.TF_STRING: | case TF_DataType.TF_STRING: | ||||
@@ -375,6 +375,9 @@ namespace Tensorflow | |||||
[DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
public static extern void TFE_TapeWatch(IntPtr tape, IntPtr tensor); | public static extern void TFE_TapeWatch(IntPtr tape, IntPtr tensor); | ||||
[DllImport(TensorFlowLibName)] | |||||
public static extern void TFE_TapeVariableAccessed(IntPtr variable); | |||||
[DllImport(TensorFlowLibName)] | [DllImport(TensorFlowLibName)] | ||||
public static extern IntPtr TFE_TapeGradient(IntPtr tape, | public static extern IntPtr TFE_TapeGradient(IntPtr tape, | ||||
IntPtr[] target, int target_size, | IntPtr[] target, int target_size, | ||||
@@ -1,5 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | |||||
using System.Text; | using System.Text; | ||||
using Tensorflow.Eager; | using Tensorflow.Eager; | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
@@ -65,7 +66,7 @@ namespace Tensorflow.Gradients | |||||
_tape.watch(x as EagerTensor); | _tape.watch(x as EagerTensor); | ||||
} | } | ||||
public Tensor gradient(Tensor target, Tensor sources) | |||||
public Tensor gradient(Tensor target, Tensor source) | |||||
{ | { | ||||
if(_recording) | if(_recording) | ||||
{ | { | ||||
@@ -76,15 +77,33 @@ namespace Tensorflow.Gradients | |||||
using var status = new Status(); | using var status = new Status(); | ||||
var et = c_api.TFE_TapeGradient(_tape, | var et = c_api.TFE_TapeGradient(_tape, | ||||
new [] { (target as EagerTensor).EagerTensorHandle }, 1, | new [] { (target as EagerTensor).EagerTensorHandle }, 1, | ||||
new [] { (sources as EagerTensor).EagerTensorHandle }, 1, | |||||
new [] { (source as EagerTensor).EagerTensorHandle }, 1, | |||||
status); | status); | ||||
status.Check(true); | status.Check(true); | ||||
return new EagerTensor(et); | return new EagerTensor(et); | ||||
} | } | ||||
public Tensor gradient(Tensor target, ResourceVariable[] sources) | |||||
{ | |||||
if (_recording) | |||||
{ | |||||
if (!_persistent) | |||||
_pop_tape(); | |||||
} | |||||
using var status = new Status(); | |||||
EagerTensorHandle et = c_api.TFE_TapeGradient(_tape, | |||||
new[] { (target as EagerTensor).EagerTensorHandle }, 1, | |||||
sources.Select(x => (x.handle as EagerTensor).EagerTensorHandle).ToArray(), sources.Length, | |||||
status); | |||||
status.Check(true); | |||||
return et; | |||||
} | |||||
public void Dispose() | public void Dispose() | ||||
{ | { | ||||
if (_recording) | |||||
_pop_tape(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -25,6 +25,11 @@ namespace Tensorflow.Gradients | |||||
c_api.TFE_TapeSetRemove(tape); | c_api.TFE_TapeSetRemove(tape); | ||||
} | } | ||||
public static void variable_accessed(ResourceVariable variable) | |||||
{ | |||||
c_api.TFE_TapeVariableAccessed(variable.handle as EagerTensor); | |||||
} | |||||
public static bool IsDtypeTrainable(DataType dtype) | public static bool IsDtypeTrainable(DataType dtype) | ||||
{ | { | ||||
switch (dtype) | switch (dtype) | ||||
@@ -220,6 +220,18 @@ namespace Tensorflow | |||||
/// <param name="name"></param> | /// <param name="name"></param> | ||||
public static Tensor identity(Tensor input, string name = null) | public static Tensor identity(Tensor input, string name = null) | ||||
{ | { | ||||
if (tf.context.executing_eagerly()) | |||||
{ | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Identity", name, new IntPtr[] | |||||
{ | |||||
input as EagerTensor | |||||
}, 1, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | |||||
var _op = _op_def_lib._apply_op_helper("Identity", name, new { input }); | var _op = _op_def_lib._apply_op_helper("Identity", name, new { input }); | ||||
return _op.output; | return _op.output; | ||||
@@ -258,14 +270,14 @@ namespace Tensorflow | |||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
using var status = new Status(); | using var status = new Status(); | ||||
var tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Fill", name, new IntPtr[] | "Fill", name, new IntPtr[] | ||||
{ | { | ||||
dims as EagerTensor, | dims as EagerTensor, | ||||
value as EagerTensor | value as EagerTensor | ||||
}, 2, null, status); | }, 2, null, status); | ||||
status.Check(true); | status.Check(true); | ||||
return new EagerTensor(tensor); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("Fill", name, new { dims, value }); | var _op = _op_def_lib._apply_op_helper("Fill", name, new { dims, value }); | ||||
@@ -281,6 +293,18 @@ namespace Tensorflow | |||||
/// <returns>A tuple of `Tensor` objects (r0, r1).</returns> | /// <returns>A tuple of `Tensor` objects (r0, r1).</returns> | ||||
public static (Tensor, Tensor) broadcast_gradient_args(Tensor s0, Tensor s1, string name = "") | public static (Tensor, Tensor) broadcast_gradient_args(Tensor s0, Tensor s1, string name = "") | ||||
{ | { | ||||
if (tf.context.executing_eagerly()) | |||||
{ | |||||
using var status = new Status(); | |||||
var _result = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"BroadcastGradientArgs", name, new IntPtr[] | |||||
{ | |||||
s0 as EagerTensor, | |||||
s1 as EagerTensor | |||||
}, 2, null, status); | |||||
status.Check(true); | |||||
} | |||||
var _op = _op_def_lib._apply_op_helper("BroadcastGradientArgs", name, new { s0, s1 }); | var _op = _op_def_lib._apply_op_helper("BroadcastGradientArgs", name, new { s0, s1 }); | ||||
return (_op.outputs[0], _op.outputs[1]); | return (_op.outputs[0], _op.outputs[1]); | ||||
@@ -371,10 +395,19 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Shape", name, null, | |||||
input, "out_type", out_type); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Shape", name, new IntPtr[] | |||||
{ | |||||
input as EagerTensor, | |||||
}, 1, | |||||
op => wrap_tfe_src.SetOpAttrs(tf.context, op, new object[] | |||||
{ | |||||
"out_type", out_type | |||||
}, status), | |||||
status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("Shape", name, new { input, out_type }); | var _op = _op_def_lib._apply_op_helper("Shape", name, new { input, out_type }); | ||||
@@ -455,12 +488,26 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"StridedSlice", name, null, | |||||
input, begin, end, strides, "begin_mask", begin_mask, | |||||
"end_mask", end_mask, "ellipsis_mask", ellipsis_mask, | |||||
"new_axis_mask", new_axis_mask, "shrink_axis_mask", shrink_axis_mask); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"StridedSlice", name, new IntPtr[] | |||||
{ | |||||
input as EagerTensor, | |||||
begin as EagerTensor, | |||||
end as EagerTensor, | |||||
strides as EagerTensor, | |||||
}, 4, | |||||
op => wrap_tfe_src.SetOpAttrs(tf.context, op, new object[] | |||||
{ | |||||
"begin_mask", begin_mask, | |||||
"end_mask", end_mask, | |||||
"ellipsis_mask", ellipsis_mask, | |||||
"new_axis_mask", new_axis_mask, | |||||
"shrink_axis_mask", shrink_axis_mask | |||||
}, status), | |||||
status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("StridedSlice", name, new | var _op = _op_def_lib._apply_op_helper("StridedSlice", name, new | ||||
@@ -173,10 +173,20 @@ namespace Tensorflow | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Prod", name, null, | |||||
input, axis, "keep_dims", keep_dims); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Prod", name, new IntPtr[] | |||||
{ | |||||
input as EagerTensor, | |||||
axis as EagerTensor | |||||
}, 2, | |||||
op => wrap_tfe_src.SetOpAttrs(tf.context, op, new object[] | |||||
{ | |||||
"keep_dims", keep_dims | |||||
}, status), | |||||
status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
catch (Exception) | catch (Exception) | ||||
{ | { | ||||
@@ -236,10 +246,15 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Add", name, null, | |||||
x, y); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Add", name, new IntPtr[] | |||||
{ | |||||
x as EagerTensor, | |||||
y as EagerTensor | |||||
}, 2, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("Add", name, args: new { x, y }); | var _op = _op_def_lib._apply_op_helper("Add", name, args: new { x, y }); | ||||
@@ -647,10 +662,14 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Sqrt", name, null, | |||||
x); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Sqrt", name, new IntPtr[] | |||||
{ | |||||
x as EagerTensor, | |||||
}, 1, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("Sqrt", name, args: new { x }); | var _op = _op_def_lib._apply_op_helper("Sqrt", name, args: new { x }); | ||||
@@ -682,10 +701,15 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Sub", name, null, | |||||
x, y); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Sub", name, new IntPtr[] | |||||
{ | |||||
x as EagerTensor, | |||||
y as EagerTensor | |||||
}, 2, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("Sub", name, args: new { x, y }); | var _op = _op_def_lib._apply_op_helper("Sub", name, args: new { x, y }); | ||||
@@ -704,10 +728,15 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Equal", name, null, | |||||
x, y); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Equal", name, new IntPtr[] | |||||
{ | |||||
x as EagerTensor, | |||||
y as EagerTensor | |||||
}, 2, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("Equal", name, args: new { x, y }); | var _op = _op_def_lib._apply_op_helper("Equal", name, args: new { x, y }); | ||||
@@ -727,10 +756,15 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"NotEqual", name, null, | |||||
x, y); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"NotEqual", name, new IntPtr[] | |||||
{ | |||||
x as EagerTensor, | |||||
y as EagerTensor | |||||
}, 2, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("NotEqual", name, args: new { x, y }); | var _op = _op_def_lib._apply_op_helper("NotEqual", name, args: new { x, y }); | ||||
@@ -742,10 +776,15 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Atan2", name, null, | |||||
y, x); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Atan2", name, new IntPtr[] | |||||
{ | |||||
y as EagerTensor, | |||||
x as EagerTensor | |||||
}, 2, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("Atan2", name, args: new { y, x }); | var _op = _op_def_lib._apply_op_helper("Atan2", name, args: new { y, x }); | ||||
@@ -757,14 +796,14 @@ namespace Tensorflow | |||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
using var status = new Status(); | using var status = new Status(); | ||||
var _result = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Mul", name, new IntPtr[] | "Mul", name, new IntPtr[] | ||||
{ | { | ||||
x as EagerTensor, | x as EagerTensor, | ||||
y as EagerTensor | y as EagerTensor | ||||
}, 2, null, status); | }, 2, null, status); | ||||
status.Check(true); | status.Check(true); | ||||
return new EagerTensor(_result); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("Mul", name, args: new { x, y }); | var _op = _op_def_lib._apply_op_helper("Mul", name, args: new { x, y }); | ||||
@@ -776,10 +815,15 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Mul", name, null, | |||||
x, y); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Mul", name, new IntPtr[] | |||||
{ | |||||
x as EagerTensor, | |||||
y as EagerTensor, | |||||
}, 1, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("Mul", name, args: new { x, y }); | var _op = _op_def_lib._apply_op_helper("Mul", name, args: new { x, y }); | ||||
@@ -832,8 +876,15 @@ namespace Tensorflow | |||||
{ | { | ||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
var _result = wrap_tfe_src.TFE_FastPathExecute(tf.context, "", "FloorDiv", name, null, x, y); | |||||
return _result; | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"FloorDiv", name, new IntPtr[] | |||||
{ | |||||
x as EagerTensor, | |||||
y as EagerTensor | |||||
}, 2, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("FloorDiv", name, args: new { x, y }); | var _op = _op_def_lib._apply_op_helper("FloorDiv", name, args: new { x, y }); | ||||
@@ -864,10 +915,8 @@ namespace Tensorflow | |||||
}, 2, | }, 2, | ||||
op => wrap_tfe_src.SetOpAttrs(tf.context, op, new object[] | op => wrap_tfe_src.SetOpAttrs(tf.context, op, new object[] | ||||
{ | { | ||||
"transpose_a", | |||||
transpose_a, | |||||
"transpose_b", | |||||
transpose_b | |||||
"transpose_a", transpose_a, | |||||
"transpose_b", transpose_b | |||||
}, status), | }, status), | ||||
status); | status); | ||||
status.Check(true); | status.Check(true); | ||||
@@ -965,6 +1014,19 @@ namespace Tensorflow | |||||
public static Tensor pow<Tx, Ty>(Tx x, Ty y, string name = null) | public static Tensor pow<Tx, Ty>(Tx x, Ty y, string name = null) | ||||
{ | { | ||||
if (tf.context.executing_eagerly()) | |||||
{ | |||||
using var status = new Status(); | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"Pow", name, new IntPtr[] | |||||
{ | |||||
x as EagerTensor, | |||||
y as EagerTensor | |||||
}, 2, null, status); | |||||
status.Check(true); | |||||
return tensor; | |||||
} | |||||
var _op = _op_def_lib._apply_op_helper("Pow", name, args: new { x, y }); | var _op = _op_def_lib._apply_op_helper("Pow", name, args: new { x, y }); | ||||
return _op.outputs[0]; | return _op.outputs[0]; | ||||
@@ -115,13 +115,13 @@ namespace Tensorflow | |||||
if (tf.context.executing_eagerly()) | if (tf.context.executing_eagerly()) | ||||
{ | { | ||||
using var status = new Status(); | using var status = new Status(); | ||||
var tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
EagerTensorHandle tensor = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name, | |||||
"ReadVariableOp", name, | "ReadVariableOp", name, | ||||
new IntPtr[] { resource as EagerTensor }, 1, | new IntPtr[] { resource as EagerTensor }, 1, | ||||
op => wrap_tfe_src.SetOpAttrs(tf.context, op, new object[] { "dtype", dtype }, status), | op => wrap_tfe_src.SetOpAttrs(tf.context, op, new object[] { "dtype", dtype }, status), | ||||
status); | status); | ||||
status.Check(true); | status.Check(true); | ||||
return new EagerTensor(tensor); | |||||
return tensor; | |||||
} | } | ||||
var _op = _op_def_lib._apply_op_helper("ReadVariableOp", name, new | var _op = _op_def_lib._apply_op_helper("ReadVariableOp", name, new | ||||
@@ -17,6 +17,7 @@ | |||||
using NumSharp; | using NumSharp; | ||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using Tensorflow.Eager; | |||||
using Tensorflow.Framework; | using Tensorflow.Framework; | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
@@ -540,6 +541,11 @@ namespace Tensorflow | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
if(x is EagerTensor) | |||||
{ | |||||
return constant_op.constant(np.arange(x.shape.Rank)); | |||||
} | |||||
var rank = array_ops.rank(x); | var rank = array_ops.rank(x); | ||||
return range(0, rank, 1); | return range(0, rank, 1); | ||||
} | } | ||||
@@ -588,7 +594,14 @@ namespace Tensorflow | |||||
=> gen_math_ops.rsqrt(x, name: name); | => gen_math_ops.rsqrt(x, name: name); | ||||
public static Tensor pow<Tx, Ty>(Tx x, Ty y, string name = null) | public static Tensor pow<Tx, Ty>(Tx x, Ty y, string name = null) | ||||
=> gen_math_ops.pow(x, y, name: name); | |||||
=> tf_with(ops.name_scope(name, "Pow", new { x, y }), scope => | |||||
{ | |||||
name = scope; | |||||
var x_tensor = ops.convert_to_tensor(x, name: "x"); | |||||
var y_tensor = ops.convert_to_tensor(y, name: "y", dtype: x_tensor.dtype.as_base_dtype()); | |||||
return gen_math_ops.pow(x_tensor, y_tensor, name: name); | |||||
}); | |||||
public static Tensor range(object start, object limit = null, object delta = null, TF_DataType dtype = TF_DataType.DtInvalid, string name = "range") | public static Tensor range(object start, object limit = null, object delta = null, TF_DataType dtype = TF_DataType.DtInvalid, string name = "range") | ||||
{ | { | ||||
@@ -54,7 +54,7 @@ namespace Tensorflow | |||||
#else | #else | ||||
#region Compute | #region Compute | ||||
public static Tensor operator +(Tensor lhs, ResourceVariable rhs) => BinaryOpWrapper("add", lhs, rhs); | |||||
public static Tensor operator +(Tensor lhs, Tensor rhs) => BinaryOpWrapper("add", lhs, rhs); | public static Tensor operator +(Tensor lhs, Tensor rhs) => BinaryOpWrapper("add", lhs, rhs); | ||||
public static Tensor operator +(Tensor lhs, NDArray rhs) => BinaryOpWrapper("add", lhs, rhs); | public static Tensor operator +(Tensor lhs, NDArray rhs) => BinaryOpWrapper("add", lhs, rhs); | ||||
public static Tensor operator +(NDArray lhs, Tensor rhs) => BinaryOpWrapper("add", lhs, rhs); | public static Tensor operator +(NDArray lhs, Tensor rhs) => BinaryOpWrapper("add", lhs, rhs); | ||||
@@ -43,7 +43,7 @@ namespace Tensorflow | |||||
{ | { | ||||
//T can only be unmanaged, I believe it is safe to say that MemoryCopy is valid for all cases this method can be called. | //T can only be unmanaged, I believe it is safe to say that MemoryCopy is valid for all cases this method can be called. | ||||
var src = (T*)buffer; | var src = (T*)buffer; | ||||
len *= ((long)itemsize); | |||||
len *= (long)itemsize; | |||||
System.Buffer.MemoryCopy(src, dst, len, len); | System.Buffer.MemoryCopy(src, dst, len, len); | ||||
} | } | ||||
} | } | ||||
@@ -113,6 +113,21 @@ namespace Tensorflow | |||||
private static EagerTensor convert_to_eager_tensor(object value, Context ctx, TF_DataType dtype = TF_DataType.DtInvalid) | private static EagerTensor convert_to_eager_tensor(object value, Context ctx, TF_DataType dtype = TF_DataType.DtInvalid) | ||||
{ | { | ||||
// convert data type | |||||
if (dtype != TF_DataType.DtInvalid && | |||||
value.GetType().Name != "NDArray" && | |||||
dtypes.as_base_dtype(dtype) != dtypes.as_dtype(value.GetType())) | |||||
{ | |||||
switch (dtype) | |||||
{ | |||||
case TF_DataType.TF_FLOAT: | |||||
value = Convert.ToSingle(value); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
switch (value) | switch (value) | ||||
{ | { | ||||
case NDArray val: | case NDArray val: | ||||
@@ -2,6 +2,7 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Text; | using System.Text; | ||||
using Tensorflow.Gradients; | |||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
namespace Tensorflow | namespace Tensorflow | ||||
@@ -65,6 +66,7 @@ namespace Tensorflow | |||||
protected Tensor _read_variable_op() | protected Tensor _read_variable_op() | ||||
{ | { | ||||
variable_accessed(this); | |||||
var result = gen_resource_variable_ops.read_variable_op(_handle, _dtype); | var result = gen_resource_variable_ops.read_variable_op(_handle, _dtype); | ||||
// _maybe_set_handle_data(_dtype, _handle, result); | // _maybe_set_handle_data(_dtype, _handle, result); | ||||
return result; | return result; | ||||
@@ -82,12 +84,26 @@ namespace Tensorflow | |||||
void variable_accessed(BaseResourceVariable variable) | void variable_accessed(BaseResourceVariable variable) | ||||
{ | { | ||||
if (variable.trainable) | if (variable.trainable) | ||||
; // tape.variable_accessed(variable) | |||||
Tape.variable_accessed(variable as ResourceVariable); | |||||
} | } | ||||
/// <summary> | |||||
/// Constructs an op which reads the value of this variable. | |||||
/// | |||||
/// Should be used when there are multiple reads, or when it is desirable to | |||||
/// read the value only after some condition is true. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
Tensor read_value() | |||||
=> tf_with(ops.name_scope("Read"), delegate | |||||
{ | |||||
var value = _read_variable_op(); | |||||
return array_ops.identity(value); | |||||
}); | |||||
public override string ToString() | public override string ToString() | ||||
=> $"tf.Variable '{name}' shape={shape} dtype={dtype.as_numpy_name()}, numpy={numpy()}"; | => $"tf.Variable '{name}' shape={shape} dtype={dtype.as_numpy_name()}, numpy={numpy()}"; | ||||
public NDArray numpy() => _read_variable_op().numpy(); | |||||
public NDArray numpy() => read_value().numpy(); | |||||
} | } | ||||
} | } |
@@ -14,6 +14,7 @@ | |||||
limitations under the License. | limitations under the License. | ||||
******************************************************************************/ | ******************************************************************************/ | ||||
using NumSharp; | |||||
using System; | using System; | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
@@ -31,6 +32,7 @@ namespace Tensorflow | |||||
public static Tensor operator -(ResourceVariable x, Tensor y) => op_helper("sub", x, y); | public static Tensor operator -(ResourceVariable x, Tensor y) => op_helper("sub", x, y); | ||||
public static Tensor operator *(ResourceVariable x, ResourceVariable y) => gen_math_ops.mul(x, y); | public static Tensor operator *(ResourceVariable x, ResourceVariable y) => gen_math_ops.mul(x, y); | ||||
public static Tensor operator *(ResourceVariable x, NDArray y) => op_helper("mul", x, y); | |||||
public static Tensor operator <(ResourceVariable x, Tensor y) => gen_math_ops.less(x.value(), y); | public static Tensor operator <(ResourceVariable x, Tensor y) => gen_math_ops.less(x.value(), y); | ||||
@@ -53,6 +55,9 @@ namespace Tensorflow | |||||
case "sub": | case "sub": | ||||
result = gen_math_ops.sub(xVal, yTensor, name); | result = gen_math_ops.sub(xVal, yTensor, name); | ||||
break; | break; | ||||
case "mul": | |||||
result = gen_math_ops.mul(xVal, yTensor, name: name); | |||||
break; | |||||
default: | default: | ||||
throw new NotImplementedException(""); | throw new NotImplementedException(""); | ||||
} | } | ||||
@@ -464,7 +464,7 @@ namespace Tensorflow | |||||
case RefVariable varVal: | case RefVariable varVal: | ||||
return varVal._TensorConversionFunction(dtype: dtype, name: name, as_ref: as_ref); | return varVal._TensorConversionFunction(dtype: dtype, name: name, as_ref: as_ref); | ||||
case ResourceVariable varVal: | case ResourceVariable varVal: | ||||
return null; | |||||
return varVal.value(); | |||||
case TensorShape ts: | case TensorShape ts: | ||||
return constant_op.constant(ts.dims, dtype: dtype, name: name); | return constant_op.constant(ts.dims, dtype: dtype, name: name); | ||||
case int[] dims: | case int[] dims: | ||||