chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
@@ -0,0 +1,81 @@
# XPU IR Pass Tests
cc_test(
test_cast_mixed_precision_op_fuse_pass
SRCS cast_mixed_precision_op_fuse_pass_test.cc
DEPS cast_mixed_precision_op_fuse_pass)
cc_test(
test_delete_isolated_node_pass
SRCS delete_isolated_node_pass_test.cc
DEPS delete_isolated_node_pass)
cc_test(
test_fused_multi_transformer_xpu_pass
SRCS fused_multi_transformer_xpu_pass_test.cc
DEPS fused_multi_transformer_xpu_pass)
cc_test(
test_fused_multi_transformer_int8_xpu_quant_pass
SRCS fused_multi_transformer_int8_xpu_quant_pass_test.cc
DEPS fused_multi_transformer_int8_xpu_quant_pass)
cc_test(
test_one_beam_size_fuse_pass
SRCS one_beam_size_fuse_pass_test.cc
DEPS one_beam_size_fuse_pass)
cc_test(
test_stack_fuse_pass
SRCS stack_fuse_pass_test.cc
DEPS stack_fuse_pass)
cc_test(
test_fused_multi_transformer_cachekv_layout_trans_pass
SRCS fused_multi_transformer_cachekv_layout_trans_pass_test.cc
DEPS fused_multi_transformer_cachekv_layout_trans_pass)
cc_test(
test_fused_multi_transformer_int8_cachekv_layout_trans_pass
SRCS fused_multi_transformer_int8_cachekv_layout_trans_pass_test.cc
DEPS fused_multi_transformer_int8_cachekv_layout_trans_pass)
cc_test(
test_multi_encoder_xpu_adaptive_seqlen_fuse_pass
SRCS multi_encoder_xpu_adaptive_seqlen_fuse_pass_test.cc
DEPS multi_encoder_xpu_adaptive_seqlen_fuse_pass)
cc_test(
test_xpu_delete_cast_op_pass
SRCS xpu_delete_cast_op_pass_test.cc
DEPS xpu_delete_cast_op_pass)
cc_test(
test_fold_interp_outsize_fuse_pass
SRCS fold_interp_outsize_fuse_pass_test.cc
DEPS fold_interp_outsize_fuse_pass)
cc_test(
test_fold_two_squeeze2_fuse_pass
SRCS fold_two_squeeze2_fuse_pass_test.cc
DEPS fold_two_squeeze2_fuse_pass)
cc_test(
test_matmul_weight_trans_pass
SRCS matmul_weight_trans_pass_test.cc
DEPS matmul_weight_trans_pass)
cc_test(
test_reshape2_matmul_xpu_fuse_pass
SRCS reshape2_matmul_xpu_fuse_pass_test.cc
DEPS reshape2_matmul_xpu_fuse_pass)
cc_test(
test_fast_where_xpu_fuse_pass
SRCS fast_where_xpu_fuse_pass_test.cc
DEPS fast_where_xpu_fuse_pass)
cc_test(
test_squeeze_excitation_fuse_pass
SRCS squeeze_excitation_fuse_pass_test.cc
DEPS squeeze_excitation_fuse_pass)
@@ -0,0 +1,71 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
TEST(CastMixedPrecisionOpFusePass, cast_before) {
Layers layers;
auto* block = layers.Block();
auto* cast_in = layers.data("cast_in");
auto* cast_out = layers.cast(cast_in, 5, 4);
OpDesc* conv2d_xpu = block->AppendOp();
conv2d_xpu->SetType("conv2d_xpu");
conv2d_xpu->SetInput("x", {cast_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("cast_mixed_precision_op_fuse_pass");
pass->Apply(graph.get());
auto num = GetNumOpNodes(graph, "cast");
PADDLE_ENFORCE_EQ(
num,
0,
common::errors::PreconditionNotMet(
"cast op should be removed from graph, but graph still has %d ops.",
num));
}
TEST(CastMixedPrecisionOpFusePass, cast_after) {
Layers layers;
auto* block = layers.Block();
auto* cast_in = layers.data("cast_in");
OpDesc* conv2d_xpu = block->AppendOp();
conv2d_xpu->SetType("conv2d_xpu");
conv2d_xpu->SetOutput("out", {cast_in->Name()});
layers.cast(cast_in, 4, 5);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("cast_mixed_precision_op_fuse_pass");
pass->Apply(graph.get());
auto num = GetNumOpNodes(graph, "cast");
PADDLE_ENFORCE_EQ(
num,
0,
common::errors::PreconditionNotMet(
"cast op should be removed from graph, but graph still has %d ops.",
num));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(cast_mixed_precision_op_fuse_pass);
@@ -0,0 +1,181 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
VarDesc* Data(paddle::framework::BlockDesc* block,
std::string name,
std::vector<int64_t> shape = {},
bool is_persistable = false,
proto::VarType::Type data_type = proto::VarType::FP32) {
auto* var = block->Var(name);
var->SetType(proto::VarType::DENSE_TENSOR);
var->SetDataType(data_type);
var->SetShape(shape);
var->SetPersistable(is_persistable);
return var;
}
void AddVarToScope(Scope* param_scope,
const std::string& name,
const DDim& dims) {
auto* tensor = param_scope->Var(name)->GetMutable<phi::DenseTensor>();
tensor->Resize(dims);
auto* cpu_ctx = static_cast<phi::CPUContext*>(
phi::DeviceContextPool::Instance().Get(phi::CPUPlace()));
auto* data = cpu_ctx->Alloc<float>(tensor);
int64_t numel = tensor->numel();
for (int64_t i = 0; i < numel; ++i) {
data[i] = 1;
}
}
Scope* CreateParamScope() {
auto param_scope = new Scope();
AddVarToScope(param_scope, "matmul0_w", {128, 128});
return param_scope;
}
int WeightNodeNum(ir::Graph* graph) {
int num = 0;
for (auto node : graph->Nodes()) {
if (node->IsVar() && node->Var()->Persistable()) {
num++;
}
}
return num;
}
int WeightTensorNum(Scope* scope) {
int num = 0;
auto vars = scope->LocalVars();
for (auto* var : vars) {
if (var->Get<phi::DenseTensor>().numel() > 0) {
num++;
}
}
return num;
}
TEST(delete_isolated_node_pass, basic) {
paddle::framework::ProgramDesc program;
auto* block0 = program.MutableBlock(0);
auto* block1 = program.AppendBlock(*block0);
auto* matmul0_x = Data(block0, "matmul0_x", {1, 128});
auto* matmul0_w = Data(block0, "matmul0_w", {128, 128}, true);
auto* matmul0_out = Data(block0, "matmul0_out", {1, 128});
OpDesc* matmul_op = block0->AppendOp();
matmul_op->SetType("matmul_v2");
matmul_op->SetInput("X", {matmul0_x->Name()});
matmul_op->SetInput("Y", {matmul0_w->Name()});
matmul_op->SetAttr("trans_x", false);
matmul_op->SetAttr("trans_y", false);
matmul_op->SetOutput("Out", {matmul0_out->Name()});
auto* while_out = Data(block0, "while_out", {1, 128});
auto* while_step_scopes = Data(block0, "while_step_scopes");
auto* while_cond = Data(block0, "while_cond");
OpDesc* while_op = block0->AppendOp();
while_op->SetType("while");
while_op->SetInput("X", {matmul0_w->Name(), matmul0_out->Name()});
while_op->SetInput("Condition", {while_cond->Name()});
while_op->SetOutput("Out", {while_out->Name()});
while_op->SetOutput("StepScopes", {while_step_scopes->Name()});
while_op->SetAttr("sub_block", {block1});
while_op->SetAttr("is_test", true);
auto* matmul1_x = Data(block1, matmul0_out->Name(), matmul0_out->GetShape());
auto* matmul1_w =
Data(block1, matmul0_w->Name(), matmul0_w->GetShape(), true);
auto* matmul1_out = Data(block1, "matmul1_out", {1, 128});
OpDesc* matmul1_op = block1->AppendOp();
matmul1_op->SetType("matmul_v2");
matmul1_op->SetInput("X", {matmul1_x->Name()});
matmul1_op->SetInput("Y", {matmul1_w->Name()});
matmul1_op->SetAttr("trans_x", false);
matmul1_op->SetAttr("trans_y", false);
matmul1_op->SetOutput("Out", {matmul1_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(program));
auto* scope = CreateParamScope();
graph->Set("__param_scope__", scope);
auto pass0 = PassRegistry::Instance().Get("fc_xpu_fuse_pass");
pass0->Apply(graph.get());
pass0->Apply(graph->GetSubGraph(1));
int weight_node_num =
WeightNodeNum(graph.get()) + WeightNodeNum(graph->GetSubGraph(1));
PADDLE_ENFORCE_EQ(weight_node_num,
6,
common::errors::PreconditionNotMet(
"Graph should have 6 weight node after "
"fc_xpu_fuse_pass, but actually has %d.",
weight_node_num));
auto pass1 = PassRegistry::Instance().Get("delete_isolated_node_pass");
pass1->Apply(graph.get());
weight_node_num =
WeightNodeNum(graph.get()) + WeightNodeNum(graph->GetSubGraph(1));
PADDLE_ENFORCE_EQ(weight_node_num,
4,
common::errors::PreconditionNotMet(
"Graph should have 4 weight node after "
"delete_isolated_node_pass, but actually has %d.",
weight_node_num));
int weight_tensor_num = WeightTensorNum(scope);
PADDLE_ENFORCE_EQ(weight_tensor_num,
2,
common::errors::PreconditionNotMet(
"Scope should have 2 weight tensor after "
"delete_isolated_node_pass, but actually has %d.",
weight_tensor_num));
for (auto* node : graph->Nodes()) {
if (node->IsOp() && node->Op()->Type() == "while") {
auto while_in_names = node->Op()->Inputs().at("X");
PADDLE_ENFORCE_EQ(while_in_names.size(),
3,
common::errors::PreconditionNotMet(
"While op should have 3 input after "
"delete_isolated_node_pass, but actually has %d.",
while_in_names.size()));
}
}
Scope& scope0 = graph->Get<framework::Scope>("__param_scope__");
Scope& scope1 =
graph->GetSubGraph(1)->Get<framework::Scope>("__param_scope__");
std::vector<std::string> shared_weight_names{matmul0_w->Name() + "_int16",
matmul0_w->Name() + "_max"};
for (auto name : shared_weight_names) {
auto* var0 = scope0.FindVar(name);
auto* var1 = scope1.FindVar(name);
PADDLE_ENFORCE(
var0 == var1,
common::errors::PreconditionNotMet(
"Variables with the same name in two scopes is different."));
}
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(delete_isolated_node_pass);
@@ -0,0 +1,304 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
#define APPLY_PASS \
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program())); \
auto pass = PassRegistry::Instance().Get("fast_where_xpu_fuse_pass"); \
pass->Apply(graph.get());
#define VERIFY_GRAPH(x, y) \
auto num_op_nodes = GetNumOpNodes(graph); \
PADDLE_ENFORCE_EQ( \
num_op_nodes, \
1, \
common::errors::PreconditionNotMet( \
"The graph contains only one op node, but %d op nodes found.", \
num_op_nodes)); \
auto fast_where_xpu_op_nodes = GetOpNodes(graph, "fast_where_xpu"); \
PADDLE_ENFORCE_EQ(fast_where_xpu_op_nodes.size(), \
1, \
common::errors::PreconditionNotMet( \
"The graph contains only a fast_where_xpu op node, " \
"but %d op nodes found.", \
fast_where_xpu_op_nodes.size())); \
const auto& x_name = fast_where_xpu_op_nodes[0]->Op()->Input("x")[0]; \
PADDLE_ENFORCE_EQ(x_name, \
#x, \
common::errors::PreconditionNotMet( \
"The input 'x' of fast_where_xpu op should be '%s', " \
"but receive '%s'.", \
#x, \
x_name)); \
const auto& y_name = fast_where_xpu_op_nodes[0]->Op()->Input("y")[0]; \
PADDLE_ENFORCE_EQ(y_name, \
#y, \
common::errors::PreconditionNotMet( \
"The input 'y' of fast_where_xpu op should be '%s', " \
"but receive '%s'.", \
#y, \
y_name));
TEST(FastWhereXPUFusePass, one_case0) {
Layers layers;
auto* condition =
layers.data("condition", {20, 1}, false, proto::VarType::BOOL);
auto* x = layers.data("x", {20, 7});
auto* y = layers.data("y", {20, 7});
auto* cast_out = layers.cast(condition, 0, 5);
cast_out->SetShape({20, 1});
auto* scale_out = layers.scale(cast_out, -1.0f, 1.0f, true);
scale_out->SetShape({20, 1});
auto* mul0_out = layers.elementwise_mul(x, scale_out);
mul0_out->SetShape({20, 7});
auto* mul1_out = layers.elementwise_mul(y, cast_out);
mul1_out->SetShape({20, 7});
auto* add_out = layers.elementwise_add(mul0_out, mul1_out);
add_out->SetShape({20, 7});
APPLY_PASS
VERIFY_GRAPH(y, x)
}
TEST(FastWhereXPUFusePass, one_case1) {
Layers layers;
auto* condition =
layers.data("condition", {20, 1}, false, proto::VarType::BOOL);
auto* x = layers.data("x", {20, 7});
auto* y = layers.data("y", {20, 7});
auto* cast_out = layers.cast(condition, 0, 5);
cast_out->SetShape({20, 1});
auto* mul0_out = layers.elementwise_mul(x, cast_out);
mul0_out->SetShape({20, 7});
auto* scale_out = layers.scale(cast_out, -1.0f, 1.0f, true);
scale_out->SetShape({20, 1});
auto* mul1_out = layers.elementwise_mul(y, scale_out);
mul1_out->SetShape({20, 7});
auto* add_out = layers.elementwise_add(mul0_out, mul1_out);
add_out->SetShape({20, 7});
APPLY_PASS
VERIFY_GRAPH(x, y)
}
TEST(FastWhereXPUFusePass, one_case2) {
Layers layers;
auto* condition =
layers.data("condition", {20, 1}, false, proto::VarType::BOOL);
auto* x = layers.data("x", {20, 7});
auto* y = layers.data("y", {20, 7});
auto* cast_out = layers.cast(condition, 0, 5);
cast_out->SetShape({20, 1});
auto* scale_out = layers.scale(cast_out, -1.0f, 1.0f, true);
scale_out->SetShape({20, 1});
auto* mul0_out = layers.elementwise_mul(scale_out, x);
mul0_out->SetShape({20, 7});
auto* mul1_out = layers.elementwise_mul(cast_out, y);
mul1_out->SetShape({20, 7});
auto* add_out = layers.elementwise_add(mul0_out, mul1_out);
add_out->SetShape({20, 7});
APPLY_PASS
VERIFY_GRAPH(y, x)
}
TEST(FastWhereXPUFusePass, one_case3) {
Layers layers;
auto* condition =
layers.data("condition", {20, 1}, false, proto::VarType::BOOL);
auto* x = layers.data("x", {20, 7});
auto* y = layers.data("y", {20, 7});
auto* cast_out = layers.cast(condition, 0, 5);
cast_out->SetShape({20, 1});
auto* mul0_out = layers.elementwise_mul(cast_out, x);
mul0_out->SetShape({20, 7});
auto* scale_out = layers.scale(cast_out, -1.0f, 1.0f, true);
scale_out->SetShape({20, 1});
auto* mul1_out = layers.elementwise_mul(scale_out, y);
mul1_out->SetShape({20, 7});
auto* add_out = layers.elementwise_add(mul0_out, mul1_out);
add_out->SetShape({20, 7});
APPLY_PASS
VERIFY_GRAPH(x, y)
}
TEST(FastWhereXPUFusePass, one_case4) {
Layers layers;
auto* condition =
layers.data("condition", {20, 1}, false, proto::VarType::BOOL);
auto* x = layers.data("x", {20, 7});
auto* y = layers.data("y", {20, 7});
auto* cast_out = layers.cast(condition, 0, 5);
cast_out->SetShape({20, 1});
auto* scale_out = layers.scale(cast_out, -1.0f, 1.0f, true);
scale_out->SetShape({20, 1});
auto* mul0_out = layers.elementwise_mul(scale_out, x);
mul0_out->SetShape({20, 7});
auto* mul1_out = layers.elementwise_mul(y, cast_out);
mul1_out->SetShape({20, 7});
auto* add_out = layers.elementwise_add(mul0_out, mul1_out);
add_out->SetShape({20, 7});
APPLY_PASS
VERIFY_GRAPH(y, x)
}
TEST(FastWhereXPUFusePass, one_case5) {
Layers layers;
auto* condition =
layers.data("condition", {20, 1}, false, proto::VarType::BOOL);
auto* x = layers.data("x", {20, 7});
auto* y = layers.data("y", {20, 7});
auto* cast_out = layers.cast(condition, 0, 5);
cast_out->SetShape({20, 1});
auto* mul0_out = layers.elementwise_mul(cast_out, x);
mul0_out->SetShape({20, 7});
auto* scale_out = layers.scale(cast_out, -1.0f, 1.0f, true);
scale_out->SetShape({20, 1});
auto* mul1_out = layers.elementwise_mul(y, scale_out);
mul1_out->SetShape({20, 7});
auto* add_out = layers.elementwise_add(mul0_out, mul1_out);
add_out->SetShape({20, 7});
APPLY_PASS
VERIFY_GRAPH(x, y)
}
#undef VERIFY_GRAPH
#define VERIFY_GRAPH(logical_op, x, y) \
auto num_op_nodes = GetNumOpNodes(graph); \
PADDLE_ENFORCE_EQ( \
num_op_nodes, \
2, \
common::errors::PreconditionNotMet( \
"The graph contains only two op nodes, but %d op nodes found.", \
num_op_nodes)); \
auto logical_op_nodes = GetOpNodes(graph, #logical_op); \
PADDLE_ENFORCE_EQ( \
logical_op_nodes.size(), \
1, \
common::errors::PreconditionNotMet( \
"The graph contains only a '%s' op node, but %d op nodes found.", \
#logical_op, \
logical_op_nodes.size())); \
auto fast_where_xpu_op_nodes = GetOpNodes(graph, "fast_where_xpu"); \
PADDLE_ENFORCE_EQ(fast_where_xpu_op_nodes.size(), \
1, \
common::errors::PreconditionNotMet( \
"The graph contains only a fast_where_xpu op node, " \
"but %d op nodes found.", \
fast_where_xpu_op_nodes.size())); \
const auto& x_name = fast_where_xpu_op_nodes[0]->Op()->Input("x")[0]; \
PADDLE_ENFORCE_EQ(x_name, \
#x, \
common::errors::PreconditionNotMet( \
"The input 'x' of fast_where_xpu op should be '%s', " \
"but receive '%s'.", \
#x, \
x_name)); \
const auto& y_name = fast_where_xpu_op_nodes[0]->Op()->Input("y")[0]; \
PADDLE_ENFORCE_EQ(y_name, \
#y, \
common::errors::PreconditionNotMet( \
"The input 'y' of fast_where_xpu op should be '%s', " \
"but receive '%s'.", \
#y, \
y_name));
TEST(FastWhereXPUFusePass, cascade_case0) {
Layers layers;
auto* condition0 =
layers.data("condition0", {20, 1}, false, proto::VarType::BOOL);
auto* condition1 =
layers.data("condition1", {20, 1}, false, proto::VarType::BOOL);
auto* x = layers.data("x", {20, 7});
auto* y = layers.data("y", {20, 7});
// fast_where_xpu0
auto* cast0_out = layers.cast(condition0, 0, 5);
cast0_out->SetShape({20, 1});
auto* mul0_out = layers.elementwise_mul(cast0_out, x);
mul0_out->SetShape({20, 7});
auto* scale0_out = layers.scale(cast0_out, -1.0f, 1.0f, true);
scale0_out->SetShape({20, 1});
auto* mul1_out = layers.elementwise_mul(scale0_out, y);
mul1_out->SetShape({20, 7});
auto* add0_out = layers.elementwise_add(mul0_out, mul1_out);
add0_out->SetShape({20, 7});
// fast_where_xpu1
auto* cast1_out = layers.cast(condition1, 0, 5);
cast1_out->SetShape({20, 1});
auto* mul2_out = layers.elementwise_mul(cast1_out, x);
mul2_out->SetShape({20, 7});
auto* scale1_out = layers.scale(cast1_out, -1.0f, 1.0f, true);
scale1_out->SetShape({20, 1});
auto* mul3_out = layers.elementwise_mul(scale1_out, add0_out);
mul3_out->SetShape({20, 7});
auto* add1_out = layers.elementwise_add(mul2_out, mul3_out);
add1_out->SetShape({20, 7});
APPLY_PASS
VERIFY_GRAPH(logical_or, x, y)
}
TEST(FastWhereXPUFusePass, cascade_case1) {
Layers layers;
auto* condition0 =
layers.data("condition0", {20, 1}, false, proto::VarType::BOOL);
auto* condition1 =
layers.data("condition1", {20, 1}, false, proto::VarType::BOOL);
auto* x = layers.data("x", {20, 7});
auto* y = layers.data("y", {20, 7});
// fast_where_xpu0
auto* cast0_out = layers.cast(condition0, 0, 5);
cast0_out->SetShape({20, 1});
auto* mul0_out = layers.elementwise_mul(cast0_out, x);
mul0_out->SetShape({20, 7});
auto* scale0_out = layers.scale(cast0_out, -1.0f, 1.0f, true);
scale0_out->SetShape({20, 1});
auto* mul1_out = layers.elementwise_mul(scale0_out, y);
mul1_out->SetShape({20, 7});
auto* add0_out = layers.elementwise_add(mul0_out, mul1_out);
add0_out->SetShape({20, 7});
// fast_where_xpu1
auto* cast1_out = layers.cast(condition1, 0, 5);
cast1_out->SetShape({20, 1});
auto* mul2_out = layers.elementwise_mul(cast1_out, add0_out);
mul2_out->SetShape({20, 7});
auto* scale1_out = layers.scale(cast1_out, -1.0f, 1.0f, true);
scale1_out->SetShape({20, 1});
auto* mul3_out = layers.elementwise_mul(scale1_out, y);
mul3_out->SetShape({20, 7});
auto* add1_out = layers.elementwise_add(mul2_out, mul3_out);
add1_out->SetShape({20, 7});
APPLY_PASS
VERIFY_GRAPH(logical_and, x, y)
}
#undef APPLY_PASS
#undef VERIFY_GRAPH
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(fast_where_xpu_fuse_pass);
@@ -0,0 +1,58 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
TEST(FoldInterpOutsizeFusePass, basic) {
Layers layers;
auto* block = layers.Block();
auto* shape_x = layers.data("shape_x", {1, 18, 288, 288});
auto* concat_y =
layers.data("concat_y", {576, 576}, true, proto::VarType::INT64);
auto* shape_out = layers.shape(shape_x);
auto* cast1_out = layers.cast(shape_out, 2, 3);
auto* slice_out = layers.slice(cast1_out, {0}, {0}, {2});
auto* concat_out = layers.concat({slice_out, concat_y}, 0);
auto split_outs = layers.split(concat_out, 0, 0, {2, 2});
auto* split_out_1 = split_outs[1];
auto* cast2_out = layers.cast(split_out_1, 3, 2);
OpDesc* bilinear_interp_v2_op = block->AppendOp();
bilinear_interp_v2_op->SetType("bilinear_interp_v2");
bilinear_interp_v2_op->SetInput("X", {shape_x->Name()});
bilinear_interp_v2_op->SetInput("OutSize", {cast2_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("fold_interp_outsize_fuse_pass");
pass->Apply(graph.get());
auto ops_num = GetNumOpNodes(graph);
PADDLE_ENFORCE_EQ(
ops_num,
1,
common::errors::PreconditionNotMet(
"graph should only have 2 op nodes, but received %d.", ops_num));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(fold_interp_outsize_fuse_pass);
@@ -0,0 +1,45 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
TEST(FoldTwoSqueeze2FusePass, basic) {
Layers layers;
auto* in_x = layers.data("in_x", {64, 1, 74, 1});
auto* squeeze2_1_out = layers.squeeze2(in_x, std::vector<int>{3});
layers.squeeze2(squeeze2_1_out, std::vector<int>{1});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("fold_two_squeeze2_fuse_pass");
pass->Apply(graph.get());
auto ops_num = GetNumOpNodes(graph);
PADDLE_ENFORCE_EQ(
ops_num,
1,
common::errors::PreconditionNotMet(
"graph should only have 2 op nodes, but received %d.", ops_num));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(fold_two_squeeze2_fuse_pass);
@@ -0,0 +1,188 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
VarDesc* Data(paddle::framework::BlockDesc* block,
std::string name,
std::vector<int64_t> shape = {},
bool is_persistable = false,
proto::VarType::Type data_type = proto::VarType::FP32) {
auto* var = block->Var(name);
var->SetType(proto::VarType::DENSE_TENSOR);
var->SetDataType(data_type);
var->SetShape(shape);
var->SetPersistable(is_persistable);
return var;
}
VarDesc* fill_constant(BlockDesc* block, std::vector<VarDesc*> shapes) {
VarDesc* out = Data(block, shapes[0]->Name() + "_out");
OpDesc* op = block->AppendOp();
op->SetType("fill_constant");
std::vector<std::string> shape_names;
for (auto shape : shapes) {
shape_names.push_back(shape->Name());
}
op->SetInput("ShapeTensorList", {shape_names});
op->SetOutput("Out", {out->Name()});
return out;
}
TEST(FillConstantReshapePass, basic) {
paddle::framework::ProgramDesc program;
auto* block = program.MutableBlock(0);
auto* shape0 = Data(block, "shape0");
auto* shape1 = Data(block, "shape1");
auto* shape2 = Data(block, "shape2");
auto* shape3 = Data(block, "shape3");
auto* shape4 = Data(block, "shape4");
auto* shape5 = Data(block, "shape5");
auto* shape6 = Data(block, "shape6");
auto* shape7 = Data(block, "shape7");
auto* shape8 = Data(block, "shape8");
auto* shape9 = Data(block, "shape9");
auto* fill0 = fill_constant(block, {shape0, shape1, shape2, shape3, shape4});
fill0->SetShape({1, 2, 3, 4, 5});
auto* fill1 = fill_constant(block, {shape5, shape6, shape7, shape8, shape9});
fill1->SetShape({1, 2, 3, 4, 5});
OpDesc* fused_multi_transformer = block->AppendOp();
fused_multi_transformer->SetType("fused_multi_transformer");
fused_multi_transformer->SetInput("CacheKV", {fill0->Name(), fill1->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(program));
auto pass = PassRegistry::Instance().Get(
"fused_multi_transformer_cachekv_layout_trans_pass");
pass->Apply(graph.get());
auto fills = GetOpNodes(graph, "fill_constant");
auto fill0_in_names = fills[0]->Op()->Input("ShapeTensorList");
std::vector<std::string> expect_fill0_out_names{
"shape5", "shape6", "shape7", "shape8", "shape9"};
std::vector<std::string> expect_fill1_out_names{
"shape0", "shape1", "shape2", "shape3", "shape4"};
PADDLE_ENFORCE_EQ(fill0_in_names,
expect_fill0_out_names,
common::errors::PreconditionNotMet(
"fill_constant name should not be updated."));
auto fill1_in_names = fills[1]->Op()->Input("ShapeTensorList");
PADDLE_ENFORCE_EQ(fill1_in_names,
expect_fill1_out_names,
common::errors::PreconditionNotMet(
"fill_constant name should not be updated."));
}
TEST(GatherReshapePass, basic) {
Layers layers;
auto* gather0_x = layers.data("gather0_x", {2, 1, 24, 512, 64});
auto* gather0_index = layers.data("gather0_index", {1});
auto* gather0_out = layers.gather(gather0_x, gather0_index, 1);
gather0_out->SetShape({2, 1, 24, 512, 64});
auto* gather1_x = layers.data("gather1_x", {2, 1, 24, 512, 64});
auto* gather1_index = layers.data("gather1_index", {1});
auto* gather1_out = layers.gather(gather1_x, gather1_index, 1);
gather1_out->SetShape({2, 1, 24, 512, 64});
auto* block = layers.Block();
OpDesc* fused_multi_transformer = block->AppendOp();
fused_multi_transformer->SetType("fused_multi_transformer");
fused_multi_transformer->SetInput("CacheKV",
{gather0_out->Name(), gather1_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get(
"fused_multi_transformer_cachekv_layout_trans_pass");
pass->Apply(graph.get());
auto gathers = GetOpNodes(graph, "gather");
for (auto* gather : gathers) {
PADDLE_ENFORCE_EQ(gather->Op()->GetAttrIfExists<int>("axis"),
1,
common::errors::PreconditionNotMet(
"gather's axis attr should not be updated by pass."));
}
}
TEST(FillConstantAndGatherReshapePass, basic) {
Layers layers;
auto* block = layers.Block();
auto* shape0 = Data(block, "shape0");
auto* shape1 = Data(block, "shape1");
auto* shape2 = Data(block, "shape2");
auto* shape3 = Data(block, "shape3");
auto* shape4 = Data(block, "shape4");
auto* shape5 = Data(block, "shape5");
auto* shape6 = Data(block, "shape6");
auto* shape7 = Data(block, "shape7");
auto* shape8 = Data(block, "shape8");
auto* shape9 = Data(block, "shape9");
auto* fill0 = fill_constant(block, {shape0, shape1, shape2, shape3, shape4});
fill0->SetShape({1, 2, 3, 4, 5});
auto* fill1 = fill_constant(block, {shape5, shape6, shape7, shape8, shape9});
fill1->SetShape({1, 2, 3, 4, 5});
OpDesc* fused_multi_transformer = block->AppendOp();
fused_multi_transformer->SetType("fused_multi_transformer");
fused_multi_transformer->SetInput("CacheKV", {fill0->Name(), fill1->Name()});
auto* gather0_x = layers.data("gather0_x", {2, 1, 24, 512, 64});
auto* gather0_index = layers.data("gather0_index", {1});
auto* gather0_out = layers.gather(gather0_x, gather0_index, 1);
gather0_out->SetShape({2, 1, 24, 512, 64});
auto* gather1_x = layers.data("gather1_x", {2, 1, 24, 512, 64});
auto* gather1_index = layers.data("gather1_index", {1});
auto* gather1_out = layers.gather(gather1_x, gather1_index, 1);
gather1_out->SetShape({2, 1, 24, 512, 64});
OpDesc* fused_multi_transformer1 = block->AppendOp();
fused_multi_transformer1->SetType("fused_multi_transformer");
fused_multi_transformer1->SetInput(
"CacheKV", {gather0_out->Name(), gather1_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get(
"fused_multi_transformer_cachekv_layout_trans_pass");
pass->Apply(graph.get());
auto fills = GetOpNodes(graph, "fill_constant");
auto fill0_in_names = fills[0]->Op()->Input("ShapeTensorList");
std::vector<std::string> expect_fill0_out_names{
"shape0", "shape3", "shape1", "shape2", "shape4"};
std::vector<std::string> expect_fill1_out_names{
"shape5", "shape8", "shape6", "shape7", "shape9"};
PADDLE_ENFORCE_EQ(fill0_in_names,
expect_fill0_out_names,
common::errors::PreconditionNotMet(
"fill_constant name should be updated."));
auto fill1_in_names = fills[1]->Op()->Input("ShapeTensorList");
PADDLE_ENFORCE_EQ(fill1_in_names,
expect_fill1_out_names,
common::errors::PreconditionNotMet(
"fill_constant name should be updated."));
auto gathers = GetOpNodes(graph, "gather");
for (auto* gather : gathers) {
PADDLE_ENFORCE_EQ(
gather->Op()->GetAttrIfExists<int>("axis"),
2,
common::errors::PreconditionNotMet(
"gather's axis attr should be updated to 2 by pass."));
}
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(fused_multi_transformer_cachekv_layout_trans_pass);
@@ -0,0 +1,190 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
VarDesc* Data(paddle::framework::BlockDesc* block,
std::string name,
std::vector<int64_t> shape = {},
bool is_persistable = false,
proto::VarType::Type data_type = proto::VarType::FP32) {
auto* var = block->Var(name);
var->SetType(proto::VarType::DENSE_TENSOR);
var->SetDataType(data_type);
var->SetShape(shape);
var->SetPersistable(is_persistable);
return var;
}
VarDesc* fill_constant(BlockDesc* block, std::vector<VarDesc*> shapes) {
VarDesc* out = Data(block, shapes[0]->Name() + "_out");
OpDesc* op = block->AppendOp();
op->SetType("fill_constant");
std::vector<std::string> shape_names;
for (auto shape : shapes) {
shape_names.push_back(shape->Name());
}
op->SetInput("ShapeTensorList", {shape_names});
op->SetOutput("Out", {out->Name()});
return out;
}
TEST(FillConstantReshapePass, basic) {
paddle::framework::ProgramDesc program;
auto* block = program.MutableBlock(0);
auto* shape0 = Data(block, "shape0");
auto* shape1 = Data(block, "shape1");
auto* shape2 = Data(block, "shape2");
auto* shape3 = Data(block, "shape3");
auto* shape4 = Data(block, "shape4");
auto* shape5 = Data(block, "shape5");
auto* shape6 = Data(block, "shape6");
auto* shape7 = Data(block, "shape7");
auto* shape8 = Data(block, "shape8");
auto* shape9 = Data(block, "shape9");
auto* fill0 = fill_constant(block, {shape0, shape1, shape2, shape3, shape4});
fill0->SetShape({1, 2, 3, 4, 5});
auto* fill1 = fill_constant(block, {shape5, shape6, shape7, shape8, shape9});
fill1->SetShape({1, 2, 3, 4, 5});
OpDesc* fused_multi_transformer_int8 = block->AppendOp();
fused_multi_transformer_int8->SetType("fused_multi_transformer_int8");
fused_multi_transformer_int8->SetInput("CacheKV",
{fill0->Name(), fill1->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(program));
auto pass = PassRegistry::Instance().Get(
"fused_multi_transformer_int8_cachekv_layout_trans_pass");
pass->Apply(graph.get());
auto fills = GetOpNodes(graph, "fill_constant");
auto fill0_in_names = fills[0]->Op()->Input("ShapeTensorList");
std::vector<std::string> expect_fill0_out_names{
"shape5", "shape6", "shape7", "shape8", "shape9"};
std::vector<std::string> expect_fill1_out_names{
"shape0", "shape1", "shape2", "shape3", "shape4"};
PADDLE_ENFORCE_EQ(fill0_in_names,
expect_fill0_out_names,
common::errors::PreconditionNotMet(
"fill_constant name should not be updated."));
auto fill1_in_names = fills[1]->Op()->Input("ShapeTensorList");
PADDLE_ENFORCE_EQ(fill1_in_names,
expect_fill1_out_names,
common::errors::PreconditionNotMet(
"fill_constant name should not be updated."));
}
TEST(GatherReshapePass, basic) {
Layers layers;
auto* gather0_x = layers.data("gather0_x", {2, 1, 24, 512, 64});
auto* gather0_index = layers.data("gather0_index", {1});
auto* gather0_out = layers.gather(gather0_x, gather0_index, 1);
gather0_out->SetShape({2, 1, 24, 512, 64});
auto* gather1_x = layers.data("gather1_x", {2, 1, 24, 512, 64});
auto* gather1_index = layers.data("gather1_index", {1});
auto* gather1_out = layers.gather(gather1_x, gather1_index, 1);
gather1_out->SetShape({2, 1, 24, 512, 64});
auto* block = layers.Block();
OpDesc* fused_multi_transformer_int8 = block->AppendOp();
fused_multi_transformer_int8->SetType("fused_multi_transformer_int8");
fused_multi_transformer_int8->SetInput(
"CacheKV", {gather0_out->Name(), gather1_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get(
"fused_multi_transformer_int8_cachekv_layout_trans_pass");
pass->Apply(graph.get());
auto gathers = GetOpNodes(graph, "gather");
for (auto* gather : gathers) {
PADDLE_ENFORCE_EQ(gather->Op()->GetAttrIfExists<int>("axis"),
1,
common::errors::PreconditionNotMet(
"gather's axis attr should not be updated by pass."));
}
}
TEST(FillConstantAndGatherReshapePass, basic) {
Layers layers;
auto* block = layers.Block();
auto* shape0 = Data(block, "shape0");
auto* shape1 = Data(block, "shape1");
auto* shape2 = Data(block, "shape2");
auto* shape3 = Data(block, "shape3");
auto* shape4 = Data(block, "shape4");
auto* shape5 = Data(block, "shape5");
auto* shape6 = Data(block, "shape6");
auto* shape7 = Data(block, "shape7");
auto* shape8 = Data(block, "shape8");
auto* shape9 = Data(block, "shape9");
auto* fill0 = fill_constant(block, {shape0, shape1, shape2, shape3, shape4});
fill0->SetShape({1, 2, 3, 4, 5});
auto* fill1 = fill_constant(block, {shape5, shape6, shape7, shape8, shape9});
fill1->SetShape({1, 2, 3, 4, 5});
OpDesc* fused_multi_transformer_int8 = block->AppendOp();
fused_multi_transformer_int8->SetType("fused_multi_transformer_int8");
fused_multi_transformer_int8->SetInput("CacheKV",
{fill0->Name(), fill1->Name()});
auto* gather0_x = layers.data("gather0_x", {2, 1, 24, 512, 64});
auto* gather0_index = layers.data("gather0_index", {1});
auto* gather0_out = layers.gather(gather0_x, gather0_index, 1);
gather0_out->SetShape({2, 1, 24, 512, 64});
auto* gather1_x = layers.data("gather1_x", {2, 1, 24, 512, 64});
auto* gather1_index = layers.data("gather1_index", {1});
auto* gather1_out = layers.gather(gather1_x, gather1_index, 1);
gather1_out->SetShape({2, 1, 24, 512, 64});
OpDesc* fused_multi_transformer_int8_1 = block->AppendOp();
fused_multi_transformer_int8_1->SetType("fused_multi_transformer_int8");
fused_multi_transformer_int8_1->SetInput(
"CacheKV", {gather0_out->Name(), gather1_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get(
"fused_multi_transformer_int8_cachekv_layout_trans_pass");
pass->Apply(graph.get());
auto fills = GetOpNodes(graph, "fill_constant");
auto fill0_in_names = fills[0]->Op()->Input("ShapeTensorList");
std::vector<std::string> expect_fill0_out_names{
"shape0", "shape3", "shape1", "shape2", "shape4"};
std::vector<std::string> expect_fill1_out_names{
"shape5", "shape8", "shape6", "shape7", "shape9"};
PADDLE_ENFORCE_EQ(fill0_in_names,
expect_fill0_out_names,
common::errors::PreconditionNotMet(
"fill_constant name should be updated."));
auto fill1_in_names = fills[1]->Op()->Input("ShapeTensorList");
PADDLE_ENFORCE_EQ(fill1_in_names,
expect_fill1_out_names,
common::errors::PreconditionNotMet(
"fill_constant name should be updated."));
auto gathers = GetOpNodes(graph, "gather");
for (auto* gather : gathers) {
PADDLE_ENFORCE_EQ(
gather->Op()->GetAttrIfExists<int>("axis"),
2,
common::errors::PreconditionNotMet(
"gather's axis attr should be updated to 2 by pass."));
}
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(fused_multi_transformer_int8_cachekv_layout_trans_pass);
@@ -0,0 +1,265 @@
/* Copyright (c) 2022 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 "glog/logging.h"
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
#define DEF_INPUT_DATA \
Layers layers; \
auto* x = layers.data("x", {1, 128, 1024}); \
auto* src_mask = layers.data("src_mask", {1, 16, 128, 128}); \
auto* ln_scale = layers.data("ln_scale", {1024}, true); \
auto* ln_bias = layers.data("ln_bias", {1024}, true); \
auto* qkv_w = layers.data("qkv_w", {3, 16, 64, 1024}, true); \
auto* qkv_bias = layers.data("qkv_bias", {3, 16, 64}, true); \
auto* out_linear_w = layers.data("out_linear_w", {1024, 1024}, true); \
auto* out_linear_bias = layers.data("out_linear_bias", {1024}, true); \
auto* ffn_ln_scale = layers.data("ffn_ln_scale", {1024}, true); \
auto* ffn_ln_bias = layers.data("ffn_ln_bias", {1024}, true); \
auto* ffn1_w = layers.data("ffn1_w", {1024, 4096}, true); \
auto* ffn1_bias = layers.data("ffn1_bias", {4096}, true); \
auto* ffn2_w = layers.data("ffn2_w", {4096, 1024}, true); \
auto* ffn2_bias = layers.data("ffn2_bias", {1024}, true); \
auto* qkv_out_scale = layers.data("qkv_out_scale", {3, 16, 64}, true); \
auto* out_linear_out_scale = \
layers.data("out_linear_out_scale", {1024}, true); \
auto* ffn1_out_scale = layers.data("ffn1_out_scale", {4096}, true); \
auto* ffn2_out_scale = layers.data("ffn2_out_scale", {1024}, true); \
std::vector<float> qkv_in_scale(48, 1.0); \
std::vector<float> out_linear_in_scale(48, 1.0); \
std::vector<float> ffn1_in_scale(48, 1.0); \
std::vector<float> ffn2_in_scale(48, 1.0);
namespace paddle {
namespace framework {
namespace ir {
void AddVarToScope(Scope* param_scope,
const std::string& name,
const DDim& dims) {
auto* tensor = param_scope->Var(name)->GetMutable<phi::DenseTensor>();
tensor->Resize(dims);
tensor->mutable_data<float>(phi::CPUPlace());
}
Scope* CreateParamScope() {
auto param_scope = new Scope();
AddVarToScope(param_scope, "ln_scale", {1024});
AddVarToScope(param_scope, "ln_bias", {1024});
AddVarToScope(param_scope, "ffn_ln_scale", {1024});
AddVarToScope(param_scope, "ffn_ln_bias", {1024});
AddVarToScope(param_scope, "qkv_w", {3, 16, 64, 1024});
AddVarToScope(param_scope, "out_linear_w", {1024, 1024});
AddVarToScope(param_scope, "ffn1_w", {1024, 4096});
AddVarToScope(param_scope, "ffn2_w", {4096, 1024});
AddVarToScope(param_scope, "qkv_bias", {3072});
AddVarToScope(param_scope, "out_linear_bias", {1024});
AddVarToScope(param_scope, "ffn1_bias", {4096});
AddVarToScope(param_scope, "ffn2_bias", {1024});
AddVarToScope(param_scope, "qkv_out_scale", {3072});
AddVarToScope(param_scope, "out_linear_out_scale", {1024});
AddVarToScope(param_scope, "ffn1_out_scale", {4096});
AddVarToScope(param_scope, "ffn2_out_scale", {1024});
return param_scope;
}
VarDesc* Data(paddle::framework::BlockDesc* block,
std::string name,
std::vector<int64_t> shape = {},
bool is_persistable = false,
proto::VarType::Type data_type = proto::VarType::FP32) {
auto* var = block->Var(name);
var->SetType(proto::VarType::DENSE_TENSOR);
var->SetDataType(data_type);
var->SetShape(shape);
var->SetPersistable(is_persistable);
return var;
}
TEST(RemoveAssignGather, basic) {
paddle::framework::ProgramDesc program;
auto* block = program.MutableBlock(0);
auto* x = Data(block, "fused_multi_transformer_x", {1, 1, 1536});
auto* cache_kv =
Data(block, "fused_multi_transformer_cache_kv", {2, 1, 24, 512, 64});
OpDesc* fused_multi_transformer_op = block->AppendOp();
fused_multi_transformer_op->SetType("fused_multi_transformer_int8");
fused_multi_transformer_op->SetInput("X", {x->Name()});
fused_multi_transformer_op->SetInput("CacheKV", {cache_kv->Name()});
fused_multi_transformer_op->SetOutput("CacheKVOut", {cache_kv->Name()});
auto* assign_out = Data(block, "assign_out", cache_kv->GetShape());
OpDesc* assign_op = block->AppendOp();
assign_op->SetType("assign");
assign_op->SetInput("X", {cache_kv->Name()});
assign_op->SetOutput("Out", {assign_out->Name()});
OpDesc* gather_op = block->AppendOp();
auto gather_index = Data(block, "gather_index", {10});
gather_op->SetType("gather");
gather_op->SetInput("X", {assign_out->Name()});
gather_op->SetInput("Index", {gather_index->Name()});
gather_op->SetAttr("axis", {1});
gather_op->SetOutput("Out", {cache_kv->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(program));
auto pass = PassRegistry::Instance().Get(
"fused_multi_transformer_int8_xpu_quant_pass");
pass->Apply(graph.get());
auto assign_num = GetNumOpNodes(graph, "assign");
auto gather_num = GetNumOpNodes(graph, "gather");
PADDLE_ENFORCE_EQ(assign_num,
0,
common::errors::PreconditionNotMet(
"assign op should be removed from the graph."));
PADDLE_ENFORCE_EQ(gather_num,
0,
common::errors::PreconditionNotMet(
"gather op should be removed from the graph."));
}
TEST(FusedMultiTransformerInt8XPUQuantPass, context_stage) {
DEF_INPUT_DATA
LOG(INFO) << "layers.fill_constant_batch_size_like start";
auto* cache_kv = layers.fill_constant_batch_size_like(
x,
static_cast<int>(proto::VarType::FP16),
0,
1,
{2, -1, 16, 1024, 64},
0);
LOG(INFO) << "layers.fill_constant_batch_size_like done";
layers.fused_multi_transformer(x,
cache_kv,
src_mask,
qkv_w,
qkv_bias,
out_linear_w,
out_linear_bias,
ffn1_w,
ffn1_bias,
ffn2_w,
ffn2_bias,
ln_scale,
ln_bias,
ffn_ln_scale,
ffn_ln_bias,
0.1,
1e-12,
nullptr,
qkv_out_scale = qkv_out_scale,
out_linear_out_scale = out_linear_out_scale,
ffn1_out_scale = ffn1_out_scale,
ffn2_out_scale = ffn2_out_scale,
qkv_in_scale = qkv_in_scale,
out_linear_in_scale = out_linear_in_scale,
ffn1_in_scale = ffn1_in_scale,
ffn2_in_scale = ffn2_in_scale);
LOG(INFO) << "layers.fused_multi_transformer done";
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
graph->Set("__param_scope__", CreateParamScope());
auto pass = PassRegistry::Instance().Get(
"fused_multi_transformer_int8_xpu_quant_pass");
if (pass.get() == nullptr) {
LOG(INFO) << "get fused_multi_transformer_int8_xpu_quant_pass failed";
}
LOG(INFO) << "get fused_multi_transformer_int8_xpu_quant_pass Done";
VLOG(3) << DebugString(graph);
graph.reset(pass->Apply(graph.release()));
int num_nodes_after =
GetNumOpNodes(graph, "fused_multi_transformer_int8_xpu");
VLOG(3) << DebugString(graph);
PADDLE_ENFORCE_EQ(
num_nodes_after,
1,
common::errors::InvalidArgument(
"After the fused_multi_transformer_int8_xpu_quant_pass, "
"The node num in graph should be 1, but the result is %d",
num_nodes_after));
}
TEST(FusedMultiTransformerInt8XPUQuantPass, decoder_stage) {
DEF_INPUT_DATA
auto* cache_kv = layers.fill_constant_batch_size_like(
x,
static_cast<int>(proto::VarType::FP16),
0,
1,
{2, -1, 16, 1024, 64},
0);
auto* time_step = layers.data("time_step", {1});
layers.fused_multi_transformer(x,
cache_kv,
src_mask,
qkv_w,
qkv_bias,
out_linear_w,
out_linear_bias,
ffn1_w,
ffn1_bias,
ffn2_w,
ffn2_bias,
ln_scale,
ln_bias,
ffn_ln_scale,
ffn_ln_bias,
0.1,
1e-12,
time_step,
qkv_out_scale = qkv_out_scale,
out_linear_out_scale = out_linear_out_scale,
ffn1_out_scale = ffn1_out_scale,
ffn2_out_scale = ffn2_out_scale,
qkv_in_scale = qkv_in_scale,
out_linear_in_scale = out_linear_in_scale,
ffn1_in_scale = ffn1_in_scale,
ffn2_in_scale = ffn2_in_scale);
LOG(INFO) << "layers.fused_multi_transformer done";
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
graph->Set("__param_scope__", CreateParamScope());
auto pass = PassRegistry::Instance().Get(
"fused_multi_transformer_int8_xpu_quant_pass");
if (pass.get() == nullptr) {
LOG(INFO) << "get fused_multi_transformer_int8_xpu_quant_pass failed";
}
graph.reset(pass->Apply(graph.release()));
int num_nodes_after =
GetNumOpNodes(graph, "fused_multi_transformer_int8_xpu");
VLOG(3) << DebugString(graph);
PADDLE_ENFORCE_EQ(
num_nodes_after,
1,
common::errors::InvalidArgument(
"After the fused_multi_transformer_int8_xpu_quant_pass, "
"The node num in graph should be 1, but the result is %d",
num_nodes_after));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(fused_multi_transformer_int8_xpu_quant_pass);
@@ -0,0 +1,225 @@
/* Copyright (c) 2022 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 "glog/logging.h"
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
#define DEF_INPUT_DATA \
Layers layers; \
auto* x = layers.data("x", {1, 128, 1024}); \
auto* src_mask = layers.data("src_mask", {1, 16, 128, 128}); \
auto* ln_scale = layers.data("ln_scale", {1024}, true); \
auto* ln_bias = layers.data("ln_bias", {1024}, true); \
auto* qkv_w = layers.data("qkv_w", {3, 16, 64, 1024}, true); \
auto* qkv_bias = layers.data("qkv_bias", {3, 16, 64}, true); \
auto* out_linear_w = layers.data("out_linear_w", {1024, 1024}, true); \
auto* out_linear_bias = layers.data("out_linear_bias", {1024}, true); \
auto* ffn_ln_scale = layers.data("ffn_ln_scale", {1024}, true); \
auto* ffn_ln_bias = layers.data("ffn_ln_bias", {1024}, true); \
auto* ffn1_w = layers.data("ffn1_w", {1024, 4096}, true); \
auto* ffn1_bias = layers.data("ffn1_bias", {4096}, true); \
auto* ffn2_w = layers.data("ffn2_w", {4096, 1024}, true); \
auto* ffn2_bias = layers.data("ffn2_bias", {1024}, true);
namespace paddle {
namespace framework {
namespace ir {
void AddVarToScope(Scope* param_scope,
const std::string& name,
const DDim& dims) {
auto* tensor = param_scope->Var(name)->GetMutable<phi::DenseTensor>();
tensor->Resize(dims);
tensor->mutable_data<float>(phi::CPUPlace());
}
Scope* CreateParamScope() {
auto param_scope = new Scope();
AddVarToScope(param_scope, "ln_scale", {1024});
AddVarToScope(param_scope, "ln_bias", {1024});
AddVarToScope(param_scope, "ffn_ln_scale", {1024});
AddVarToScope(param_scope, "ffn_ln_bias", {1024});
AddVarToScope(param_scope, "qkv_w", {3, 16, 64, 1024});
AddVarToScope(param_scope, "out_linear_w", {1024, 1024});
AddVarToScope(param_scope, "ffn1_w", {1024, 4096});
AddVarToScope(param_scope, "ffn2_w", {4096, 1024});
AddVarToScope(param_scope, "qkv_bias", {3072});
AddVarToScope(param_scope, "out_linear_bias", {1024});
AddVarToScope(param_scope, "ffn1_bias", {4096});
AddVarToScope(param_scope, "ffn2_bias", {1024});
return param_scope;
}
VarDesc* Data(paddle::framework::BlockDesc* block,
std::string name,
std::vector<int64_t> shape = {},
bool is_persistable = false,
proto::VarType::Type data_type = proto::VarType::FP32) {
auto* var = block->Var(name);
var->SetType(proto::VarType::DENSE_TENSOR);
var->SetDataType(data_type);
var->SetShape(shape);
var->SetPersistable(is_persistable);
return var;
}
TEST(RemoveAssignGather, basic) {
paddle::framework::ProgramDesc program;
auto* block = program.MutableBlock(0);
auto* x = Data(block, "fused_multi_transformer_x", {1, 1, 1536});
auto* cache_kv =
Data(block, "fused_multi_transformer_cache_kv", {2, 1, 24, 512, 64});
OpDesc* fused_multi_transformer_op = block->AppendOp();
fused_multi_transformer_op->SetType("fused_multi_transformer");
fused_multi_transformer_op->SetInput("X", {x->Name()});
fused_multi_transformer_op->SetInput("CacheKV", {cache_kv->Name()});
fused_multi_transformer_op->SetOutput("CacheKVOut", {cache_kv->Name()});
auto* assign_out = Data(block, "assign_out", cache_kv->GetShape());
OpDesc* assign_op = block->AppendOp();
assign_op->SetType("assign");
assign_op->SetInput("X", {cache_kv->Name()});
assign_op->SetOutput("Out", {assign_out->Name()});
OpDesc* gather_op = block->AppendOp();
auto gather_index = Data(block, "gather_index", {10});
gather_op->SetType("gather");
gather_op->SetInput("X", {assign_out->Name()});
gather_op->SetInput("Index", {gather_index->Name()});
gather_op->SetAttr("axis", {1});
gather_op->SetOutput("Out", {cache_kv->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(program));
auto pass = PassRegistry::Instance().Get("fused_multi_transformer_xpu_pass");
pass->Apply(graph.get());
auto assign_num = GetNumOpNodes(graph, "assign");
auto gather_num = GetNumOpNodes(graph, "gather");
PADDLE_ENFORCE_EQ(assign_num,
0,
common::errors::PreconditionNotMet(
"assign op should be removed from the graph."));
PADDLE_ENFORCE_EQ(gather_num,
0,
common::errors::PreconditionNotMet(
"gather op should be removed from the graph."));
}
TEST(FusedMultiTransformerXPUPass, context_stage) {
DEF_INPUT_DATA
auto* cache_kv = layers.fill_constant_batch_size_like(
x,
static_cast<int>(proto::VarType::FP32),
0,
1,
{2, -1, 16, 1024, 64},
0);
layers.fused_multi_transformer(x,
cache_kv,
src_mask,
qkv_w,
qkv_bias,
out_linear_w,
out_linear_bias,
ffn1_w,
ffn1_bias,
ffn2_w,
ffn2_bias,
ln_scale,
ln_bias,
ffn_ln_scale,
ffn_ln_bias,
0.1,
1e-12);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
graph->Set("__param_scope__", CreateParamScope());
auto pass = PassRegistry::Instance().Get("fused_multi_transformer_xpu_pass");
if (pass.get() == nullptr) {
LOG(INFO) << "get fused_multi_transformer_xpu_pass failed";
}
graph.reset(pass->Apply(graph.release()));
int num_nodes_after = GetNumOpNodes(graph, "fused_multi_transformer_xpu");
VLOG(3) << DebugString(graph);
PADDLE_ENFORCE_EQ(
num_nodes_after,
1,
common::errors::InvalidArgument(
"After the fuse_multi_transformer_layer_pass, "
"The node num in graph should be 1, but the result is %d",
num_nodes_after));
}
TEST(FusedMultiTransformerXPUPass, decoder_stage) {
DEF_INPUT_DATA
auto* cache_kv = layers.fill_constant_batch_size_like(
x,
static_cast<int>(proto::VarType::FP32),
0,
1,
{2, -1, 16, 1024, 64},
0);
auto* time_step = layers.data("time_step", {1});
layers.fused_multi_transformer(x,
cache_kv,
src_mask,
qkv_w,
qkv_bias,
out_linear_w,
out_linear_bias,
ffn1_w,
ffn1_bias,
ffn2_w,
ffn2_bias,
ln_scale,
ln_bias,
ffn_ln_scale,
ffn_ln_bias,
0.1,
1e-12,
time_step);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
graph->Set("__param_scope__", CreateParamScope());
auto pass = PassRegistry::Instance().Get("fused_multi_transformer_xpu_pass");
if (pass.get() == nullptr) {
LOG(INFO) << "get fused_multi_transformer_xpu_pass failed";
}
graph.reset(pass->Apply(graph.release()));
int num_nodes_after = GetNumOpNodes(graph, "fused_multi_transformer_xpu");
VLOG(3) << DebugString(graph);
PADDLE_ENFORCE_EQ(
num_nodes_after,
1,
common::errors::InvalidArgument(
"After the fuse_multi_transformer_layer_pass, "
"The node num in graph should be 1, but the result is %d",
num_nodes_after));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(fused_multi_transformer_xpu_pass);
@@ -0,0 +1,56 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace framework {
namespace ir {
TEST(MatMulWeightTransPass, basic) {
Layers layers;
auto* reshape2_in = layers.data("reshape2_in", {64, 256, 1, 1});
auto* reshape2_out = layers.reshape2(reshape2_in, std::vector<int>{-1, 256});
auto* matmul_y = layers.data("matmul_y", {8, 256}, true);
layers.matmul_v2(reshape2_out, matmul_y, nullptr, false, true);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("matmul_weight_trans_pass");
VLOG(3) << DebugString(graph);
pass->Apply(graph.get());
VLOG(3) << DebugString(graph);
bool trans_y = true;
for (auto* node : graph->Nodes()) {
if (node->IsOp() && node->Op()->Type() == "matmul_v2") {
trans_y = PADDLE_GET_CONST(bool, node->Op()->GetAttr("trans_y"));
}
}
PADDLE_ENFORCE_EQ(
trans_y,
false,
common::errors::PreconditionNotMet(
"The attribute of matmul_v2 trans_y should be false after pass"));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(matmul_weight_trans_pass);
@@ -0,0 +1,105 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
TEST(MultiEncoderXPUAdaptiveSeqlenFusePass, V1) {
Layers layers;
auto* block = layers.Block();
auto* embedding_xpu_out = layers.data("embedding_xpu_out");
OpDesc* embedding_xpu = block->AppendOp();
embedding_xpu->SetType("embedding_with_eltwise_add_xpu");
embedding_xpu->SetOutput("out", {embedding_xpu_out->Name()});
auto* layer_norm_out = layers.layer_norm(embedding_xpu_out)[0];
auto* mask = layers.data("mask");
auto* matmul_out = layers.matmul(mask, mask);
auto* scale_out = layers.scale(matmul_out);
auto* stack_out = layers.stack({scale_out, scale_out});
OpDesc* multi_encoder_xpu = block->AppendOp();
multi_encoder_xpu->SetType("multi_encoder_xpu");
multi_encoder_xpu->SetInput("x", {layer_norm_out->Name()});
multi_encoder_xpu->SetInput("mask", {stack_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get(
"multi_encoder_xpu_adaptive_seqlen_fuse_pass");
pass->Apply(graph.get());
auto num = GetNumOpNodes(graph, "matmul") + GetNumOpNodes(graph, "scale") +
GetNumOpNodes(graph, "stack");
PADDLE_ENFORCE_EQ(
num,
0,
common::errors::PreconditionNotMet(
"matmul/scale/stack ops should be removed from graph, but graph "
"still has %d ops.",
num));
}
TEST(MultiEncoderXPUAdaptiveSeqlenFusePass, V2) {
Layers layers;
auto* block = layers.Block();
auto* embedding_xpu_out = layers.data("embedding_xpu_out");
OpDesc* embedding_xpu = block->AppendOp();
embedding_xpu->SetType("embedding_with_eltwise_add_xpu");
embedding_xpu->SetOutput("out", {embedding_xpu_out->Name()});
auto* layer_norm_out = layers.layer_norm(embedding_xpu_out)[0];
auto* mask = layers.data("mask");
auto* not_equal_y = layers.data("not_equal_y");
auto* not_equal_out = layers.not_equal(mask, not_equal_y);
auto* cast_out = layers.cast(not_equal_out);
auto* unsqueeze_0_out = layers.unsqueeze2(cast_out);
auto* matmul_out = layers.matmul_v2(unsqueeze_0_out, unsqueeze_0_out);
auto* scale_0_out = layers.scale(matmul_out);
auto* scale_1_out = layers.scale(scale_0_out);
auto* unsqueeze_1_out = layers.unsqueeze2(scale_1_out);
auto* tile_out = layers.tile(unsqueeze_1_out);
OpDesc* multi_encoder_xpu = block->AppendOp();
multi_encoder_xpu->SetType("multi_encoder_xpu");
multi_encoder_xpu->SetInput("x", {layer_norm_out->Name()});
multi_encoder_xpu->SetInput("mask", {tile_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get(
"multi_encoder_xpu_adaptive_seqlen_fuse_pass");
pass->Apply(graph.get());
auto num = GetNumOpNodes(graph, "not_equal") + GetNumOpNodes(graph, "cast") +
GetNumOpNodes(graph, "unsqueeze2") +
GetNumOpNodes(graph, "matmul_v2") + GetNumOpNodes(graph, "scale") +
GetNumOpNodes(graph, "tile");
PADDLE_ENFORCE_EQ(num,
0,
common::errors::PreconditionNotMet(
"not_equal/cast/unsqueeze2/matmul_v2/scale ops should "
"be removed from graph, but graph "
"still has %d ops.",
num));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(multi_encoder_xpu_adaptive_seqlen_fuse_pass);
@@ -0,0 +1,221 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
template <typename T = float>
void AddVarToScope(Scope* param_scope,
const std::string& name,
const DDim& dims,
T value = 0) {
auto* tensor = param_scope->Var(name)->GetMutable<phi::DenseTensor>();
tensor->Resize(dims);
auto* cpu_ctx = static_cast<phi::CPUContext*>(
phi::DeviceContextPool::Instance().Get(phi::CPUPlace()));
auto* data = cpu_ctx->Alloc<T>(tensor);
for (int64_t i = 0; i < tensor->numel(); i++) {
data[i] = value;
}
}
VarDesc* Data(paddle::framework::BlockDesc* block,
std::string name,
std::vector<int64_t> shape = {},
bool is_persistable = false,
proto::VarType::Type data_type = proto::VarType::FP32) {
auto* var = block->Var(name);
var->SetType(proto::VarType::DENSE_TENSOR);
var->SetDataType(data_type);
var->SetShape(shape);
var->SetPersistable(is_persistable);
return var;
}
TEST(RemoveAssignGather, basic) {
paddle::framework::ProgramDesc program;
auto* block = program.MutableBlock(0);
OpDesc* beam_search_op = block->AppendOp();
beam_search_op->SetType("beam_search");
beam_search_op->SetAttr("beam_size", 1);
auto* x = Data(block, "fused_multi_transformer_x", {1, 1, 1536});
auto* cache_kv =
Data(block, "fused_multi_transformer_cache_kv", {2, 1, 24, 512, 64});
OpDesc* fused_multi_transformer_op = block->AppendOp();
fused_multi_transformer_op->SetType("fused_multi_transformer");
fused_multi_transformer_op->SetInput("X", {x->Name()});
fused_multi_transformer_op->SetInput("CacheKV", {cache_kv->Name()});
fused_multi_transformer_op->SetOutput("CacheKVOut", {cache_kv->Name()});
auto* assign_out = Data(block, "assign_out", cache_kv->GetShape());
OpDesc* assign_op = block->AppendOp();
assign_op->SetType("assign");
assign_op->SetInput("X", {cache_kv->Name()});
assign_op->SetOutput("Out", {assign_out->Name()});
OpDesc* gather_op = block->AppendOp();
gather_op->SetType("gather");
gather_op->SetInput("X", {assign_out->Name()});
gather_op->SetOutput("Out", {cache_kv->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(program));
auto pass = PassRegistry::Instance().Get("one_beam_size_fuse_pass");
pass->Apply(graph.get());
auto assign_num = GetNumOpNodes(graph, "assign");
auto gather_num = GetNumOpNodes(graph, "gather");
PADDLE_ENFORCE_EQ(assign_num,
0,
common::errors::PreconditionNotMet(
"assign op should be removed from the graph."));
PADDLE_ENFORCE_EQ(gather_num,
0,
common::errors::PreconditionNotMet(
"gather op should be removed from the graph."));
}
TEST(FoldShapeAssociatedOps, basic) {
Layers layers;
auto* block = layers.Block();
OpDesc* beam_search_op = block->AppendOp();
beam_search_op->SetType("beam_search");
beam_search_op->SetAttr("beam_size", 1);
auto* shape_x = layers.data("shape_x", {1, 46256});
auto* shape_out = layers.shape(shape_x);
auto* slice_out = layers.slice(shape_out, {0}, {0}, {1});
auto* div_out = layers.elementwise_div(slice_out, slice_out);
auto* cast0_out = layers.cast(div_out);
auto* cast1_out = layers.cast(slice_out);
auto* scale0_out = layers.scale(slice_out);
auto* cast2_out = layers.cast(scale0_out);
auto* range_out = layers.range(cast2_out, cast1_out, cast0_out);
auto* unsqueeze2_out = layers.unsqueeze2(range_out);
auto* scale1_out = layers.scale(unsqueeze2_out);
auto* add_x = layers.data("add_x", {1, 2});
auto* add_out = layers.elementwise_add(add_x, scale1_out);
layers.flatten_contiguous_range(add_out);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("one_beam_size_fuse_pass");
pass->Apply(graph.get());
auto ops_num = GetNumOpNodes(graph);
PADDLE_ENFORCE_EQ(
ops_num,
2,
common::errors::PreconditionNotMet(
"graph should only have 2 op nodes, but received %d.", ops_num));
}
TEST(RemoveBeamSearchAssociatedOps, basic) {
Layers layers;
auto* lod_reset_0_x = layers.data("lod_reset_0_x");
auto* lod_reset_0_y = layers.data("lod_reset_0_y");
auto* lod_reset_0_out = layers.lod_reset(lod_reset_0_x, lod_reset_0_y);
auto* lod_reset_1_x = layers.data("lod_reset_1_x");
auto* lod_reset_1_y = layers.data("lod_reset_1_y");
auto* lod_reset_1_out = layers.lod_reset(lod_reset_1_x, lod_reset_1_y);
auto* pre_ids = layers.data("pre_ids");
auto* pre_scores = layers.data("pre_scores");
auto beam_search_outs =
layers.beam_search(lod_reset_0_out, lod_reset_1_out, pre_ids, pre_scores);
auto* parent_idx = beam_search_outs[0];
auto* selected_ids = beam_search_outs[1];
auto* selected_scores = beam_search_outs[2];
auto* write_to_array_0_i = layers.data("write_to_array_0_i");
layers.write_to_array(selected_ids, write_to_array_0_i);
auto* write_to_array_1_i = layers.data("write_to_array_1_i");
layers.write_to_array(selected_scores, write_to_array_1_i);
auto* is_empty_out = layers.is_empty(selected_ids);
layers.logical_not(is_empty_out);
layers.cast(parent_idx);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto* param_scope = new Scope();
graph->Set("__param_scope__", param_scope);
auto pass = PassRegistry::Instance().Get("one_beam_size_fuse_pass");
pass->Apply(graph.get());
auto beam_search_num = GetNumOpNodes(graph, "beam_search");
PADDLE_ENFORCE_EQ(beam_search_num,
0,
common::errors::PreconditionNotMet(
"beam_search op should be removed from the graph."));
}
TEST(RemoveWriteReadArrayOps, basic) {
Layers layers;
auto* block = layers.Block();
OpDesc* beam_search_op = block->AppendOp();
beam_search_op->SetType("beam_search");
beam_search_op->SetAttr("beam_size", 1);
auto* write_x = layers.data("write_x", {1}, true);
auto* write_i = layers.data("write_i");
auto* write_out = layers.write_to_array(write_x, write_i);
auto* read_i = layers.data("read_i");
layers.read_from_array(write_out, read_i);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto* param_scope = new Scope();
graph->Set("__param_scope__", param_scope);
AddVarToScope(param_scope, write_x->Name(), {1});
auto pass = PassRegistry::Instance().Get("one_beam_size_fuse_pass");
pass->Apply(graph.get());
auto write_read_num = GetNumOpNodes(graph, "write_to_array") +
GetNumOpNodes(graph, "read_from_array");
PADDLE_ENFORCE_EQ(write_read_num,
0,
common::errors::PreconditionNotMet(
"write_to_array and read_from_array ops should be "
"removed from the graph."));
}
TEST(RemoveGatherOps, basic) {
Layers layers;
auto* block = layers.Block();
OpDesc* beam_search_op = block->AppendOp();
beam_search_op->SetType("beam_search");
beam_search_op->SetAttr("beam_size", 1);
auto* gather_x = layers.data("gather_x");
auto* gather_i = layers.data("gather_i", {1}, true);
layers.gather(gather_x, gather_i, 0);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto* param_scope = new Scope();
graph->Set("__param_scope__", param_scope);
AddVarToScope<int>(param_scope, gather_i->Name(), {1}, 0);
auto pass = PassRegistry::Instance().Get("one_beam_size_fuse_pass");
pass->Apply(graph.get());
auto gather_num = GetNumOpNodes(graph, "gather");
PADDLE_ENFORCE_EQ(gather_num,
0,
common::errors::PreconditionNotMet(
"gather op should be removed from the graph."));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(one_beam_size_fuse_pass);
@@ -0,0 +1,105 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
#include "paddle/fluid/platform/enforce.h"
namespace paddle {
namespace framework {
namespace ir {
TEST(Squeeze2MatmulXPUFusePass, basic) {
Layers layers;
auto* squeeze2_in = layers.data("squeeze2_in", {64, 1, 74, 1});
auto* squeeze2_out = layers.squeeze2(squeeze2_in, std::vector<int>{1, 3});
auto* matmul_y = layers.data("matmul_y", {74, 64}, true);
auto* matmul_out =
layers.matmul(squeeze2_out, matmul_y, nullptr, false, false);
auto* ele_y = layers.data("ele_y", {64}, true);
layers.elementwise_add(matmul_out, ele_y);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("squeeze2_matmul_xpu_fuse_pass");
VLOG(3) << DebugString(graph);
pass->Apply(graph.get());
VLOG(3) << DebugString(graph);
auto ops_num = GetNumOpNodes(graph);
PADDLE_ENFORCE_EQ(
ops_num,
3,
common::errors::PreconditionNotMet(
"graph should only have 2 op nodes, but received %d.", ops_num));
}
TEST(ReShape2MatmulXPUFusePass, basic) {
Layers layers;
auto* reshape2_in = layers.data("reshape2_in", {64, 1, 74, 1});
auto* reshape2_out = layers.reshape2(reshape2_in, std::vector<int>{-1, 74});
auto* matmul_y = layers.data("matmul_y", {74, 64}, true);
auto* matmul_out =
layers.matmul(reshape2_out, matmul_y, nullptr, false, false);
auto* ele_y = layers.data("ele_y", {64}, true);
layers.elementwise_add(matmul_out, ele_y);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("reshape2_matmul_xpu_fuse_pass");
VLOG(3) << DebugString(graph);
pass->Apply(graph.get());
VLOG(3) << DebugString(graph);
auto ops_num = GetNumOpNodes(graph);
PADDLE_ENFORCE_EQ(
ops_num,
3,
common::errors::PreconditionNotMet(
"graph should only have 2 op nodes, but received %d.", ops_num));
}
TEST(MapMatmulV2ToMatmulXPUPass, basic) {
Layers layers;
auto* matmul_x = layers.data("matmul_x", {64, 74});
auto* matmul_y = layers.data("matmul_y", {74, 64}, true);
layers.matmul_v2(matmul_x, matmul_y, nullptr, false, false);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("map_matmulv2_to_matmul_xpu_pass");
VLOG(3) << DebugString(graph);
pass->Apply(graph.get());
VLOG(3) << DebugString(graph);
auto matmuls = GetOpNodes(graph, "matmul");
for (auto* matmul : matmuls) {
PADDLE_ENFORCE_EQ(
std::abs(matmul->Op()->GetAttrIfExists<float>("alpha") - 1.f) < 1e-5f,
true,
common::errors::PreconditionNotMet(
"matmul_v2 is mapped to matmul by pass."));
}
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(reshape2_matmul_xpu_fuse_pass);
@@ -0,0 +1,63 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
TEST(SqueezeExcitationFusePass, V1) {
Layers layers;
auto* block = layers.Block();
auto* pool2d_inp = layers.data("pool2d_inp", {1, 24, 14, 14});
auto* pool2d_out = layers.pool2d(pool2d_inp, false);
auto* conv2d_xpu_op1_out = layers.data("conv2d_xpu_op1_out");
OpDesc* conv2d_xpu_op1 = block->AppendOp();
conv2d_xpu_op1->SetType("conv2d_xpu");
conv2d_xpu_op1->SetInput("x", {pool2d_out->Name()});
conv2d_xpu_op1->SetOutput("out", {conv2d_xpu_op1_out->Name()});
auto* conv2d_xpu_op2_out = layers.data("conv2d_xpu_op2_out");
OpDesc* conv2d_xpu_op2 = block->AppendOp();
conv2d_xpu_op2->SetType("conv2d_xpu");
conv2d_xpu_op2->SetInput("x", {conv2d_xpu_op1_out->Name()});
conv2d_xpu_op2->SetOutput("out", {conv2d_xpu_op2_out->Name()});
layers.elementwise_mul(pool2d_inp, conv2d_xpu_op2_out);
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("squeeze_excitation_fuse_pass");
pass->Apply(graph.get());
auto num = GetNumOpNodes(graph, "pool2d") +
GetNumOpNodes(graph, "conv2d_xpu") +
GetNumOpNodes(graph, "elementwise_mul");
PADDLE_ENFORCE_EQ(num,
0,
common::errors::PreconditionNotMet(
"pool2d/conv2d_xpu/elementwise_mul ops should be "
"removed from graph, but graph "
"still has %d ops. ",
num));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(squeeze_excitation_fuse_pass);
@@ -0,0 +1,53 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
TEST(StackFusePass, basic) {
Layers layers;
auto* block = layers.Block();
auto* stack_x = layers.data("stack_x", {-1, 64, 64});
auto* stack_out = layers.stack({stack_x, stack_x, stack_x}, 1);
stack_out->SetShape({-1, 3, 64, 64});
auto* add_x = layers.data("add_x", {-1, 24, 64, 64});
layers.elementwise_add(add_x, stack_out);
OpDesc* fused_multi_transformer_op = block->AppendOp();
fused_multi_transformer_op->SetType("fused_multi_transformer");
fused_multi_transformer_op->SetInput("SrcMask", {stack_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(layers.main_program()));
auto pass = PassRegistry::Instance().Get("stack_fuse_pass");
pass->Apply(graph.get());
auto stack_num = GetNumOpNodes(graph, "stack");
PADDLE_ENFORCE_EQ(stack_num,
0,
common::errors::PreconditionNotMet(
"stack op should be removed from graph, but graph "
"still has %d stack op.",
stack_num));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(stack_fuse_pass);
@@ -0,0 +1,209 @@
// 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.
#include <gtest/gtest.h>
#include "paddle/fluid/framework/ir/pass.h"
#include "paddle/fluid/framework/ir/pass_tester_helper.h"
namespace paddle {
namespace framework {
namespace ir {
VarDesc* Data(paddle::framework::BlockDesc* block,
std::string name,
std::vector<int64_t> shape = {},
bool is_persistable = false,
proto::VarType::Type data_type = proto::VarType::FP32) {
auto* var = block->Var(name);
var->SetType(proto::VarType::DENSE_TENSOR);
var->SetDataType(data_type);
var->SetShape(shape);
var->SetPersistable(is_persistable);
return var;
}
VarDesc* AddCast(BlockDesc* block,
VarDesc* input,
int in_dtype = 5,
int out_dtype = 5) {
VarDesc* out = Data(block, input->Name() + "_out");
OpDesc* op = block->AppendOp();
op->SetType("cast");
op->SetInput("X", {input->Name()});
op->SetOutput("Out", {out->Name()});
op->SetAttr("in_dtype", in_dtype);
op->SetAttr("out_dtype", out_dtype);
return out;
}
int GetOpNum(Graph* graph, std::string op_type = "") {
int num_nodes = 0;
for (auto* node : graph->Nodes()) {
if (node->IsOp() && node->Op() &&
(node->Op()->Type() == op_type || op_type.empty())) {
num_nodes++;
}
}
return num_nodes;
}
TEST(ApplyCastSoftmaxPass, basic) {
paddle::framework::ProgramDesc program;
auto* block = program.MutableBlock(0);
auto* cast0_in = Data(block, "cast0_in", {1});
auto* cast0_out = AddCast(block, cast0_in, 4, 5);
auto* softmax_out = Data(block, "softmax_out", {1});
OpDesc* softmax = block->AppendOp();
softmax->SetType("softmax");
softmax->SetInput("X", {cast0_out->Name()});
softmax->SetOutput("Out", {softmax_out->Name()});
AddCast(block, softmax_out, 5, 4);
std::unique_ptr<ir::Graph> graph(new ir::Graph(program));
auto scope = new Scope();
graph->Set("__param_scope__", scope);
auto pass = PassRegistry::Instance().Get("xpu_delete_cast_op_pass");
pass->Apply(graph.get());
int cast_num_in_graph = GetOpNum(graph->GetSubGraph(0), "cast");
PADDLE_ENFORCE_EQ(
GetOpNum(graph->GetSubGraph(0), "cast"),
0,
common::errors::PreconditionNotMet(
"graph should have 0 cast after xpu_delete_cast_op_pass, "
"but actually has %d.",
cast_num_in_graph));
}
TEST(ApplyCastLayerNormPass, basic) {
paddle::framework::ProgramDesc program;
auto* block = program.MutableBlock(0);
auto* cast0_in = Data(block, "cast0_in", {1});
auto* cast0_out = AddCast(block, cast0_in, 4, 5);
auto* layer_norm_out = Data(block, "layer_norm_out", {1});
OpDesc* layer_norm = block->AppendOp();
layer_norm->SetType("layer_norm");
layer_norm->SetInput("X", {cast0_out->Name()});
layer_norm->SetOutput("Y", {layer_norm_out->Name()});
AddCast(block, layer_norm_out, 5, 4);
std::unique_ptr<ir::Graph> graph(new ir::Graph(program));
auto scope = new Scope();
graph->Set("__param_scope__", scope);
auto pass = PassRegistry::Instance().Get("xpu_delete_cast_op_pass");
pass->Apply(graph.get());
int cast_num_in_graph = GetOpNum(graph->GetSubGraph(0), "cast");
PADDLE_ENFORCE_EQ(
GetOpNum(graph->GetSubGraph(0), "cast"),
0,
common::errors::PreconditionNotMet(
"graph should have 0 cast after xpu_delete_cast_op_pass, "
"but actually has %d.",
cast_num_in_graph));
}
TEST(ApplyCastCacheKVInitializationPass, basic) {
paddle::framework::ProgramDesc program;
auto* block = program.MutableBlock(0);
auto* shape_in =
Data(block, "shape_in", {64, 128}, false, proto::VarType::INT64);
auto* shape0_out =
Data(block, "shape0_out", {2}, false, proto::VarType::INT32);
auto* shape1_out =
Data(block, "shape1_out", {2}, false, proto::VarType::INT32);
auto* slice0_out =
Data(block, "slice0_out", {1}, false, proto::VarType::INT32);
auto* slice1_out =
Data(block, "slice1_out", {1}, false, proto::VarType::INT32);
auto* elementwise_add_in0 =
Data(block, "elementwise_add_in0", {1}, false, proto::VarType::INT64);
auto* elementwise_add_out =
Data(block, "elementwise_add_out", {1}, false, proto::VarType::INT64);
auto* scale_out = Data(block, "scale_out", {1}, false, proto::VarType::INT64);
OpDesc* shape0 = block->AppendOp();
shape0->SetType("shape");
shape0->SetInput("X", {shape_in->Name()});
shape0->SetOutput("Out", {shape0_out->Name()});
OpDesc* shape1 = block->AppendOp();
shape1->SetType("shape");
shape1->SetInput("X", {shape_in->Name()});
shape1->SetOutput("Out", {shape1_out->Name()});
OpDesc* slice0 = block->AppendOp();
slice0->SetType("slice");
slice0->SetInput("X", {shape0_out->Name()});
slice0->SetOutput("Out", {slice0_out->Name()});
OpDesc* slice1 = block->AppendOp();
slice1->SetType("slice");
slice1->SetInput("X", {shape1_out->Name()});
slice1->SetOutput("Out", {slice1_out->Name()});
auto cast0_out = AddCast(block,
slice1_out,
static_cast<int>(proto::VarType::INT32),
static_cast<int>(proto::VarType::INT64));
OpDesc* elementwise_add = block->AppendOp();
elementwise_add->SetType("elementwise_add");
elementwise_add->SetInput("X", {elementwise_add_in0->Name()});
elementwise_add->SetInput("Y", {cast0_out->Name()});
elementwise_add->SetOutput("Out", {elementwise_add_out->Name()});
OpDesc* scale = block->AppendOp();
scale->SetType("scale");
scale->SetInput("X", {elementwise_add_out->Name()});
scale->SetOutput("Out", {scale_out->Name()});
scale->SetAttr("scale", 1.0f);
scale->SetAttr("bias", 64.0f);
auto* cast1_out = AddCast(block,
scale_out,
static_cast<int>(proto::VarType::INT64),
static_cast<int>(proto::VarType::INT32));
OpDesc* fill_constant = block->AppendOp();
fill_constant->SetType("fill_constant");
fill_constant->SetInput("X", {slice0_out->Name()});
fill_constant->SetInput("Y", {cast1_out->Name()});
std::unique_ptr<ir::Graph> graph(new ir::Graph(program));
auto scope = new Scope();
graph->Set("__param_scope__", scope);
auto pass = PassRegistry::Instance().Get("xpu_delete_cast_op_pass");
pass->Apply(graph.get());
int shape_num_in_graph = GetOpNum(graph->GetSubGraph(0), "shape");
PADDLE_ENFORCE_EQ(
GetOpNum(graph->GetSubGraph(0), "shape"),
1,
common::errors::PreconditionNotMet("graph should have 1 shape after "
"xpu_delete_cast_op_pass, "
"but actually has %d.",
shape_num_in_graph));
int cast_num_in_graph = GetOpNum(graph->GetSubGraph(0), "cast");
PADDLE_ENFORCE_EQ(
GetOpNum(graph->GetSubGraph(0), "cast"),
1,
common::errors::PreconditionNotMet("graph should have 1 cast after "
"xpu_delete_cast_op_pass, "
"but actually has %d.",
cast_num_in_graph));
}
} // namespace ir
} // namespace framework
} // namespace paddle
USE_PASS(xpu_delete_cast_op_pass);