BERT-base模型是一个迁移能力很强的通用语义表示模型,但是模型中也有一些参数冗余。本教程将介绍如何使用PaddleSlim对PaddleNLP中BERT-base模型进行压缩。
本教程只会演示如何快速启动相应训练,详细教程请参考: BERT
利用bert-base-uncased
模型首先在GLUE数据集上进行finetune,得到需要压缩的模型,之后基于此模型进行压缩。压缩后模型参数大小减小26%(从110M减少到81M),压缩后模型在GLUE dev数据集上的精度和压缩前模型在GLUE dev数据集上的精度对比如下表所示:
Task | Metric | Baseline | Result with PaddleSlim |
---|---|---|---|
SST-2 | Accuracy | 0.93005 | 0.931193 |
QNLI | Accuracy | 0.91781 | 0.920740 |
CoLA | Mattehew's corr | 0.59557 | 0.601244 |
MRPC | F1/Accuracy | 0.91667/0.88235 | 0.91740/0.88480 |
STS-B | Person/Spearman corr | 0.88847/0.88350 | 0.89271/0.88958 |
QQP | Accuracy/F1 | 0.90581/0.87347 | 0.90994/0.87947 |
MNLI | Matched acc/MisMatched acc | 0.84422/0.84825 | 0.84687/0.85242 |
RTE | Accuracy | 0.711191 | 0.718412 |
表1-1: GLUE数据集精度对比
压缩前后模型的耗时如下表所示:
Device | Batch Size | Model | TRT(FP16) | Latency(ms) |
T4 | 16 | BERT | N | 110.71 |
Y | 22.0 | |||
Compressed BERT | N | 69.62 | ||
Y | 14.93 | |||
40 | BERT | N | 252.78 | |
Y | 53.67 | |||
Compressed BERT | N | 168.71 | ||
Y | 37.22 | |||
V100 | 16 | BERT | N | 33.28 |
Compressed BERT | N | 21.83 | ||
Intel(R) Xeon(R) Gold 5117 CPU @ 2.00GHz | 16 | BERT | N | 10831.73 |
Compressed BERT | N | 7682.93 |
表1-2: 模型速度对比
压缩后模型在T4机器上相比原始模型在FP32的情况下加速59%,在TensorRT FP16的情况下加速47.3%。 压缩后模型在V100机器上相比原始模型在FP32的情况下加速52.5%。 压缩后模型在Intel(R) Xeon(R) Gold 5117 CPU上相比原始模型在FP32的情况下加速41%。
本教程示例以GLUE/SST-2 数据集为例。
本教程基于PaddleNLP中BERT模型进行压缩,依赖PaddleNLP2.0beta及之后版本和Paddle2.0rc1及之后版本。
pip install paddlenlp
pip install paddlepaddle_gpu>=2.0rc1
首先需要对Pretrain-Model在实际的下游任务上进行Fine-tuning,得到需要压缩的模型。Fine-tuning流程参考Fine-tuning教程 Fine-tuning 在dev上的结果如压缩结果表1-1『Baseline』那一列所示。
python -u ./run_glue_ofa.py --model_type bert \
--model_name_or_path ${task_pretrained_model_dir} \
--task_name $TASK_NAME --max_seq_length 128 \
--batch_size 32 \
--learning_rate 2e-5 \
--num_train_epochs 6 \
--logging_steps 10 \
--save_steps 100 \
--output_dir ./tmp/$TASK_NAME \
--n_gpu 1 \
--width_mult_list 1.0 0.8333333333333334 0.6666666666666666 0.5
其中参数释义如下:
model_type
指示了模型类型,当前仅支持BERT模型。model_name_or_path
指示了某种特定配置的模型,对应有其预训练模型和预训练时使用的 tokenizer。若模型相关内容保存在本地,这里也可以提供相应目录地址。task_name
表示 Fine-tuning 的任务。max_seq_length
表示最大句子长度,超过该长度将被截断。batch_size
表示每次迭代每张卡上的样本数目。learning_rate
表示基础学习率大小,将于learning rate scheduler产生的值相乘作为当前学习率。num_train_epochs
表示训练轮数。logging_steps
表示日志打印间隔。save_steps
表示模型保存及评估间隔。output_dir
表示模型保存路径。n_gpu
表示使用的 GPU 卡数。若希望使用多卡训练,将其设置为指定数目即可;若为0,则使用CPU。width_mult_list
表示压缩训练过程中,对每层Transformer Block的宽度选择的范围。
压缩训练之后在dev上的结果如表1-1中『Result with PaddleSlim』列所示,延时情况如表1-2所示。
OFA API介绍参考API
下游任务模型是从TinyBERT官方repo转换得到。
Task | Metric | TinyBERT(L=4, D=312) | Result with OFA |
---|---|---|---|
SST-2 | Accuracy | 0.9234 | 0.9220 |
QNLI | Accuracy | 0.8746 | 0.8720 |
CoLA | Mattehew's corr | 0.4961 | 0.5048 |
MRPC | F1/Accuracy | 0.8998/0.8554 | 0.9003/0.8578 |
STS-B | Person/Spearman corr | 0.8635/0.8631 | 0.8717/0.8706 |
QQP | Accuracy/F1 | 0.9047/0.8751 | 0.9034/0.8733 |
MNLI | Matched acc/MisMatched acc | 0.8256/0.8294 | 0.8211/0.8261 |
RTE | Accuracy | 0.6534 | 0.6787 |
以GLUE/QQP任务为例。
export CUDA_VISIBLE_DEVICES=3
export TASK_NAME='QQP'
python -u ./run_glue_ofa.py --model_type bert \
--model_name_or_path ${PATH_OF_QQP} \
--task_name $TASK_NAME --max_seq_length 128 \
--batch_size 32 \
--learning_rate 2e-5 \
--num_train_epochs 6 \
--logging_steps 10 \
--save_steps 500 \
--output_dir ./tmp/$TASK_NAME/ \
--n_gpu 1 \
--width_mult_list 1.0 0.8333333333333334 0.6666666666666666 0.5
根据传入的config导出相应的子模型并转为静态图模型。
python3.7 -u ./export_model.py --model_type bert \
--model_name_or_path ${PATH_OF_QQP_MODEL_AFTER_OFA} \
--max_seq_length 128 \
--sub_model_output_dir ./tmp/$TASK_NAME/dynamic_model \
--static_sub_model ./tmp/$TASK_NAME/static_model \
--n_gpu 1 \
--width_mult 0.6666666666666666
其中参数释义如下:
model_type
指示了模型类型,当前仅支持BERT模型。model_name_or_path
指示了某种特定配置的经过OFA训练后保存的模型,对应有其预训练模型和预训练时使用的tokenizer。若模型相关内容保存在本地,这里也可以提供相应目录地址。max_seq_length
表示最大句子长度,超过该长度将被截断。默认:128.sub_model_output_dir
指示了导出子模型动态图参数的目录。static_sub_model
指示了导出子模型静态图模型及参数的目录,设置为None,则表示不导出静态图模型。默认:None。n_gpu
表示使用的 GPU 卡数。若希望使用多卡训练,将其设置为指定数目即可;若为0,则使用CPU。默认:1.width_mult
表示导出子模型的宽度。默认:1.0.