FastGeneration是PaddleNLP v2.2版本加入的文本生成高性能加速功能,其支持GPT、OPT、BART、UnifiedTransformer等多种NLP生成类预训练模型,并且支持多种解码策略,可以用于机器翻译、文本续写、文本摘要、对话生成等多种NLG任务的GPU场景预测加速。
功能底层依托于NV FasterTransformer,该库针对标准的Transformer和GPT模型、beam search和sampling解码策略进行了性能优化。PaddleNLP FastGeneration在其之上进行了扩展,实现了更多模型和生成策略的优化支持,并将功能入口封装于model.generate
函数。功能的开启和关闭通过传入use_fast
参数进行控制(默认为关闭状态)。通过调用generate函数,用户可以简单的使用模型高性能推理功能。下图展示了FastGeneration的启动流程:
- 全面支持生成式预训练模型。包括GPT、OPT、CodeGen、GPTJ、BART、mBART、UnifiedTransformer和UNIMO-text。
- 支持大多数主流解码策略。包括Beam Search、Sampling、Greedy Search。以及Diverse Sibling Search、Length Penalty等子策略。
- 解码速度快。最高可达非加速版generate函数的18倍。并支持FP16混合精度计算。
- 易用性强。功能的入口为
model.generate
,与非加速版生成api的使用方法相同,当满足加速条件时使用jit即时编译高性能算子并用于生成,不满足则自动切换回非加速版生成api。 - GPT、UnifiedTransformer和UNIMO-text模型支持高性能并行推理,在具备MPI和NCCL的环境中一行代码即可开启使用,允许通过多张小显存容量的 GPU 使用百亿大模型,预测速度较单卡也进一步提升。百亿模型四卡并行高性能推理速度达单卡高性能推理速度2+倍。
下表为PaddleNLP FastGeneration对预训练模型和解码策略的支持情况(GPU)。
Model Name | GPT2 | OPT | CodeGen | GPTJ | BART | mBART | UnifiedTransformer |
---|---|---|---|---|---|---|---|
Model Structure | Decoder | Decoder | Decoder | Decoder | Encoder-Decoder | Encoder-Decoder | Prefix-LM |
Beam Search | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
Top-K Sampling | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Top-P Sampling | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Diverse Sibling Search | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
Forced Decoding | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ |
Length Penalty | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ |
Temperature | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Repetition Penalty | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
FastGeneration的高性能解码相比原版generate方法加速明显,并且与竞品相比有也有极大的速度优势。以下为性能对比图:
- batch_size = 4, out_seq_len = 32
- Device: Tesla V100-SXM2-16GB
- CUDA version 11.2
- cudnn version 8
- torch version 1.10.0+cu113
- transformers version 4.12.5
- 环境和超参
- Platform: Tesla V100-SXM2-32GB
- CUDA 10.1
- CUDNN 7.6.5
- PaddlePaddle-gpu 2.3.1.post101
- transformers==4.21.1
- torch==1.11.0
- Batch Size: 1
- Input Length: 60
- Output Length: 20
- Platform: A100-40G
- 环境和超参
- Platform: Tesla V100-SXM2-32GB
- CUDA 10.1
- CUDNN 7.6.5
- PaddlePaddle-gpu 2.3.2.post101
- transformers==4.21.1
- torch==1.11.0
- Batch Size: 4
- Input Length: 60
- Output Length: 20
- Decode_strategy: beam search
- num_beams: 4
更详细的性能数据请参见这里
为体现FastGeneration的易用性,我们在samples
文件夹中内置了几个典型任务示例,下面以基于GPT模型的中文文本续写任务为例:
python samples/gpt_sample.py
如果是第一次执行,PaddleNLP会启动即时编译(JIT Compile)自动编译高性能解码算子。
...
2021-11-17 13:42:56,771 - INFO - execute command: cd /10.2/hub/PaddleNLP/paddlenlp/ops/extenstions && /usr/local/bin/python FasterTransformer_setup.py build
INFO:utils.cpp_extension:execute command: cd /10.2/hub/PaddleNLP/paddlenlp/ops/extenstions && /usr/local/bin/python FasterTransformer_setup.py build
grep: warning: GREP_OPTIONS is deprecated; please use an alias or script
running build
running build_ext
-- The C compiler identification is GNU 8.2.0
-- The CXX compiler identification is GNU 8.2.0
-- The CUDA compiler identification is NVIDIA 10.2.89
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr
...
编译过程通常会花费几分钟的时间编译只会进行一次,之后再次使用高性能解码就不需要重新编译了,编译完成后会继续运行,可以看到生成的结果如下:
Model input: 花间一壶酒,独酌无相亲。举杯邀明月,
Result: 对影成三人。
打开示例代码 samples/gpt_sample.py
,我们可以看到如下代码:
...
model = GPTLMHeadModel.from_pretrained(model_name)
...
outputs, _ = model.generate(
input_ids=inputs_ids, max_length=10, decode_strategy='greedy_search',
use_fast=True)
...
可以看到,FastGeneration的使用方法与 model.generate()
相同,只需传入输入tensor和解码相关参数即可,使用非常简便。如果要使用非加速版的 model.generate()
方法,只需传入 use_fast=False
即可,示例如下:
...
outputs, _ = model.generate(
input_ids=inputs_ids, max_length=10, decode_strategy='greedy_search', use_fast=False)
...
NOTE: 需要注意的是,如果传入 model.generate()
的参数不满足高性能版本的要求。程序会做出提示并自动切换为非加速版本,例如我们在上面的例子中传入 min_length=1
,会得到如下提示:
...
[2021-11-17 14:21:06,132] [ WARNING] - 'min_length != 0' is not supported yet in the fast version
[2021-11-17 14:21:06,132] [ WARNING] - FastGeneration is not available, and the original version would be used instead.
...
关于该函数的详细介绍可以参考API文档generate和Aistudio教程文本生成任务实战:如何使用PaddleNLP实现各种解码策略。samples
文件夹中的其他示例的使用方法相同。
FastGeneration对GPT、UnifiedTransformer和UNIMO-text模型在高性能推理的基础上还实现了模型并行功能,其中GPT支持Tensor Parallel和Layer Parallel(Pipeline Parallel)两种并行策略的组合,UnifiedTransformer和UNIMO-text支持Tensor Parallel。关于这两种并行策略的详细介绍请参考Megatron论文。
并行推理当前依赖MPI(MPICH、OpenMPI均可)和NCCL,如需使用还请先安装依赖。在使用时,相比上面的单卡高性能加速代码中也只增加了from_pretrained
创建加载模型之前加上enable_ft_para()
一行。
GPT高性能并行推理的完整使用示例已在gpt_mp_sample.py
中提供,按照如下方式启动即可:
mpirun -n 4 python gpt_mp_sample.py --tensor_para_size 4 --layer_para_size 1
其中-n 4
指明使用的进程和GPU数,tensor_para_size
和tensor_para_size
分别指明Tensor Parallel和Layer Parallel各自使用的GPU数,均设置为1则进行单卡预测。另外加上--use_fp16
以使用FP16,加上--profile
可以进行相应设置的性能测试。其他生成相关的参数设置释义如下:
model_name
指定使用的GPT模型,默认为gpt-cpm-larg-cn
。max_length
指定生成的最大长度,默认为50。topk
用于Top-K采样策略,采样时将只从概率最高K个token中采样,默认为1,即greedy search。topp
用于Top-P采样策略,采样时将只从概率最高且累加概率不超过该值的token中采样,默认为1.0。temperature
用于调整预测概率分布,默认为1.0,即保持模型原有的预测概率。
使用gpt-cpm-larg-cn
(2.6B)和默认设置,在V100上4卡Tensor Parallel较单卡高性能预测速度提升约40%。
PLATO-XL百亿对话预训练模型(11B UnifiedTransformer模型)高性能并行推理的完整使用示例已在plato_xl_sample.py
中提供(当前只支持Tensor Parallel),按照如下方式启动即可:
mpirun -n 4 python plato_xl_sample.py
参数释义基本同上。在V100上4卡Tensor Parallel高性能预测为单卡高性能预测速度的2倍。
除了以上示例之外,PaddleNLP的examples中大多使用了model.generate
的示例都可以通过调整到合适的参数使用高性能推理。具体如下:
- examples/dialogue/unified_transformer
- model_zoo/gpt/fast_gpt
- examples/text_generation/unimo-text
- examples/text_summarization/bart
下面我们以基于 Unified Transformer
的任务型对话为例展示一下FastGeneration的加速效果:
打开以上链接中Unified Transformer对应的example,找到README中对应预测的脚本。稍作修改如下:
export CUDA_VISIBLE_DEVICES=0
python infer.py \
--model_name_or_path=unified_transformer-12L-cn-luge \
--output_path=./predict.txt \
--logging_steps=10 \
--seed=2021 \
--max_seq_len=512 \
--max_knowledge_len=256 \
--batch_size=4 \
--min_dec_len=1 \
--max_dec_len=64 \
--num_return_sequences=1 \
--decode_strategy=sampling \
--top_k=5 \
--faster
--device=gpu
由于这里只是展示性能,我们直接在 model_name_or_path
填入PaddleNLP预训练模型名称 unified_transformer-12L-cn-luge
。
可以看到,由于该任务为对话任务,我们为了防止模型生成过多安全回复(如:哈哈哈、不错等),保证生成结果具有更多的随机性,我们选择TopK-sampling作为解码策略,并让k=5。
打开 infer.py
,可以看到我们传入的脚本参数大多都提供给了 model.generate()
方法:
output = model.generate(
input_ids=input_ids,
token_type_ids=token_type_ids,
position_ids=position_ids,
attention_mask=attention_mask,
seq_len=seq_len,
max_length=args.max_dec_len,
min_length=args.min_dec_len,
decode_strategy=args.decode_strategy,
temperature=args.temperature,
top_k=args.top_k,
top_p=args.top_p,
num_beams=args.num_beams,
length_penalty=args.length_penalty,
early_stopping=args.early_stopping,
num_return_sequences=args.num_return_sequences,
use_fp16_decoding=args.use_fp16_decoding,
use_fast=args.faster)
运行脚本,输出结果如下:
step 10 - 1.695s/step
step 20 - 1.432s/step
step 30 - 1.435s/step
可以看到,非加速版 generate()
方法的预测速度为每个step耗时1.5秒左右。
下面我们在启动脚本中传入 --faster
参数,该参数会向 generate()
方法传入 use_fast=True
,启动加速模式。同时我们需要设置 --min_dec_len=0
,因为FastGeneration当前还不支持该参数。新的脚本启动参数如下:
export CUDA_VISIBLE_DEVICES=0
python infer.py \
--model_name_or_path=unified_transformer-12L-cn-luge \
--output_path=./predict.txt \
--logging_steps=10 \
--seed=2021 \
--max_seq_len=512 \
--max_knowledge_len=256 \
--batch_size=4 \
--min_dec_len=0 \
--max_dec_len=64 \
--num_return_sequences=1 \
--decode_strategy=sampling \
--top_k=5 \
--device=gpu \
--faster
再次运行脚本,输出结果如下(由于我们已经编译过高性能算子,所以这里不会重新编译):
[2021-11-23 13:38:09,200] [ DEBUG] - skipping 'FastGeneration' extension (up-to-date) build
step 10 - 0.250s/step
step 20 - 0.156s/step
step 30 - 0.141s/step
可以看到,FastGeneration的预测速度为每个step耗时0.15秒左右,相比非加速版提速超过9倍。