diff --git a/onnxruntime/core/optimizer/layer_norm_fusion.cc b/onnxruntime/core/optimizer/layer_norm_fusion.cc index 4b30a42e31..a4c543df56 100644 --- a/onnxruntime/core/optimizer/layer_norm_fusion.cc +++ b/onnxruntime/core/optimizer/layer_norm_fusion.cc @@ -218,25 +218,36 @@ Status LayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level) } nodes_to_remove.push_back(last_add_node); - // Get the inputs for the new LayerNormalization node + // Get the inputs for the new LayerNormalization node. NodeArg* scale = nullptr; NodeArg* bias = nullptr; for (size_t i = 0; i < mul_node.MutableInputDefs().size(); i++) { if (graph_utils::NodeArgIsConstant(graph, *(mul_node.MutableInputDefs()[i])) || graph_utils::IsGraphInput(graph, mul_node.MutableInputDefs()[i])) { - scale = mul_node.MutableInputDefs()[i]; + // Scale must be 1d. + if (mul_node.MutableInputDefs()[i]->Shape()->dim_size() == 1) { + scale = mul_node.MutableInputDefs()[i]; + } } } for (size_t i = 0; i < last_add_node.MutableInputDefs().size(); i++) { if (graph_utils::NodeArgIsConstant(graph, *(last_add_node.MutableInputDefs()[i])) || graph_utils::IsGraphInput(graph, last_add_node.MutableInputDefs()[i])) { - bias = mul_node.MutableInputDefs()[i]; + // Bias must be 1d. + if (last_add_node.MutableInputDefs()[i]->Shape()->dim_size() == 1) { + bias = last_add_node.MutableInputDefs()[i]; + } } } if (scale == nullptr || bias == nullptr) { continue; } + + // Scale and bias must have the same dimension. + if (scale->Shape()->dim(0).dim_value() != bias->Shape()->dim(0).dim_value()) { + continue; + } const std::vector layer_norm_input_defs{reduce_mean_node.MutableInputDefs()[0], scale, bias}; Node& layer_norm_node = graph.AddNode(graph.GenerateNodeName("LayerNormalization"), "LayerNormalization", diff --git a/onnxruntime/test/optimizer/graph_transform_test.cc b/onnxruntime/test/optimizer/graph_transform_test.cc index 39e07d43f1..81e19a1751 100644 --- a/onnxruntime/test/optimizer/graph_transform_test.cc +++ b/onnxruntime/test/optimizer/graph_transform_test.cc @@ -839,6 +839,21 @@ TEST(GraphTransformationTests, LayerNormFusionTest) { ASSERT_TRUE(op_to_count["Pow"] == 0); ASSERT_TRUE(op_to_count["Sqrt"] == 0); ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); + + for (const Node& node : graph.Nodes()) { + if (node.OpType() == "LayerNormalization") { + // LayerNormalization should have three inputs. + EXPECT_EQ(node.InputDefs().size(), 3) << "LayerNormalization number of inputs does not equal to 3. Got:" << node.InputDefs().size(); + // LayerNormalization input "scale" and "bias" should have the same dimension. + const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); + const TensorShapeProto* bias_shape = node.InputDefs()[2]->Shape(); + EXPECT_EQ(scale_shape->dim_size(), 1) << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); + EXPECT_EQ(bias_shape->dim_size(), 1) << "LayerNormalization bias should be 1D. Got: " << bias_shape->dim_size(); + EXPECT_EQ(scale_shape->dim(0).dim_value(), bias_shape->dim(0).dim_value()); + } else { + EXPECT_TRUE(false) << "Unexpected node " << node.Name(); + } + } } TEST(GraphTransformationTests, LayerNormWithSubDupFusionTest) { @@ -860,6 +875,21 @@ TEST(GraphTransformationTests, LayerNormWithSubDupFusionTest) { ASSERT_TRUE(op_to_count["Pow"] == 0); ASSERT_TRUE(op_to_count["Sqrt"] == 0); ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); + + for (const Node& node : graph.Nodes()) { + if (node.OpType() == "LayerNormalization") { + // LayerNormalization should have three inputs. + EXPECT_EQ(node.InputDefs().size(), 3) << "LayerNormalization number of inputs does not equal to 3. Got:" << node.InputDefs().size(); + // LayerNormalization input "scale" and "bias" should have the same dimension. + const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); + const TensorShapeProto* bias_shape = node.InputDefs()[2]->Shape(); + EXPECT_EQ(scale_shape->dim_size(), 1) << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); + EXPECT_EQ(bias_shape->dim_size(), 1) << "LayerNormalization bias should be 1D. Got: " << bias_shape->dim_size(); + EXPECT_EQ(scale_shape->dim(0).dim_value(), bias_shape->dim(0).dim_value()); + } else { + EXPECT_TRUE(false) << "Unexpected node " << node.Name(); + } + } } #endif