BERT-base模型是一个迁移能力很强的通用语义表示模型,但是模型中也有一些参数冗余。本教程将介绍如何使用PaddleSlim对BERT-base模型进行压缩。
- 对Fine-tuning得到模型通过计算参数及其梯度的乘积得到参数的重要性,把模型参数根据重要性进行重排序。
- 超网络中最大的子网络选择和Bert-base模型网络结构一致的网络结构,其他小的子网络是对最大网络的进行不同的宽度选择来得到的,宽度选择具体指的是网络中的参数进行裁剪,所有子网络在整个训练过程中都是参数共享的。
- 用重排序之后的模型参数作为超网络模型的初始化参数。
- Fine-tuning之后的模型作为教师网络,超网络作为学生网络,进行知识蒸馏。
利用bert-base-uncased
模型首先在GLUE数据集上进行finetune,得到需要压缩的模型,之后基于此模型进行压缩。压缩后模型参数大小减小26%(从110M减少到81M),压缩后模型在GLUE dev数据集上的精度和压缩前模型在GLUE dev数据集上的精度对比如下表所示:
Task | Metric | Result | 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 数据集为例。
模型压缩功能依赖最新版本的PaddleSlim
git clone https://github.com/PaddlePaddle/PaddleSlim
python setup.py build && python setup.py install
首先需要对Pretrain-Model在实际的下游任务上进行Finetuning,得到需要压缩的模型。Fine-tuning流程参考Fine-tuning教程
cd ../../benchmark/glue/
export CUDA_VISIBLE_DEVICES=0
export TASK_NAME=SST-2
python -u ./run_glue.py \
--model_type bert \
--model_name_or_path bert-base-uncased \
--task_name $TASK_NAME \
--max_seq_length 128 \
--batch_size 32 \
--learning_rate 2e-5 \
--num_train_epochs 3 \
--logging_steps 1 \
--save_steps 500 \
--output_dir ./tmp/$TASK_NAME/ \
--device gpu \
参数详细含义参考README.md Fine-tuning 在dev上的结果如压缩结果表1-1中Result那一列所示。
单卡训练
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 \
--device gpu \
--width_mult_list 1.0 0.8333333333333334 0.6666666666666666 0.5
多卡训练
unset CUDA_VISIBLE_DEVICES
python -m paddle.distributed.launch --gpus "0,1" 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 \
--device gpu \
--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
表示模型保存路径。device
表示训练使用的设备, 'gpu'表示使用GPU, 'xpu'表示使用百度昆仑卡, 'cpu'表示使用CPU。width_mult_list
表示压缩训练过程中,对每层Transformer Block的宽度选择的范围。
压缩训练之后在dev上的结果如压缩结果表格中Result with PaddleSlim那一列所示,延时情况如表1-2所示。
根据传入的config导出相应的子模型并转为静态图模型。
启动命令:
python -u ./export_model.py --model_type bert \
--model_name_or_path ${PATH_OF_MODEL_AFTER_OFA} \
--max_seq_length 128 \
--sub_model_output_dir ./tmp/$TASK_NAME/dynamic_model \
--static_sub_model ./tmp/$TASK_NAME/static_model \
--device gpu \
--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。device
表示训练使用的设备, 'gpu'表示使用GPU, 'xpu'表示使用百度昆仑卡, 'cpu'表示使用CPU。width_mult
表示导出子模型的宽度。默认:1.0.
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 |
- Lu Hou, Zhiqi Huang, Lifeng Shang, Xin Jiang, Xiao Chen, Qun Liu. DynaBERT: Dynamic BERT with Adaptive Width and Depth.
- H. Cai, C. Gan, T. Wang, Z. Zhang, and S. Han. Once for all: Train one network and specialize it for efficient deployment.