@@ -124,10 +124,10 @@ namespace Tensorflow | |||
=> gen_nn_ops.relu(features, name); | |||
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, | |||
string data_format = "NHWC", | |||
bool is_training = true, | |||
@@ -19,7 +19,6 @@ using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Reflection; | |||
using Tensorflow.Gradients; | |||
using static Tensorflow.Binding; | |||
namespace Tensorflow | |||
{ | |||
@@ -49,14 +48,48 @@ namespace Tensorflow | |||
RegisterGradientFunction(m.GetCustomAttribute<RegisterGradient>().Name, | |||
(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; | |||
} | |||
); | |||
@@ -17,6 +17,10 @@ namespace Tensorflow.NumPy | |||
float val => GetAtIndex<float>(0) == val, | |||
double val => GetAtIndex<double>(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), | |||
_ => base.Equals(obj) | |||
}; | |||
@@ -191,10 +191,10 @@ namespace Tensorflow.Operations | |||
} | |||
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 exponential_avg_factor = 1.0f, | |||
string data_format = "NHWC", | |||
@@ -150,20 +150,18 @@ namespace Tensorflow | |||
/// <param name="name"></param> | |||
/// <returns></returns> | |||
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, | |||
string data_format = "NHWC", | |||
bool is_training = true, | |||
string name = null, | |||
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; | |||
epsilon = epsilon > min_epsilon ? epsilon : min_epsilon; | |||
@@ -29,6 +29,8 @@ namespace Tensorflow | |||
{ | |||
get | |||
{ | |||
if (Length == 1) | |||
return items[0][index]; | |||
return items[index]; | |||
} | |||
@@ -214,10 +214,10 @@ namespace Tensorflow.Keras.Layers | |||
{ | |||
return tf.nn.fused_batch_norm( | |||
inputs, | |||
gamma, | |||
beta, | |||
mean: moving_mean, | |||
variance: moving_variance, | |||
gamma.AsTensor(), | |||
beta.AsTensor(), | |||
mean: moving_mean.AsTensor(), | |||
variance: moving_variance.AsTensor(), | |||
epsilon: epsilon, | |||
is_training: true, | |||
data_format: _data_format, | |||
@@ -228,10 +228,10 @@ namespace Tensorflow.Keras.Layers | |||
{ | |||
return tf.nn.fused_batch_norm( | |||
inputs, | |||
gamma, | |||
beta, | |||
mean: moving_mean, | |||
variance: moving_variance, | |||
gamma.AsTensor(), | |||
beta.AsTensor(), | |||
mean: moving_mean.AsTensor(), | |||
variance: moving_variance.AsTensor(), | |||
epsilon: epsilon, | |||
is_training: false, | |||
data_format: _data_format); | |||
@@ -101,7 +101,7 @@ namespace Tensorflow.Keras.Layers | |||
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 input_shape = inputs.shape; | |||
var ndims = len(input_shape); | |||
@@ -109,6 +109,13 @@ namespace Tensorflow.Keras.Layers | |||
foreach (var dim in axis) | |||
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) | |||
{ | |||
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 offset = tf.zeros(new Shape((int)pre_dim), dtype: DType); | |||
/*outputs = tf.nn.fused_batch_norm( | |||
outputs = tf.nn.fused_batch_norm( | |||
inputs, | |||
scale: scale, | |||
offset: offset, | |||
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 | |||
{ | |||
} | |||
// If some components of the shape got lost due to adjustments, fix that. | |||
outputs.shape = input_shape; | |||
return outputs; | |||
} | |||
} | |||
@@ -152,7 +152,6 @@ namespace TensorFlowNET.UnitTest | |||
//the core method | |||
void Core(int tid) | |||
{ | |||
Assert.IsNull(tf.peak_default_graph()); | |||
//graph is created automatically to perform create these operations | |||
var a1 = tf.constant(new[] { 2f }, shape: new[] { 1 }); | |||
var a2 = tf.constant(new[] { 3f }, shape: new[] { 1 }); | |||
@@ -5,6 +5,7 @@ using Tensorflow; | |||
using Tensorflow.Keras; | |||
using static Tensorflow.Binding; | |||
using static Tensorflow.KerasApi; | |||
using System.Linq; | |||
namespace TensorFlowNET.Keras.UnitTest | |||
{ | |||
@@ -86,7 +87,7 @@ namespace TensorFlowNET.Keras.UnitTest | |||
var emb = keras.layers.Embedding(256, 12, input_length: 4); | |||
var input_array = np.arange(12).reshape((3, 4)).astype(np.float32); | |||
var output = emb.Apply(input_array); | |||
Assert.AreEqual(new Shape(3, 4, 12), output.shape); | |||
Assert.AreEqual((3, 4, 12), output.shape); | |||
} | |||
/// <summary> | |||
@@ -159,7 +160,8 @@ namespace TensorFlowNET.Keras.UnitTest | |||
var inputs = tf.constant(np.arange(10).reshape((5, 2)) * 10, dtype: tf.float32); | |||
var layer = keras.layers.LayerNormalization(axis: 1); | |||
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 })); | |||
} | |||
} | |||
} |