From 5be6665b8603f0409926f93f0336680fd7ac7ce6 Mon Sep 17 00:00:00 2001 From: Tianlei Wu Date: Thu, 5 Mar 2020 18:31:52 -0800 Subject: [PATCH] Update Gelu Fusion to support new graph pattern from PyTorch 1.4 (#3148) * update GeluFusion to support pattern from PyTorch 1.4; * Fix a bug that missing the check of an edge between mul2 and root. * update script to fuse gelu from PyTorch 1.4 * Add test for python optimizer --- onnxruntime/core/optimizer/gelu_fusion.cc | 110 +++++++++---- .../python/tools/bert/BertOnnxModel.py | 48 ++++-- .../tools/bert/test_bert_optimization.py | 8 + .../BertForQuestionAnswering.onnx | Bin 0 -> 101833 bytes .../test_data_set_0/input_0.pb | Bin 0 -> 99 bytes .../test_data_set_0/input_1.pb | Bin 0 -> 100 bytes .../test_data_set_0/input_2.pb | Bin 0 -> 101 bytes .../test_data_set_0/output_0.pb | 3 + .../test_data_set_0/output_1.pb | 2 + .../test/optimizer/graph_transform_test.cc | 57 +++++++ .../transform/fusion/gelu_format2_0.onnx | Bin 0 -> 501 bytes .../transform/fusion/gelu_format2_1.onnx | Bin 0 -> 501 bytes .../gelu_format2_1_use_graph_input.onnx | Bin 0 -> 424 bytes .../testdata/transform/fusion/gelu_gen.py | 149 ++++++++++++++++++ 14 files changed, 331 insertions(+), 46 deletions(-) create mode 100644 onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/BertForQuestionAnswering.onnx create mode 100644 onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/test_data_set_0/input_0.pb create mode 100644 onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/test_data_set_0/input_1.pb create mode 100644 onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/test_data_set_0/input_2.pb create mode 100644 onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/test_data_set_0/output_0.pb create mode 100644 onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/test_data_set_0/output_1.pb create mode 100644 onnxruntime/test/testdata/transform/fusion/gelu_format2_0.onnx create mode 100644 onnxruntime/test/testdata/transform/fusion/gelu_format2_1.onnx create mode 100644 onnxruntime/test/testdata/transform/fusion/gelu_format2_1_use_graph_input.onnx create mode 100644 onnxruntime/test/testdata/transform/fusion/gelu_gen.py diff --git a/onnxruntime/core/optimizer/gelu_fusion.cc b/onnxruntime/core/optimizer/gelu_fusion.cc index a54c390935..6697c5117d 100644 --- a/onnxruntime/core/optimizer/gelu_fusion.cc +++ b/onnxruntime/core/optimizer/gelu_fusion.cc @@ -24,7 +24,25 @@ static bool IsSupportedDataType(const Node& node) { } return true; } +/* + This function fuses subgraph like the following into one Gelu node. + Subgraph pattern 1: + +-------Mul(0.5)---------------------+ + | | + | v + [root] --> Div -----> Erf --> Add --> Mul ==> + (B=1.4142...) (1) + Subgraph pattern 2: + +------------------------------------+ + | | + | v + [root] --> Div -----> Erf --> Add --> Mul -->Mul ==> + (B=1.4142...) (1) (0.5) + + After Fusion: + [root]--> Gelu ==> +*/ Status GeluFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const { GraphViewer graph_viewer(graph); const auto& node_topology_list = graph_viewer.GetNodesInTopologicalOrder(); @@ -68,13 +86,9 @@ Status GeluFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, cons continue; } - // Check the other input node(e.g. not of type Erf) is 1.0f. - const Node& add_first_input_node = *(add_node.InputNodesBegin()); - int add_const_input_index = 0; - if (add_first_input_node.OpType().compare("Erf") == 0) { - add_const_input_index = 1; - } - const auto& add_const_input_arg = add_node.InputDefs()[add_const_input_index]; + // Check the other input node (e.g. not the Erf) is 1.0f. + bool is_erf_first_input = (add_node.InputDefs()[0]->Name() == erf_node.MutableOutputDefs()[0]->Name()); + const auto& add_const_input_arg = add_node.InputDefs()[is_erf_first_input ? 1 : 0]; if (!optimizer_utils::IsInitializerWithExpectedValue(graph, *add_const_input_arg, 1.0f, true)) { continue; } @@ -87,35 +101,60 @@ Status GeluFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, cons continue; } - const Node* p_mul2_node = nullptr; - for (auto iter = mul_node.InputNodesBegin(); iter != mul_node.InputNodesEnd(); ++iter) { - if ((*iter).OpType().compare("Mul") == 0) { - // find the other input node of Mul - p_mul2_node = &(*iter); - break; + bool is_pattern_1 = true; + const Node* p_mul2_node = graph_utils::FirstParentByType(mul_node, "Mul"); + if (p_mul2_node != nullptr) { + // Match subgraph pattern 1 + Node& mul2_node = *graph.GetNode(p_mul2_node->Index()); + if (!graph_utils::IsSupportedOptypeVersionAndDomain(mul2_node, "Mul", {7}) || + mul2_node.GetExecutionProviderType() != div.GetExecutionProviderType() || + mul2_node.GetOutputEdgesCount() != 1 || + !IsSupportedDataType(mul2_node)) { + continue; } - } - if (p_mul2_node == nullptr) { - continue; - } - Node& mul2_node = *graph.GetNode(p_mul2_node->Index()); - if (!graph_utils::IsSupportedOptypeVersionAndDomain(mul2_node, "Mul", {7}) || - mul2_node.GetExecutionProviderType() != div.GetExecutionProviderType() || - mul2_node.GetOutputEdgesCount() != 1 || - !IsSupportedDataType(mul2_node)) { - continue; - } + // One input of mul2_node shall be the subgraph input + auto root_index = optimizer_utils::IndexOfNodeInput(*p_mul2_node, *div.InputDefs()[0]); + if (root_index < 0) + continue; - // Check the other input node(e.g. not of type Add) is 0.5f. - int mul_const_input_index = 0; - if (mul2_node.InputDefs()[0]->Name() == div.MutableInputDefs()[0]->Name()) { - mul_const_input_index = 1; - } + // Check the other input node is 0.5f. + int mul_const_input_index = (root_index == 0 ? 1 : 0); - const auto& mul_const_input_arg = mul2_node.InputDefs()[mul_const_input_index]; - if (!optimizer_utils::IsInitializerWithExpectedValue(graph, *mul_const_input_arg, 0.5f, true)) { - continue; + const auto& mul_const_input_arg = mul2_node.InputDefs()[mul_const_input_index]; + if (!optimizer_utils::IsInitializerWithExpectedValue(graph, *mul_const_input_arg, 0.5f, true)) { + continue; + } + } else { + is_pattern_1 = false; + + // Match subgraph pattern 2 + if (mul_node.GetOutputEdgesCount() != 1) { + continue; + } + + // Another input of Mul node shall be the subgraph input. + auto root_index = optimizer_utils::IndexOfNodeInput(mul_node, *div.InputDefs()[0]); + if (root_index < 0) + continue; + + Node& mul2_node = *graph.GetNode(mul_node.OutputNodesBegin()->Index()); + if (!graph_utils::IsSupportedOptypeVersionAndDomain(mul2_node, "Mul", {7}) || + mul_node.GetExecutionProviderType() != div.GetExecutionProviderType() || + !IsSupportedDataType(mul_node)) { + continue; + } + + int mul_const_input_index = 0; + if (mul2_node.InputDefs()[0]->Name() == mul_node.MutableOutputDefs()[0]->Name()) { + mul_const_input_index = 1; + } + const auto& mul_const_input_arg = mul2_node.InputDefs()[mul_const_input_index]; + if (!optimizer_utils::IsInitializerWithExpectedValue(graph, *mul_const_input_arg, 0.5f, true)) { + continue; + } + + p_mul2_node = &mul2_node; } const std::vector gelu_input_defs{div.MutableInputDefs()[0]}; @@ -131,7 +170,12 @@ Status GeluFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, cons // move input edges to div (first in list) across to the gelu_node. // move output definitions and output edges from mul_node (last in list) to gelu_node. // remove all the other nodes. - graph_utils::FinalizeNodeFusion(graph, {div, erf_node, add_node, mul2_node, mul_node}, gelu_node); + Node& mul2 = *graph.GetNode(p_mul2_node->Index()); + if (is_pattern_1) { + graph_utils::FinalizeNodeFusion(graph, {div, erf_node, add_node, mul2, mul_node}, gelu_node); + } else { + graph_utils::FinalizeNodeFusion(graph, {div, erf_node, add_node, mul_node, mul2}, gelu_node); + } modified = true; } diff --git a/onnxruntime/python/tools/bert/BertOnnxModel.py b/onnxruntime/python/tools/bert/BertOnnxModel.py index 48639aec75..b1a6cc6214 100644 --- a/onnxruntime/python/tools/bert/BertOnnxModel.py +++ b/onnxruntime/python/tools/bert/BertOnnxModel.py @@ -234,15 +234,24 @@ class BertOnnxModel(OnnxModel): """ Fuse Gelu with Erf into one node: - +-------Mul(B=0.5)-------------------+ + Pattern 1: + +-------Mul(0.5)---------------------+ | | | v [root] --> Div -----> Erf --> Add --> Mul --> - (B=1.4142...) (B=1) + (B=1.4142...) (1) + + Pattern 2: + +------------------------------------+ + | | + | v + [root] --> Div -----> Erf --> Add --> Mul -->Mul --> + (B=1.4142...) (1) (0.5) Note that constant input for Add and Mul could be first or second input: like either A=0.5 or B=0.5 is fine. """ def fuse_gelu_with_elf(self, gelu_op_name): + logger.debug(f"start fuse_gelu_with_elf({gelu_op_name})") input_name_to_nodes = self.input_name_to_nodes() output_name_to_node = self.output_name_to_node() @@ -276,25 +285,38 @@ class BertOnnxModel(OnnxModel): if self.find_constant_input(div, 1.4142, delta=0.001) != 1: continue - root_node = self.get_parent(div, 0, output_name_to_node) - if root_node is None: - continue + subgraph_input = div.input[0] - mul_half = self.match_parent(mul_after_erf, 'Mul', None, output_name_to_node) - if mul_half is None: - continue + another = 1 if mul_after_erf.input[0] == add_after_erf.output[0] else 0 + if subgraph_input == mul_after_erf.input[another]: # pattern 2 + children = input_name_to_nodes[mul_after_erf.output[0]] + if len(children) != 1 or children[0].op_type != 'Mul': + continue + mul_half = children[0] + if not self.has_constant_input(mul_half, 0.5): + continue + subgraph_output = mul_half.output[0] + else: # pattern 1 + mul_half = self.match_parent(mul_after_erf, 'Mul', another, output_name_to_node) + if mul_half is None: + continue - if not self.has_constant_input(mul_half, 0.5): - continue + if not self.has_constant_input(mul_half, 0.5): + continue + + if subgraph_input not in mul_half.input: + continue + + subgraph_output = mul_after_erf.output[0] subgraph_nodes = [div, erf_node, add_after_erf, mul_after_erf, mul_half] - if not self.is_safe_to_fuse_nodes(subgraph_nodes, [mul_after_erf.output[0]], input_name_to_nodes, output_name_to_node): + if not self.is_safe_to_fuse_nodes(subgraph_nodes, [subgraph_output], input_name_to_nodes, output_name_to_node): continue nodes_to_remove.extend(subgraph_nodes) gelu_node = onnx.helper.make_node(gelu_op_name, - inputs=[root_node.output[0]], - outputs=[mul_after_erf.output[0]]) + inputs=[subgraph_input], + outputs=[subgraph_output]) gelu_node.domain = "com.microsoft" nodes_to_add.append(gelu_node) diff --git a/onnxruntime/python/tools/bert/test_bert_optimization.py b/onnxruntime/python/tools/bert/test_bert_optimization.py index 3509d9a695..45f6e0a5e5 100644 --- a/onnxruntime/python/tools/bert/test_bert_optimization.py +++ b/onnxruntime/python/tools/bert/test_bert_optimization.py @@ -22,6 +22,7 @@ from OnnxModel import OnnxModel BERT_TEST_MODELS = { "bert_pytorch_0": 'test_data\\bert_squad_pytorch1.4_opset11\\BertForQuestionAnswering_0.onnx', "bert_pytorch_1": 'test_data\\bert_squad_pytorch1.4_opset11\\BertForQuestionAnswering_1.onnx', + "bert_squad_pytorch1.4_opset10_fp32": 'test_data\\bert_squad_pytorch1.4_opset10_fp32\\BertForQuestionAnswering.onnx', "bert_keras_0": 'test_data\\bert_mrpc_tensorflow2.1_opset10\\TFBertForSequenceClassification_1.onnx' } @@ -155,6 +156,13 @@ class TestBertOptimization(unittest.TestCase): } self.verify_node_count(bert_model, expected_node_count) + def test_pytorch_model_2_cpu(self): + input = BERT_TEST_MODELS['bert_squad_pytorch1.4_opset10_fp32'] + bert_model = optimize_model(input, 'bert', gpu_only=False, + num_heads=2, hidden_size=8, sequence_length=10, + input_int32=False, float16=False) + self.assertTrue(bert_model.is_fully_optimized()) + def test_keras_model_1_cpu(self): input = BERT_TEST_MODELS['bert_keras_0'] diff --git a/onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/BertForQuestionAnswering.onnx b/onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/BertForQuestionAnswering.onnx new file mode 100644 index 0000000000000000000000000000000000000000..e785236fd73282d1dfc239d613fde4a031c82be8 GIT binary patch literal 101833 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 z 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

Vh6fW~bd#)hZr`bwN7Ruw1j2qM~?K)-3 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 literal 0 HcmV?d00001 diff --git a/onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/test_data_set_0/input_0.pb b/onnxruntime/python/tools/bert/test_data/bert_squad_pytorch1.4_opset10_fp32/test_data_set_0/input_0.pb new file mode 100644 index 0000000000000000000000000000000000000000..23ef229fb0634fd4d2f958523dc449aadc1f89c0 GIT binary patch literal 99 zcmd;J p_model; + ASSERT_TRUE(Model::Load(model_uri, p_model, nullptr, DefaultLoggingManager().DefaultLogger()).IsOK()); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + graph_transformation_mgr.Register(onnxruntime::make_unique(), TransformerLevel::Level2); + auto ret = graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, DefaultLoggingManager().DefaultLogger()); + ASSERT_TRUE(ret.IsOK()); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["Erf"] == 0); + ASSERT_TRUE(op_to_count["Mul"] == 0); + ASSERT_TRUE(op_to_count["Gelu"] == 1); +} + +TEST(GraphTransformationTests, GeluFusionTestFormat2) { + auto model_uri = MODEL_FOLDER "fusion/gelu_format2_1.onnx"; + std::shared_ptr p_model; + ASSERT_TRUE(Model::Load(model_uri, p_model, nullptr, DefaultLoggingManager().DefaultLogger()).IsOK()); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + graph_transformation_mgr.Register(onnxruntime::make_unique(), TransformerLevel::Level2); + auto ret = graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, DefaultLoggingManager().DefaultLogger()); + ASSERT_TRUE(ret.IsOK()); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["Erf"] == 0); + ASSERT_TRUE(op_to_count["Mul"] == 0); + ASSERT_TRUE(op_to_count["Gelu"] == 1); +} + +TEST(GraphTransformationTests, GeluFusionTestFormat2GraphInput) { + auto model_uri = MODEL_FOLDER "fusion/gelu_format2_1_use_graph_input.onnx"; + std::shared_ptr p_model; + ASSERT_TRUE(Model::Load(model_uri, p_model, nullptr, DefaultLoggingManager().DefaultLogger()).IsOK()); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + graph_transformation_mgr.Register(onnxruntime::make_unique(), TransformerLevel::Level2); + auto ret = graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, DefaultLoggingManager().DefaultLogger()); + ASSERT_TRUE(ret.IsOK()); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["Erf"] == 0); + ASSERT_TRUE(op_to_count["Mul"] == 0); + ASSERT_TRUE(op_to_count["Gelu"] == 1); +} + TEST(GraphTransformationTests, BiasGeluTest) { auto model_uri = MODEL_FOLDER "fusion/bias_gelu_fusion.onnx"; std::shared_ptr p_model; diff --git a/onnxruntime/test/testdata/transform/fusion/gelu_format2_0.onnx b/onnxruntime/test/testdata/transform/fusion/gelu_format2_0.onnx new file mode 100644 index 0000000000000000000000000000000000000000..53ebed581331699e3d1a438325dc5ae652c62307 GIT binary patch literal 501 zcmaKoO-{ow5QS5c26x0yFbjkc3$iEz0aAn5uqi~apb{5g6Q!|JEICe^I#tH<`e117=(=&_=zlm(`d;puc tJC0TI3JAM1HWf_52D%%cLhB9x-xxYzc@XZwc9LgT8BfZ5mZ!?=d;=x1kg)&& literal 0 HcmV?d00001 diff --git a/onnxruntime/test/testdata/transform/fusion/gelu_format2_1.onnx b/onnxruntime/test/testdata/transform/fusion/gelu_format2_1.onnx new file mode 100644 index 0000000000000000000000000000000000000000..05f54a66fb84802edd7118c2fba253895ebae3a1 GIT binary patch literal 501 zcmaJ-OHRWu6ii53+$TQau|OEHAd4apAT@{$n?eN(DscfeQ5w6&QsRWvsmhK^aR?5; zeXx_zB1K{|(wjH-%p20htxU@0C0|Bqp77f*2X3GvWL_%t1mjW(^&TcXVnWVni}A@* zqk#dmw$MwZ)o;NF&^0ry z(0A?`gA1sJwk5raRvGpKm%W~I_4(A`xDT$&En z7vs*1CuNvNO7TL5!TG*tkJcBD-Ea4ESd*($#;#?3G^94J;~3H!zVv^4KZYY>;{j}9 tXA-IS6$p0c{4L=UHpt!N6q;=Kzi{M&<-uqVw&N_lN<~~`^K7a-`v)Ckkg)&& literal 0 HcmV?d00001 diff --git a/onnxruntime/test/testdata/transform/fusion/gelu_format2_1_use_graph_input.onnx b/onnxruntime/test/testdata/transform/fusion/gelu_format2_1_use_graph_input.onnx new file mode 100644 index 0000000000000000000000000000000000000000..db983ed59cb7c4aa1d12fe38a07fb67319939b11 GIT binary patch literal 424 zcmaiwy-ve06h@QA4ek{`!3+o^1~Py^0*SD(6e1X?#0#)QY3vkBi5*g>DjP4wqwqEi z*r_ROET81#&%VdTA=y+?E-&~pubYbBd=20PhC()-hEd&BSDBDPlYof@#U?VT7>|Q{ zv48`xlmxsjDK_D@9@-L)VU#nrIt#WykX_S0KJhd=)u@L+q1%*dW7cu8SAIB%Jftic1*a+vzDdw||N$ W0xyDe7q$vjU)G{%)m)W2^1lHlHgshG literal 0 HcmV?d00001 diff --git a/onnxruntime/test/testdata/transform/fusion/gelu_gen.py b/onnxruntime/test/testdata/transform/fusion/gelu_gen.py new file mode 100644 index 0000000000..dca31ffba7 --- /dev/null +++ b/onnxruntime/test/testdata/transform/fusion/gelu_gen.py @@ -0,0 +1,149 @@ +import onnx +from onnx import helper +from onnx import AttributeProto, TensorProto, GraphProto, OperatorSetIdProto +from onnx import numpy_helper +import numpy as np + +""" +Generate test model for Gelu subgraph pattern 2: + +------------------------------------+ + | | + | v + [root] --> Div -----> Erf --> Add --> Mul -->Mul ==> + (B=1.4142...) (1) (0.5) +""" + +has_bias = True # change it to True to generate gelu_format2_*_with_bias.onnx +gelu_use_graph_input = False # change it to False to let Gelu don't have graph inputs as inputs. +switch_order = True # switch order of inputs for Mul and Add + +X = helper.make_tensor_value_info('input', TensorProto.FLOAT, ["batch", "seqlen", 64]) +Y = helper.make_tensor_value_info('output', TensorProto.FLOAT, ["batch", "seqlen", 64]) + +value = (0.01 * np.arange(64)).astype(np.float32).reshape((64)) +bias_initializer = numpy_helper.from_array(value, "input_bias") + +value = np.asarray([1.4142099618911743]).astype(np.float32).reshape(()) +initializer_sqrt_2 = numpy_helper.from_array(value, "mul1_init") + +value = np.asarray([0.5]).astype(np.float32).reshape(()) +initializer_0_5 = numpy_helper.from_array(value, "mul3_init") + +value = np.asarray([1.0]).astype(np.float32).reshape(()) +initializer_1 = numpy_helper.from_array(value, "add1_init") + + +nodes = [] +gelu_input = "input" +if not gelu_use_graph_input: + leading_identity = helper.make_node( + 'Identity', + [gelu_input], + ['identity_leading'], + name="identity_leading" + ) + gelu_input = "identity_leading" + nodes.append(leading_identity) + +gelu_root = gelu_input +if has_bias: + add0 = helper.make_node( + 'Add', + [gelu_input, bias_initializer.name] if switch_order else [bias_initializer.name, gelu_input], + ['add0'], + name="add0_node" + ) + gelu_root = "add0" + nodes.append(add0) + + +div = helper.make_node( + 'Div', + [gelu_root, initializer_sqrt_2.name], + ['div'], + name="div_node" +) +nodes.append(div) + +erf = helper.make_node( + 'Erf', + ['div'], + ['erf'], + name="erf_node" +) +nodes.append(erf) + +add1 = helper.make_node( + 'Add', + ['erf', initializer_1.name] if switch_order else [initializer_1.name, 'erf'], + ['add1'], + name="add1" +) +nodes.append(add1) + +mul = helper.make_node( + 'Mul', + [gelu_root, 'add1'] if switch_order else ['add1', gelu_root], + ['mul'], + name="mul_node" +) +nodes.append(mul) + +mul2 = helper.make_node( + 'Mul', + ['mul', initializer_0_5.name] if switch_order else [initializer_0_5.name, 'mul'], + ['mul2'], + name="mul2_node" +) +nodes.append(mul2) + +ending_identity = helper.make_node( + 'Identity', + ['mul2'], + ['output'], + name="identity_ending" +) +nodes.append(ending_identity) + +initializers = [] +if has_bias: + initializers = [bias_initializer] + +initializers.extend([initializer_sqrt_2, initializer_1, initializer_0_5]) + +# Create the graph (GraphProto) +graph_def = helper.make_graph( + nodes, + 'gelu_pattern_2', + [X], + [Y], + initializers +) + +opsets = [] +onnxdomain = OperatorSetIdProto() +onnxdomain.version = 10 +onnxdomain.domain = "" # The empty string ("") or absence of this field implies the operator set that is defined as part of the ONNX specification. +opsets.append(onnxdomain) + +msdomain = OperatorSetIdProto() +msdomain.version = 1 +msdomain.domain = "com.microsoft" + +opsets.append(msdomain) +kwargs={} +kwargs["opset_imports"] = opsets + +model_def = helper.make_model(graph_def, producer_name='onnx-example', **kwargs) + +file_name = "gelu_format2_0" if switch_order else "gelu_format2_1" +if has_bias: + file_name += "_with_bias" + +if gelu_use_graph_input: + file_name += "_use_graph_input" + +file_name += ".onnx" +onnx.save(model_def, file_name) +print(file_name) +