@@ -124,10 +124,10 @@ namespace Tensorflow | |||||
=> gen_nn_ops.relu(features, name); | => gen_nn_ops.relu(features, name); | ||||
public Tensor[] fused_batch_norm(Tensor x, | public Tensor[] fused_batch_norm(Tensor x, | ||||
IVariableV1 scale, | |||||
IVariableV1 offset, | |||||
IVariableV1 mean = null, | |||||
IVariableV1 variance = null, | |||||
Tensor scale, | |||||
Tensor offset, | |||||
Tensor mean = null, | |||||
Tensor variance = null, | |||||
float epsilon = 0.001f, | float epsilon = 0.001f, | ||||
string data_format = "NHWC", | string data_format = "NHWC", | ||||
bool is_training = true, | bool is_training = true, | ||||
@@ -19,7 +19,6 @@ using System.Collections.Generic; | |||||
using System.Linq; | using System.Linq; | ||||
using System.Reflection; | using System.Reflection; | ||||
using Tensorflow.Gradients; | using Tensorflow.Gradients; | ||||
using static Tensorflow.Binding; | |||||
namespace Tensorflow | namespace Tensorflow | ||||
{ | { | ||||
@@ -49,14 +48,48 @@ namespace Tensorflow | |||||
RegisterGradientFunction(m.GetCustomAttribute<RegisterGradient>().Name, | RegisterGradientFunction(m.GetCustomAttribute<RegisterGradient>().Name, | ||||
(oper, out_grads) => | (oper, out_grads) => | ||||
{ | { | ||||
tf.Logger.Debug($"Caculate Gradient: {oper.name} {m.Name}"); | |||||
var results = g.InvokeMember(m.Name, | |||||
BindingFlags.InvokeMethod, | |||||
null, | |||||
null, | |||||
args: new object[] { oper, out_grads }) as Tensor[]; | |||||
foreach (var result in results.Where(x => x != null)) | |||||
tf.Logger.Debug($"Gradient: {result.name} {result.shape}"); | |||||
// tf.Logger.Debug($"Caculate Gradient: {oper.name} {m.Name}"); | |||||
var results = m.Name switch | |||||
{ | |||||
"_AddGrad" => math_grad._AddGrad(oper, out_grads), | |||||
"_AddV2Grad" => math_grad._AddV2Grad(oper, out_grads), | |||||
"_BiasAddGrad" => nn_grad._BiasAddGrad(oper, out_grads), | |||||
"_CastGrad" => math_grad._CastGrad(oper, out_grads), | |||||
"_ConcatGradV2" => array_grad._ConcatGradV2(oper, out_grads), | |||||
"_Conv2DGrad" => nn_grad._Conv2DGrad(oper, out_grads), | |||||
"_ExpandDimsGrad" => array_grad._ExpandDimsGrad(oper, out_grads), | |||||
"_ExpGrad" => math_grad._ExpGrad(oper, out_grads), | |||||
"_FusedBatchNormV3Grad" => nn_grad._FusedBatchNormV3Grad(oper, out_grads), | |||||
"_IdGrad" => math_grad._IdGrad(oper, out_grads), | |||||
"_LeakyReluGrad" => nn_grad._LeakyReluGrad(oper, out_grads), | |||||
"_Log1pGrad" => math_grad._Log1pGrad(oper, out_grads), | |||||
"_MaximumGrad" => math_grad._MaximumGrad(oper, out_grads), | |||||
"_MeanGrad" => math_grad._MeanGrad(oper, out_grads), | |||||
"_MinimumGrad" => math_grad._MinimumGrad(oper, out_grads), | |||||
"_MulGrad" => math_grad._MulGrad(oper, out_grads), | |||||
"_NegGrad" => math_grad._NegGrad(oper, out_grads), | |||||
"_PadGrad" => array_grad._PadGrad(oper, out_grads), | |||||
"_PowGrad" => math_grad._PowGrad(oper, out_grads), | |||||
"_RealDivGrad" => math_grad._RealDivGrad(oper, out_grads), | |||||
"_ReadGrad" => resource_variable_grad._ReadGrad(oper, out_grads), | |||||
"_ReshapeGrad" => array_grad._ReshapeGrad(oper, out_grads), | |||||
"_ResizeNearestNeighborGrad" => image_grad._ResizeNearestNeighborGrad(oper, out_grads), | |||||
"_SelectGrad" => math_grad._SelectGrad(oper, out_grads), | |||||
"_SigmoidGrad" => math_grad._SigmoidGrad(oper, out_grads), | |||||
"_SumGrad" => math_grad._SumGrad(oper, out_grads), | |||||
"_SubGrad" => math_grad._SubGrad(oper, out_grads), | |||||
"_StridedSliceGrad" => array_grad._StridedSliceGrad(oper, out_grads), | |||||
_ => g.InvokeMember(m.Name, | |||||
BindingFlags.InvokeMethod, | |||||
null, | |||||
null, | |||||
args: new object[] { oper, out_grads }) as Tensor[] | |||||
}; | |||||
// foreach (var result in results.Where(x => x != null)) | |||||
// tf.Logger.Debug($"Gradient: {result.name} {result.shape}"); | |||||
return results; | return results; | ||||
} | } | ||||
); | ); | ||||
@@ -17,6 +17,10 @@ namespace Tensorflow.NumPy | |||||
float val => GetAtIndex<float>(0) == val, | float val => GetAtIndex<float>(0) == val, | ||||
double val => GetAtIndex<double>(0) == val, | double val => GetAtIndex<double>(0) == val, | ||||
string val => StringData(0) == val, | string val => StringData(0) == val, | ||||
int[] val => ToArray<int>().SequenceEqual(val), | |||||
long[] val => ToArray<long>().SequenceEqual(val), | |||||
float[] val => ToArray<float>().SequenceEqual(val), | |||||
double[] val => ToArray<double>().SequenceEqual(val), | |||||
NDArray val => Equals(this, val), | NDArray val => Equals(this, val), | ||||
_ => base.Equals(obj) | _ => base.Equals(obj) | ||||
}; | }; | ||||
@@ -191,10 +191,10 @@ namespace Tensorflow.Operations | |||||
} | } | ||||
public static Tensors fused_batch_norm_v3(Tensor x, | public static Tensors fused_batch_norm_v3(Tensor x, | ||||
IVariableV1 scale, | |||||
IVariableV1 offset, | |||||
IVariableV1 mean, | |||||
IVariableV1 variance, | |||||
Tensor scale, | |||||
Tensor offset, | |||||
Tensor mean, | |||||
Tensor variance, | |||||
float epsilon = 0.0001f, | float epsilon = 0.0001f, | ||||
float exponential_avg_factor = 1.0f, | float exponential_avg_factor = 1.0f, | ||||
string data_format = "NHWC", | string data_format = "NHWC", | ||||
@@ -150,20 +150,18 @@ namespace Tensorflow | |||||
/// <param name="name"></param> | /// <param name="name"></param> | ||||
/// <returns></returns> | /// <returns></returns> | ||||
public static Tensor[] fused_batch_norm(Tensor x, | public static Tensor[] fused_batch_norm(Tensor x, | ||||
IVariableV1 scale, | |||||
IVariableV1 offset, | |||||
IVariableV1 mean, | |||||
IVariableV1 variance, | |||||
Tensor scale, | |||||
Tensor offset, | |||||
Tensor mean = null, | |||||
Tensor variance = null, | |||||
float epsilon = 0.001f, | float epsilon = 0.001f, | ||||
string data_format = "NHWC", | string data_format = "NHWC", | ||||
bool is_training = true, | bool is_training = true, | ||||
string name = null, | string name = null, | ||||
float exponential_avg_factor = 1.0f) | float exponential_avg_factor = 1.0f) | ||||
{ | { | ||||
/*if (mean == null) | |||||
mean = constant_op.constant(new float[0]); | |||||
if (variance == null) | |||||
variance = constant_op.constant(new float[0]);*/ | |||||
mean = mean ?? constant_op.constant(new float[0]); | |||||
variance = variance ?? constant_op.constant(new float[0]); | |||||
var min_epsilon = 1.001e-5f; | var min_epsilon = 1.001e-5f; | ||||
epsilon = epsilon > min_epsilon ? epsilon : min_epsilon; | epsilon = epsilon > min_epsilon ? epsilon : min_epsilon; | ||||
@@ -29,6 +29,8 @@ namespace Tensorflow | |||||
{ | { | ||||
get | get | ||||
{ | { | ||||
if (Length == 1) | |||||
return items[0][index]; | |||||
return items[index]; | return items[index]; | ||||
} | } | ||||
@@ -214,10 +214,10 @@ namespace Tensorflow.Keras.Layers | |||||
{ | { | ||||
return tf.nn.fused_batch_norm( | return tf.nn.fused_batch_norm( | ||||
inputs, | inputs, | ||||
gamma, | |||||
beta, | |||||
mean: moving_mean, | |||||
variance: moving_variance, | |||||
gamma.AsTensor(), | |||||
beta.AsTensor(), | |||||
mean: moving_mean.AsTensor(), | |||||
variance: moving_variance.AsTensor(), | |||||
epsilon: epsilon, | epsilon: epsilon, | ||||
is_training: true, | is_training: true, | ||||
data_format: _data_format, | data_format: _data_format, | ||||
@@ -228,10 +228,10 @@ namespace Tensorflow.Keras.Layers | |||||
{ | { | ||||
return tf.nn.fused_batch_norm( | return tf.nn.fused_batch_norm( | ||||
inputs, | inputs, | ||||
gamma, | |||||
beta, | |||||
mean: moving_mean, | |||||
variance: moving_variance, | |||||
gamma.AsTensor(), | |||||
beta.AsTensor(), | |||||
mean: moving_mean.AsTensor(), | |||||
variance: moving_variance.AsTensor(), | |||||
epsilon: epsilon, | epsilon: epsilon, | ||||
is_training: false, | is_training: false, | ||||
data_format: _data_format); | data_format: _data_format); | ||||
@@ -101,7 +101,7 @@ namespace Tensorflow.Keras.Layers | |||||
protected override Tensors Call(Tensors inputs, Tensor state = null, bool? training = null) | protected override Tensors Call(Tensors inputs, Tensor state = null, bool? training = null) | ||||
{ | { | ||||
Tensors outputs = null; | |||||
Tensor outputs = null; | |||||
var inputs_dtype = inputs.dtype.as_base_dtype(); | var inputs_dtype = inputs.dtype.as_base_dtype(); | ||||
var input_shape = inputs.shape; | var input_shape = inputs.shape; | ||||
var ndims = len(input_shape); | var ndims = len(input_shape); | ||||
@@ -109,6 +109,13 @@ namespace Tensorflow.Keras.Layers | |||||
foreach (var dim in axis) | foreach (var dim in axis) | ||||
broadcast_shape[dim] = input_shape.as_int_list()[dim]; | broadcast_shape[dim] = input_shape.as_int_list()[dim]; | ||||
Func<IVariableV1, Tensor> _broadcast = v => | |||||
{ | |||||
if (v.shape.ndim != ndims && !axis.SequenceEqual(new int[] { ndims - 1 })) | |||||
return tf.reshape(v.AsTensor(), broadcast_shape); | |||||
return v.AsTensor(); | |||||
}; | |||||
if (_fused) | if (_fused) | ||||
{ | { | ||||
var tensor_shape = tf.shape(inputs); | var tensor_shape = tf.shape(inputs); | ||||
@@ -127,18 +134,28 @@ namespace Tensorflow.Keras.Layers | |||||
var scale = tf.ones(new Shape((int)pre_dim), dtype: DType); | var scale = tf.ones(new Shape((int)pre_dim), dtype: DType); | ||||
var offset = tf.zeros(new Shape((int)pre_dim), dtype: DType); | var offset = tf.zeros(new Shape((int)pre_dim), dtype: DType); | ||||
/*outputs = tf.nn.fused_batch_norm( | |||||
outputs = tf.nn.fused_batch_norm( | |||||
inputs, | inputs, | ||||
scale: scale, | scale: scale, | ||||
offset: offset, | offset: offset, | ||||
epsilon: epsilon, | epsilon: epsilon, | ||||
data_format: "NCHW");*/ | |||||
data_format: "NCHW")[0]; | |||||
outputs = tf.reshape(outputs, tensor_shape); | |||||
(scale, offset) = (_broadcast(gamma), _broadcast(beta)); | |||||
outputs = outputs * tf.cast(scale, outputs.dtype); | |||||
outputs = outputs + tf.cast(offset, outputs.dtype); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
} | } | ||||
// If some components of the shape got lost due to adjustments, fix that. | |||||
outputs.shape = input_shape; | |||||
return outputs; | return outputs; | ||||
} | } | ||||
} | } | ||||
@@ -152,7 +152,6 @@ namespace TensorFlowNET.UnitTest | |||||
//the core method | //the core method | ||||
void Core(int tid) | void Core(int tid) | ||||
{ | { | ||||
Assert.IsNull(tf.peak_default_graph()); | |||||
//graph is created automatically to perform create these operations | //graph is created automatically to perform create these operations | ||||
var a1 = tf.constant(new[] { 2f }, shape: new[] { 1 }); | var a1 = tf.constant(new[] { 2f }, shape: new[] { 1 }); | ||||
var a2 = tf.constant(new[] { 3f }, shape: new[] { 1 }); | var a2 = tf.constant(new[] { 3f }, shape: new[] { 1 }); | ||||
@@ -5,6 +5,7 @@ using Tensorflow; | |||||
using Tensorflow.Keras; | using Tensorflow.Keras; | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
using static Tensorflow.KerasApi; | using static Tensorflow.KerasApi; | ||||
using System.Linq; | |||||
namespace TensorFlowNET.Keras.UnitTest | namespace TensorFlowNET.Keras.UnitTest | ||||
{ | { | ||||
@@ -86,7 +87,7 @@ namespace TensorFlowNET.Keras.UnitTest | |||||
var emb = keras.layers.Embedding(256, 12, input_length: 4); | var emb = keras.layers.Embedding(256, 12, input_length: 4); | ||||
var input_array = np.arange(12).reshape((3, 4)).astype(np.float32); | var input_array = np.arange(12).reshape((3, 4)).astype(np.float32); | ||||
var output = emb.Apply(input_array); | var output = emb.Apply(input_array); | ||||
Assert.AreEqual(new Shape(3, 4, 12), output.shape); | |||||
Assert.AreEqual((3, 4, 12), output.shape); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -159,7 +160,8 @@ namespace TensorFlowNET.Keras.UnitTest | |||||
var inputs = tf.constant(np.arange(10).reshape((5, 2)) * 10, dtype: tf.float32); | var inputs = tf.constant(np.arange(10).reshape((5, 2)) * 10, dtype: tf.float32); | ||||
var layer = keras.layers.LayerNormalization(axis: 1); | var layer = keras.layers.LayerNormalization(axis: 1); | ||||
var output = layer.Apply(inputs); | var output = layer.Apply(inputs); | ||||
// Assert.AreEqual((10, 16, 16, 3), output.shape); | |||||
Assert.AreEqual((5, 2), output.shape); | |||||
Assert.IsTrue(output[0].numpy().Equals(new[] { -0.99998f, 0.99998f })); | |||||
} | } | ||||
} | } | ||||
} | } |