蒸餾實(shí)戰(zhàn):將 BERT 教師模型的任務(wù)知識(shí)蒸餾進(jìn) Bi-LSTM 學(xué)生模型)
人工智能大模型預(yù)訓(xùn)練微調(diào)LoRARLHF強(qiáng)化學(xué)習(xí)分布式訓(xùn)練【免費(fèi)下載鏈接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.項(xiàng)目地址https://gitcode.com/gh_mirrors/pa/PaddleNLP點(diǎn)擊查看免費(fèi)下載本文以 PaddleNLP 中slm/examples/model_compression/distill_lstm/目錄下的蒸餾實(shí)驗(yàn)為核心完整講清“把特定任務(wù)下 fine-tuned BERT 的知識(shí)蒸餾到 Bi-LSTM 小模型”這一經(jīng)典壓縮方案包括教師/學(xué)生模型的劃分、均方誤差蒸餾損失與交叉熵?fù)p失的加權(quán)方式、基于 Masking 與 n-gram 采樣的數(shù)據(jù)增強(qiáng)細(xì)節(jié)、三個(gè)訓(xùn)練階段BERT fine-tuning、小模型獨(dú)立訓(xùn)練、蒸餾的完整可運(yùn)行命令、各超參數(shù)的默認(rèn)值與含義以及官方給出的蒸餾實(shí)驗(yàn)結(jié)果。讀完本文你可以按步驟在自己的環(huán)境里復(fù)現(xiàn)整套 BERT → Bi-LSTM 蒸餾流程并能看懂每個(gè)參數(shù)背后的源碼實(shí)現(xiàn)。示例總覽目錄結(jié)構(gòu)與核心文件該實(shí)驗(yàn)實(shí)現(xiàn)參考論文《Distilling Task-Specific Knowledge from BERT into Simple Neural Networks》Tang et al., 2019。目錄內(nèi)各文件分工如下引自 README. ├── small.py # 小模型結(jié)構(gòu)以及對(duì)小模型單獨(dú)訓(xùn)練的腳本 ├── bert_distill.py # 用教師模型BERT蒸餾學(xué)生模型的蒸餾腳本 ├── data.py # 定義了dataloader等數(shù)據(jù)讀取接口 ├── utils.py # 定義了將樣本轉(zhuǎn)成id的轉(zhuǎn)換接口 ├── args.py # 參數(shù)配置腳本 └── README.md # 文檔本文件在模型蒸餾中較大的模型本例中的 BERT稱為教師模型較小的模型本例中的 Bi-LSTM稱為學(xué)生模型。學(xué)生模型通過蒸餾相關(guān)的損失函數(shù)學(xué)習(xí)教師模型的輸出分布數(shù)據(jù)、詞表與訓(xùn)練腳本的組織方式都圍繞這一“教師—學(xué)生”結(jié)構(gòu)展開。蒸餾損失MSE 為主、交叉熵可加權(quán)README 指出本實(shí)驗(yàn)的蒸餾損失是均方誤差MSE函數(shù)輸入分別為學(xué)生模型輸出與教師模型輸出。這一描述在 bert_distill.py 中可以得到源碼級(jí)印證一次訓(xùn)練 step 的完整流程為教師模型前向不參與梯度# Calculate teacher models forward. with paddle.no_grad(): teacher_logits teacher.model(bert_input_ids, bert_segment_ids)學(xué)生模型前向QQP 為雙句輸入其余任務(wù)為單句# Calculate student models forward. if args.task_name qqp: logits model(student_input_ids_1, seq_len_1, student_input_ids_2, seq_len_2) else: logits model(student_input_ids, seq_len)聯(lián)合損失由--alpha控制兩個(gè)損失的權(quán)重平衡loss args.alpha * ce_loss(logits, labels) (1 - args.alpha) * mse_loss(logits, teacher_logits)結(jié)合 args.py 可以看到--alpha默認(rèn)值為0.0即 README 中的三條蒸餾命令均未顯式指定 alpha實(shí)際訓(xùn)練中損失完全來自 MSE學(xué)生模型只擬合教師模型的 logits不使用真實(shí)標(biāo)簽——這正是“借助教師模型的暗知識(shí)”的核心機(jī)制。如需同時(shí)利用真實(shí)標(biāo)簽把--alpha調(diào)大即可在 MSE 與交叉熵之間取得平衡。教師模型本身由BertForSequenceClassification.from_pretrained(teacher_dir)從第一步訓(xùn)練產(chǎn)出的檢查點(diǎn)加載并固定處于eval()狀態(tài)見 bert_distill.py 的TeacherModel類。數(shù)據(jù)增強(qiáng)Masking 與 n-gram 采樣論文為讓教師模型表達(dá)更多可供學(xué)習(xí)的信息對(duì)訓(xùn)練數(shù)據(jù)做了增強(qiáng)共提出三種方式Masking、POS-guided word replacement、n-gram sampling。README 特別說明本實(shí)驗(yàn)只實(shí)現(xiàn)了第 1 種Masking和第 3 種n-gram sampling。兩者的具體實(shí)現(xiàn)位于 data.pyMasking以概率p_mask默認(rèn) 0.1將已分詞結(jié)果中的 token 替換為[MASK]。英文數(shù)據(jù)上支持--whole_word_mask參數(shù)切換為整詞掩碼模式n-gram sampling以概率p_ng默認(rèn) 0.25從每條樣本中截取一段長度為 n 的連續(xù)片段n 的取值范圍默認(rèn)(2, 6)中文版本為(2, 10)見 apply_data_augmentation_for_cn迭代次數(shù)每條訓(xùn)練樣本額外增強(qiáng)--n_iter次默認(rèn) 20因此訓(xùn)練集規(guī)模會(huì)膨脹為原來的約1 n_iter倍。def apply_data_augmentation( data, task_name, tokenizer, n_iter20, p_mask0.1, p_ng0.25, ngram_range(2, 6), whole_word_maskFalse, seed0 ): ... for example in data: for _ in range(n_iter): ... new_data.append({sentence: words, labels: example[labels]})數(shù)據(jù)增強(qiáng)在create_distill_loader中通過train_ds.map(data_aug_fn, batchedTrue)統(tǒng)一接入data.py并打印 “Data augmentation has been applied.” 提示。中文任務(wù)ChnSentiCorp由于 BERT 與 jieba 分詞結(jié)果不一致增強(qiáng)時(shí)會(huì)同步產(chǎn)出兩套 token 序列l(wèi)stm_tokensjieba 分詞供學(xué)生模型與bert_tokensBERT 分詞供教師模型保證兩個(gè)模型看到的是同一句增強(qiáng)文本這也是中文蒸餾能成立的關(guān)鍵設(shè)計(jì)。增強(qiáng)樣本會(huì)繼承原樣本標(biāo)簽因此學(xué)生模型實(shí)際上是在“遠(yuǎn)大于原始訓(xùn)練集”的數(shù)據(jù)上擬合教師輸出。數(shù)據(jù)、預(yù)訓(xùn)練模型與詞表準(zhǔn)備數(shù)據(jù)集使用 GLUE 中的 SST-2、QQP 以及中文情感分類數(shù)據(jù)集 ChnSentiCorp 的訓(xùn)練集作為訓(xùn)練語料驗(yàn)證集dev用于評(píng)估。數(shù)據(jù)集通過paddlenlp.datasets.load_dataset自動(dòng)下載存放于paddlenlp.utils.env.DATA_HOME路徑下例如 Linux 系統(tǒng)下 QQP 默認(rèn)在~/.paddlenlp/datasets/glue/QQPChnSentiCorp 在~/.paddlenlp/datasets/chnsenticorp。源碼側(cè)對(duì)應(yīng) data.py 中的load_dataset(glue, task_name, ...)與load_dataset(task_name, ...)。教師預(yù)訓(xùn)練模型bert-base-uncased英文任務(wù)、bert-base-chinese與bert-wwm-ext-chinese中文任務(wù)同樣自動(dòng)下載到MODEL_HOME例如~/.paddlenlp/models/bert-base-uncased。學(xué)生模型詞表中文任務(wù)的輸入使用 jieba 分詞詞表與 PaddleNLP 文本分類項(xiàng)目使用的 senta 詞表一致文件為senta_word_dict.txt可從 PaddleNLP 官方數(shù)據(jù)源下載默認(rèn)存放命令見原 README 的wget說明放置在本示例目錄下。為了節(jié)省顯存與運(yùn)行時(shí)間可以先對(duì) ChnSentiCorp 中未出現(xiàn)的詞做過濾再把過濾后的詞表路徑與詞表大小分別配置到--vocab_path與--vocab_size參數(shù)中。英文任務(wù)的詞表來源英文任務(wù)下學(xué)生模型直接復(fù)用教師 BERT 的BertTokenizer作為詞表見 data.py非中文任務(wù)分支vocab BertTokenizer.from_pretrained(model_name)因此英文任務(wù)的--vocab_size對(duì)應(yīng) BERT 詞表大小 30522中文任務(wù)則由Vocab.load_vocabulary加載 senta 詞表unk_token[UNK]、pad_token[PAD]。階段一訓(xùn)練教師模型BERT fine-tuning蒸餾的前提是先有一個(gè)任務(wù)特定的強(qiáng)教師模型。GLUE 任務(wù)可以復(fù)用本倉庫 glue 示例目錄 下的 run_glue.py更多說明見 glue 的 README。以 SST-2 任務(wù)為例原 README 給出的命令為cd ../../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 \注意--output_dir指向蒸餾目錄下的pretrained_models/$TASK_NAME/即教師模型產(chǎn)物就為后續(xù)的--teacher_dir參數(shù)準(zhǔn)備好了位置。若訓(xùn)練基于 ChnSentiCorp 的 BERT fine-tuning 模型原 README 建議進(jìn)入文本分類示例目錄 slm/examples/text_classification 下的多分類示例把預(yù)訓(xùn)練模型改為bert-base-chinese或bert-wwm-ext-chinese進(jìn)行 fine-tuning。訓(xùn)練完成后將效果最好的模型保存在本示例的pretrained_models/$TASK_NAME/下模型目錄應(yīng)包含model_config.json、model_state.pdparams、tokenizer_config.json及vocab.txt這幾個(gè)文件——這與BertForSequenceClassification.from_pretrained(teacher_dir)的加載要求一致。階段二獨(dú)立訓(xùn)練 Bi-LSTM 學(xué)生模型蒸餾效果的對(duì)照基線small.py 定義了 Bi-LSTM 學(xué)生模型結(jié)構(gòu)并完成獨(dú)立訓(xùn)練使用nn.CrossEntropyLoss直接擬合真實(shí)標(biāo)簽其作用是作為不蒸餾的對(duì)照基線。模型結(jié)構(gòu)要點(diǎn)見 small.pynn.Embedding(vocab_size, embed_dim, padding_idx)學(xué)生模型詞嵌入層默認(rèn)embed_dim300nn.LSTM(embed_dim, hidden_size, num_layers, bidirectional)雙向 LSTM默認(rèn) 1 層、hidden_size300單句任務(wù)取雙向 LSTM 末時(shí)刻的兩個(gè)方向隱狀態(tài)拼接后經(jīng)fc2*hidden → hidden與tanh再經(jīng)output_layer輸出 logits雙句任務(wù)QQP額外拼接兩句的“和”與“絕對(duì)差”向量輸入維度變?yōu)?*hidden經(jīng)fc_1再輸出。三個(gè)任務(wù)的獨(dú)立訓(xùn)練命令原 README 原樣保留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/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.enCUDA_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 w2w.google_news.target.word-word.dim300.en # 注意原README為 w2v.google_news.target.word-word.dim300.en當(dāng)前版本的重要注意論文中曾使用 Google News 預(yù)訓(xùn)練 Word Embedding 初始化小模型的 Embedding 層但當(dāng)前倉庫代碼中 BiLSTM.init明確拋出異?!癟okenEmbedding is deprecated in PaddleNLP since 3.0, please set embedding_name to None”。因此按當(dāng)前倉庫運(yùn)行英文任務(wù)時(shí)請去掉--embedding_name參數(shù)Embedding 層將隨機(jī)初始化后端到端訓(xùn)練。階段三執(zhí)行蒸餾BERT → Bi-LSTM蒸餾階段加載教師模型并對(duì)學(xué)生模型訓(xùn)練數(shù)據(jù)管線會(huì)自動(dòng)施加前述數(shù)據(jù)增強(qiáng)。三個(gè)任務(wù)的蒸餾命令原 README 原樣保留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 \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.enCUDA_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.en各命令的要點(diǎn)--teacher_dir指向階段一保存的最佳 BERT 檢查點(diǎn)目錄命令中的best_model_610、best_model_17000、best_bert_wwm_ext_model_880為示例命名實(shí)際請以自己訓(xùn)練輸出的最佳模型目錄為準(zhǔn)--model_name既用于加載教師的BertTokenizer蒸餾 batch 中 BERT 側(cè)輸入即由它生成中文任務(wù)下還會(huì)作為小模型訓(xùn)練數(shù)據(jù)的詞表來源--n_iter控制每條樣本的數(shù)據(jù)增強(qiáng)次數(shù)QQP 命令中設(shè)為 10默認(rèn) 20同樣注意按當(dāng)前倉庫代碼--embedding_name參數(shù)會(huì)導(dǎo)致ValueError實(shí)際運(yùn)行英文任務(wù)時(shí)請將其移除訓(xùn)練與保存邏輯與small.py一致每--save_steps步保存step_N.pdparams與step_N.pdopt每--log_freq步在 dev 集上評(píng)估并打印 loss、accQQP 另含 precision/recall/f1。關(guān)鍵參數(shù)說明來自 args.py完整的參數(shù)定義在 args.py核心參數(shù)與默認(rèn)值如下表參數(shù)默認(rèn)值說明--task_namesst-2任務(wù)名支持sst-2/qqp/chnsenticorp--optimizeradadelta優(yōu)化器僅支持adam|adadeltaAdadelta 使用rho0.95--lr1.0學(xué)習(xí)率--num_layers1LSTM 層數(shù)--emb_dim/--hidden_size300/300學(xué)生模型嵌入維度 / LSTM 隱層維度--output_dim2分類數(shù)本實(shí)驗(yàn)均為二分類--vocab_size10000學(xué)生模型詞表大小需與--vocab_path詞表一致--batch_size/--max_epoch64/12批大小 / 最大訓(xùn)練輪數(shù)--max_seq_length128序列最大長度--n_iter20數(shù)據(jù)增強(qiáng)時(shí)每條樣本的增強(qiáng)迭代次數(shù)--dropout_prob0.0LSTM dropout--init_scale0.1全連接層權(quán)重 Uniform 初始化區(qū)間[-scale, scale]--log_freq/--save_steps10/100日志頻率 / 保存 checkpoint 頻率按 step--model_namebert-base-uncased教師模型名其 tokenizer 會(huì)被學(xué)生數(shù)據(jù)管線復(fù)用--teacher_dir無教師模型目錄蒸餾時(shí)必填--vocab_pathMODEL_HOME/bert-base-uncased/...學(xué)生模型詞表路徑中文任務(wù)用 senta 詞表--alpha0.0交叉熵?fù)p失與 MSE 蒸餾損失的權(quán)重平衡系數(shù)--whole_word_maskFalse數(shù)據(jù)增強(qiáng)時(shí)使用整詞掩碼--init_from_ckptNone從既有 checkpoint 恢復(fù)模型與優(yōu)化器--seed2021隨機(jī)種子保證參數(shù)初始化與數(shù)據(jù)增強(qiáng)可復(fù)現(xiàn)--devicegpu運(yùn)行設(shè)備可選gpu/cpu/xpu--embedding_nameNone預(yù)訓(xùn)練詞嵌入名當(dāng)前版本傳入非空值會(huì)直接報(bào)錯(cuò)見上文說明README 提醒訓(xùn)練不同任務(wù)時(shí)需要調(diào)整對(duì)應(yīng)超參數(shù)表中各命令里的 epoch、lr、batch_size、dropout 即為官方推薦的組合。蒸餾實(shí)驗(yàn)結(jié)果官方實(shí)驗(yàn)在 GLUE 的 SST-2、QQP 與 ChnSentiCorp 上進(jìn)行均用各自 dev 集評(píng)價(jià)指標(biāo)為準(zhǔn)確率QQP 另含 f1。對(duì)比結(jié)果原 README 表格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(acc)/0.873472(f1)0.9516670.955000Bi-LSTM0.8543580.856616(acc)/0.799682(f1)0.9200000.920000Distilled Bi-LSTM0.8876150.875216(acc)/0.831254(f1)0.9325000.934167可以看到用 BERT 教師模型蒸餾后的 Bi-LSTM 相對(duì)獨(dú)立訓(xùn)練的 Bi-LSTM在 SST-2、QQP、ChnSentiCorp 上分別提升約 3.3%、1.9%、1.4%與教師模型的差距明顯縮小——這正是“教師暗知識(shí) 數(shù)據(jù)增強(qiáng)”在小模型上的收益體現(xiàn)。小結(jié)與參考資料本示例用不到 600 行代碼串起了任務(wù)知識(shí)蒸餾的完整閉環(huán)教師模型 fine-tuning復(fù)用 run_glue.py→ 學(xué)生模型獨(dú)立訓(xùn)練基線small.py→ 帶數(shù)據(jù)增強(qiáng)的蒸餾訓(xùn)練bert_distill.py、data.py、utils.py。其中損失函數(shù)、數(shù)據(jù)增強(qiáng)與詞表設(shè)計(jì)均可通過args.py參數(shù)靈活調(diào)整適合作為理解“教師-學(xué)生”范式在序列分類任務(wù)上如何落地的最小完整樣例。參考文獻(xiàn)Tang R, Lu Y, Liu L, Mou L, Vechtomova O, Lin J.Distilling Task-Specific Knowledge from BERT into Simple Neural Networks. arXiv preprint arXiv:1903.12136, 2019.贊分享人工智能大模型預(yù)訓(xùn)練微調(diào)LoRARLHF強(qiáng)化學(xué)習(xí)分布式訓(xùn)練【免費(fèi)下載鏈接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.項(xiàng)目地址https://gitcode.com/gh_mirrors/pa/PaddleNLP點(diǎn)擊查看免費(fèi)下載相關(guān)推薦PaddleNLP 由 BERT 到 Bi-LSTM 的知識(shí)蒸餾實(shí)戰(zhàn)任務(wù)特定知識(shí)蒸餾完整指南PaddleNLP 由 BERT 到 Bi LSTM 的知識(shí)蒸餾實(shí)戰(zhàn)任務(wù)特定知識(shí)蒸餾完整指南 導(dǎo)讀 本文基于 PaddleNLP 倉庫中的蒸餾示例 dist人工智能大模型預(yù)訓(xùn)練微調(diào)LoRARLHF強(qiáng)化學(xué)習(xí)分布式訓(xùn)練模型推理服務(wù)推理引擎模型量化模型壓縮本地部署NLPPaddleNLP 知識(shí)蒸餾實(shí)戰(zhàn)從 BERT 到 Bi-LSTM 的 Task-Specific 蒸餾指南PaddleNLP 知識(shí)蒸餾實(shí)戰(zhàn)從 BERT 到 Bi LSTM 的 Task Specific 蒸餾指南 導(dǎo)讀 本文基于 PaddleNLP 倉庫中的 di人工智能大模型預(yù)訓(xùn)練微調(diào)LoRARLHF強(qiáng)化學(xué)習(xí)分布式訓(xùn)練模型推理服務(wù)推理引擎模型量化模型壓縮本地部署NLP知識(shí)蒸餾實(shí)戰(zhàn)nlp-tutorial師生模型的知識(shí)傳遞完整指南知識(shí)蒸餾實(shí)戰(zhàn)nlp tutorial師生模型的知識(shí)傳遞完整指南 nlp tutorial是面向深度學(xué)習(xí)研究者的自然語言處理教程項(xiàng)目通過一系列實(shí)踐案例幫助開發(fā)示例工程上一篇Thumbfast架構(gòu)解析mpv播放器實(shí)時(shí)縮略圖生成引擎的實(shí)現(xiàn)原理與實(shí)踐指南下一篇sudo-rs的系統(tǒng)集成與systemd和日志服務(wù)交互創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考