!27792 add add,concat and activation fusion

Merge pull request !27792 from wangyanling/concatactivation
This commit is contained in:
i-robot 2021-12-22 01:54:24 +00:00 committed by Gitee
commit 375ee5691f
9 changed files with 440 additions and 12 deletions

View File

@ -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})

View File

@ -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

View File

@ -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 <memory>
#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<schema::MetaGraphT>;
using CNodeTptr = std::unique_ptr<schema::CNodeT>;
namespace {
CNodeTptr BuildAdd(const string &name, std::vector<uint32_t> input_index, std::vector<uint32_t> output_index) {
auto add_node = std::make_unique<schema::CNodeT>();
add_node->inputIndex = input_index;
add_node->outputIndex = output_index;
add_node->primitive = std::make_unique<schema::PrimitiveT>();
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<schema::CNodeT>();
concat_node->inputIndex = {opt::kInputIndexTwo, opt::kInputIndexFive};
concat_node->outputIndex = {opt::kInputIndexSix};
concat_node->primitive = std::make_unique<schema::PrimitiveT>();
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<schema::TensorT> &input, std::vector<int32_t> 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<schema::MetaGraphT>();
meta_graph->name = "graph";
// add node1
std::vector<uint32_t> input_index{0, 1};
std::vector<uint32_t> 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<uint32_t>({opt::kInputIndexThree, opt::kInputIndexFour});
output_index = std::vector<uint32_t>({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<schema::CNodeT>();
next_node->inputIndex = {opt::kInputIndexSix};
next_node->outputIndex = {opt::kInputIndexSeven};
next_node->primitive = std::make_unique<schema::PrimitiveT>();
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<schema::TensorT>();
BuildTensorT(input0, {1, kAddInputTensorWSize});
input0->offset = -1;
meta_graph->allTensors.emplace_back(std::move(input0));
// input 1: data
auto input2 = std::make_unique<schema::TensorT>();
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<schema::TensorT>();
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<schema::TensorT>();
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<schema::TensorT>();
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<schema::TensorT>();
BuildTensorT(add_node2_out, {1, kAddInputTensorWSize});
meta_graph->allTensors.emplace_back(std::move(add_node2_out));
// concat output
auto concat_output = std::make_unique<schema::TensorT>();
BuildTensorT(concat_output, {1, kConcatInputTensorWDims});
meta_graph->allTensors.emplace_back(std::move(concat_output));
// final output
auto output = std::make_unique<schema::TensorT>();
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

View File

@ -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 <string>
#include <memory>
#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<opt::AddConcatActivationFusion>(); }
void InitGraph() override {
this->graph_ = std::make_shared<FuncGraph>();
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<ops::AddFusion>();
MS_CHECK_TRUE_MSG(prim != nullptr, nullptr, "create AddFusion primitivec failed");
prim->Init(ActivationType::NO_ACTIVATION);
auto add_primitive = NewValueNode(std::shared_ptr<ops::PrimitiveC>(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<ops::Concat>();
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<ops::PrimitiveC>(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<ops::Activation>();
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<ops::PrimitiveC>(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

View File

@ -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;

View File

@ -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<opt::AddConcatActivationFusion>());
fusion_pm->AddPass(std::make_shared<opt::SqueezeFusion>());
fusion_pm->AddPass(std::make_shared<opt::TransposeFusion>());
fusion_pm->AddPass(std::make_shared<opt::ReshapeReshapeFusion>());

View File

@ -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;

View File

@ -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 <memory>
#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<CondVar>(IsSpecifiedNode<&prim::kPrimActivation>);
MS_CHECK_TRUE_RET(is_act != nullptr, {});
auto is_concat = std::make_shared<CondVar>(IsSpecifiedNode<&prim::kPrimConcat>);
MS_CHECK_TRUE_RET(is_concat != nullptr, {});
auto is_seq_var = std::make_shared<SeqVar>();
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<CNodePtr>();
MS_CHECK_TRUE_RET(act_cnode != nullptr, nullptr);
auto concat_node = act_cnode->input(1);
auto concat_cnode = concat_node->cast<CNodePtr>();
MS_CHECK_TRUE_RET(concat_node != nullptr, nullptr);
if (concat_cnode->size() != kInputIndexThree || !utils::isa<CNode>(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<CNodePtr>();
auto right_add_prim = GetValueNode<std::shared_ptr<ops::AddFusion>>(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<int64_t>(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<CNodePtr>();
auto left_add_prim = GetValueNode<std::shared_ptr<ops::AddFusion>>(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<int64_t>(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<std::shared_ptr<ops::Activation>>(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

View File

@ -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 <string>
#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_