PaddleNLP 模型压缩实战指南:从 BERT 蒸馏到 Bi-LSTM 与 DynaBERT 宽度压缩
PaddleNLP 模型压缩实战指南从 BERT 蒸馏到 Bi-LSTM 与 DynaBERT 宽度压缩【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址: https://gitcode.com/gh_mirrors/pa/PaddleNLP本文基于 docs/zh/advanced_guide/model_compression 系列文档系统讲解 PaddleNLP 中两类经典模型压缩路线由 BERT 到 Bi-LSTM 的知识蒸馏与基于 DynaBERT 策略的 BERT 宽度压缩。读完本文你将掌握模型裁剪、量化和蒸馏的基本原理能够复现从 BERT 微调、小模型单独训练到最终蒸馏的全流程并了解如何借助 PaddleSlim 的 OFAOnce-For-All超网络在推理阶段直接裁剪 BERT 宽度而不损失精度。一、模型压缩概述近些年基于 Transformer 的语言模型在机器翻译、阅读理解、文本匹配、自然语言推理等自然语言处理任务上取得了实质性进展。然而海量的参数和计算资源的大量耗费使 BERT 及其变体在部署中困难重重。模型压缩的发展使得这些问题得到了缓解。模型压缩在保证一定精度的情况下能够降低模型的存储、加速模型的推理时间。常见的模型压缩方法主要包括模型裁剪Pruning、量化Quantization和蒸馏Distillation三种下文分别介绍。1. 模型裁剪模型裁剪是通过对已经训练好的模型中不重要的网络连接进行裁剪减少模型的冗余和计算量从而减少网络存储、大幅度进行加速的模型压缩方法。裁剪的对象可以是神经元、注意力头Head或整个层其核心难点在于如何判断哪些部分不重要DynaBERT 教程中利用参数梯度与参数大小计算重要性的做法正是这一思路的典型实现。2. 量化一般而言神经网络模型的参数都用 32 bit 长度的浮点型数表示。实际上有时不需要保留那么高的精度可以通过量化方法减少模型的存储空间通常用 INT8 代替 Float32 存储。例如SGDStochastic Gradient Descent所需要的精度仅为 6~8 bit因此合理的量化网络也可在保证精度的情况下减小模型的存储体积并且能够大幅度加速使得神经网络在 CPU 上的运行成为可能。通常量化包含多种方法例如二值神经网络、三元权重网络以及 XNOR 网络。3. 蒸馏蒸馏的本质是 student 模型参数量较少的模型对 teacher 模型参数量较多的模型的拟合student 模型从 teacher 模型中学到知识比自己单独学习效果更好。比较常见的方法通常是由 BERT-base 蒸馏到 Bi-LSTM 或 Transformer 层数更少的 BERT 小模型。例如 DistilBERT 保留了 BERT-base 97% 的精度减少了 40% 的参数推理速度快了 60%。4. 模型压缩示例总览本系列文档介绍了两个基于飞桨实现的常见模型压缩示例《由BERT到Bi-LSTM的知识蒸馏》可以作为蒸馏实验的 Hello World 示例完整走通微调教师模型 → 训练学生模型 → 蒸馏三步流程对应仓库 slm/examples/model_compression/distill_lstm《使用DynaBERT中的策略对BERT进行压缩》使用 DynaBERT 策略同时对不同尺寸的子网络进行训练训练完成后可在推理阶段直接对模型裁剪对应仓库 slm/examples/model_compression/ofa。下面分别展开两篇教程的完整实操流程。二、由 BERT 到 Bi-LSTM 的知识蒸馏本例将特定任务下 BERT 模型的知识蒸馏到基于 Bi-LSTM 的小模型中主要参考论文Distilling Task-Specific Knowledge from BERT into Simple Neural Networks实现。完整实验代码位于 slm/examples/model_compression/distill_lstm目录结构如下distill_lstm/ ├── small.py # 小模型结构以及对小模型单独训练的脚本 ├── bert_distill.py # 用教师模型 BERT 蒸馏学生模型的蒸馏脚本 ├── data.py # 定义了 dataloader 等数据读取接口 ├── utils.py # 定义了将样本转成 id 的转换接口 ├── args.py # 参数配置脚本 └── README.md # 文档1. 整体原理在本例中较大的模型 BERT 被称为教师模型Bi-LSTM 被称为学生模型。小模型学习大模型的知识需要学习蒸馏相关的损失函数。在本实验中损失函数是均方误差损失函数MSE传入函数的两个参数分别是学生模型的输出和教师模型的输出。在论文的模型蒸馏阶段作者为了让教师模型表达出更多的暗知识dark knowledge通常指分类任务中低概率类别与高概率类别的关系供学生模型学习对训练数据进行了数据增强。通过数据增强可以产生更多无标签的训练数据在训练过程中学生模型可借助教师模型的暗知识在更大的数据集上进行训练产生更好的蒸馏效果。论文作者使用了三种数据增强方式A. Masking以一定的概率将原数据中的 word token 替换成[MASK]B. POS-guided word replacement以一定的概率将原数据中的词用与其有相同 POS tag 的词替换C. n-gram sampling以一定的概率从每条数据中采样 n-gram其中 n 的范围可通过人工设置。需要指出的是仓库实现见 distill_lstm/README.md在英文数据集任务上使用了 Google News 语料预训练的 Word Embedding 初始化小模型的 Embedding 层实际实验只使用了第 1 种和第 3 种数据增强方式。2. 三个训练阶段总览本实验分为三个训练过程在特定任务上对 BERT 进行微调得到教师模型在特定任务上对基于 Bi-LSTM 的小模型进行单独训练用于评价蒸馏效果将 BERT 模型的知识蒸馏到基于 Bi-LSTM 的小模型上。3. 数据与预训练模型获取本实验使用 GLUE 中的 SST-2、QQP 以及中文情感分类数据集 ChnSentiCorp 中的训练集作为训练语料用数据集中的验证集评估模型效果。运行实验时数据集会被自动下载到paddlenlp.utils.env.DATA_HOME路径下。例如在 Linux 系统下GLUE 中的 QQP 数据集默认存储路径是~/.paddlenlp/datasets/glue/QQPChnSentiCorp 数据集则会下载到~/.paddlenlp/datasets/chnsenticorp。对于 BERT 微调任务实验使用了预训练模型bert-base-uncased、bert-wwm-ext-chinese、bert-base-chinese这些模型在训练时会被自动下载到paddlenlp.utils.env.MODEL_HOME路径下例如bert-base-uncased在 Linux 系统下位于~/.paddlenlp/models/bert-base-uncased。在中文数据集上训练小模型时输入利用 jieba 分词词表可下载senta_word_dict.txt下载方式见 distill_lstm/README.md。为节省显存和运行时间可以对 ChnSentiCorp 中未出现的词先进行过滤并将最后的词表文件名和词表大小配置到参数--vocab_path与--vocab_size中。4. 第一步微调 BERT 教师模型以 GLUE 的 SST-2 任务为例使用bert-base-uncased做微调之后可以得到一个在 SST-2 任务上的教师模型把在 dev 上取得最好 Accuracy 的模型保存下来用于第三步的蒸馏。参考命令如下对应 slm/examples/benchmark/glue 目录下的run_glue.pycd slm/examples/benchmark/glue export CUDA_VISIBLE_DEVICES0 export TASK_NAMESST-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 128 \ --learning_rate 3e-5 \ --num_train_epochs 3 \ --logging_steps 10 \ --save_steps 10 \ --output_dir ../model_compression/distill_lstm/pretrained_models/$TASK_NAME/ \ --device gpu如果需要训练基于 ChnSentiCorp 数据集的 BERT 微调模型可以进入 slm/applications/text_classification/multi_class 目录将预训练模型改成 BERT并基于bert-base-chinese和bert-wwm-ext-chinese模型进行微调训练。训练完成之后将训练效果最好的模型保存在pretrained_models/$TASK_NAME/目录下模型目录下包含model_config.json、model_state.pdparams、tokenizer_config.json及vocab.txt这几个文件。5. 第二步定义 Bi-LSTM 小模型并单独训练在本示例中小模型是双向 LSTM 分类模型网络层分别是Embedding、LSTM、带有tanh激活函数的Linear层最后经过一个全连接的输出层得到 logits。LSTM网络层定义如下见 small.pyself.lstm nn.LSTM(embed_dim, hidden_size, num_layers, bidirectional, dropoutdropout_prob)基于 Bi-LSTM 的小模型的forward函数定义如下def forward(self, x, seq_len): x_embed self.embedder(x) lstm_out, (hidden, _) self.lstm( x_embed, sequence_lengthseq_len) # 双向LSTM out paddle.concat((hidden[-2, :, :], hidden[-1, :, :]), axis1) out paddle.tanh(self.fc(out)) logits self.output_layer(out) return logits从源码看BiLSTM的forward还针对 QQP 这类句对任务做了扩展当输入x_2不为None时会将两个句子的隐状态拼接为[out_1, out_2, out_1 out_2, |out_1 - out_2|]四元特征后过fc_1这正是文本匹配任务常用的交互特征构造方式。单独训练小模型可以分别基于 ChnSentiCorp、SST-2、QQP 数据集运行# ChnSentiCorp CUDA_VISIBLE_DEVICES0 python small.py \ --task_name chnsenticorp \ --max_epoch 20 \ --vocab_size 1256608 \ --batch_size 64 \ --model_name bert-wwm-ext-chinese \ --optimizer adam \ --lr 3e-4 \ --dropout_prob 0.2 \ --vocab_path senta_word_dict.txt \ --save_steps 10000 \ --output_dir small_models/chnsenticorp/# SST-2 CUDA_VISIBLE_DEVICES0 python small.py \ --task_name sst-2 \ --vocab_size 30522 \ --max_epoch 10 \ --batch_size 64 \ --lr 1.0 \ --dropout_prob 0.4 \ --output_dir small_models/SST-2 \ --save_steps 10000 \ --embedding_name w2v.google_news.target.word-word.dim300.en# QQP CUDA_VISIBLE_DEVICES0 python small.py \ --task_name qqp \ --vocab_size 30522 \ --max_epoch 35 \ --batch_size 256 \ --lr 2.0 \ --dropout_prob 0.4 \ --output_dir small_models/QQP \ --save_steps 10000 \ --embedding_name w2v.google_news.target.word-word.dim300.en各参数的具体说明可参阅 args.py注意在训练不同任务时需要调整对应的超参数。6. 第三步数据增强与蒸馏蒸馏时使用的训练数据集并不只包含数据集中原有的数据而是按照上文原理介绍中的 AMasking、Cn-gram sampling两种方法进行数据增强后的总数据。在多数情况下alpha会被设置为 0表示无视硬标签学生模型只利用数据增强后的无标签数据进行训练。根据教师模型提供的软标签teacher_logits对比学生模型的logits计算均方误差损失。由于数据增强过程产生了更多的数据学生模型可以从教师模型中学到更多的暗知识。数据增强的核心代码如下def ngram_sampling(words, words_2None, p_ng0.25, ngram_range(2, 6)): if np.random.rand() p_ng: ngram_len np.random.randint(ngram_range[0], ngram_range[1] 1) ngram_len min(ngram_len, len(words)) start np.random.randint(0, len(words) - ngram_len 1) words words[start:start ngram_len] if words_2: words_2 words_2[start:start ngram_len] return words if not words_2 else (words, words_2) def data_augmentation(data, whole_word_maskwhole_word_mask): # 1. Masking words [] if not whole_word_mask: tokenized_list tokenizer.tokenize(data) words [ tokenizer.mask_token if np.random.rand() p_mask else word for word in tokenized_list ] else: for word in data.split(): words [[tokenizer.mask_token]] if np.random.rand( ) p_mask else [tokenizer.tokenize(word)] # 2. N-gram sampling words ngram_sampling(words, p_ngp_ng, ngram_rangengram_range) words flatten(words) if isinstance(words[0], list) else words new_text .join(words) return words, new_text蒸馏阶段主要是让学生模型Bi-LSTM去学习教师模型的输出 logits核心训练循环如下与 bert_distill.py 中的实现一致ce_loss nn.CrossEntropyLoss() # 交叉熵损失函数 mse_loss nn.MSELoss() # 均方误差损失函数 for epoch in range(args.max_epoch): for i, batch in enumerate(train_data_loader): bert_input_ids, bert_segment_ids, student_input_ids, seq_len, labels batch # Calculate teacher models forward. with paddle.no_grad(): teacher_logits teacher.model(bert_input_ids, bert_segment_ids) # Calculate student models forward. logits model(student_input_ids, seq_len) # Calculate the loss, usually args.alpha equals to 0. loss args.alpha * ce_loss(logits, labels) ( 1 - args.alpha) * mse_loss(logits, teacher_logits) loss.backward() optimizer.step()在源码实现中教师模型通过TeacherModel类封装BertForSequenceClassification.from_pretrained(teacher_dir)后置为eval()教师前向计算被包裹在paddle.no_grad()中不参与梯度更新损失函数alpha * ce_loss (1 - alpha) * mse_loss与文档代码完全一致alpha默认 0.0见 args.py 中--alpha参数的说明。运行蒸馏的命令分别基于 ChnSentiCorp、SST-2、QQP 数据集# ChnSentiCorp CUDA_VISIBLE_DEVICES0 python bert_distill.py \ --task_name chnsenticorp \ --vocab_size 1256608 \ --max_epoch 6 \ --lr 1.0 \ --dropout_prob 0.1 \ --batch_size 64 \ --model_name bert-wwm-ext-chinese \ --teacher_dir pretrained_models/chnsenticorp/best_bert_wwm_ext_model_880 \ --vocab_path senta_word_dict.txt \ --output_dir distilled_models/chnsenticorp \ --save_steps 10000# SST-2 CUDA_VISIBLE_DEVICES0 python bert_distill.py \ --task_name sst-2 \ --vocab_size 30522 \ --max_epoch 6 \ --lr 1.0 \ --dropout_prob 0.2 \ --batch_size 128 \ --model_name bert-base-uncased \ --output_dir distilled_models/SST-2 \ --teacher_dir pretrained_models/SST-2/best_model_610 \ --save_steps 10000 \ --embedding_name w2v.google_news.target.word-word.dim300.en# QQP CUDA_VISIBLE_DEVICES0 python bert_distill.py \ --task_name qqp \ --vocab_size 30522 \ --max_epoch 6 \ --lr 1.0 \ --dropout_prob 0.2 \ --batch_size 256 \ --model_name bert-base-uncased \ --n_iter 10 \ --output_dir distilled_models/QQP \ --teacher_dir pretrained_models/QQP/best_model_17000 \ --save_steps 10000 \ --embedding_name w2v.google_news.target.word-word.dim300.en7. 蒸馏实验结果本蒸馏实验基于 GLUE 的 SST-2、QQP 与中文情感分类 ChnSentiCorp 数据集使用各自验证集dev评估评价指标为准确率accQQP 中额外包含 F1 值。利用 BERT 教师模型蒸馏 Bi-LSTM 学生模型相比 Bi-LSTM 小模型单独训练在 SST-2、QQP、ChnSentiCorp 上分别有 3.3%、1.9%、1.4% 的提升ModelSST-2 (dev acc)QQP (dev acc/f1)ChnSentiCorp (dev acc)ChnSentiCorp (dev acc)Teacher modelbert-base-uncasedbert-base-uncasedbert-base-chinesebert-wwm-ext-chineseBERT-base0.9300460.905813 / 0.8734720.9516670.955000Bi-LSTM0.8543580.856616 / 0.7996820.9200000.920000Distilled Bi-LSTM0.8876150.875216 / 0.8312540.9325000.9341678. 关键参数说明以下参数定义见 args.py在训练不同任务时需相应调整参数默认值说明--task_namesst-2任务名支持sst-2、qqp、chnsenticorp--optimizeradadelta优化器仅支持adam或adadelta训练小模型时常用adam--lr1.0学习率SST-2/QQP 蒸馏常用 1.0ChnSentiCorp 单独训练小模型常用 3e-4--num_layers1LSTM 层数--emb_dim300Embedding 维度--hidden_size300LSTM 隐层大小--output_dim2分类类别数--batch_size64训练 batch size--max_epoch12最大训练轮数--max_seq_length128句子最大长度--n_iter20数据增强中每个样本的迭代次数--dropout_prob0.0Dropout 概率--init_scale0.1参数初始化范围--padding_idx0Embedding 的 padding 索引--model_namebert-base-uncased教师模型名其 tokenizer 会被小模型复用--teacher_dir无教师模型目录--vocab_pathBERT 词表默认路径学生模型词表路径--vocab_size10000学生模型词表大小--alpha0.0交叉熵损失与均方误差损失的权重平衡系数--whole_word_maskFalse数据增强中是否使用整词掩码--devicegpu运行设备支持gpu、cpu、xpu--seed2021随机种子三、使用 DynaBERT 策略对 BERT 进行压缩本教程使用DynaBERT: Dynamic BERT with Adaptive Width and Depth论文中的训练策略把原始模型作为超网络中最大的子模型超网络指包含所有搜索空间在内的一个网络。原始模型包含多个相同大小的 Transformer Block每次训练前会选择当前轮次要训练的子模型每个子模型包含多个相同大小的 Sub Transformer Block每个 Sub Transformer Block 是选择不同宽度的 Transformer Block 得到的。一个 Transformer Block 包含一个 Multi-Head Attention 和一个 Feed-Forward NetworkSub Transformer Block 的获得方式为一个Multi-Head Attention层中有多个 Head每次选择不同宽度的子模型时会同时对 Head 数量进行等比例减少。例如原始模型有 12 个 Head本次训练选择宽度为原始宽度 75% 的子模型则本次训练中所有 Transformer Block 的 Head 数量为 9。Feed-Forward Network层中Linear的参数大小进行等比例减少。例如原始模型 FFN 层特征维度为 3072本次训练选择宽度为原始宽度 75% 的子模型则本次训练中所有 Transformer Block 中 FFN 层的特征维度为 2304。完整实验代码位于 slm/examples/model_compression/ofa包含run_glue_ofa.py、run_glue_ofa_depth.py、export_model.py等脚本其中run_glue_ofa_depth.py还扩展了深度维度的搜索。1. 整体原理与流程整体流程如下图所示首先对预训练模型的参数和 head 根据其重要性进行重排序把重要的参数和 head 排在参数的前侧保证训练过程中的参数裁剪不会裁剪掉这些重要的参数。参数重要性的计算先使用 dev 数据计算一遍每个参数的梯度然后根据梯度和参数的整体大小来计算当前参数的重要性head 重要性的计算传入一个全 1 的 head mask计算该 mask 的梯度根据 mask 的梯度判断每个Multi-Head Attention层中每个 Head 的重要性。使用原本的预训练模型作为蒸馏过程中的教师网络。同时定义一个超网络这个超网络中最大的子网络的结构和教师网络相同其他小的子网络是对最大网络进行不同的宽度选择得到的。宽度选择具体指对网络中的参数进行裁剪所有子网络在整个训练过程中都是参数共享的。使用重排序之后的预训练模型参数初始化超网络并把这个超网络作为学生网络。分别为Embedding层、每个 transformer block 层和最后的 logits 添加蒸馏损失。每个 batch 数据在训练前首先会选择当前要训练的子网络配置子网络配置目前仅包括对整个模型宽度的选择参数更新时仅会更新当前子网络计算中用到的那部分参数。通过以上方式优化整个超网络参数训练完成后选择满足加速要求和精度要求的子模型。2. 压缩前准备微调 BERT在本例中也需要训练基于特定任务的 BERT 模型方法同《由BERT到Bi-LSTM的知识蒸馏》教程中所述基于 GLUE 数据集微调bert-base-uncased。下面重点介绍模型压缩过程。3. 基于 PaddleSlim 的压缩实现步骤3.1 定义初始网络定义原始 BERT-base 模型并定义一个字典保存原始模型参数。普通模型转换为超网络之后由于其组网 OP 的改变导致原始模型加载的参数失效所以需要定义一个字典保存原始模型的参数并用来初始化超网络model BertForSequenceClassification.from_pretrained(bert, num_classes2) origin_weights {} for name, param in model.named_parameters(): origin_weights[name] param3.2 构建超网络定义搜索空间并根据搜索空间把普通网络转换为超网络# 定义搜索空间 sp_config supernet(expand_ratio[0.25, 0.5, 0.75, 1.0]) # 转换模型为超网络 model Convert(sp_config).convert(model) paddleslim.nas.ofa.utils.set_state_dict(model, origin_weights)其中expand_ratio列表定义了可选的宽度倍数25%、50%、75%、100%set_state_dict负责把保存的原始参数按重排序后的位置载入超网络。3.3 定义教师网络构造教师网络teacher_model BertForSequenceClassification.from_pretrained(bert, num_classes2)3.4 配置蒸馏相关参数需要配置的参数包括教师模型实例需要添加蒸馏的层——在教师网络和学生网络的Embedding层和每一个Transformer Block层之间添加蒸馏损失中间层的蒸馏损失使用默认的 MSE 损失函数配置lambda_distill参数表示整体蒸馏损失的缩放比例mapping_layers [bert.embeddings] for idx in range(model.bert.config[num_hidden_layers]): mapping_layers.append(bert.encoder.layers.{}.format(idx)) default_distill_config { lambda_distill: 0.1, teacher_model: teacher_model, mapping_layers: mapping_layers, } distill_config DistillConfig(**default_distill_config)3.5 定义 Once-For-All 模型将普通模型和蒸馏相关配置传给OFA接口自动添加蒸馏过程并把超网络训练方式转为OFA训练方式ofa_model paddleslim.nas.ofa.OFA(model, distill_configdistill_config)3.6 计算神经元和 head 的重要性并重排序head_importance, neuron_importance utils.compute_neuron_head_importance( sst-2, ofa_model.model, dev_data_loader, num_layersmodel.bert.config[num_hidden_layers], num_headsmodel.bert.config[num_attention_heads]) reorder_neuron_head(ofa_model.model, head_importance, neuron_importance)3.7 传入当前 OFA 训练所处的阶段ofa_model.set_epoch(epoch) ofa_model.set_task(width)3.8 传入网络配置开始训练本示例使用 DynaBERT 的策略进行超网络训练。在每个 batch 内依次以不同宽度倍数1.0、0.75、0.5、0.25切出子网络收集各宽度下的表示蒸馏损失与 logits 软标签损失累加后统一反向传播width_mult_list [1.0, 0.75, 0.5, 0.25] lambda_logit 0.1 for width_mult in width_mult_list: net_config paddleslim.nas.ofa.utils.dynabert_config(ofa_model, width_mult) ofa_model.set_net_config(net_config) logits, teacher_logits ofa_model(input_ids, segment_ids, attention_mask[None, None]) rep_loss ofa_model.calc_distill_loss() logit_loss soft_cross_entropy(logits, teacher_logits.detach()) loss rep_loss lambda_logit * logit_loss loss.backward() optimizer.step() lr_scheduler.step() ofa_model.model.clear_gradients()可以看到每个宽度子网络的 loss 由两部分构成rep_loss中间层表示蒸馏损失来自calc_distill_loss()与lambda_logit * logit_loss输出 logits 的软交叉熵损失这正是 DynaBERT 的核心训练目标。4. 关键注意点monkey patch BERTModel 的 forward由于在计算 head 重要性时会利用一个 mask 来收集梯度所以需要通过 monkey patch 的方式重新实现BERTModel类的forward函数。示例如下from paddlenlp.transformers import BertModel def bert_forward(self, input_ids, token_type_idsNone, position_idsNone, attention_mask[None, None]): wtype self.pooler.dense.fn.weight.dtype if hasattr( self.pooler.dense, fn) else self.pooler.dense.weight.dtype if attention_mask[0] is None: attention_mask[0] paddle.unsqueeze( (input_ids self.pad_token_id).astype(wtype) * -1e9, axis[1, 2]) embedding_output self.embeddings( input_idsinput_ids, position_idsposition_ids, token_type_idstoken_type_ids) encoder_outputs self.encoder(embedding_output, attention_mask) sequence_output encoder_outputs pooled_output self.pooler(sequence_output) return sequence_output, pooled_output BertModel.forward bert_forward5. 压缩结果参考依据 ofa/README.md 中公开的实验记录利用bert-base-uncased模型在 GLUE 数据集上微调得到待压缩模型后基于 PaddleSlim 压缩压缩后模型参数大小减小 26%从 110M 减少到 81M且压缩后模型在 GLUE dev 数据集上的精度与压缩前基本持平甚至略有提升TaskMetricResultResult with PaddleSlimSST-2Accuracy0.930050.931193QNLIAccuracy0.917810.920740CoLAMattehews corr0.595570.601244MRPCF1/Accuracy0.91667 / 0.882350.91740 / 0.88480STS-BPerson/Spearman corr0.88847 / 0.883500.89271 / 0.88958QQPAccuracy/F10.90581 / 0.873470.90994 / 0.87947MNLIMatched acc / MisMatched acc0.84422 / 0.848250.84687 / 0.85242RTEAccuracy0.7111910.718412四、总结与进阶方向从本文两篇教程可以看到PaddleNLP 覆盖了模型压缩的两条经典路线逐任务蒸馏BERT → Bi-LSTM以数据增强 MSE 软标签损失为核心适合把任务特定的小模型快速部署到资源受限场景是理解蒸馏机制的 Hello World超网络宽度压缩DynaBERT / OFA一次训练得到多个宽度共享参数的子网络推理时按需裁剪兼顾精度与加速适合需要对同一模型做多档位部署的场景。如果需要进一步深入可以继续阅读蒸馏实现slm/examples/model_compression/distill_lstmsmall.py、bert_distill.py、args.py、data.py、utils.pyOFA 压缩实现slm/examples/model_compression/ofarun_glue_ofa.py、run_glue_ofa_depth.py、export_model.py模型压缩文档入口docs/zh/advanced_guide/model_compression 与 slm/examples/model_compression 下的 minilmv2、pp-minilm 等更多压缩示例包含通用蒸馏、裁剪与后量化脚本。上述代码与文档均位于当前仓库可直接查看源码、配置文件与测试数据来验证文中描述的实现细节。【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址: https://gitcode.com/gh_mirrors/pa/PaddleNLP创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考