diff --git a/mindspore/lite/test/CMakeLists.txt b/mindspore/lite/test/CMakeLists.txt index ca13657c605..e21aac2cf33 100644 --- a/mindspore/lite/test/CMakeLists.txt +++ b/mindspore/lite/test/CMakeLists.txt @@ -113,15 +113,7 @@ if(MSLITE_ENABLE_CONVERTER) ${TEST_DIR}/st/graph_test.cc ${TEST_DIR}/st/sub_graph_test.cc ${TEST_DIR}/ut/src/dynamic_library_loader_test.cc - ${TEST_DIR}/ut/tools/optimizer/fusion/fusion_inout_test/fusion_inout_test.cc - ${TEST_DIR}/ut/tools/optimizer/fusion/fusion_inout_test/conv_fusion_inout_test.cc - ${TEST_DIR}/ut/tools/optimizer/fusion/fusion_inout_test/conv_act_fusion_inout_test.cc - ${TEST_DIR}/ut/tools/optimizer/fusion/fusion_inout_test/conv_bias_fusion_inout_test.cc - ${TEST_DIR}/ut/tools/optimizer/fusion/conv_biasadd_fusion_test.cc - ${TEST_DIR}/ut/tools/optimizer/fusion/conv_bn_fusion_test.cc - ${TEST_DIR}/ut/tools/optimizer/fusion/conv_scale_fusion_test.cc - ${TEST_DIR}/ut/tools/optimizer/fusion/conv_activation_fusion_test.cc - ${TEST_DIR}/ut/tools/optimizer/fusion/constant_folding_fusion_test.cc + ${TEST_DIR}/ut/tools/optimizer/fusion/*.cc ) list(APPEND TEST_UT_SRC ${TEST_CONVERTER_UT_SRC}) diff --git a/mindspore/lite/test/runtest.sh b/mindspore/lite/test/runtest.sh index 0c2934f1bb9..821198d0f60 100644 --- a/mindspore/lite/test/runtest.sh +++ b/mindspore/lite/test/runtest.sh @@ -34,7 +34,7 @@ echo 'run common ut tests' ## ./lite-test --gtest_filter="TestTfliteParser*" ./lite-test --gtest_filter="ConvActFusionInoutTest*" ./lite-test --gtest_filter="ConvBiasFusionInoutTest*" - +./lite-test --gtest_filter="ConcatActFusionInoutTest*" # test cases of framework # test cases of FP32 OP diff --git a/mindspore/lite/test/ut/tools/optimizer/fusion/add_concat_act_fusion_test.cc b/mindspore/lite/test/ut/tools/optimizer/fusion/add_concat_act_fusion_test.cc new file mode 100644 index 00000000000..f24eb8d4acf --- /dev/null +++ b/mindspore/lite/test/ut/tools/optimizer/fusion/add_concat_act_fusion_test.cc @@ -0,0 +1,171 @@ +/** + * Copyright 2020-2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "schema/inner/model_generated.h" +#include "include/model.h" +#include "common/common_test.h" +#include "include/lite_session.h" +#include "include/context.h" +#include "include/errorcode.h" +#include "src/common/log_adapter.h" +#include "tools/converter/anf_transform.h" +#include "tools/anf_exporter/anf_exporter.h" +#include "tools/optimizer/common/gllo_utils.h" +#include "test/common/import_from_meta_graphT.h" + +namespace mindspore { +constexpr size_t kAddInputTensorWSize = 128; +constexpr size_t kConcatInputTensorWDims = 256; +constexpr size_t kGraphNodeSize = 3; +class AddConcatActivationFusionTest : public mindspore::CommonTest { + public: + AddConcatActivationFusionTest() = default; +}; +using MetaGraphTptr = std::shared_ptr; +using CNodeTptr = std::unique_ptr; + +namespace { +CNodeTptr BuildAdd(const string &name, std::vector input_index, std::vector output_index) { + auto add_node = std::make_unique(); + add_node->inputIndex = input_index; + add_node->outputIndex = output_index; + add_node->primitive = std::make_unique(); + add_node->primitive->value.type = schema::PrimitiveType_AddFusion; + auto prim1 = new schema::AddFusionT; + prim1->activation_type = mindspore::schema::ActivationType_NO_ACTIVATION; + add_node->primitive->value.value = prim1; + add_node->name = name; + return add_node; +} + +CNodeTptr BuildConcat() { + auto concat_node = std::make_unique(); + concat_node->inputIndex = {opt::kInputIndexTwo, opt::kInputIndexFive}; + concat_node->outputIndex = {opt::kInputIndexSix}; + concat_node->primitive = std::make_unique(); + concat_node->primitive->value.type = schema::PrimitiveType_Concat; + auto prim1 = new schema::ConcatT; + prim1->axis = 1; + concat_node->primitive->value.value = prim1; + concat_node->name = "Concat"; + return concat_node; +} + +void BuildTensorT(const std::unique_ptr &input, std::vector shape) { + input->nodeType = lite::NodeType_Parameter; + input->format = schema::Format_NHWC; + input->dataType = TypeId::kNumberTypeFloat32; + input->dims = shape; + return; +} + +MetaGraphTptr BuildGraph(schema::ActivationType activation_type) { + auto meta_graph = std::make_shared(); + meta_graph->name = "graph"; + + // add node1 + std::vector input_index{0, 1}; + std::vector output_index{opt::kInputIndexTwo}; + auto add_node1 = BuildAdd("add_node1", input_index, output_index); + meta_graph->nodes.emplace_back(std::move(add_node1)); + + // add node2 + input_index = std::vector({opt::kInputIndexThree, opt::kInputIndexFour}); + output_index = std::vector({opt::kInputIndexFive}); + auto add_node2 = BuildAdd("add_node2", input_index, output_index); + meta_graph->nodes.emplace_back(std::move(add_node2)); + + // concat node + auto caoncat_node = BuildConcat(); + meta_graph->nodes.emplace_back(std::move(caoncat_node)); + + // relu node + auto next_node = std::make_unique(); + next_node->inputIndex = {opt::kInputIndexSix}; + next_node->outputIndex = {opt::kInputIndexSeven}; + next_node->primitive = std::make_unique(); + next_node->primitive->value.type = schema::PrimitiveType_Activation; + auto prim4 = new schema::ActivationT; + prim4->activation_type = activation_type; + next_node->primitive->value.value = prim4; + next_node->name = "activation"; + meta_graph->nodes.emplace_back(std::move(next_node)); + + meta_graph->inputIndex = {0, 1, opt::kInputIndexThree, opt::kInputIndexFour}; + meta_graph->outputIndex = {opt::kInputIndexSeven}; + + // input 0: data + auto input0 = std::make_unique(); + BuildTensorT(input0, {1, kAddInputTensorWSize}); + input0->offset = -1; + meta_graph->allTensors.emplace_back(std::move(input0)); + + // input 1: data + auto input2 = std::make_unique(); + BuildTensorT(input2, {1, kAddInputTensorWSize}); + input2->offset = -1; + meta_graph->allTensors.emplace_back(std::move(input2)); + + // output 1: data + auto add_node1_out = std::make_unique(); + BuildTensorT(add_node1_out, {1, kAddInputTensorWSize}); + meta_graph->allTensors.emplace_back(std::move(add_node1_out)); + + // input 2: data + auto add_node2_input1 = std::make_unique(); + BuildTensorT(add_node2_input1, {1, kAddInputTensorWSize}); + add_node2_input1->offset = -1; + meta_graph->allTensors.emplace_back(std::move(add_node2_input1)); + + // input 3: data + auto add_node2_input2 = std::make_unique(); + BuildTensorT(add_node2_input2, {1, kAddInputTensorWSize}); + add_node2_input2->offset = -1; + meta_graph->allTensors.emplace_back(std::move(add_node2_input2)); + + // output 2: data + auto add_node2_out = std::make_unique(); + BuildTensorT(add_node2_out, {1, kAddInputTensorWSize}); + meta_graph->allTensors.emplace_back(std::move(add_node2_out)); + + // concat output + auto concat_output = std::make_unique(); + BuildTensorT(concat_output, {1, kConcatInputTensorWDims}); + meta_graph->allTensors.emplace_back(std::move(concat_output)); + + // final output + auto output = std::make_unique(); + BuildTensorT(output, {1, kConcatInputTensorWDims}); + meta_graph->allTensors.emplace_back(std::move(output)); + return meta_graph; +} +} // namespace +TEST_F(AddConcatActivationFusionTest, TestAddConcatReluNode) { + auto meta_graph = BuildGraph(schema::ActivationType_RELU6); + auto func_graph = lite::AnfImporterFromMetaGraphT::Fb2Anf(meta_graph.get()); + auto anf_transform = new lite::AnfTransform(); + auto new_graph = anf_transform->Transform(func_graph); + ASSERT_NE(nullptr, new_graph); + auto new_meta_graph = lite::Export(new_graph); + ASSERT_EQ(new_meta_graph->nodes.size(), kGraphNodeSize); + for (auto &cnode : new_meta_graph->nodes) { + if (cnode->primitive->value.type == schema::PrimitiveType_AddFusion) { + ASSERT_EQ(cnode->primitive->value.AsAddFusion()->activation_type, schema::ActivationType_RELU6); + } + } +} +} // namespace mindspore diff --git a/mindspore/lite/test/ut/tools/optimizer/fusion/fusion_inout_test/add_concat_act_fusion_inout_test.cc b/mindspore/lite/test/ut/tools/optimizer/fusion/fusion_inout_test/add_concat_act_fusion_inout_test.cc new file mode 100644 index 00000000000..4847b771992 --- /dev/null +++ b/mindspore/lite/test/ut/tools/optimizer/fusion/fusion_inout_test/add_concat_act_fusion_inout_test.cc @@ -0,0 +1,120 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "test/ut/tools/optimizer/fusion/fusion_inout_test/fusion_inout_test.h" +#include "ir/anf.h" +#include "backend/optimizer/common/pass.h" +#include "backend/optimizer/common/optimizer.h" +#include "backend/optimizer/common/pass_manager.h" +#include "tools/optimizer/fusion/add_concat_activation_fusion.h" +#include "backend/kernel_compiler/cpu/nnacl/op_base.h" +#include "ops/fusion/activation.h" +#include "ops/concat.h" +#include "ops/fusion/add_fusion.h" + +namespace mindspore { +namespace { +constexpr size_t kAddInputTensorWSize = 128; +} +class ConcatActFusionInoutTest : public FusionInoutTest { + public: + ConcatActFusionInoutTest() = default; + + protected: + void InitPass() override { this->pass_ = std::make_shared(); } + + void InitGraph() override { + this->graph_ = std::make_shared(); + MS_CHECK_TRUE_MSG(graph_ != nullptr, , "Create FuncGraph failed"); + auto left_add_node = AddAdd(graph_, "left_add_node"); + if (left_add_node == nullptr) { + this->graph_ = nullptr; + return; + } + auto right_add_node = AddAdd(graph_, "right_add_node"); + if (right_add_node == nullptr) { + this->graph_ = nullptr; + return; + } + auto concat_node = AddConcat(graph_, left_add_node, right_add_node, "concat"); + if (concat_node == nullptr) { + this->graph_ = nullptr; + return; + } + + auto act = AddAct(graph_, concat_node, "concat_act"); + if (act == nullptr) { + this->graph_ = nullptr; + return; + } + + auto ret = AddReturn(graph_, {act}); + if (ret == nullptr) { + this->graph_ = nullptr; + return; + } + } + CNodePtr AddAdd(const FuncGraphPtr &graph, const std::string &name) { + AnfNodePtr input1 = + AddParameter(graph_, 0, {add_left_h_, add_left_w_}, kNumberTypeFloat32, "graph_" + name + "_input1"); + AnfNodePtr input2 = + AddParameter(graph_, 0, {add_left_h_, add_left_w_}, kNumberTypeFloat32, "graph_" + name + "_input2"); + auto prim = std::make_unique(); + MS_CHECK_TRUE_MSG(prim != nullptr, nullptr, "create AddFusion primitivec failed"); + prim->Init(ActivationType::NO_ACTIVATION); + auto add_primitive = NewValueNode(std::shared_ptr(prim.release())); + MS_CHECK_TRUE_RET(add_primitive != nullptr, nullptr); + auto add_fusion = graph->NewCNode({add_primitive, input1, input2}); + MS_CHECK_TRUE_MSG(add_fusion != nullptr, nullptr, "create AddFusion failed"); + add_fusion->set_fullname_with_scope(name); + return add_fusion; + } + + CNodePtr AddConcat(const FuncGraphPtr &graph, const AnfNodePtr &input1, const AnfNodePtr &input2, + const std::string &name) { + auto concat_primitive = std::make_unique(); + MS_CHECK_TRUE_MSG(concat_primitive != nullptr, nullptr, "create concat primitivec failed"); + concat_primitive->Init(); + concat_primitive->set_axis(1); + auto concat_primc = NewValueNode(std::shared_ptr(concat_primitive.release())); + MS_CHECK_TRUE_RET(concat_primc != nullptr, nullptr); + auto concat = graph->NewCNode({concat_primc, input1, input2}); + MS_CHECK_TRUE_MSG(concat != nullptr, nullptr, "create Concat failed"); + concat->set_fullname_with_scope(name); + return concat; + } + + CNodePtr AddAct(const FuncGraphPtr &graph, const AnfNodePtr &input, const std::string &name) { + auto prim = std::make_unique(); + MS_CHECK_TRUE_MSG(prim != nullptr, nullptr, "create Act primitivec failed"); + prim->Init(); + prim->set_activation_type(ActivationType::RELU6); + auto act_primitive = NewValueNode(std::shared_ptr(prim.release())); + MS_CHECK_TRUE_RET(act_primitive != nullptr, nullptr); + auto act = graph->NewCNode({act_primitive, input}); + MS_CHECK_TRUE_MSG(act != nullptr, nullptr, "create Act failed"); + act->set_fullname_with_scope(name); + return act; + } + + private: + int add_left_h_ = 1; + int add_left_w_ = kAddInputTensorWSize; +}; + +TEST_F(ConcatActFusionInoutTest, test) { ASSERT_EQ(DoTest(), true); } +} // namespace mindspore diff --git a/mindspore/lite/test/ut/tools/optimizer/fusion/fusion_inout_test/fusion_inout_test.cc b/mindspore/lite/test/ut/tools/optimizer/fusion/fusion_inout_test/fusion_inout_test.cc index 5fa4d7144cc..f84fb641b69 100644 --- a/mindspore/lite/test/ut/tools/optimizer/fusion/fusion_inout_test/fusion_inout_test.cc +++ b/mindspore/lite/test/ut/tools/optimizer/fusion/fusion_inout_test/fusion_inout_test.cc @@ -67,8 +67,11 @@ ParameterPtr FusionInoutTest::AddParameter(const FuncGraphPtr &graph, size_t dat } } auto tensor_info = lite::CreateTensorInfo(data, data_size, shape, data_type); - free(data); - data = nullptr; + if (data != nullptr) { + free(data); + data = nullptr; + } + if (tensor_info == nullptr) { MS_LOG(ERROR) << "CreateTensorInfo failed"; return nullptr; diff --git a/mindspore/lite/tools/converter/anf_transform.cc b/mindspore/lite/tools/converter/anf_transform.cc index 7f8ab779d1c..296c2f4a071 100644 --- a/mindspore/lite/tools/converter/anf_transform.cc +++ b/mindspore/lite/tools/converter/anf_transform.cc @@ -56,6 +56,7 @@ #include "tools/optimizer/fusion/scale_activation_fusion.h" #include "tools/optimizer/fusion/scale_scale_fusion.h" #include "tools/optimizer/fusion/fullconnected_fusion.h" +#include "tools/optimizer/fusion/add_concat_activation_fusion.h" #include "tools/optimizer/graph/add_tensor_array.h" #include "tools/optimizer/graph/redundant_op_remove_pass.h" #include "tools/optimizer/graph/clip_convert_activation_pass.h" @@ -178,6 +179,7 @@ int AnfTransform::RunFusionPass(const FuncGraphPtr &old_graph, const converter:: // The training model only does the fusion of the inference part // remove quantdtype when awaretraining + fusion_pm->AddPass(std::make_shared()); fusion_pm->AddPass(std::make_shared()); fusion_pm->AddPass(std::make_shared()); fusion_pm->AddPass(std::make_shared()); diff --git a/mindspore/lite/tools/optimizer/common/gllo_utils.h b/mindspore/lite/tools/optimizer/common/gllo_utils.h index 3ea19b19ca5..a520e82a74f 100644 --- a/mindspore/lite/tools/optimizer/common/gllo_utils.h +++ b/mindspore/lite/tools/optimizer/common/gllo_utils.h @@ -44,6 +44,8 @@ inline constexpr int kInputIndexTwo = 2; inline constexpr int kInputIndexThree = 3; inline constexpr int kInputIndexFour = 4; inline constexpr int kInputIndexFive = 5; +inline constexpr int kInputIndexSix = 6; +inline constexpr int kInputIndexSeven = 7; inline constexpr size_t kInputSizeTwo = 2; inline constexpr size_t kInputSizeThree = 3; inline constexpr size_t kInputSizeFour = 4; diff --git a/mindspore/lite/tools/optimizer/fusion/add_concat_activation_fusion.cc b/mindspore/lite/tools/optimizer/fusion/add_concat_activation_fusion.cc new file mode 100644 index 00000000000..280e2451f2a --- /dev/null +++ b/mindspore/lite/tools/optimizer/fusion/add_concat_activation_fusion.cc @@ -0,0 +1,103 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "tools/optimizer/fusion/add_concat_activation_fusion.h" +#include +#include "ops/concat.h" +#include "ops/fusion/activation.h" +#include "ops/fusion/add_fusion.h" +#include "tools/optimizer/common/gllo_utils.h" +#include "nnacl/op_base.h" + +namespace mindspore::opt { +const BaseRef AddConcatActivationFusion::DefinePattern() const { + auto is_act = std::make_shared(IsSpecifiedNode<&prim::kPrimActivation>); + MS_CHECK_TRUE_RET(is_act != nullptr, {}); + auto is_concat = std::make_shared(IsSpecifiedNode<&prim::kPrimConcat>); + MS_CHECK_TRUE_RET(is_concat != nullptr, {}); + auto is_seq_var = std::make_shared(); + MS_CHECK_TRUE_RET(is_seq_var != nullptr, {}); + VectorRef pattern_ref = VectorRef({is_act, is_concat, is_seq_var}); + return pattern_ref; +} + +const AnfNodePtr AddConcatActivationFusion::Process(const FuncGraphPtr &func_graph, const AnfNodePtr &node, + const EquivPtr &) const { + if (func_graph == nullptr || node == nullptr) { + lite::ReturnCode::GetSingleReturnCode()->UpdateReturnCode(lite::RET_NULL_PTR); + return nullptr; + } + if (!CheckPrimitiveType(node, prim::kPrimActivation)) { + MS_LOG(INFO) << "node is not activation node"; + return nullptr; + } + auto act_cnode = node->cast(); + MS_CHECK_TRUE_RET(act_cnode != nullptr, nullptr); + auto concat_node = act_cnode->input(1); + auto concat_cnode = concat_node->cast(); + MS_CHECK_TRUE_RET(concat_node != nullptr, nullptr); + if (concat_cnode->size() != kInputIndexThree || !utils::isa(concat_cnode->input(kInputIndexTwo))) { + MS_LOG(INFO) << "concat node must link two add node in front"; + return nullptr; + } + auto right_add_node = concat_cnode->input(1); + MS_CHECK_TRUE_RET(right_add_node != nullptr, nullptr); + if (!CheckPrimitiveType(right_add_node, prim::kPrimAddFusion)) { + MS_LOG(INFO) << "right node is not add node"; + return nullptr; + } + auto right_add_cnode = right_add_node->cast(); + auto right_add_prim = GetValueNode>(right_add_cnode->input(0)); + MS_CHECK_TRUE_RET(right_add_prim != nullptr, nullptr); + if (right_add_prim->GetAttr(ops::kActivationType) == nullptr) { + right_add_prim->AddAttr(ops::kActivationType, MakeValue(ActivationType::NO_ACTIVATION)); + } + if (right_add_prim->get_activation_type() != ActivationType::NO_ACTIVATION) { + MS_LOG(INFO) << "right add node has activation"; + return nullptr; + } + + auto left_add_node = concat_cnode->input(kInputIndexTwo); + MS_CHECK_TRUE_RET(left_add_node != nullptr, nullptr); + if (!CheckPrimitiveType(left_add_node, prim::kPrimAddFusion)) { + return nullptr; + } + auto left_add_cnode = left_add_node->cast(); + auto left_add_prim = GetValueNode>(left_add_cnode->input(0)); + MS_CHECK_TRUE_RET(left_add_prim != nullptr, nullptr); + if (left_add_prim->GetAttr(ops::kActivationType) == nullptr) { + left_add_prim->AddAttr(ops::kActivationType, MakeValue(ActivationType::NO_ACTIVATION)); + } + if (left_add_prim->get_activation_type() != ActivationType::NO_ACTIVATION) { + MS_LOG(INFO) << "left add node has activation"; + return nullptr; + } + + auto act_prim = GetValueNode>(act_cnode->input(0)); + MS_CHECK_TRUE_RET(act_prim != nullptr, nullptr); + if (act_prim->GetAttr(ops::kActivationType) != nullptr) { + right_add_prim->set_activation_type(act_prim->get_activation_type()); + left_add_prim->set_activation_type(act_prim->get_activation_type()); + } + + // delete activation node + auto manager = func_graph->manager(); + MS_CHECK_TRUE_RET(manager != nullptr, nullptr); + (void)manager->Replace(act_cnode, act_cnode->input(1)); + + return nullptr; +} +} // namespace mindspore::opt diff --git a/mindspore/lite/tools/optimizer/fusion/add_concat_activation_fusion.h b/mindspore/lite/tools/optimizer/fusion/add_concat_activation_fusion.h new file mode 100644 index 00000000000..7af773fcdcf --- /dev/null +++ b/mindspore/lite/tools/optimizer/fusion/add_concat_activation_fusion.h @@ -0,0 +1,35 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_TOOLS_OPTIMIZER_FUSION_ADD_CONCAT_ACTIVATION_FUSION_H_ +#define MINDSPORE_LITE_TOOLS_OPTIMIZER_FUSION_ADD_CONCAT_ACTIVATION_FUSION_H_ + +#include +#include "backend/optimizer/common/optimizer.h" + +namespace mindspore::opt { +class AddConcatActivationFusion : public PatternProcessPass { + public: + explicit AddConcatActivationFusion(bool multigraph = true, const std::string &name = "AddConcatActivationFusion") + : PatternProcessPass(name, multigraph) {} + ~AddConcatActivationFusion() override = default; + + private: + const BaseRef DefinePattern() const override; + const AnfNodePtr Process(const FuncGraphPtr &, const AnfNodePtr &, const EquivPtr &) const override; +}; +} // namespace mindspore::opt +#endif // MINDSPORE_LITE_TOOLS_OPTIMIZER_FUSION_ADD_CONCAT_ACTIVATION_FUSION_H_