未验证 提交 c9a39758 编写于 作者: P Paulina Gacek 提交者: GitHub

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
上级 2f2bf4e8
......@@ -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()
......@@ -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<std::string>()
.End()
.AddAttr("is_reverse")
.IsType<bool>()
.End()
.AddAttr("use_seq")
.IsType<bool>()
.End()
.AddAttr("origin_mode")
.IsType<bool>()
.End()
.AddAttr("use_mkldnn")
.IsType<bool>()
.End()
.AddAttr("mkldnn_data_type")
.IsType<std::string>()
.End()
.AddAttr("Scale_data")
.IsType<float>()
.End()
.AddAttr("Shift_data")
.IsType<float>()
.End()
.AddAttr("Scale_weights")
.IsType<std::vector<float>>()
.End()
.AddAttr("force_fp32_output")
.IsType<bool>()
.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));
......@@ -32,6 +32,7 @@ namespace ir {
class MultiGRUFusePass : public FusePassBase {
public:
virtual ~MultiGRUFusePass() {}
MultiGRUFusePass();
protected:
void ApplyImpl(ir::Graph* graph) const override;
......
// 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 <gtest/gtest.h>
#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<std::string>& inputs,
const std::vector<std::string>& 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<std::string> 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<std::string> multi_gru_inputs,
const std::string multi_gru_output,
bool origin_mode) {
// Apply pass
std::unique_ptr<ir::Graph> 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<int>("layers"), 1);
EXPECT_EQ(op->GetAttrIfExists<bool>("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<std::string> 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<std::string> 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<std::string> 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);
......@@ -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<std::string>()
.End()
.AddAttr("gate_activation")
.IsType<std::string>()
.End()
.AddAttr("layers")
.IsType<int>()
.End()
.AddAttr("origin_mode")
.IsType<bool>()
.End()
.AddAttr("mkldnn_data_type")
.IsType<std::string>()
.End()
.AddAttr("Scale_data")
.IsType<float>()
.End()
.AddAttr("Shift_data")
.IsType<float>()
.End()
.AddAttr("force_fp32_output")
.IsType<bool>()
.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));
......@@ -30,6 +30,7 @@ namespace ir {
class MultiGruSeqFusePass : public FusePassBase {
public:
virtual ~MultiGruSeqFusePass() {}
MultiGruSeqFusePass();
protected:
void ApplyImpl(ir::Graph* graph) const override;
......
// 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 <gtest/gtest.h>
#include <initializer_list>
#include "paddle/fluid/framework/ir/mkldnn/multi_gru_seq_fuse_pass.h"
namespace paddle {
namespace framework {
namespace ir {
const std::vector<std::string> churn_out_vars(ProgramDesc* prog,
const std::string& prefix,
int number) {
auto v = std::vector<std::string>();
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<std::string>& names) {
for (auto name : names) prog->MutableBlock(0)->Var(name);
}
void SetMultiGruOp(ProgramDesc* prog,
const std::string x,
const std::vector<std::string> wx,
const std::vector<std::string> wh,
const std::vector<std::string> 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<std::string> wx1 =
churn_out_vars(&prog, "wx1", 2 * layers1);
const std::vector<std::string> wx2 =
churn_out_vars(&prog, "wx2", 2 * layers2);
const std::vector<std::string> wh1 =
churn_out_vars(&prog, "wh1", 2 * layers1);
const std::vector<std::string> wh2 =
churn_out_vars(&prog, "wh2", 2 * layers2);
const std::vector<std::string> b1 = churn_out_vars(&prog, "b1", 2 * layers1);
const std::vector<std::string> 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<ir::Graph> 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<int>("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<bool>("origin_mode"), origin_mode1);
} else {
EXPECT_EQ(op->GetAttrIfExists<int>("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<bool>("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);
......@@ -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)
......
......@@ -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"]],
}
......
# 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()
# 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()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册