这篇文章描述了FasterTransformer为Decoder/Decoding
提供了什么支持,解释工作流和优化。我们也提供了一个引导来帮助用户在FasterTransformer上运行Decoder/Decoding
模型。最后,我们提供了基准测试来证明FasterTransformer在Decoder/Decoding
的速度。这篇文章中,Decoder
指的是transformer解码器模块,其包含了2个注意力块和一个前馈网络。在图1中红色块的单元是指解码块。另外,Decoding
引用了整个翻译过程,包括位置编码,嵌入查找,少量层是解码器和beam搜索,或者采样方法来选择token。图1展示了包含beam查找的解码和采样的区别。
尽管大多数方式的解码步骤是相识的,我们仍然发现有很多不同的方式来计算概率和实现beam查找。所以,如果你选择的beam搜索算法是不同于我们实现的,而且你很难修改beam搜索核心,使用FasterTransformer解码器的TensorFlow/PyTorch解码是推荐选择。然而,使用FasterTransformer解码器的TensorFlow/PyTorch解码性能比FasterTransformer解码的性能更差,特别是在小批量的规模上。
图1表示了FasterTransformer解码器和解码的工作流。交叉注意力输入后,他们将从编码器收到一些结果,使用起始的ids或者 之前步骤生成ids 作为 解码输入 而且生成各自的输出ids作为响应。
接下来的样例展示了如何运行多GPU和多节点GPU模型。
examples/cpp/decoding.cc
: 一个样例在C++中运行随机的权重和输入的解码。examples/tensorflow/decoding/translate_example.py
: 一个样例在Tensorflow中运行用FasterTransformer编码器/编码 端到端的翻译任务,我们在这个样例中也使用FasterTransform编码器算子源码在src/fastertransformer/models/decoder/Decoder.cc
, 参数,输入和输出:
src/fastertransformer/utils/cublasMMWrapper.h
.src/fastertransformer/utils/allocator.h
源码放在了src/fastertransformer/models/decoding/Decoding.cc
。代码的参数,输入和输出是:
尽管这里很多参数,但大部分是固定的。比如参数5~11是模型的超参数,当确定模型的超参数后是固定的。参数18, 19, 20 和 22 是关于CUDA的一些设置,在进程中是固定的。
SelfAttention
和CrossAttention
的请求中的序列长度总是1,我们用自定义的混合多头注意力内核来优化。第二,我们融合很多小岛算子到一个内核中。比如,AddBiasResidualLayerNorm
结合了加偏置、加前模块残差、和计算层的归一化到一个内核中。第三,我们优化前k操作和采样来加速beam搜索和采样。最后,为了阻止重新计算前k和前v,我们申请了一个缓存区来存在他们的每一步。尽管消耗了额外的内存,我们节约了重计算的消耗、每一步都申请缓存区、一系列的消耗。接下来章节列出了使用FasterTransformer的依赖。
这些组件在以下的NGC TensorFlow Docker镜像中很容易获取到。
确保你有以下组件:
关于如何使用NGC容器的更多信息,看以下来自NVIDIA GPU云文档和深度学习文档的章节:
那些不能使用NGC容器的,配置需要的环境或创建自己的容器,可以看 NVIDIA容器支持的版本矩阵。
准备
你可以选择你期望的tensorflow版本和python版本。这里,我们列出了一些可能的镜像:
为了实现最优性能,我们建议使用最新的镜像。比如,运行镜像nvcr.io/nvidia/tensorflow:22.09-tf1-py3
通过命令:
nvidia-docker run -ti --shm-size 5g --rm nvcr.io/nvidia/tensorflow:22.09-tf1-py3 bash
git clone https://github.com/NVIDIA/FasterTransformer.git
mkdir -p FasterTransformer/build
cd FasterTransformer/build
git submodule init && git submodule update
-DSM=xx
中的xx
,在以下脚本意味着你的GPU能力。比如60 (P40) 或 61 (P4) 或 70 (V100) 或 75(T4) 或 80 (A100)。默认设置包含 70, 75, 80 and 86.cmake -DSM=xx -DCMAKE_BUILD_TYPE=Release ..
make -j12
nvcr.io/nvidia/tensorflow:22.09-tf1-py3
,那就cmake -DSM=xx -DCMAKE_BUILD_TYPE=Release -DBUILD_TF=ON -DTF_PATH=/usr/local/lib/python3.8/dist-packages/tensorflow_core/ ..
make -j12
cmake -DSM=xx -DCMAKE_BUILD_TYPE=Release -DBUILD_PYT=ON ..
make -j12
这将编译TorchScript自定义类。请确保PyTorch >= 1.5.0
。gemm_config.in
文件pip install opennmt-py==1.1.1
3.1 生成 gemm_config.in
文件./bin/decoding_gemm
./bin/decoding_gemm 8 4 8 64 2048 31538 32 512 1
数据类型 = 0(FP32) 或 1(FP16) 或2(BF16)python ../examples/pytorch/decoder/decoder_example.py <--data_type fp32/fp16/bf16> <--time>
python ../examples/pytorch/decoder/decoder_example.py 8 6 32 8 64 --data_type fp16 --time
输出应该像下面这样:step: 30 Mean relative diff: 0.01395416259765625 Max relative diff: 1.38671875 Min relative diff: 0.0
step: 31 Mean relative diff: 0.0148468017578125 Max relative diff: 2.880859375 Min relative diff: 0.0
[INFO] ONMTDecoder time costs: 218.37 ms
[INFO] FTDecoder time costs: 25.15 ms
注意的是相关区别会非常大。是由于随机初始化权重和输入,而且它不影响翻译的结果。python pytorch/decoding_sample.py <--data_type fp32/fp16/bf16> <--time>
python ../examples/pytorch/decoding/decoding_example.py 8 6 32 8 64 4 31538 --data_type fp16 --time
输出应该如下:[INFO] TorchDecoding time costs: 289.08 ms
[INFO] TorchDecoding (with FTDecoder) time costs: 104.15 ms
[INFO] FTDecoding time costs: 30.57 ms
随机初始化参数可能导致不同的结果。你可以根据接下来的指导下载预训练模型,并加上 --use_pretrained
,然后你就能得到相同的结果。bash ../examples/pytorch/decoding/utils/download_model.sh
然后你可以运行样例:python ../examples/pytorch/decoding/translate_example.py --batch_size --beam_size --model_type --data_type --output_file
你也可以使用--input_file
设置输入文件来翻译。
可以为:
decoding_ext
: 使用我们的FasterTransformer解码单元torch_decoding
:使用FasterTransformer解码方式的PyTorch版本解码torch_decoding_with_decoder_ext
:使用FasterTransformer解码方式的PyTorch版本解码,但是用FasterTransformer解码器替换了其解码器。
可以为fp32
或fp16
或 bf16
python ../examples/pytorch/decoding/utils/recover_bpe.py
python ../examples/pytorch/decoding/utils/recover_bpe.py
我们模型中的
是pytorch/translation/data/test.de
,
是来自translate_example.py
的输出。sacrebleu
:pip install sacrebleu
cat | sacrebleu
下面的脚本在FP32下运行翻译,并得到bleu分数:./bin/decoding_gemm 128 4 8 64 2048 31538 100 512 0
python ../examples/pytorch/decoding/translate_example.py --batch_size 128 --beam_size 4 --model_type decoding_ext --data_type fp32 --output_file output.txt
python ../examples/pytorch/decoding/utils/recover_bpe.py ../examples/pytorch/decoding/utils/translation/test.de debpe_ref.txt
python ../examples/pytorch/decoding/utils/recover_bpe.py output.txt debpe_output.txt
pip install sacrebleu
cat debpe_output.txt | sacrebleu debpe_ref.txt
硬件配置:
为了运行下面的基准,我们需要安装unix计算工具"bc":
apt-get install bc
为了明确真实应用里的提速,在这个基准测试中,我们同时在TensorFlow和PyTorch上使用了真正的端到端模型和任务。很难直接比较 v3.1 and v4.0 的基准性能。但是我们的测试,对比 v3.1 v4.0带来了至多50%的加速,特别是在大batch上。
我们演示了端到端翻译中PyTorch、FT解码器和FT解码的吞吐量。这里,PyTorch意味着程序完全运行在PyTorch上。FT解码器意味着我们用FasterTransformer替换了解码器翻译层。FT解码意味着我们用FasterTransformer完整的替换了解码器。
我们也跳过BLEU分数,因为PyTorch, FT Decoder and FT Decoding 的分数被关了。
同时,所有方法的bleu分数都关了,结果可能有点不同,生成的token数量也不相同。所以我们使用吞吐量而不是延时来展示基准的性能。
可以获取这个基准,通过运行这个:../sample/pytorch/scripts/profile_decoder_decoding.sh
这里的基准,我们更新了以下参数:
在A100和PyTorch上的Beam搜索性能:
export NVIDIA_TF32_OVERRIDE=0
来强制程序运行在FP32下。