Skip to content

Commit ca145bb

Browse files
authored
Add tiny bert model (#313)
* add tinybert model * add distilbert model * add tinybert model * update tinybert's forward * update tokenizer path * add small model in transformers.md * add task_distill and data augmentation * simplify the task distill, and update distillation result * update readme and copyright * remove distillation from pretrainingmodel, update readme * fix distillation program error, modify tinybert modeling * update experiment result * move distiller out of tinybert modeling * remove import from transformer init, and update distillation result * rename distiller-> distill_utils
1 parent 3b0a95d commit ca145bb

File tree

11 files changed

+1545
-8
lines changed

11 files changed

+1545
-8
lines changed

docs/transformers.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
|[ELECTRA](https://arxiv.org/abs/2003.10555) | ElectraTokenizer| ElectraModel<br>ElectraForSequenceClassification<br>ElectraForTokenClassification<br>|`electra-small`<br> `electra-base`<br> `electra-large`<br> `chinese-electra-small`<br> `chinese-electra-base`<br>|
1919
|[XLNet](https://arxiv.org/abs/1906.08237)| XLNetTokenizer| XLNetModel<br> XLNetForSequenceClassification<br> XLNetForTokenClassification |`xlnet-base-cased`<br> `xlnet-large-cased`<br> `chinese-xlnet-base`<br> `chinese-xlnet-mid`<br> `chinese-xlnet-large`|
2020
|[UnifiedTransformer](https://arxiv.org/abs/2006.16779)| UnifiedTransformerTokenizer| UnifiedTransformerModel<br> UnifiedTransformerLMHeadModel |`unified_transformer-12L-cn`<br> `unified_transformer-12L-cn-luge` |
21+
|[DistilBERT](https://arxiv.org/abs/1910.01108) |DistilBertTokenizer|DistilBertModel<br>DistilBertForSequenceClassification<br>DistilBertForQuestionAnswering<br>DistilBertForTokenClassification<br>DistilBertForMaskedLM | `distilbert-base-uncased`<br>`distilbert-base-cased` |
22+
|[TinyBERT](https://arxiv.org/abs/1909.10351) |TinyBertTokenizer | TinyBertModel<br>TinyBertForPretraining<br>TinyBertForSequenceClassification | `tinybert-4l-312d`<br>`tinybert-6l-768d`<br>`tinybert-4l-312d-v2`<br>`tinybert-6l-768d-v2` |
2123
|[Transformer](https://arxiv.org/abs/1706.03762) |- | TransformerModel | - |
2224

2325
**NOTE**:其中中文的预训练模型有`albert-chinese-tiny, albert-chinese-small, albert-chinese-base, albert-chinese-large, albert-chinese-xlarge, albert-chinese-xxlarge, bert-base-chinese, bert-wwm-chinese, bert-wwm-ext-chinese, ernie-1.0, ernie-tiny, gpt-cpm-large-cn, roberta-wwm-ext, roberta-wwm-ext-large, rbt3, rbtl3, chinese-electra-base, chinese-electra-small, chinese-xlnet-base, chinese-xlnet-mid, chinese-xlnet-large, unified_transformer-12L-cn, unified_transformer-12L-cn-luge`
@@ -77,9 +79,9 @@ for input_ids, token_type_ids, labels in train_data_loader():
7779

7880
|任务|模型|应用场景|预训练权重|
7981
|---|---|---|---|
80-
|文本分类<br>SequenceClassification |AlbertForSequenceClassification <br> BertForSequenceClassification <br> ErnieForSequenceClassification <br> RobertaForSequenceClassification <br> ElectraForSequenceClassification <br> XLNetForSequenceClassification | [文本分类](../examples/text_classification/pretrained_models/)[阅读理解](../examples/machine_reading_comprehension/DuReader-yesno/)| [见上表](#Transformer预训练模型汇总)|
81-
|序列标注<br>TokenClassification|AlbertForTokenClassification <br> BertForTokenClassification <br> ErnieForTokenClassification <br> RobertaForTokenClassification <br> ElectraForTokenClassification <br> XLNetForTokenClassification | [命名实体标注](../examples/information_extraction/msra_ner/)|[见上表](#Transformer预训练模型汇总)|
82-
|问答任务<br>QuestionAnswering|AlbertForQuestionAnswering <br> BertForQuestionAnswering <br> ErnieForQuestionAnswering <br> RobertaForQuestionAnswering| [阅读理解](../examples/machine_reading_comprehension/SQuAD/)|[见上表](#Transformer预训练模型汇总)|
82+
|文本分类<br>SequenceClassification |AlbertForSequenceClassification <br> BertForSequenceClassification <br> ErnieForSequenceClassification <br> RobertaForSequenceClassification <br> ElectraForSequenceClassification <br> XLNetForSequenceClassification <br> DistilBertForSequenceClassification <br> TinyBertForSequenceClassification| [文本分类](../examples/text_classification/pretrained_models/)[阅读理解](../examples/machine_reading_comprehension/DuReader-yesno/)| [见上表](#Transformer预训练模型汇总)|
83+
|序列标注<br>TokenClassification|AlbertForTokenClassification <br> BertForTokenClassification <br> ErnieForTokenClassification <br> RobertaForTokenClassification <br> ElectraForTokenClassification <br> XLNetForTokenClassification <br> DistilBertForTokenClassification| [命名实体标注](../examples/information_extraction/msra_ner/)|[见上表](#Transformer预训练模型汇总)|
84+
|问答任务<br>QuestionAnswering|AlbertForQuestionAnswering <br> BertForQuestionAnswering <br> ErnieForQuestionAnswering <br> RobertaForQuestionAnswering <br> DistilBertForQuestionAnswering| [阅读理解](../examples/machine_reading_comprehension/SQuAD/)|[见上表](#Transformer预训练模型汇总)|
8385
|文本生成<br>TextGeneration | ErnieForGeneration <br> GPTForGreedyGeneration |[文本生成](../examples/text_generation/ernie-gen)|[见上表](#Transformer预训练模型汇总)|
8486
|机器翻译<br>MachineTranslation| TransformerModel | [机器翻译](../examples/machine_translation/transformer/)|[见上表](#Transformer预训练模型汇总)|
8587

examples/model_compression/distill_lstm/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
本实验使用GLUE中的SST-2、QQP以及中文情感分类数据集ChnSentiCorp中的训练集作为训练语料,用数据集中的验证集评估模型的效果。运行本目录下的实验,数据集会被自动下载到`paddlenlp.utils.env.DATA_HOME` 路径下,例如在linux系统下,例如对于GLUE中的QQP数据集,默认存储路径是`~/.paddlenlp/datasets/glue/QQP`,对于ChnSentiCorp数据集,则会下载到 `~/.paddlenlp/datasets/chnsenticorp`
3535

36-
对于BERT的fine-tuning任务,本实验中使用了预训练模型`bert-bas-uncased``bert-wwm-ext-chinese``bert-base-chinese`。同样,这几个模型在训练时会被自动下载到`paddlenlp.utils.env.DATA_HOME`路径下。例如,对于`bert-base-uncased`模型,在linux系统下,会被下载到`~/.paddlenlp/models/bert-base-uncased`下。
36+
对于BERT的fine-tuning任务,本实验中使用了预训练模型`bert-bas-uncased``bert-wwm-ext-chinese``bert-base-chinese`。同样,这几个模型在训练时会被自动下载到`paddlenlp.utils.env.MODEL_HOME`路径下。例如,对于`bert-base-uncased`模型,在linux系统下,会被下载到`~/.paddlenlp/models/bert-base-uncased`下。
3737

3838
在中文数据集上的小模型训练的输入利用jieba分词,其中词表同本repo下[文本分类项目](../../text_classification/rnn)的词表,可通过运行以下命令进行下载:
3939

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# TinyBERT: Distilling BERT for Natural Language Understanding
2+
以下是本例的简要目录结构及说明:
3+
```
4+
.
5+
├── task_distill.py # 在特定任务上下的蒸馏脚本
6+
├── data_augmentation.py # 离线数据增强脚本
7+
└── README.md # 文档,本文件
8+
```
9+
## 简介
10+
本目录下的实验主要参考论文[《TinyBERT: Distilling BERT for Natural Language Understanding》](https://arxiv.org/abs/1909.10351)实现。
11+
TinyBERT中蒸馏的整体过程:首先进行通用蒸馏,然后用数据增强后的数据,在特定任务上进行蒸馏,本文主要进行了第二阶段的蒸馏,模型是利用第一阶段得到的通用小模型`tinybert-6l-768d-v2`进行初始化。
12+
13+
<p align="center">
14+
<img src="./imgs/tinybert.png" width="950"/><br />
15+
TinyBERT蒸馏流程图
16+
</p>
17+
18+
19+
在模型蒸馏中,较大的模型(在本例中是BERT base)通常被称为教师模型,较小的模型(在本例中是层数为6的BERT,下文都称TinyBERT6)通常被称为学生模型。
20+
知识的蒸馏通常是通过让学生模型学习相关的蒸馏相损失函数实现,在本实验中,蒸馏的学习目标由两个部分组成,分别是中间层的蒸馏损失和预测层的蒸馏损失。其中,中间层的蒸馏包括对Embedding层的蒸馏、对每个Transformer layer输出的蒸馏、以及对每个Transformer中attention矩阵(softmax之前的结果)的蒸馏,三者均采用的是均方误差损失函数。而预测层蒸馏的学习目标则是学生模型输出的logits和教师模型输出的logits的交叉熵损失。
21+
22+
由于教师模型是12层,学生模型的层数少于教师模型的层数,因此需要选择一种layer mapping的方式。论文中采用了一种固定的映射方式,当学生模型的层数为教师模型的1/2时,学生第i层的attention矩阵,需要学习教师的第2i+1层的attention矩阵,Transformer layer输出同理。
23+
24+
实验分为两个大的训练过程:先对BERT-base进行微调,得到教师模型,再进行蒸馏的训练。其中,蒸馏过程也分为两个步骤:先对中间层进行蒸馏多个epochs(论文中针对具体任务可能是10、20或者30个),再对预测层蒸馏3个epochs。
25+
26+
需要注意的是,在使用不同教师模型时,`tinybert-6l-768d-v2``tinybert-4l-312d-v2`这两个v2版本的预训练模型中开放的从学生embedding输出、transformer中间层输出到教师相应输出的转换矩阵是每层独立的,而其他的`tinybert-6l-768d``tinybert-4l-312d``tinybert-6l-768d-zh``tinybert-4l-312-zh`则是多层之间的参数共用一个转换矩阵的。
27+
28+
## 数据、预训练模型介绍及获取
29+
30+
本实验使用GLUE中数据集中的训练集作为训练语料,用数据集中的验证集评估模型的效果。
31+
32+
运行本目录下的实验,数据集会被自动下载到`paddlenlp.utils.env.DATA_HOME` 路径下,例如在linux系统下,对于GLUE中的QQP数据集,默认存储路径是`~/.paddlenlp/datasets/Glue/QQP`
33+
34+
对于BERT的fine-tuning任务,本实验中使用了预训练模型`bert-base-uncased`。同样,这几个模型在训练时会被自动下载到`paddlenlp.utils.env.MODEL_HOME`路径下。例如,对于`bert-base-uncased`模型,在linux系统下,会被下载到`~/.paddlenlp/models/bert-base-uncased`下。
35+
36+
## 蒸馏实验过程
37+
38+
### 对BERT Fine-tuning得到教师模型
39+
以GLUE的SST-2任务为例,调用BERT fine-tune的训练脚本,配置如下的参数,训练SST-2任务:
40+
41+
```shell
42+
cd ../../benchmark/glue/
43+
export CUDA_VISIBLE_DEVICES=0
44+
export TASK_NAME=SST-2
45+
46+
python -u ./run_glue.py \
47+
--model_type bert \
48+
--model_name_or_path bert-base-uncased \
49+
--task_name $TASK_NAME \
50+
--max_seq_length 128 \
51+
--batch_size 32 \
52+
--learning_rate 2e-5 \
53+
--num_train_epochs 3 \
54+
--logging_steps 1 \
55+
--save_steps 500 \
56+
--output_dir ./tmp/$TASK_NAME/ \
57+
--n_gpu 1 \
58+
59+
```
60+
61+
训练完成之后,可将训练效果最好的模型保存在本项目下的`pretrained_models/$TASK_NAME/`下。模型目录下有`model_config.json`, `model_state.pdparams`, `tokenizer_config.json``vocab.txt`这几个文件。
62+
63+
64+
### 对TinyBERT在特定任务下蒸馏
65+
66+
先蒸馏中间层:
67+
68+
```shell
69+
export CUDA_VISIBLE_DEVICES=0
70+
export TASK_NAME=SST-2
71+
export TEACHER_DIR=../pretrained_models/SST-2/best_model_610
72+
73+
python task_distill.py \
74+
--model_type tinybert \
75+
--student_model_name_or_path tinybert-6l-768d-v2 \
76+
--task_name $TASK_NAME \
77+
--intermediate_distill \
78+
--max_seq_length 64 \
79+
--batch_size 32 \
80+
--T 1 \
81+
--teacher_model_type bert \
82+
--teacher_path $TEACHER_DIR \
83+
--learning_rate 5e-5 \
84+
--num_train_epochs 20 \
85+
--logging_steps 10 \
86+
--save_steps 10 \
87+
--output_dir ./tmp/$TASK_NAME/ \
88+
--device gpu
89+
90+
```
91+
92+
其中参数释义如下:
93+
94+
- `model_type` 学生模型类型,默认且目前仅支持tinybert。
95+
- `student_model_name_or_path` 中间层蒸馏后,学生模型存放的目录
96+
- `max_seq_length` 表示最大句子长度,超过该长度将被截断。默认:128
97+
- `T` softmax的温度,用于对softmax做平滑,在训练中起到放大负标签效果的作用。默认:1
98+
- `teacher_model_type` 教师模型的类型,默认且目前仅支持bert
99+
- `teacher_path` 教师Fine-tuned模型的目录
100+
- `output_dir` 学生模型存放的目录
101+
- `device` 表示运行该程序的设备,默认是gpu
102+
103+
然后对预测层进行蒸馏:
104+
105+
```shell
106+
107+
export TEACHER_DIR=../pretrained_models/SST-2/best_model_610
108+
109+
python task_distill.py \
110+
--model_type tinybert \
111+
--student_model_name_or_path tmp/TASK_NAME best_inter_model \
112+
--task_name $TASK_NAME \
113+
--max_seq_length 64 \
114+
--batch_size 32 \
115+
--T 1 \
116+
--teacher_model_type bert \
117+
--teacher_path $TEACHER_DIR \
118+
--learning_rate 3e-5 \
119+
--num_train_epochs 3 \
120+
--logging_steps 10 \
121+
--save_steps 10 \
122+
--output_dir ./tmp/$TASK_NAME/ \
123+
--device gpu
124+
125+
```
126+
其中参数释义如下:
127+
128+
- `student_model_name_or_path` 中间层蒸馏后,学生模型存放的目录
129+
其他参数说明同上。
130+
131+
### 实验中使用的超参数
132+
133+
| | SST-2 | QQP | MRPC | CoLA | RTE | MNLI | QNLI |
134+
| -------------------------------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- |
135+
| batch_size | 32 | 32 | 32 | 32 | 32 | 32 | 32 |
136+
| max_seq_length | 64 | 128 | 128 | 64 | 128 | 128 | 128 |
137+
| max_epochs_of_intermediate_layer | 20 | 10 | 20 | 50 | 20 | 10 | 10 |
138+
| max_epochs_of_prediction_layer | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
139+
| learning_rate(inter/pred) | 5e-5/3e-5 | 5e-5/3e-5 | 5e-5/3e-5 | 5e-5/3e-5 | 5e-5/3e-5 | 5e-5/3e-5 | 5e-5/3e-5 |
140+
141+
142+
143+
## 蒸馏实验结果
144+
145+
本文档的实验基于TinyBERT的6层、hidden_size为768的通用蒸馏得到的模型,用未使用数据增强的原始数据集训练,并基于验证集进行评价。得到以下实验结果:
146+
147+
148+
| | SST-2 | QQP(acc/f1) | MRPC(acc/f1) | CoLA | RTE | MNLI-m | MNLI-mm | QNLI |
149+
| ----------------- | ----- | ----------- | ------------ | ----- | ----- | ------ | ------- | ----- |
150+
| BERT-base | 93.00 | 90.58/87.35 | 88.23/91.67 | 59.56 | 73.65 | 84.42 | 84.83 | 91.78 |
151+
| TinyBERT(6l-768d) | 93.00 | 91.13/88.20 | 88.48/91.91 | 52.64 | 72.94 | 84.57 | 84.63 | 91.36 |
152+
153+
154+
155+
## 数据增强扩充训练集(推荐)
156+
157+
TinyBERT使用的数据增强需要用到BERT预训练模型和Glove Embeddings做词替换。
158+
159+
即对于样本中的词,有一定的概率会被近义词替换。对于single-piece的词,会利用BERT的预训练模型,把选中的词替换成mask token,然后返回模型预测的top k个概率最大的词,最后随机选择其中一个词做替换;对于非single-piece的词,则使用Glove Embedding,找到top k个最近似的词,随机选择一个做替换。
160+
161+
先下载glove embeddings
162+
163+
```
164+
wget http://nlp.stanford.edu/data/glove.6B.zip
165+
```
166+
167+
然后运行下面的命令对GLUE数据集进行扩展
168+
```
169+
export TASK_NAME=SST-2
170+
export GLOVE_EMB="glove/glove.6B.300d.txt"
171+
python data_augmentation.py --pretrained_bert_model bert-base-uncased \
172+
--glove_embs $GLOVE_EMB \
173+
--glue_dir /root/.paddlenlp/datasets/Glue/ \
174+
--task_name $TASK_NAME
175+
176+
```
177+
178+
运行结束后,在glue_dir/$TASK_NAME目录下,会生成`train_aug.tsv`的数据增强后的训练集文件。
179+
利用`task_distill.py`时,带上--use_aug这个参数,程序会读取`train_aug.tsv`作训练集进行训练。
180+
181+
经过实验,利用数据增强后的数据集,在RTE数据集上,Acc由0.7148提升至0.7184。
182+
183+
## 参考文献
184+
185+
Jiao X, Yin Y, Shang L, et al. [TinyBERT: Distilling BERT for Natural Language Understanding](https://arxiv.org/abs/1909.10351)[J]. arXiv preprint arXiv:1909.10351v5, 2020.

0 commit comments

Comments
 (0)