Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 80c1f77

Browse files
authored
Add faster transformer for decoding (PaddlePaddle#37)
* add faster transformer * add README * add fp16 * add big config * delete temp time record * improve performance * vocab_size * add decoding sample config * add desription for variable in op.cc * add clang format * add reader description * update comments * process format and rm useless import * comments * add decription * undo useless change * update load * update according to comments * ulter * update readme * add more info in readme * update readme * gpu:0 -> gpu
1 parent 6d7dc6c commit 80c1f77

20 files changed

Lines changed: 1852 additions & 0 deletions

.clang-format

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# This file is used by clang-format to autoformat paddle source code
2+
#
3+
# The clang-format is part of llvm toolchain.
4+
# It need to install llvm and clang to format source code style.
5+
#
6+
# The basic usage is,
7+
# clang-format -i -style=file PATH/TO/SOURCE/CODE
8+
#
9+
# The -style=file implicit use ".clang-format" file located in one of
10+
# parent directory.
11+
# The -i means inplace change.
12+
#
13+
# The document of clang-format is
14+
# http://clang.llvm.org/docs/ClangFormat.html
15+
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
16+
---
17+
Language: Cpp
18+
BasedOnStyle: Google
19+
IndentWidth: 2
20+
TabWidth: 2
21+
ContinuationIndentWidth: 4
22+
MaxEmptyLinesToKeep: 2
23+
AccessModifierOffset: -2 # The private/protected/public has no indent in class
24+
Standard: Cpp11
25+
AllowAllParametersOfDeclarationOnNextLine: true
26+
BinPackParameters: false
27+
BinPackArguments: false
28+
...
29+

.clang_format.hook

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
readonly VERSION="3.8"
5+
6+
version=$(clang-format -version)
7+
8+
if ! [[ $version == *"$VERSION"* ]]; then
9+
echo "clang-format version check failed."
10+
echo "a version contains '$VERSION' is needed, but get '$version'"
11+
echo "you can install the right version, and make an soft-link to '\$PATH' env"
12+
exit -1
13+
fi
14+
15+
clang-format $@

examples/machine_translation/transformer/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ python deploy/python/inference.py --config ./configs/transformer.base.yaml
132132

133133
翻译结果同样将会保存在 `predict.txt` 文件中,可以在配置文件中自定义更改 `output_file` 来指定预测结果写入到的文件的名称。
134134

135+
## 使用 Faster Transformer 实现预测
136+
137+
具体的说明可以参考 `faster_transformer/README.md``cd faster_transformer/` 即可查看。
138+
135139
## 模型评估
136140

137141
预测结果中每行输出是对应行输入的得分最高的翻译,对于使用 BPE 的数据,预测出的翻译结果也将是 BPE 表示的数据,要还原成原始的数据(这里指 tokenize 后的数据)才能进行正确的评估。评估过程具体如下(BLEU 是翻译任务常用的自动评估方法指标):
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Faster Transformer 预测
2+
3+
在这里我们集成了 Nvidia [Faster Transformer](https://github.com/NVIDIA/DeepLearningExamples/tree/master/FasterTransformer) 用于预测加速。同时集成了 Faster Transformer float32 以及 float16 预测。目前仅集成 beam search 作为解码的策略,并应用在动态图 Transformer 英德翻译的推理预测中。以下是使用 Faster Transformer 的说明。
4+
5+
## 使用环境说明
6+
7+
* 本项目依赖于 PaddlePaddle 2.0.1 及以上版本或适当的 develop 版本
8+
* CMake >= 3.10
9+
* CUDA 10.1 或是更新的版本(需要 PaddlePaddle 框架一致)
10+
* gcc 版本需要与编译 PaddlePaddle 版本一致,比如使用 gcc8.2
11+
* 推荐使用 Python3
12+
* [Faster Transformer](https://github.com/NVIDIA/DeepLearningExamples/tree/master/FasterTransformer/v3.1#setup) 使用必要的环境
13+
14+
## 快速开始
15+
16+
### 编译自定义OP
17+
18+
自定义 OP 需要将实现的 C++、CUDA 代码编译成动态库,我们提供对应的 CMakeLists.txt ,可以参考使用如下的方式完成编译。同样的自定义 op 编译的说明也可以在自定义 op 对应的路径 `PaddleNLP/paddlenlp/ext_op/` 下面找到。
19+
20+
#### 克隆 PaddleNLP
21+
22+
首先,因为需要基于当前环境重新编译,当前的 paddlenlp 的 python 包里面并不包含 Faster Transformer 相关 lib,需要克隆一个 PaddleNLP,并重新编译:
23+
``` sh
24+
git clone https://github.com/PaddlePaddle/PaddleNLP.git
25+
```
26+
27+
其次,配置环境变量,让我们可以使用当前 clone 的 paddlenlp,并进入到自定义 OP 的路径,准备后续的编译操作:
28+
29+
``` sh
30+
export PYTHONPATH=$PWD/PaddleNLP/:$PYTHONPATH
31+
cd PaddleNLP/paddlenlp/ext_op/
32+
```
33+
34+
#### 编译
35+
36+
编译之前,请确保安装的 PaddlePaddle 的版本需要大于 2.0.1,并且正常可用。
37+
38+
编译自定义 OP 可以参照一下步骤:
39+
40+
``` sh
41+
mkdir build
42+
cd build/
43+
cmake .. -DSM=xx -DCMAKE_BUILD_TYPE=Release
44+
make -j
45+
cd ../
46+
```
47+
48+
注意:`xx` 是指的所用 GPU 的 compute capability。举例来说,可以将之指定为 70(V100) 或是 75(T4)。
49+
50+
最终,编译会在 `./build/lib/` 路径下,产出 `libdecoding_op.so`,即需要的 Faster Transformer decoding 执行的库。
51+
52+
## 使用 Faster Transformer 完成预测
53+
54+
编写 python 脚本的时候,调用 `FasterTransformer` API 并传入 `libdecoding_op.so` 的位置即可实现将 Faster Transformer 用于当前的预测。
55+
56+
举例如下:
57+
58+
``` python
59+
from paddlenlp.ext_op import FasterTransformer
60+
61+
transformer = FasterTransformer(
62+
src_vocab_size=args.src_vocab_size,
63+
trg_vocab_size=args.trg_vocab_size,
64+
max_length=args.max_length + 1,
65+
n_layer=args.n_layer,
66+
n_head=args.n_head,
67+
d_model=args.d_model,
68+
d_inner_hid=args.d_inner_hid,
69+
dropout=args.dropout,
70+
weight_sharing=args.weight_sharing,
71+
bos_id=args.bos_idx,
72+
eos_id=args.eos_idx,
73+
beam_size=args.beam_size,
74+
max_out_len=args.max_out_len,
75+
decoding_lib=args.decoding_lib,
76+
use_fp16_decoding=args.use_fp16_decoding)
77+
```
78+
79+
更详细的例子可以参考 `encoder_decoding_predict.py`,我们提供了更详细用例。
80+
81+
82+
#### 数据准备
83+
84+
公开数据集:WMT 翻译大赛是机器翻译领域最具权威的国际评测大赛,其中英德翻译任务提供了一个中等规模的数据集,这个数据集是较多论文中使用的数据集,也是 Transformer 论文中用到的一个数据集。我们也将[WMT'14 EN-DE 数据集](http://www.statmt.org/wmt14/translation-task.html)作为示例提供。
85+
86+
同时,我们提供了一份已经处理好的数据集,可以编写如下代码,对应的数据集将会自动下载并且解压到 `~/.paddlenlp/datasets/machine_translation/WMT14ende/`
87+
88+
``` python
89+
# 获取默认的数据处理方式
90+
transform_func = WMT14ende.get_default_transform_func(root=root)
91+
# 下载并处理 WMT14.en-de 翻译数据集
92+
dataset = WMT14ende.get_datasets(mode="train", transform_func=transform_func)
93+
```
94+
95+
96+
#### 模型推断
97+
98+
使用模型推断前提是需要指定一个合适的 checkpoint,需要在对应的 `../configs/transformer.base.yaml` 中修改对应的模型载入的路径参数 `init_from_params`
99+
100+
我们提供一个已经训练好的动态图的 base model 的 checkpoint 以供使用,可以通过[tranformer-base-wmt_ende_bpe](https://paddlenlp.bj.bcebos.com/models/transformers/transformer/tranformer-base-wmt_ende_bpe.tar.gz)下载。
101+
102+
``` sh
103+
wget https://paddlenlp.bj.bcebos.com/models/transformers/transformer/tranformer-base-wmt_ende_bpe.tar.gz
104+
tar -zxf tranformer-base-wmt_ende_bpe.tar.gz
105+
```
106+
107+
然后,需要修改对应的 `../configs/transformer.base.yaml` 配置文件中的 `init_from_params` 的值为 `./base_trained_models/step_final/`
108+
109+
#### 使用动态图预测(使用 float32 decoding 预测)
110+
111+
以英德翻译数据为例,模型训练完成后可以执行以下命令对指定文件中的文本进行翻译:
112+
113+
``` sh
114+
# setting visible devices for prediction
115+
export CUDA_VISIBLE_DEVICES=0
116+
export FLAGS_fraction_of_gpu_memory_to_use=0.1
117+
cp -rf ../../../../paddlenlp/ext_op/build/third-party/build/bin/decoding_gemm ./
118+
./decoding_gemm 8 4 8 64 38512 32 512 0
119+
python encoder_decoding_predict.py --config ../configs/transformer.base.yaml --decoding-lib ../../../../paddlenlp/ext_op/build/lib/libdecoding_op.so
120+
```
121+
122+
其中,`--config` 选项用于指明配置文件的位置,而 `--decoding-lib` 选项用于指明编译好的 Faster Transformer decoding lib 的位置。
123+
124+
翻译结果会输出到 `output_file` 指定的文件。执行预测时需要设置 `init_from_params` 来给出模型所在目录,更多参数的使用可以在 `./sample/config/transformer.base.yaml` 文件中查阅注释说明并进行更改设置。如果执行不提供 `--config` 选项,程序将默认使用 base model 的配置。
125+
126+
127+
#### 使用动态图预测(使用 float16 decoding 预测)
128+
129+
float16 与 float32 预测的基本流程相同,不过在使用 float16 的 decoding 进行预测的时候,需要再加上 `--use-fp16-decoding` 选项。后按照与之前相同的方式执行即可。具体执行方式如下:
130+
131+
``` sh
132+
# setting visible devices for prediction
133+
export CUDA_VISIBLE_DEVICES=0
134+
export FLAGS_fraction_of_gpu_memory_to_use=0.1
135+
cp -rf ../../../../paddlenlp/ext_op/build/third-party/build/bin/decoding_gemm ./
136+
./decoding_gemm 8 4 8 64 38512 32 512 1
137+
python encoder_decoding_predict.py --config ../configs/transformer.base.yaml --decoding-lib ../../../../paddlenlp/ext_op/build/lib/libdecoding_op.so --use-fp16-decoding
138+
```
139+
140+
其中,`--config` 选项用于指明配置文件的位置,而 `--decoding-lib` 选项用于指明编译好的 Faster Transformer decoding lib 的位置。
141+
142+
翻译结果会输出到 `output_file` 指定的文件。执行预测时需要设置 `init_from_params` 来给出模型所在目录,更多参数的使用可以在 `./sample/config/transformer.base.yaml` 文件中查阅注释说明并进行更改设置。如果执行不提供 `--config` 选项,程序将默认使用 base model 的配置。
143+
144+
需要注意的是,目前预测仅实现了单卡的预测,原因在于,翻译后面需要的模型评估依赖于预测结果写入文件顺序,多卡情况下,目前暂未支持将结果按照指定顺序写入文件。
145+
146+
## 模型评估
147+
148+
评估方式与动态图评估方式相同,预测结果中每行输出是对应行输入的得分最高的翻译,对于使用 BPE 的数据,预测出的翻译结果也将是 BPE 表示的数据,要还原成原始的数据(这里指 tokenize 后的数据)才能进行正确的评估。评估过程具体如下(BLEU 是翻译任务常用的自动评估方法指标):
149+
150+
``` sh
151+
# 还原 predict.txt 中的预测结果为 tokenize 后的数据
152+
sed -r 's/(@@ )|(@@ ?$)//g' predict.txt > predict.tok.txt
153+
# 若无 BLEU 评估工具,需先进行下载
154+
git clone https://github.com/moses-smt/mosesdecoder.git
155+
# 以英德翻译 newstest2014 测试数据为例
156+
perl mosesdecoder/scripts/generic/multi-bleu.perl ~/.paddlenlp/datasets/machine_translation/WMT14ende/WMT14.en-de/wmt14_ende_data/newstest2014.tok.de < predict.tok.txt
157+
```
158+
159+
执行上述操作之后,可以看到类似如下的结果,此处结果是 base model 在 newstest2014 上的 BLEU 结果:
160+
```
161+
BLEU = 26.89, 58.4/32.6/20.5/13.4 (BP=1.000, ratio=1.010, hyp_len=65166, ref_len=64506)
162+
```
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import sys
2+
import os
3+
import numpy as np
4+
from attrdict import AttrDict
5+
import argparse
6+
import time
7+
8+
import paddle
9+
import paddle.nn as nn
10+
import paddle.nn.functional as F
11+
12+
import yaml
13+
from pprint import pprint
14+
15+
from paddlenlp.transformers import TransformerModel
16+
from paddlenlp.transformers import position_encoding_init
17+
from paddlenlp.ext_op import FasterTransformer
18+
19+
sys.path.append("../")
20+
import reader
21+
22+
23+
def parse_args():
24+
parser = argparse.ArgumentParser()
25+
parser.add_argument(
26+
"--config",
27+
default="../configs/transformer.base.yaml",
28+
type=str,
29+
help="Path of the config file. ")
30+
parser.add_argument(
31+
"--decoding-lib",
32+
default="../../../../paddlenlp/ext_op/build/lib/libdecoding_op.so",
33+
type=str,
34+
help="Path of libdecoding_op.so. ")
35+
parser.add_argument(
36+
"--use-fp16-decoding",
37+
action="store_true",
38+
help="Whether to use fp16 decoding to predict. ")
39+
args = parser.parse_args()
40+
return args
41+
42+
43+
def post_process_seq(seq, bos_idx, eos_idx, output_bos=False, output_eos=False):
44+
"""
45+
Post-process the decoded sequence.
46+
"""
47+
eos_pos = len(seq) - 1
48+
for i, idx in enumerate(seq):
49+
if idx == eos_idx:
50+
eos_pos = i
51+
break
52+
seq = [
53+
idx for idx in seq[:eos_pos + 1]
54+
if (output_bos or idx != bos_idx) and (output_eos or idx != eos_idx)
55+
]
56+
return seq
57+
58+
59+
def do_predict(args):
60+
place = "gpu"
61+
paddle.set_device(place)
62+
63+
# Define data loader
64+
test_loader, to_tokens = reader.create_infer_loader(args)
65+
66+
# Define model
67+
transformer = FasterTransformer(
68+
src_vocab_size=args.src_vocab_size,
69+
trg_vocab_size=args.trg_vocab_size,
70+
max_length=args.max_length + 1,
71+
n_layer=args.n_layer,
72+
n_head=args.n_head,
73+
d_model=args.d_model,
74+
d_inner_hid=args.d_inner_hid,
75+
dropout=args.dropout,
76+
weight_sharing=args.weight_sharing,
77+
bos_id=args.bos_idx,
78+
eos_id=args.eos_idx,
79+
beam_size=args.beam_size,
80+
max_out_len=args.max_out_len,
81+
decoding_lib=args.decoding_lib,
82+
use_fp16_decoding=args.use_fp16_decoding)
83+
84+
# Set evaluate mode
85+
transformer.eval()
86+
87+
# Load checkpoint.
88+
transformer.load(init_from_params=os.path.join(args.init_from_params,
89+
"transformer.pdparams"))
90+
91+
f = open(args.output_file, "w")
92+
with paddle.no_grad():
93+
for (src_word, ) in test_loader:
94+
finished_seq = transformer(src_word=src_word)
95+
finished_seq = finished_seq.numpy().transpose([1, 2, 0])
96+
for ins in finished_seq:
97+
for beam_idx, beam in enumerate(ins):
98+
if beam_idx >= args.n_best:
99+
break
100+
id_list = post_process_seq(beam, args.bos_idx, args.eos_idx)
101+
word_list = to_tokens(id_list)
102+
sequence = " ".join(word_list) + "\n"
103+
f.write(sequence)
104+
105+
106+
if __name__ == "__main__":
107+
ARGS = parse_args()
108+
yaml_file = ARGS.config
109+
with open(yaml_file, 'rt') as f:
110+
args = AttrDict(yaml.safe_load(f))
111+
pprint(args)
112+
args.decoding_lib = ARGS.decoding_lib
113+
args.use_fp16_decoding = ARGS.use_fp16_decoding
114+
115+
do_predict(args)

paddlenlp/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from . import data
1818
from . import datasets
1919
from . import embeddings
20+
from . import ext_op
2021
from . import layers
2122
from . import metrics
2223
from . import models

0 commit comments

Comments
 (0)