diff --git a/src/ngraph_builder.cc b/src/ngraph_builder.cc index 97e16062..62dff1bb 100644 --- a/src/ngraph_builder.cc +++ b/src/ngraph_builder.cc @@ -1717,34 +1717,36 @@ static Status TranslateFusedBatchNormOp( std::shared_ptr ng_batch_norm; if (tf_is_training) { - ng_batch_norm = make_shared(tf_epsilon, ng_scale, - ng_offset, ng_input); + ng_batch_norm = make_shared( + ng_input, ng_scale, ng_offset, tf_epsilon); - shared_ptr ng_y, ng_mean, ng_variance; - ng_y = make_shared(ng_batch_norm, 0); - ng_mean = make_shared(ng_batch_norm, 1); - ng_variance = make_shared(ng_batch_norm, 2); + shared_ptr ng_y_out, ng_mean_out, ng_variance_out; + ng_y_out = make_shared(ng_batch_norm, 0); + ng_mean_out = make_shared(ng_batch_norm, 1); + ng_variance_out = make_shared(ng_batch_norm, 2); - BatchToTensorflow(is_nhwc, ng_y); + BatchToTensorflow(is_nhwc, ng_y_out); - SaveNgOp(ng_op_map, op->name(), ng_y); - SaveNgOp(ng_op_map, op->name(), ng_mean); - SaveNgOp(ng_op_map, op->name(), ng_variance); + SaveNgOp(ng_op_map, op->name(), ng_y_out); + SaveNgOp(ng_op_map, op->name(), ng_mean_out); + SaveNgOp(ng_op_map, op->name(), ng_variance_out); // Output reserve_space_1: A 1D Tensor for the computed batch mean, to be // reused in the gradient computation. - SaveNgOp(ng_op_map, op->name(), ng_mean); + SaveNgOp(ng_op_map, op->name(), ng_mean_out); // Output reserve_space_2: A 1D Tensor for the computed batch variance //(inverted variance in the cuDNN case), to be reused in the gradient // computation. - SaveNgOp(ng_op_map, op->name(), ng_variance); + SaveNgOp(ng_op_map, op->name(), ng_variance_out); } else { ng_batch_norm = make_shared( - tf_epsilon, ng_scale, ng_offset, ng_input, ng_mean, ng_variance); + ng_input, ng_scale, ng_offset, ng_mean, ng_variance, tf_epsilon); BatchToTensorflow(is_nhwc, ng_batch_norm); SaveNgOp(ng_op_map, op->name(), ng_batch_norm); + // When train=false, only one output is expected + // Note here: EXPECT_EQ(1, tensors_expected.size()); + // https://github.com/tensorflow/tensorflow/blob/a767a02ca976d00b9e8e06042bdc2a2bb33b00eb/tensorflow/core/grappler/optimizers/remapper_test.cc#L47 } - SaveNgOp(ng_op_map, op->name(), ng_batch_norm); return Status::OK(); } @@ -1807,7 +1809,7 @@ static Status TranslateFusedBatchNormGradOp( std::shared_ptr ng_batch_norm_backprop; ng_batch_norm_backprop = make_shared( - tf_epsilon, ng_scale, ng_beta, ng_input, ng_mean, ng_variance, ng_delta); + ng_input, ng_scale, ng_beta, ng_mean, ng_variance, ng_delta, tf_epsilon); shared_ptr ng_input_delta_op = make_shared(ng_batch_norm_backprop, 0); diff --git a/test/test_nn_ops.cpp b/test/test_nn_ops.cpp index ee2e10e8..d92088bd 100644 --- a/test/test_nn_ops.cpp +++ b/test/test_nn_ops.cpp @@ -912,6 +912,81 @@ TEST(NNOps, Conv2DBackpropInputNHWCWithDilation) { } } // end of op Conv2DBackpropInputNHWCWithDilation +// FusedBatchNorm : Forward pass, training = true +// TODO fix this test +TEST(NNOps, DISABLED_FusedBatchNormNHWCTrainTrue) { + Scope root = Scope::NewRootScope(); + + // 4D tensor for the gradient with respect to y + Tensor x(DT_FLOAT, TensorShape({5, 4, 3, 2})); + // 4D tensor for input data + Tensor scale(DT_FLOAT, TensorShape({2})); + // 1D tensor for scaling the normalized x + Tensor offset(DT_FLOAT, TensorShape({2})); + // 1D (empty) tensor for population mean + Tensor mean(DT_FLOAT, TensorShape({0})); + // 1D (empty) tensor for population variance + Tensor variance(DT_FLOAT, TensorShape({0})); + + AssignInputValuesRandom(x, -10.0f, 5.0f); + AssignInputValuesRandom(scale, -10.0f, 5.0f); + AssignInputValuesRandom(offset, -2.0f, 2.0f); + // We will not fill mean and variance, + // since it is not used when training=true + + auto attrs = ops::FusedBatchNorm::Attrs(); + attrs.is_training_ = true; + attrs.epsilon_ = 0.0001f; + attrs.data_format_ = "NHWC"; + + // test grab all the outputs from the FusedBatchNorm op + vector static_input_indexes = {}; + vector output_datatypes(5, DT_FLOAT); + auto R = ops::FusedBatchNorm(root, x, scale, offset, mean, variance, attrs); + std::vector sess_run_fetchoutputs = { + R.y, R.batch_mean, R.batch_variance, R.reserve_space_1, + R.reserve_space_2}; + OpExecuter opexecuter(root, "FusedBatchNorm", static_input_indexes, + output_datatypes, sess_run_fetchoutputs); + opexecuter.RunTest(); +} + +// FusedBatchNorm : Forward pass, training = false +TEST(NNOps, FusedBatchNormNHWCTrainFalse) { + Scope root = Scope::NewRootScope(); + + // 4D tensor for the gradient with respect to y + Tensor x(DT_FLOAT, TensorShape({5, 4, 3, 2})); + // 4D tensor for input data + Tensor scale(DT_FLOAT, TensorShape({2})); + // 1D tensor for scaling the normalized x + Tensor offset(DT_FLOAT, TensorShape({2})); + // 1D tensor for population mean + Tensor mean(DT_FLOAT, TensorShape({2})); + // 1D tensor for population variance + Tensor variance(DT_FLOAT, TensorShape({2})); + + AssignInputValuesRandom(x, -5.0f, 10.0f); + AssignInputValuesRandom(scale, -10.0f, 10.0f); + AssignInputValuesRandom(offset, -1.6f, 1.6f); + AssignInputValuesRandom(mean, 1.1f, 1.5f); + AssignInputValuesRandom(variance, 0.5f, 1.5f); + + auto attrs = ops::FusedBatchNorm::Attrs(); + attrs.is_training_ = false; + attrs.epsilon_ = 0.0001f; + attrs.data_format_ = "NHWC"; + + // test grab all the outputs from the FusedBatchNorm op + vector static_input_indexes = {}; + vector output_datatypes = {DT_FLOAT}; + auto R = ops::FusedBatchNorm(root, x, scale, offset, mean, variance, attrs); + std::vector sess_run_fetchoutputs = {R.y}; + OpExecuter opexecuter(root, "FusedBatchNorm", static_input_indexes, + output_datatypes, sess_run_fetchoutputs); + opexecuter.RunTest(); +} + // FusedBatchNormGrad : Gradient for batch normalization // On TF CPU: only supports NHWC TEST(NNOps, FusedBatchNormGradNHWC) {