三次讲到了BERT。第一次是nlp中的经典深度学习模型(二),第二次是transformer & bert &GPT,这是第三次。
文章目录
- 1 关于预训练模型
- 1.1预训练概念
- 1.2 再谈语言模型
- 1.3 ELMo
- 1.4 GPT
- 2 BERT
- 2.1 BERT特点
- 2.2架构
- 2.3 预训练任务
- 2.3.1 masked language model
- 2.3.2 next sentence prediction
- 2.3.4 Subword
- 2.4 微调fine-tuning
- 3后记
1 关于预训练模型
1.1预训练概念
预训练模型最早用于CV领域。
深度学习模型就是一个y=fθ(x)y=f_{\theta}(x)y=fθ(x)查找最优θ\thetaθ的过程。如果参数θ\thetaθ初始值合适的话,会加快模型训练进度。
预训练就是在任务上优化参数,最后得出一套参数。这套参数可以作为下游任务的初始值。
为什么预训练模型可以提升模型的精度?
用一个例子来说明。厨师需要做很多种菜,例如:宫保鸡丁、鱼香肉丝、地三鲜。厨师可以每次对每个菜选择不同的原材料、加工,成菜。厨师也可以先把菜加工成半成品,例如煮好的鸡肉、胡萝卜丝、切好的土豆块。有了这些半成品,可以加快出菜速度。可以把预训练得到的参数理解为半成品。
1.2 再谈语言模型
语言模型就是 计算一个句子出现概率的模型。
P(x1,x2...xn)=P(x1)∗P(x2∣x1)∗P(x3∣x1,x2)...P(xn∣x1,x2,,,xn−1)P(x_1,x_2...x_n)= P(x_1)*P(x_2|x_1)*P(x_3|x_1,x_2)...P(x_n|x_1,x_2,,,x_{n-1})P(x1,x2...xn)=P(x1)∗P(x2∣x1)∗P(x3∣x1,x2)...P(xn∣x1,x2,,,xn−1)
各种算法,模型就是去无限逼近右边式子中的条件概率 。
使用语言模型做预训练,训练得到的参数,可以用于其他任务中。
1.3 ELMo
预训练在nlp中正式提出是在ELMo中。
ELMo是一个三层的网络结构:
- 字符CNN
- 一个正向语言模型
- 一个逆向语言模型
训练了一个正向和逆向的语言模型。
逆向语言模型是在计算:P(x1,x2,...xn)=P(xn)P(xn−1∣xn)P(xn−2∣xn,xn−1)...P(x1)P(x_1,x_2,...x_n)= P(x_n)P(x_{n-1}|x_n)P(x_{n-2}|x_n,x_{n-1})...P(x_1)P(x1,x2,...xn)=P(xn)P(xn−1∣xn)P(xn−2∣xn,xn−1)...P(x1)
1.4 GPT
GPT是使用transformer替换了ELMo中的LSTM。
训练了一个从左到右的语言模型任务。
GPT2和GPT3是使用了更多的参数,有些情况下layer normal放在了Attention之前。得到了更好的效果。
2 BERT
2.1 BERT特点
BERT: Bidirectional Encoder Representations from Transformers
bert相比较其他框架的优点是:
1 与GPT相比,GPT也使用了transformer,但GPT只训练了一个从左到右的模型。
2 与ELMo相比,ELMo使用的是LSTM,训练的是两个独立的从左到右,和从右到左两个模型。
3 bert是在无标注的数据集上做预训练,在每一层都包含左右的context信息。
4 应用于其他任务的时候只需要再加一层输出层即可。
5 应用于其他任务,不需要修改bert的架构。
2.2架构
横线表示了堆叠起来的transformer模型。
bert模型输入的是两个句子的拼接或者一个单独的句子。例如[CLS] my do is cute[SEP] he likes play ##ing[SEP]
bert模型的输入= token embedding + position embedding + segment embedding
token embedding:是经过wordpiece之后的一个一个token。
position embedding :表示不同的位置,要求就是不同位置用不同的数值表示即可。
segment embedding:表示两个句子。例如第一个句子用EAE_AEA表示,第二个句子用EBE_BEB表示。
bert模型的输出:表示[CLS]的隐状态C,表示第i个token隐状态的YiY_iYi。
bert有两个版本:
Bert-base:L=12(有12层),H=768(隐状态的大小是768),A=12(multi self Attention的head有12个)
Bert-base:L=24(有24层),H=1024(隐状态的大小是1024),A=16(multi self Attention的head有16个)
2.3 预训练任务
预训练任务有2个:masked language model 和 next sentence prediction。
预训练的数据集是BooksCorpus (800M words) 和 English Wikipedia (2,500M words)。
2.3.1 masked language model
bert想要训练一个深度的双向语言模型。所以设计了MLM任务。
不要预测下一个词,而是预测上下文。
问题:如何防止模型拷贝答案?
方法:masked。将数据集中15%的词标记为mask,模型去预测这些被mask的词。这样做的好处是在预测一个词的时候会同时用到这个词的左右的信息。这种方式可以更好的建模词左右的上下文信息。
问题:预训练阶段能看到mask标记,但是调优阶段是看不到这个标记的,这在一定程度上影响了准确率。
方法:不要总是标记为mask。在确定第i个位置是mask之后。1. 80%的概率标记为mask,2. 10%的概率保持不变,3. 10%的概率改为其他字符。
如果只有mask,对于其他词(被masked的词)不能学习到好的表达。
如果只有mask和其他字符,那就学不到正确的词。
如果只用mask和正确的词,那模型可能会只记住单词,不学习。
模型输出:被mask位置的词的上下文词向量,以及[CLS]位置的句子表示。
2.3.2 next sentence prediction
输入是句子对(A,B)
生成句子对A和B,50%的情况B是A真正的下一句,50%是随机选择的一个句子。
ps:后续实际中证明这个任务对下游任务并没有帮助。没有它,下游任务效果可能会更好。但是这个任务对于句子对分类任务是有帮助的。
在RoBera中抛弃了这个任务。
2.3.4 Subword
传统词表示不能解决未看到的词。
bert中使用的token方式是subword,使用BPE(Byte-Pair Encoding)的方式生成token。
e.g. subword = sub + word
学习方式:Byte Pair Encoding(BPE)
参考链接:https://zhuanlan.zhihu.com/p/86965595
https://huggingface.co/transformers/tokenizer_summary.html
在中文中直接以字进行训练就可以。
2.4 微调fine-tuning
nlp中所有的任务都是分类任务。
将bert模型应用于单个句子的分类中,使用CLS的隐状态参与分类得到分类标签。
3后记
今天早上一直不明白怎么用bert的输出作为下游的起始。一直在想它做预测的只是被mask的部分,那学到的词向量只是部分词向量呢?而且作为词向量应该是前面一些层的参数,不会是最后输出层。
后来听老师讲预训练模型训练才发现自己的思维被前面的词向量模型固定了。
预先训练模型,再使用有两种策略:feature-based 和 fine-tuning.
feature-based :skip-gram cbow ELmo都是这种策略。在一个语言模型的任务上训练,得到词向量表示。词向量用于下游任务。
fine-tuning: GPT、bert是这种策略。这种策略是预先训练一个模型。在下游任务的时候,在模型上面继续加层,实现目标。这个模型的整体架构不发生大的变化。在下游任务训练的时候,所有的参数都以预训练的的参数为基准。这就类似于CNN在图像分类上的预训练-微调模式一样。
在下游任务中可以固定前面的模型参数不变,也可以前面部分的参数一起参与训练。这个看效果而定。
所以bert被下游使用的是整个网络结构,以及所有结构中的参数。当然参与变化层运算的是最后一层的输出。
这类似于使用CNN的GoogleNet预训练,训练自己的图像分类器。只是修改最后一层输出分类的个数,就变成自己的模型了。