Files
2026-07-13 12:40:42 +08:00

169 lines
7.1 KiB
C++

// 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 <cstdint>
#include <vector>
#include "paddle/fluid/framework/scope.h"
#include "paddle/fluid/pir/dialect/operator/ir/op_dialect.h"
#include "paddle/fluid/pir/dialect/operator/ir/pd_op.h"
#include "paddle/fluid/pir/transforms/general/constant_folding_pass.h"
#include "paddle/fluid/pir/transforms/general/dead_code_elimination_pass.h"
#include "paddle/fluid/pir/transforms/gpu/multihead_matmul_fuse_pass.h"
#include "paddle/phi/common/place.h"
#include "paddle/pir/include/core/builtin_dialect.h"
#include "paddle/pir/include/pass/pass_manager.h"
#include "paddle/phi/core/kernel_registry.h"
PD_DECLARE_KERNEL(multihead_matmul, GPU, ALL_LAYOUT);
void BuildProgram(pir::Builder &builder) { // NOLINT
paddle::dialect::FullOp matmul_1_in_1 =
builder.Build<paddle::dialect::FullOp>(std::vector<int64_t>{1, 300, 256},
0.9,
phi::DataType::FLOAT32,
phi::CPUPlace());
// The first path to matmul with scale (q).
paddle::dialect::FullOp matmul_1_in_2 =
builder.Build<paddle::dialect::FullOp>(std::vector<int64_t>{256, 256},
1.1,
phi::DataType::FLOAT32,
phi::CPUPlace());
paddle::dialect::MatmulOp matmul_1 = builder.Build<paddle::dialect::MatmulOp>(
matmul_1_in_1.out(), matmul_1_in_2.out(), false, false);
paddle::dialect::FullOp add_1_in_2 = builder.Build<paddle::dialect::FullOp>(
std::vector<int64_t>{256}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace());
paddle::dialect::AddOp add_1 =
builder.Build<paddle::dialect::AddOp>(matmul_1.out(), add_1_in_2.out());
paddle::dialect::ReshapeOp reshape_1 =
builder.Build<paddle::dialect::ReshapeOp>(
add_1.out(), std::vector<int64_t>{0, 0, 8, 32});
paddle::dialect::TransposeOp transpose_1 =
builder.Build<paddle::dialect::TransposeOp>(reshape_1.out(),
std::vector<int>{0, 2, 1, 3});
paddle::dialect::ScaleOp scale_op = builder.Build<paddle::dialect::ScaleOp>(
transpose_1.out(), 0.1767766922712326, 0.0, true);
// The second path to matmul (k).
paddle::dialect::FullOp matmul_2_in_2 =
builder.Build<paddle::dialect::FullOp>(std::vector<int64_t>{256, 256},
1.1,
phi::DataType::FLOAT32,
phi::CPUPlace());
paddle::dialect::MatmulOp matmul_2 = builder.Build<paddle::dialect::MatmulOp>(
matmul_1_in_1.out(), matmul_2_in_2.out(), false, false);
paddle::dialect::FullOp add_2_in_2 = builder.Build<paddle::dialect::FullOp>(
std::vector<int64_t>{256}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace());
paddle::dialect::AddOp add_op2 =
builder.Build<paddle::dialect::AddOp>(matmul_2.out(), add_2_in_2.out());
paddle::dialect::ReshapeOp reshape_2 =
builder.Build<paddle::dialect::ReshapeOp>(
add_op2.out(), std::vector<int64_t>{0, 0, 8, 32});
paddle::dialect::TransposeOp transpose_2 =
builder.Build<paddle::dialect::TransposeOp>(reshape_2.out(),
std::vector<int>{0, 2, 1, 3});
// The third path to matmul (v).
paddle::dialect::FullOp matmul_3_in_2 =
builder.Build<paddle::dialect::FullOp>(std::vector<int64_t>{256, 256},
1.1,
phi::DataType::FLOAT32,
phi::CPUPlace());
paddle::dialect::MatmulOp matmul_3 = builder.Build<paddle::dialect::MatmulOp>(
matmul_1_in_1.out(), matmul_3_in_2.out(), false, false);
paddle::dialect::FullOp add_3_in_2 = builder.Build<paddle::dialect::FullOp>(
std::vector<int64_t>{256}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace());
paddle::dialect::AddOp add_3 =
builder.Build<paddle::dialect::AddOp>(matmul_3.out(), add_3_in_2.out());
paddle::dialect::ReshapeOp reshape_3 =
builder.Build<paddle::dialect::ReshapeOp>(
add_3.out(), std::vector<int64_t>{0, 0, 8, 32});
paddle::dialect::TransposeOp transpose_3 =
builder.Build<paddle::dialect::TransposeOp>(reshape_3.out(),
std::vector<int>{0, 2, 1, 3});
// softmax(qk)v
paddle::dialect::MatmulOp matmul_4 = builder.Build<paddle::dialect::MatmulOp>(
scale_op.out(), transpose_2.out(), false, true);
paddle::dialect::FullOp add_4_in_2 = builder.Build<paddle::dialect::FullOp>(
std::vector<int64_t>{1, 8, 300, 300},
1.5,
phi::DataType::FLOAT32,
phi::CPUPlace());
paddle::dialect::AddOp add_4 =
builder.Build<paddle::dialect::AddOp>(matmul_4.out(), add_4_in_2.out());
paddle::dialect::SoftmaxOp softmax_op =
builder.Build<paddle::dialect::SoftmaxOp>(add_4.out(), -1);
paddle::dialect::MatmulOp matmul_5 = builder.Build<paddle::dialect::MatmulOp>(
softmax_op.out(), transpose_3.out(), false, false);
paddle::dialect::TransposeOp transpose_4 =
builder.Build<paddle::dialect::TransposeOp>(matmul_5.out(),
std::vector<int>{0, 2, 1, 3});
paddle::dialect::ReshapeOp reshape_4 =
builder.Build<paddle::dialect::ReshapeOp>(
transpose_4.out(), std::vector<int64_t>{0, 0, 256});
builder.Build<paddle::dialect::FetchOp>(reshape_4.out(), "out", 0);
}
TEST(DrrTest, AttentionFuse) {
pir::IrContext *ctx = pir::IrContext::Instance();
ctx->GetOrRegisterDialect<paddle::dialect::OperatorDialect>();
ctx->GetOrRegisterDialect<pir::BuiltinDialect>();
pir::Program program(ctx);
pir::Builder builder = pir::Builder(ctx, program.block());
BuildProgram(builder);
EXPECT_EQ(program.block()->size(), 33u);
pir::PassManager pm(ctx);
pm.AddPass(pir::CreateMultiHeadMatmulFusePass());
std::unique_ptr<pir::Pass> constant_folding_pass =
pir::CreateConstantFoldingPass();
constant_folding_pass->Set(pir::Pass::kPlaceAttr,
new phi::Place{phi::GPUPlace{}});
constant_folding_pass->Set(pir::Pass::kParamScopeAttr,
new paddle::framework::Scope{});
pm.AddPass(std::move(constant_folding_pass));
pm.AddPass(pir::CreateDeadCodeEliminationPass());
pm.EnableIRPrinting();
PADDLE_ENFORCE_EQ(pm.Run(&program),
true,
common::errors::Unavailable("pm fail to run program"));
EXPECT_EQ(program.block()->size(), 2u);
}