Transformer高性能加速#
使用环境说明#
本项目依赖于 PaddlePaddle 2.1.0 及以上版本或适当的 develop 版本
CMake >= 3.10
CUDA 10.1 或 10.2(需要 PaddlePaddle 框架一致)
gcc 版本需要与编译 PaddlePaddle 版本一致,比如使用 gcc8.2
推荐使用 Python3
FasterTransformer 使用必要的环境
环境依赖
attrdict
pyyaml
pip install attrdict pyyaml
快速开始#
我们实现了基于 FasterTransformer 的自定义 op 的接入,打造了 FastGeneration 的能力用于加速文本生成模型在 GPU 上的预测性能。接下来,我们将分别介绍基于 Python 动态图和预测库使用 FastGeneration 自定义 op 的方式,包括 op 的编译与使用。
Python 动态图使用自定义 op#
JIT 自动编译#
目前当基于动态图使用 FastGeneration 预测加速自定义 op 时,PaddleNLP 提供了 Just In Time 的自动编译,在一些 API 上,用户无需关注编译流程,可以直接执行对应的 API,程序会自动编译需要的第三方库。
以 Transformer 为例,可以直接调用 TransformerGenerator()
这个 API,程序会自动编译。使用示例可以参考 Transformer 预测加速使用示例-sample,Transformer 预测加速使用示例-机器翻译。
编译自定义OP#
除了自动编译外,如果需要自行编译,我们已经提供对应的 CMakeLists.txt,可以参考使用如下的方式完成编译。
PaddleNLP 准备#
首先,如果需要从源码自行编译,可以直接使用 Python 的 package 下的 paddlenlp,或是可从 github 克隆一个 PaddleNLP,并重新编译:
以下以从 github 上 clone 一个新版 PaddleNLP 为例:
git clone https://github.com/PaddlePaddle/PaddleNLP.git
其次,配置环境变量,让我们可以使用当前 clone 的 paddlenlp,并进入到自定义 OP 的路径,准备后续的编译操作:
export PYTHONPATH=$PWD/PaddleNLP/:$PYTHONPATH
cd PaddleNLP/paddlenlp/ops/
编译#
编译之前,请确保安装的 PaddlePaddle 的版本高于 2.1.0 或是基于最新的 develop 分支的代码编译,并且正常可用。
编译自定义 OP 可以参照一下步骤:
mkdir build
cd build/
cmake .. -DCMAKE_BUILD_TYPE=Release -DPY_CMD=python3.x
make -j
cd ../
可以使用的编译选项包括:
-DPY_CMD
: 指定当前装有 PaddlePaddle 版本的 python 环境,比如-DPY_CMD=python3.7
。若未指定-DPY_CMD
将会默认使用系统命令python
对应的 Python。-DSM
: 是指的所用 GPU 的 compute capability,建议不使用该选项设置,未设置时将自动检测。如要设置,需根据 [compute capability](https://developer.nvidia.com/zh-cn/cuda-gpus#compute) 进行设置,如 V100 时设置-DSM=70
或 T4 时设置-DSM=75
。-DWITH_GPT
: 是否编译带有 GPT 相关的 lib。若使用 GPT-2 高性能推理,需要加上-DWITH_GPT=ON
。默认为 OFF。-DWITH_UNIFIED
: 是否编译带有 Unified Transformer 或是 UNIMOText 相关的 lib。若使用,需要加上-DWITH_UNIFIED=ON
。默认为 ON。-DWITH_BART
: 是否编译带有 BART 支持的相关 lib。若使用,需要加上-DWITH_BART=ON
。默认为 ON。-DWITH_DECODER
: 是否编译带有 decoder 优化的 lib。默认为 ON。
最终,编译会在 /build/lib/
路径下,产出 libdecoding_op.so
,即需要的 FastGeneration decoding 执行的库。
使用 Transformer decoding 高性能推理#
编写 python 脚本的时候,调用 FasterTransformer API 即可实现 Transformer 模型的高性能预测。
举例如下:
from paddlenlp.ops import FasterTransformer
transformer = FasterTransformer(
src_vocab_size=args.src_vocab_size,
trg_vocab_size=args.trg_vocab_size,
max_length=args.max_length + 1,
n_layer=args.n_layer,
n_head=args.n_head,
d_model=args.d_model,
d_inner_hid=args.d_inner_hid,
dropout=args.dropout,
weight_sharing=args.weight_sharing,
bos_id=args.bos_idx,
eos_id=args.eos_idx,
decoding_strategy=args.decoding_strategy,
beam_size=args.beam_size,
topk=args.topk,
topp=args.topp,
max_out_len=args.max_out_len,
decoding_lib=args.decoding_lib,
use_fp16_decoding=args.use_fp16_decoding)
若当前环境下没有需要的自定义 op 的动态库,将会使用 JIT 自动编译需要的动态库。如果需要自行编译自定义 op 所需的动态库,可以如前文所述进行编译。编译好后,使用 FasterTransformer(decoding_lib="/path/to/lib", ...)
可以完成导入。
更详细的例子可以参考 Transformer 预测加速使用示例-sample,Transformer 预测加速使用示例-机器翻译,我们提供了更详细用例。
Transformer decoding 示例代码#
使用 PaddlePaddle 仅执行 decoding 测试(float32):
export CUDA_VISIBLE_DEVICES=0
export FLAGS_fraction_of_gpu_memory_to_use=0.1
# 执行 decoding_gemm 目的是基于当前环境、配置,提前确定一个性能最佳的矩阵乘算法,不是必要的步骤
./build/third-party/build/fastertransformer/bin/decoding_gemm 32 4 8 64 30000 32 512 0
python ./fast_transformer/sample/decoding_sample.py --config ./fast_transformer/sample/config/decoding.sample.yaml --decoding_lib ./build/lib/libdecoding_op.so
使用 PaddlePaddle 仅执行 decoding 测试(float16):
执行 float16 的 decoding,需要在执行的时候,加上 --use_fp16_decoding
选项。
export CUDA_VISIBLE_DEVICES=0
export FLAGS_fraction_of_gpu_memory_to_use=0.1
# 执行 decoding_gemm 目的是基于当前环境、配置,提前确定一个性能最佳的矩阵乘算法,不是必要的步骤
./build/third-party/build/fastertransformer/bin/decoding_gemm 32 4 8 64 30000 32 512 1
python ./fast_transformer/sample/decoding_sample.py --config ./fast_transformer/sample/config/decoding.sample.yaml --decoding_lib ./build/lib/libdecoding_op.so --use_fp16_decoding
其中,decoding_gemm
不同参数的意义可以参考 FasterTransformer 文档。这里提前执行 decoding_gemm
,可以在当前路径下生成一个 config 文件,里面会包含针对当前 decoding 部分提供的配置下,性能最佳的矩阵乘的算法,并在执行的时候读入这个数据。
C++ 预测库使用自定义 op#
编译自定义OP#
在 C++ 预测库使用自定义 OP 需要将实现的 C++、CUDA 代码**以及 C++ 预测的 demo**编译成一个可执行文件。因预测库支持方式与 Python 不同,这个过程将不会产生自定义 op 的动态库,将直接得到可执行文件。我们已经提供对应的 CMakeLists.txt ,可以参考使用如下的方式完成编译。并获取执行 demo。
PaddleNLP 准备#
首先,因为需要基于当前环境重新编译,当前的 paddlenlp 的 python 包里面并不包含 FastGeneration 相关 lib,需要从源码自行编译,可以直接使用 Python 的 package 下的 paddlenlp,或是可从 github 克隆一个 PaddleNLP,并重新编译:
以下以从 github 上 clone 一个新版 PaddleNLP 为例:
git clone https://github.com/PaddlePaddle/PaddleNLP.git
其次,让我们可以使用当前 clone 的 paddlenlp,并进入到自定义 OP 的路径,准备后续的编译操作:
cd PaddleNLP/paddlenlp/ops/
编译#
编译之前,请确保安装的 PaddlePaddle 的版本高于 2.1.0 或是基于最新的 develop 分支的代码编译,并且正常可用。
编译自定义 OP 可以参照一下步骤:
mkdir build
cd build/
cmake .. -DCMAKE_BUILD_TYPE=Release -DPADDLE_LIB=/path/to/paddle_inference_lib/ -DDEMO=./demo/transformer_e2e.cc -DON_INFER=ON -DWITH_MKL=ON
make -j
cd ../
可以使用的编译选项包括:
-DPADDLE_LIB
: 需要指明使用的 PaddlePaddle 预测库的路径/path/to/paddle_inference_install_dir/
,需要使用的 PaddlePaddle 的 lib 可以选择自行编译或者直接从官网下载 paddle_inference_linux_lib。需要注意的是,在该路径下,预测库的组织结构满足: .. code-block:. ├── CMakeCache.txt ├── paddle/ ├── include/ └── lib/ ├── third_party/ ├── cudaerror/ ├── install/ └── threadpool/ └── version.txt
-DDEMO
: 说明预测库使用 demo 的位置。比如指定 -DDEMO=./demo/transformer_e2e.cc 或是 -DDEMO=./demo/gpt.cc。最好使用绝对路径,若使用相对路径,需要是相对于PaddleNLP/paddlenlp/ops/fast_transformer/src/
的相对路径。-DSM
: 是指的所用 GPU 的 compute capability,建议不使用该选项设置,未设置时将自动检测。如要设置,需根据 [compute capability](https://developer.nvidia.com/zh-cn/cuda-gpus#compute) 进行设置,如 V100 时设置-DSM=70
或 T4 时设置-DSM=75
。-DWITH_GPT
: 是否编译带有 GPT 相关的 lib。若使用 GPT-2 高性能推理,需要加上-DWITH_GPT=ON
。默认为 OFF。-DWITH_UNIFIED
: 是否编译带有 Unified Transformer 或是 UNIMOText 相关的 lib。若使用,需要加上-DWITH_UNIFIED=ON
。默认为 ON。-DWITH_BART
: 是否编译带有 BART 支持的相关 lib。若使用,需要加上-DWITH_BART=ON
。默认为 ON。-DWITH_DECODER
: 是否编译带有 decoder 优化的 lib。默认为 ON。-DWITH_MKL
: 若当前是使用的 mkl 的 Paddle lib,那么需要打开 MKL 以引入 MKL 相关的依赖。-DON_INFER
: 是否编译 paddle inference 预测库。当使用预测库的自定义 op 的时候,请务必开启 `-DON_INFER=ON` 选项,否则,不会得到预测库的可执行文件。
执行 Transformer decoding on PaddlePaddle#
编译完成后,在 build/bin/
路径下将会看到 transformer_e2e
的一个可执行文件。通过设置对应的设置参数完成执行的过程。
cd bin/
./transformer_e2e -batch_size <batch_size> -gpu_id <gpu_id> -model_dir <model_directory> -vocab_file <dict_file> -data_file <input_data>
举例说明:
cd bin/
# 执行 decoding_gemm 目的是基于当前环境、配置,提前确定一个性能最佳的矩阵乘算法,不是必要的步骤
../third-party/build/fastertransformer/bin/decoding_gemm 8 5 8 64 38512 256 512 0
./transformer_e2e -batch_size 8 -gpu_id 0 -model_dir ./infer_model/ -vocab_file DATA_HOME/WMT14ende/WMT14.en-de/wmt14_ende_data_bpe/vocab_all.bpe.33708 -data_file DATA_HOME/WMT14ende/WMT14.en-de/wmt14_ende_data_bpe/newstest2014.tok.bpe.33708.en
其中:
decoding_gemm
不同参数的意义可以参考 FasterTransformer 文档。这里提前执行decoding_gemm
,可以在当前路径下生成一个 config 文件,里面会包含针对当前 decoding 部分提供的配置下,性能最佳的矩阵乘的算法,并在执行的时候读入这个数据。DATA_HOME
则是paddlenlp.utils.env.DATA_HOME
返回的路径。
预测所需要的模型文件,可以通过 fast_transformer/README.md 文档中所记述的方式导出。