From c9a39758bf3a1dfb6e764d39594e7fc92eba4c7b Mon Sep 17 00:00:00 2001 From: Paulina Gacek Date: Mon, 6 Mar 2023 10:14:56 +0100 Subject: [PATCH] Rewrite multi_gru_fuse_pass_tester & multi_gru_seq_fuse_pass_tester (#50094) * first approach * test finished * cpp test deleted * CmakeList corrected * multi_gru_seq_fuse_pass rewritten * dummy cout deleted * review changes * timeout extended --- paddle/fluid/framework/ir/CMakeLists.txt | 8 - .../ir/mkldnn/multi_gru_fuse_pass.cc | 96 +++++++- .../framework/ir/mkldnn/multi_gru_fuse_pass.h | 1 + .../ir/mkldnn/multi_gru_fuse_pass_tester.cc | 181 --------------- .../ir/mkldnn/multi_gru_seq_fuse_pass.cc | 54 +++++ .../ir/mkldnn/multi_gru_seq_fuse_pass.h | 1 + .../mkldnn/multi_gru_seq_fuse_pass_tester.cc | 192 ---------------- .../unittests/ir/inference/CMakeLists.txt | 3 + .../unittests/ir/inference/program_config.py | 4 + .../test_onednn_multi_gru_fuse_pass.py | 134 +++++++++++ .../test_onednn_multi_gru_seq_fuse_pass.py | 213 ++++++++++++++++++ 11 files changed, 505 insertions(+), 382 deletions(-) delete mode 100644 paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass_tester.cc delete mode 100644 paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass_tester.cc create mode 100644 python/paddle/fluid/tests/unittests/ir/inference/test_onednn_multi_gru_fuse_pass.py create mode 100644 python/paddle/fluid/tests/unittests/ir/inference/test_onednn_multi_gru_seq_fuse_pass.py diff --git a/paddle/fluid/framework/ir/CMakeLists.txt b/paddle/fluid/framework/ir/CMakeLists.txt index e602b899fe..a27780b025 100755 --- a/paddle/fluid/framework/ir/CMakeLists.txt +++ b/paddle/fluid/framework/ir/CMakeLists.txt @@ -483,12 +483,4 @@ if(WITH_MKLDNN) test_cpu_bfloat16_pass SRCS mkldnn/cpu_bfloat16_pass_tester.cc DEPS cpu_bfloat16_pass) - cc_test( - test_multi_gru_fuse_pass - SRCS mkldnn/multi_gru_fuse_pass_tester.cc - DEPS multi_gru_fuse_pass) - cc_test( - test_multi_gru_seq_fuse_pass - SRCS mkldnn/multi_gru_seq_fuse_pass_tester.cc - DEPS multi_gru_seq_fuse_pass) endif() diff --git a/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass.cc b/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass.cc index e83cc1fa6a..08aafa4a60 100644 --- a/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass.cc +++ b/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass.cc @@ -18,6 +18,7 @@ #include "paddle/fluid/framework/eigen.h" #include "paddle/fluid/framework/ir/graph_pattern_detector.h" +#include "paddle/fluid/framework/op_version_registry.h" #include "paddle/phi/core/errors.h" #include "paddle/utils/string/pretty_log.h" @@ -57,6 +58,11 @@ void MultiGRUFusePass::ApplyImpl(ir::Graph* graph) const { int fused_count = 0; auto handler = [&](const GraphPatternDetector::subgraph_t& subgraph, Graph* g) { + if (!IsCompat(subgraph, g)) { + LOG(WARNING) << "Pass in op compat failed."; + return; + } + GET_IR_NODE_FROM_SUBGRAPH(x, x, pattern); GET_IR_NODE_FROM_SUBGRAPH(gru1, gru1, pattern); GET_IR_NODE_FROM_SUBGRAPH(gru2, gru2, pattern); @@ -99,7 +105,6 @@ void MultiGRUFusePass::ApplyImpl(ir::Graph* graph) const { multi_gru_desc.SetAttr("layers", 1); auto multi_gru = g->CreateOpNode(&multi_gru_desc); // OpDesc will be copied. - IR_NODE_LINK_TO(x, multi_gru); IR_NODE_LINK_TO(b1, multi_gru); IR_NODE_LINK_TO(b2, multi_gru); @@ -119,8 +124,97 @@ void MultiGRUFusePass::ApplyImpl(ir::Graph* graph) const { fused_count); } +MultiGRUFusePass::MultiGRUFusePass() { + AddOpCompat(OpCompat("concat")) + .AddInput("X") + .End() + .AddInput("AxisTensor") + .IsTensor() + .IsOptional() + .End() + .AddOutput("Out") + .IsTensor() + .End() + .AddAttr("axis") + .IsNumEQ(1) + .End(); + + AddOpCompat(OpCompat("fusion_gru")) + .AddInput("X") + .IsTensor() + .End() + .AddInput("H0") + .IsTensor() + .IsOptional() + .End() + .AddInput("WeightX") + .IsTensor() + .End() + .AddInput("WeightH") + .IsTensor() + .End() + .AddInput("Bias") + .IsTensor() + .IsOptional() + .End() + .AddOutput("Hidden") + .IsTensor() + .End() + .AddOutput("XX") + .IsTensor() + .End() + .AddOutput("ReorderedH0") + .IsTensor() + .IsOptional() + .End() + .AddOutput("BatchedInput") + .IsTensor() + .IsOptional() + .End() + .AddOutput("BatchedOut") + .IsTensor() + .IsOptional() + .End() + .AddAttr("activation") + .IsType() + .End() + .AddAttr("is_reverse") + .IsType() + .End() + .AddAttr("use_seq") + .IsType() + .End() + .AddAttr("origin_mode") + .IsType() + .End() + .AddAttr("use_mkldnn") + .IsType() + .End() + .AddAttr("mkldnn_data_type") + .IsType() + .End() + .AddAttr("Scale_data") + .IsType() + .End() + .AddAttr("Shift_data") + .IsType() + .End() + .AddAttr("Scale_weights") + .IsType>() + .End() + .AddAttr("force_fp32_output") + .IsType() + .End(); +} + } // namespace ir } // namespace framework } // namespace paddle REGISTER_PASS(multi_gru_fuse_pass, paddle::framework::ir::MultiGRUFusePass); + +REGISTER_PASS_CAPABILITY(multi_gru_fuse_pass) + .AddCombination( + paddle::framework::compatible::OpVersionComparatorCombination() + .EQ("concat", 0) + .LE("fusion_gru", 1)); diff --git a/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass.h b/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass.h index cf53ecec92..fd8dec353e 100644 --- a/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass.h +++ b/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass.h @@ -32,6 +32,7 @@ namespace ir { class MultiGRUFusePass : public FusePassBase { public: virtual ~MultiGRUFusePass() {} + MultiGRUFusePass(); protected: void ApplyImpl(ir::Graph* graph) const override; diff --git a/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass_tester.cc b/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass_tester.cc deleted file mode 100644 index b50d9a8d4b..0000000000 --- a/paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass_tester.cc +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. -// -// 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 "paddle/fluid/framework/ir/mkldnn/multi_gru_fuse_pass.h" - -namespace paddle { -namespace framework { -namespace ir { - -void SetOp(ProgramDesc* prog, - const std::string& type, - const std::vector& inputs, - const std::vector& outputs, - bool is_reverse = false, - bool origin_mode = false) { - auto* op = prog->MutableBlock(0)->AppendOp(); - - op->SetType(type); - if (type == "fusion_gru") { - op->SetInput("X", {inputs[0]}); - op->SetInput("WeightX", {inputs[1]}); - op->SetInput("WeightH", {inputs[2]}); - op->SetInput("Bias", {inputs[3]}); - op->SetOutput("Hidden", {outputs[0]}); - op->SetAttr("is_reverse", is_reverse); - op->SetAttr("origin_mode", origin_mode); - } else if (type == "concat") { - op->SetInput("X", {inputs[0], inputs[1]}); - op->SetOutput("Out", {outputs[0]}); - } else { - FAIL() << "Unexpected operator type."; - } -} - -static const std::initializer_list variable_names = { - "x", "wx1", "wx2", "wh1", "wh2", "b1", "b2", "h1", "h2", "out"}; - -// (x, wx1, wh1, b1) -> fusion_gru1 -> h1 -// (x, wx2, wh2, b2) -> fusion_gru2 -> h2 -// (h1, h2) -> concat -> out -ProgramDesc BuildProgramDesc(bool origin_mode1, bool origin_mode2) { - ProgramDesc prog; - - for (auto& v : variable_names) { - prog.MutableBlock(0)->Var(v); - } - SetOp(&prog, - "fusion_gru", - {"x", "wx1", "wh1", "b1"}, - {"h1"}, - false, - origin_mode1); - SetOp(&prog, - "fusion_gru", - {"x", "wx2", "wh2", "b2"}, - {"h2"}, - true, - origin_mode2); - SetOp(&prog, "concat", {"h1", "h2"}, {"out"}); - return prog; -} - -void MainTest(const ProgramDesc& prog, - int removed_nodes_count, - int added_nodes_count, - const std::vector multi_gru_inputs, - const std::string multi_gru_output, - bool origin_mode) { - // Apply pass - std::unique_ptr graph(new ir::Graph(prog)); - Scope scope; - graph->SetNotOwned(kParamScopeAttr, &scope); - int original_nodes_num = graph->Nodes().size(); - auto pass = PassRegistry::Instance().Get("multi_gru_fuse_pass"); - graph.reset(pass->Apply(graph.release())); - int current_nodes_num = graph->Nodes().size(); - - // Verify graph after fuse - int count_multi_gru = 0; - for (auto* node : graph->Nodes()) { - if (node->IsOp()) { - auto* op = node->Op(); - if (op->Type() == "multi_gru") { - EXPECT_EQ(op->Input("X")[0], multi_gru_inputs[0]); - EXPECT_EQ(op->Input("WeightX").size(), 2u); - EXPECT_EQ(op->Input("WeightX")[0], multi_gru_inputs[1]); - EXPECT_EQ(op->Input("WeightX")[1], multi_gru_inputs[2]); - EXPECT_EQ(op->Input("WeightH").size(), 2u); - EXPECT_EQ(op->Input("WeightH")[0], multi_gru_inputs[3]); - EXPECT_EQ(op->Input("WeightH")[1], multi_gru_inputs[4]); - EXPECT_EQ(op->Input("Bias").size(), 2u); - EXPECT_EQ(op->Input("Bias")[0], multi_gru_inputs[5]); - EXPECT_EQ(op->Input("Bias")[1], multi_gru_inputs[6]); - EXPECT_EQ(op->Output("Hidden")[0], multi_gru_output); - EXPECT_EQ(op->GetAttrIfExists("layers"), 1); - EXPECT_EQ(op->GetAttrIfExists("origin_mode"), origin_mode); - ++count_multi_gru; - } - } - } - EXPECT_EQ(original_nodes_num - removed_nodes_count + added_nodes_count, - current_nodes_num); - EXPECT_EQ(count_multi_gru, added_nodes_count); -} - -TEST(MultiGruFusePass, same_origin_modes_1) { - bool origin_mode1 = false; - bool origin_mode2 = false; - - // nodes to be removed: 2x fusion_gru + 2x hidden(output) + concat - const int removed_nodes_count = 5; - // nodes to be added: multi_gru - const int added_nodes_count = 1; - - const std::initializer_list multi_gru_inputs = { - "x", "wx1", "wx2", "wh1", "wh2", "b1", "b2"}; - MainTest(BuildProgramDesc(origin_mode1, origin_mode2), - removed_nodes_count, - added_nodes_count, - multi_gru_inputs, - "out", - origin_mode1); -} - -TEST(MultiGruFusePass, same_origin_modes_2) { - bool origin_mode1 = true; - bool origin_mode2 = true; - - // nodes to be removed: 2x fusion_gru + 2x hidden(output) + concat - const int removed_nodes_count = 5; - // nodes to be added: multi_gru - const int added_nodes_count = 1; - - const std::initializer_list multi_gru_inputs = { - "x", "wx1", "wx2", "wh1", "wh2", "b1", "b2"}; - MainTest(BuildProgramDesc(origin_mode1, origin_mode2), - removed_nodes_count, - added_nodes_count, - multi_gru_inputs, - "out", - origin_mode1); -} - -TEST(MultiGruFusePass, different_origin_modes) { - bool origin_mode1 = true; - bool origin_mode2 = false; - - // the fuse should not be applied, so - // nodes to be removed: none - const int removed_nodes_count = 0; - // nodes to be added: none - const int added_nodes_count = 0; - - const std::initializer_list multi_gru_inputs = { - "x", "wx1", "wx2", "wh1", "wh2", "b1", "b2"}; - MainTest(BuildProgramDesc(origin_mode1, origin_mode2), - removed_nodes_count, - added_nodes_count, - multi_gru_inputs, - "out", - origin_mode1); -} - -} // namespace ir -} // namespace framework -} // namespace paddle - -USE_PASS(multi_gru_fuse_pass); diff --git a/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.cc b/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.cc index 35813bc22d..697a34904c 100644 --- a/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.cc +++ b/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.cc @@ -21,6 +21,7 @@ #include "paddle/fluid/framework/eigen.h" #include "paddle/fluid/framework/ir/graph_pattern_detector.h" +#include "paddle/fluid/framework/op_version_registry.h" #include "paddle/fluid/platform/mkldnn_helper.h" #include "paddle/phi/core/errors.h" #include "paddle/utils/string/pretty_log.h" @@ -61,6 +62,11 @@ void MultiGruSeqFusePass::ApplyImpl(ir::Graph* graph) const { int fused_count = 0; auto handler = [&](const GraphPatternDetector::subgraph_t& subgraph, Graph* g) { + if (!IsCompat(subgraph, g)) { + LOG(WARNING) << "Pass in op compat failed."; + return; + } + GET_IR_NODE_FROM_SUBGRAPH(x, x, pattern); GET_IR_NODE_FROM_SUBGRAPH(gru1, gru1, pattern); GET_IR_NODE_FROM_SUBGRAPH(wx11, wx11, pattern); @@ -134,9 +140,57 @@ void MultiGruSeqFusePass::ApplyImpl(ir::Graph* graph) const { fused_count); } +MultiGruSeqFusePass::MultiGruSeqFusePass() { + AddOpCompat(OpCompat("multi_gru")) + .AddInput("X") + .IsTensor() + .End() + .AddInput("WeightX") + .End() + .AddInput("WeightH") + .End() + .AddInput("Bias") + .IsOptional() + .End() + .AddInput("Scale_weights") + .IsOptional() + .End() + .AddOutput("Hidden") + .IsTensor() + .End() + .AddAttr("activation") + .IsType() + .End() + .AddAttr("gate_activation") + .IsType() + .End() + .AddAttr("layers") + .IsType() + .End() + .AddAttr("origin_mode") + .IsType() + .End() + .AddAttr("mkldnn_data_type") + .IsType() + .End() + .AddAttr("Scale_data") + .IsType() + .End() + .AddAttr("Shift_data") + .IsType() + .End() + .AddAttr("force_fp32_output") + .IsType() + .End(); +} + } // namespace ir } // namespace framework } // namespace paddle REGISTER_PASS(multi_gru_seq_fuse_pass, paddle::framework::ir::MultiGruSeqFusePass); +REGISTER_PASS_CAPABILITY(multi_gru_seq_fuse_pass) + .AddCombination( + paddle::framework::compatible::OpVersionComparatorCombination().EQ( + "multi_gru", 0)); diff --git a/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.h b/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.h index af58ae2bda..451a2ebaa9 100644 --- a/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.h +++ b/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.h @@ -30,6 +30,7 @@ namespace ir { class MultiGruSeqFusePass : public FusePassBase { public: virtual ~MultiGruSeqFusePass() {} + MultiGruSeqFusePass(); protected: void ApplyImpl(ir::Graph* graph) const override; diff --git a/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass_tester.cc b/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass_tester.cc deleted file mode 100644 index 42d52dd314..0000000000 --- a/paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass_tester.cc +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. -// -// 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 "paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.h" - -namespace paddle { -namespace framework { -namespace ir { - -const std::vector churn_out_vars(ProgramDesc* prog, - const std::string& prefix, - int number) { - auto v = std::vector(); - for (int i = 0; i < number; ++i) { - auto name = prefix + std::to_string(i); - prog->MutableBlock(0)->Var(name); - v.push_back(name); - } - return v; -} - -void create_vars(ProgramDesc* prog, - const std::initializer_list& names) { - for (auto name : names) prog->MutableBlock(0)->Var(name); -} - -void SetMultiGruOp(ProgramDesc* prog, - const std::string x, - const std::vector wx, - const std::vector wh, - const std::vector b, - const std::string h, - int layers, - bool origin_mode) { - auto* op = prog->MutableBlock(0)->AppendOp(); - op->SetType("multi_gru"); - op->SetInput("X", {x}); - op->SetInput("WeightX", wx); - op->SetInput("WeightH", wh); - op->SetInput("Bias", b); - op->SetOutput("Hidden", {h}); - op->SetAttr("layers", layers); - op->SetAttr("origin_mode", origin_mode); -} - -// (x, wx1, wh1, b1) -> multi_gru1 -> h1 -// (h1, wx2, wh2, b2) -> multi_gru2 -> h2 -void MainTest(int layers1, int layers2, bool origin_mode1, bool origin_mode2) { - ProgramDesc prog; - - // Create variables - create_vars(&prog, {"x", "h1", "h2"}); - const std::vector wx1 = - churn_out_vars(&prog, "wx1", 2 * layers1); - const std::vector wx2 = - churn_out_vars(&prog, "wx2", 2 * layers2); - const std::vector wh1 = - churn_out_vars(&prog, "wh1", 2 * layers1); - const std::vector wh2 = - churn_out_vars(&prog, "wh2", 2 * layers2); - const std::vector b1 = churn_out_vars(&prog, "b1", 2 * layers1); - const std::vector b2 = churn_out_vars(&prog, "b2", 2 * layers2); - - // Create program descriptor - SetMultiGruOp(&prog, "x", wx1, wh1, b1, "h1", layers1, origin_mode1); - SetMultiGruOp(&prog, "h1", wx2, wh2, b2, "h2", layers2, origin_mode2); - - // Apply pass - std::unique_ptr graph(new ir::Graph(prog)); - Scope scope; - graph->SetNotOwned(kParamScopeAttr, &scope); - int original_nodes_num = graph->Nodes().size(); - auto pass = PassRegistry::Instance().Get("multi_gru_seq_fuse_pass"); - graph.reset(pass->Apply(graph.release())); - int current_nodes_num = graph->Nodes().size(); - - // Verify graph after fuse - bool should_fuse = origin_mode1 == origin_mode2; - int count_multi_gru = 0; - auto layers = layers1; - auto wx = wx1; - auto wh = wh1; - auto b = b1; - auto h = "h1"; - if (should_fuse) { - layers += layers2; - wx.insert(wx.end(), wx2.begin(), wx2.end()); - wh.insert(wh.end(), wh2.begin(), wh2.end()); - b.insert(b.end(), b2.begin(), b2.end()); - h = "h2"; - } - for (auto* node : graph->Nodes()) { - if (node->IsOp()) { - auto* op = node->Op(); - if (op->Type() == "multi_gru") { - if (op->Input("X")[0] == "x") { - EXPECT_EQ(op->GetAttrIfExists("layers"), layers); - EXPECT_EQ(op->Input("WeightX").size(), 2u * layers); - EXPECT_EQ(op->Input("WeightH").size(), 2u * layers); - EXPECT_EQ(op->Input("Bias").size(), 2u * layers); - for (int i = 0; i < 2 * layers; ++i) { - EXPECT_EQ(op->Input("WeightX")[i], wx[i]); - EXPECT_EQ(op->Input("WeightH")[i], wh[i]); - EXPECT_EQ(op->Input("Bias")[i], b[i]); - } - EXPECT_EQ(op->Output("Hidden")[0], h); - EXPECT_EQ(op->GetAttrIfExists("origin_mode"), origin_mode1); - } else { - EXPECT_EQ(op->GetAttrIfExists("layers"), layers2); - EXPECT_EQ(op->Input("X")[0], "h1"); - EXPECT_EQ(op->Input("WeightX").size(), 2u * layers2); - EXPECT_EQ(op->Input("WeightH").size(), 2u * layers2); - EXPECT_EQ(op->Input("Bias").size(), 2u * layers2); - for (int i = 0; i < 2 * layers2; ++i) { - EXPECT_EQ(op->Input("WeightX")[i], wx2[i]); - EXPECT_EQ(op->Input("WeightH")[i], wh2[i]); - EXPECT_EQ(op->Input("Bias")[i], b2[i]); - } - EXPECT_EQ(op->Output("Hidden")[0], "h2"); - EXPECT_EQ(op->GetAttrIfExists("origin_mode"), origin_mode2); - } - ++count_multi_gru; - } - } - } - - // If the fuse is applied, then: - // nodes to be removed: 2x multi_gru + 1x hidden(output) - // nodes to be added: multi_gru - // If the fuse is not applied, then: - // nodes to be removed: none - // nodes to be added: none - const int removed_nodes_count = should_fuse ? 3 : 0; - const int added_nodes_count = should_fuse ? 1 : 0; - - EXPECT_EQ(original_nodes_num - removed_nodes_count + added_nodes_count, - current_nodes_num); - EXPECT_EQ(count_multi_gru, should_fuse ? 1 : 2); -} - -TEST(MultiGruSeqFusePass, same_origin_modes_1) { - int layers1 = 1; - int layers2 = 1; - bool origin_mode1 = false; - bool origin_mode2 = false; - MainTest(layers1, layers2, origin_mode1, origin_mode2); -} - -TEST(MultiGruSeqFusePass, same_origin_modes_2) { - int layers1 = 2; - int layers2 = 3; - bool origin_mode1 = false; - bool origin_mode2 = false; - MainTest(layers1, layers2, origin_mode1, origin_mode2); -} - -TEST(MultiGruSeqFusePass, same_origin_modes_3) { - int layers1 = 2; - int layers2 = 1; - bool origin_mode1 = true; - bool origin_mode2 = true; - MainTest(layers1, layers2, origin_mode1, origin_mode2); -} - -TEST(MultiGruSeqFusePass, different_origin_modes) { - int layers1 = 2; - int layers2 = 2; - bool origin_mode1 = true; - bool origin_mode2 = false; - MainTest(layers1, layers2, origin_mode1, origin_mode2); -} - -} // namespace ir -} // namespace framework -} // namespace paddle - -USE_PASS(multi_gru_seq_fuse_pass); diff --git a/python/paddle/fluid/tests/unittests/ir/inference/CMakeLists.txt b/python/paddle/fluid/tests/unittests/ir/inference/CMakeLists.txt index 2cc14e6411..65d27f9f0e 100755 --- a/python/paddle/fluid/tests/unittests/ir/inference/CMakeLists.txt +++ b/python/paddle/fluid/tests/unittests/ir/inference/CMakeLists.txt @@ -228,6 +228,9 @@ if(WITH_GPU AND TENSORRT_FOUND) set_tests_properties(test_onednn_conv_bias_fuse_pass PROPERTIES TIMEOUT 300) set_tests_properties(test_onednn_conv_concat_activation_fuse_pass PROPERTIES TIMEOUT 300) + set_tests_properties(test_onednn_multi_gru_fuse_pass PROPERTIES TIMEOUT 120) + set_tests_properties(test_onednn_multi_gru_seq_fuse_pass PROPERTIES TIMEOUT + 120) set_tests_properties(test_flatten2_matmul_fuse_pass PROPERTIES TIMEOUT 240) set_tests_properties(test_squeeze2_matmul_fuse_pass PROPERTIES TIMEOUT 240) set_tests_properties(test_reshape2_matmul_fuse_pass PROPERTIES TIMEOUT 240) diff --git a/python/paddle/fluid/tests/unittests/ir/inference/program_config.py b/python/paddle/fluid/tests/unittests/ir/inference/program_config.py index cd9edd8350..9bb0a492cd 100644 --- a/python/paddle/fluid/tests/unittests/ir/inference/program_config.py +++ b/python/paddle/fluid/tests/unittests/ir/inference/program_config.py @@ -448,6 +448,8 @@ def create_quant_model( "pad2d", "reshape", "layer_norm", + "fusion_gru", + "multi_gru", "quantize", "dequantize", ] @@ -499,6 +501,8 @@ def create_quant_model( "pad2d": [["X"], ["Out"]], "flatten": [["X"], ["Out"]], "flatten2": [["X"], ["Out"]], + "fusion_gru": [["X", "WeightX", "WeightH"], ["Hidden", "XX"]], + "multi_gru": [["X", "WeightX", "WeightH"], ["Hidden"]], "quantize": [["Input"], ["Output"]], "dequantize": [["Input"], ["Output"]], } diff --git a/python/paddle/fluid/tests/unittests/ir/inference/test_onednn_multi_gru_fuse_pass.py b/python/paddle/fluid/tests/unittests/ir/inference/test_onednn_multi_gru_fuse_pass.py new file mode 100644 index 0000000000..1133504a14 --- /dev/null +++ b/python/paddle/fluid/tests/unittests/ir/inference/test_onednn_multi_gru_fuse_pass.py @@ -0,0 +1,134 @@ +# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved. +# +# 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. + +import unittest +from functools import partial + +import hypothesis.strategies as st +import numpy as np +from auto_scan_test import PassAutoScanTest +from program_config import OpConfig, ProgramConfig, TensorConfig + + +class TestOneDNNMultiGruFusePass(PassAutoScanTest): + def sample_program_config(self, draw): + input_dim_1 = draw(st.integers(min_value=1, max_value=128)) * 3 + input_dim_2 = input_dim_1 // 3 + frame_size = draw(st.integers(min_value=1, max_value=128)) + weight_x_shape = [input_dim_2, frame_size * 3] + weight_h_shape = [frame_size, frame_size * 3] + with_bias = draw(st.booleans()) + bias_shape = [1, frame_size * 3] + lod = [[0, input_dim_1]] + + def generate_data(shape): + return np.random.random(shape).astype(np.float32) + + def generate_bias(shape): + if with_bias: + return np.random.random(shape).astype(np.float32) + else: + return np.zeros(shape).astype(np.float32) + + fusion_gru_op_1 = OpConfig( + type='fusion_gru', + inputs={ + 'X': ['input_data'], + 'WeightX': ['weight_x_1'], + 'WeightH': ['weight_h_1'], + 'Bias': ['bias_1'], + }, + outputs={ + 'Hidden': ['fusion_gru_output_hidden_1'], + 'XX': ['fusion_gru_output_xx_1'], + }, + attrs={ + 'origin_mode': False, + 'is_reverse': False, + }, + ) + + fusion_gru_op_2 = OpConfig( + type='fusion_gru', + inputs={ + 'X': ['input_data'], + 'WeightX': ['weight_x_2'], + 'WeightH': ['weight_h_2'], + 'Bias': ['bias_2'], + }, + outputs={ + 'Hidden': ['fusion_gru_output_hidden_2'], + 'XX': ['fusion_gru_output_xx_2'], + }, + attrs={'origin_mode': False, 'is_reverse': True}, + ) + + concat_op = OpConfig( + type='concat', + inputs={ + 'X': [ + 'fusion_gru_output_hidden_1', + 'fusion_gru_output_hidden_2', + ] + }, + outputs={'Out': ['concat_output']}, + attrs={'axis': 1}, + ) + + program_config = ProgramConfig( + ops=[fusion_gru_op_1, fusion_gru_op_2, concat_op], + weights={ + "weight_x_1": TensorConfig( + data_gen=partial(generate_data, weight_x_shape) + ), + "weight_h_1": TensorConfig( + data_gen=partial(generate_data, weight_h_shape) + ), + 'bias_1': TensorConfig( + data_gen=partial(generate_bias, bias_shape) + ), + "weight_x_2": TensorConfig( + data_gen=partial(generate_data, weight_x_shape) + ), + "weight_h_2": TensorConfig( + data_gen=partial(generate_data, weight_h_shape) + ), + 'bias_2': TensorConfig( + data_gen=partial(generate_data, bias_shape) + ), + }, + inputs={ + 'input_data': TensorConfig( + lod=lod, + data_gen=partial(generate_data, [input_dim_1, input_dim_2]), + ), + }, + outputs=['concat_output'], + ) + + return program_config + + def sample_predictor_configs(self, program_config): + config = self.create_inference_config( + use_mkldnn=True, + passes=['multi_gru_fuse_pass'], + ) + yield config, ['multi_gru'], (1e-5, 1e-5) + + def test(self): + self.run_and_statis(quant=False, passes=['multi_gru_fuse_pass']) + + +if __name__ == '__main__': + unittest.main() diff --git a/python/paddle/fluid/tests/unittests/ir/inference/test_onednn_multi_gru_seq_fuse_pass.py b/python/paddle/fluid/tests/unittests/ir/inference/test_onednn_multi_gru_seq_fuse_pass.py new file mode 100644 index 0000000000..dbb1439dda --- /dev/null +++ b/python/paddle/fluid/tests/unittests/ir/inference/test_onednn_multi_gru_seq_fuse_pass.py @@ -0,0 +1,213 @@ +# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved. +# +# 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. + +import unittest +from functools import partial + +import hypothesis.strategies as st +import numpy as np +from auto_scan_test import PassAutoScanTest +from program_config import OpConfig, ProgramConfig, TensorConfig + + +class TestOneDNNMultiGruSeqFusePass(PassAutoScanTest): + def sample_program_config(self, draw): + input_dim_1 = 6 * draw(st.integers(min_value=1, max_value=32)) + input_dim_2 = input_dim_1 // 3 + frame_size = input_dim_1 // 6 + weight_x_shape = [input_dim_2, frame_size * 3] + weight_h_shape = [frame_size, frame_size * 3] + with_bias = draw(st.booleans()) + bias_shape = [1, frame_size * 3] + lod = [[0, input_dim_1]] + + def generate_data(shape): + return np.random.random(shape).astype(np.float32) + + def generate_bias(shape): + if with_bias: + return np.random.random(shape).astype(np.float32) + else: + return np.zeros(shape).astype(np.float32) + + fusion_gru_op_1 = OpConfig( + type='fusion_gru', + inputs={ + 'X': ['input_data'], + 'WeightX': ['weight_x_1'], + 'WeightH': ['weight_h_1'], + 'Bias': ['bias_1'], + }, + outputs={ + 'Hidden': ['fusion_gru_output_hidden_1'], + 'XX': ['fusion_gru_output_xx_1'], + }, + attrs={ + 'origin_mode': False, + 'is_reverse': False, + 'use_mkldnn': True, + }, + ) + + fusion_gru_op_2 = OpConfig( + type='fusion_gru', + inputs={ + 'X': ['input_data'], + 'WeightX': ['weight_x_2'], + 'WeightH': ['weight_h_2'], + 'Bias': ['bias_2'], + }, + outputs={ + 'Hidden': ['fusion_gru_output_hidden_2'], + 'XX': ['fusion_gru_output_xx_2'], + }, + attrs={ + 'origin_mode': False, + 'is_reverse': True, + 'use_mkldnn': True, + }, + ) + + concat_op_1 = OpConfig( + type='concat', + inputs={ + 'X': [ + 'fusion_gru_output_hidden_1', + 'fusion_gru_output_hidden_2', + ] + }, + outputs={'Out': ['concat_output_1']}, + attrs={'axis': 1, 'use_mkldnn': True}, + ) + + fusion_gru_op_3 = OpConfig( + type='fusion_gru', + inputs={ + 'X': ['concat_output_1'], + 'WeightX': ['input_weight_x_3'], + 'WeightH': ['input_weight_h_3'], + 'Bias': ['bias_3'], + }, + outputs={ + 'Hidden': ['fusion_gru_output_hidden_3'], + 'XX': ['fusion_gru_output_xx_3'], + }, + attrs={ + 'origin_mode': False, + 'is_reverse': False, + }, + ) + + fusion_gru_op_4 = OpConfig( + type='fusion_gru', + inputs={ + 'X': ['concat_output_1'], + 'WeightX': ['input_weight_x_4'], + 'WeightH': ['input_weight_h_4'], + 'Bias': ['bias_4'], + }, + outputs={ + 'Hidden': ['fusion_gru_output_hidden_4'], + 'XX': ['fusion_gru_output_xx_4'], + }, + attrs={'origin_mode': False, 'is_reverse': True}, + ) + + concat_op_2 = OpConfig( + type='concat', + inputs={ + 'X': [ + 'fusion_gru_output_hidden_3', + 'fusion_gru_output_hidden_4', + ] + }, + outputs={'Out': ['concat_output_2']}, + attrs={'axis': 1}, + ) + + program_config = ProgramConfig( + ops=[ + fusion_gru_op_1, + fusion_gru_op_2, + concat_op_1, + fusion_gru_op_3, + fusion_gru_op_4, + concat_op_2, + ], + weights={ + "weight_x_1": TensorConfig( + data_gen=partial(generate_data, weight_x_shape) + ), + "weight_h_1": TensorConfig( + data_gen=partial(generate_data, weight_h_shape) + ), + 'bias_1': TensorConfig( + data_gen=partial(generate_bias, bias_shape) + ), + "weight_x_2": TensorConfig( + data_gen=partial(generate_data, weight_x_shape) + ), + "weight_h_2": TensorConfig( + data_gen=partial(generate_data, weight_h_shape) + ), + 'bias_2': TensorConfig( + data_gen=partial(generate_data, bias_shape) + ), + "input_weight_x_3": TensorConfig( + data_gen=partial(generate_data, weight_x_shape) + ), + "input_weight_h_3": TensorConfig( + data_gen=partial(generate_data, weight_h_shape) + ), + 'bias_3': TensorConfig( + data_gen=partial(generate_bias, bias_shape) + ), + "input_weight_x_4": TensorConfig( + data_gen=partial(generate_data, weight_x_shape) + ), + "input_weight_h_4": TensorConfig( + data_gen=partial(generate_data, weight_h_shape) + ), + 'bias_4': TensorConfig( + data_gen=partial(generate_data, bias_shape) + ), + }, + inputs={ + 'input_data': TensorConfig( + lod=lod, + data_gen=partial(generate_data, [input_dim_1, input_dim_2]), + ), + }, + outputs=['concat_output_2'], + ) + + return program_config + + def sample_predictor_configs(self, program_config): + config = self.create_inference_config( + use_mkldnn=True, + passes=['multi_gru_fuse_pass', 'multi_gru_seq_fuse_pass'], + ) + yield config, ['multi_gru'], (1e-5, 1e-5) + + def test(self): + self.run_and_statis( + quant=False, + passes=['multi_gru_fuse_pass', 'multi_gru_seq_fuse_pass'], + max_examples=50, + ) + + +if __name__ == '__main__': + unittest.main() -- GitLab