借着公司项目相对没有那么忙的空档,梳理一下相关的文档,便于后续的回顾与学习。
BERT: Bidirectional Encoder Representation from Transformers
目录
有一种说法,NLP任务分成两部分,预训练产生词(字)向量和对词向量进行操作;体现在的bert中就是预训练网络作为产生词向量的网络,然后fine-tune就是对词向量操作(NLP的下游任务)
一、预训练网络
词向量模型:
词向量的进化史,是从word2vec—> ELMo ----> BERT的
a. word2vec
主要是高维转低维,也能发现向量间的关系,训练方式有CBOW与Skip-Gram这两种,CBOW是周围向量去推理中心向量,Skip-Gram则刚好相反,通过中心向量去推理周围向量;因为计算|V|的数据量比较大,可以采用负例采样的方式进行优化;也可以使用层次softmax进行优化;
优点:
<1>考虑了上下文的信息,是当时的SOTA;
<2>降维操作减少了计算量,速度更快;
缺点:
<1>词和向量是一对一的关系,无法解决一词多义;
<2>一种静态的表示,无法做动态优化,每次需要重新训练才行;
相关论文:
Efficient estimation of word representations in vector space
Distributed Representations of Words and Phrases and their Compositionality
b. ELMo
论文:
Deep contextualized word representations
为了解决词和向量是一对一,但是不能表达一词多义的问题,提出了ELMo(Embeddings from Language Models)的方法,使用了多层的双向网络.
前向网络:计算token的概率的公式:
p
(
t
1
,
t
2
,
…
,
t
N
)
=
∏
k
=
1
N
p
(
t
k
∣
t
1
,
t
2
,
…
,
t
k
−
1
)
p(t_1,t_2,\ldots,t_N) = \prod_{k=1}^{N}p(t_k|t_1,t_2,\ldots,t_{k-1})
p(t1,t2,…,tN)=k=1∏Np(tk∣t1,t2,…,tk−1)
定义
h
→
k
,
j
L
M
\overrightarrow {h}_{k,j}^{LM}
hk,jLM为的第j层LSTM前向网络的输出
后向网络:计算token的概率公式:
p
(
t
1
,
t
2
,
…
,
t
N
)
=
∏
k
=
1
N
p
(
t
k
∣
t
k
+
1
,
t
k
+
2
,
…
,
t
N
)
p(t_1,t_2,\ldots,t_N) = \prod_{k=1}^{N}p(t_k|t_{k+1},t_{k+2},\ldots,t_N)
p(t1,t2,…,tN)=k=1∏Np(tk∣tk+1,tk+2,…,tN)
定义
h
←
k
,
j
L
M
\overleftarrow {h}_{k,j}^{LM}
hk,jLM为的第j层LSTM后向网络的输出
最大似然函数:
∑
k
=
1
N
(
log
p
(
t
k
∣
t
1
,
t
2
,
…
,
t
k
−
1
;
Θ
x
,
Θ
→
L
S
T
M
,
Θ
s
)
+
log
p
(
t
k
∣
t
k
+
1
,
t
k
+
2
,
…
,
t
N
)
;
Θ
x
,
Θ
←
L
S
T
M
,
Θ
s
)
)
\sum_{k=1}^{N}(\log p(t_k|t_1,t_2,\ldots,t_{k-1};\Theta_x, \overrightarrow {\Theta}_{LSTM},\Theta_s) + \log p(t_k|t_{k+1},t_{k+2},\ldots,t_N);\Theta_x, \overleftarrow {\Theta}_{LSTM},\Theta_s))
k=1∑N(logp(tk∣t1,t2,…,tk−1;Θx,ΘLSTM,Θs)+logp(tk∣tk+1,tk+2,…,tN);Θx,ΘLSTM,Θs))
ELMo中对word representations采用LSTM网络层的的两个输出加上原始的输入作为它的表示,对于一个为L层的bi-LSTM,那么对应word representations的构成集合有2L+1个,即:
R
k
=
{
X
k
L
M
,
h
→
k
,
j
L
M
,
h
←
k
,
j
L
M
∣
j
=
1
,
…
,
L
}
R_k = \{X_k^{LM}, \overrightarrow h_{k,j}^{LM}, \overleftarrow h_{k,j}^{LM} | j= 1,\ldots,L\}
Rk={XkLM,hk,jLM,hk,jLM∣j=1,…,L}
R
k
=
{
h
k
,
j
L
M
∣
j
=
0
,
…
,
L
}
R_k = \{h_{k,j}^{LM} | j= 0,\ldots,L\}
Rk={hk,jLM∣j=0,…,L}
最终计算ELMo的定义如下
E
L
M
o
k
t
a
s
k
=
E
(
R
k
;
Θ
t
a
s
k
)
=
γ
t
a
s
k
∑
j
=
0
L
s
j
t
a
s
k
h
k
,
j
L
M
ELMo_k^{task} = E(R_k;\Theta ^{task}) = \gamma^{task}\sum_{j=0}^{L}s_j^{task}h_{k,j}^{LM}
ELMoktask=E(Rk;Θtask)=γtaskj=0∑Lsjtaskhk,jLM
输入向量,可以使用word2vec,也可以使用CNN-BIG-LSTM
ELMo分为两个阶段,第一个阶段是利用语言模型做预训练,第二个阶段是做下游任务(是不是有点像bert的雏形了),词向量模型就是第一个阶段。
c. BERT
论文:
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
Attention Is All You Need
第一篇论文是BERT,第二篇论文是Transformer
transformer的网络结构图如下:
然后bert主要用到了它的左侧即inputs测,也叫作transformer的encode。
BERT的预训练网络结构是:
从上图可以看出输入进入到Input Embedding层,然后进入一个多层的重复网络,Embedding层输出进入Multi-Head Attention层,然后经过一个residual-network的正则化,再进入一个前馈网络(Feed-Forward),最后进行一个residual-network的正则化作为下一层的输出;
input embedding层
包括三个embedding,分别对应字的embed,段落的embed,位置的embed,字的embed是根据词表的大小映射的,段落的embed是因为bert后续有NSP的任务,所以有句子的embed,位置的embed主要是针对模型对位置不敏感所添加的特定信息;位置信息使用正余弦函数,因为三角函数的关系,f(pos+k)可以用f(pos)和f(k)来表示,使用的公式是:
f
(
p
o
s
,
2
i
)
=
s
i
n
(
p
o
s
/
1000
0
2
i
/
d
m
o
d
e
l
)
f(pos, 2i) = sin(pos/10000^{2i/d_{model}})
f(pos,2i)=sin(pos/100002i/dmodel)
f
(
p
o
s
,
2
i
+
1
)
=
c
o
s
(
p
o
s
/
1000
0
(
2
i
+
1
)
/
d
m
o
d
e
l
)
f(pos, 2i+1) = cos(pos/10000^{(2i+1)/d_{model}})
f(pos,2i+1)=cos(pos/10000(2i+1)/dmodel)
Multi-Head Attention层
模型的结构图如下:
Q,K,V分别代表query,key,value,对应的解释是注意力模型引入的3个值,通过计算找出相对应的关系;假设是翻译模型,原文是“我是中国人”,然后译文是“I am chinese”,对于此类型,在解码器解码为I时,此时的query为“I”, key为“我是中国人”,value是注意力计算的解码概率矩阵(即context vector或者通过计算生成context vector),对于bert中的Q,K,V都是输入向量自己本身,也叫作自注意力模型; 然后三个矩阵进入Scaled-Dot-Product Attention中,那么先把Scaled-Dot-Product Attention层介绍完成后,再来对Multi-Head Attentio层进行总结。
推荐一个关于注意力模型的解释:
深度学习中的注意力模型(2017版)
Scaled Dot-Product Attention
上图说明Q与K进行乘法计算,然后对计算的记过进行scale(缩放),对缩放的结果与mask相乘(去除输入语句中相对应的padding),然后进行softmax,得到注意力矩阵,与value进行相乘得到Scaled Dot-Product Attention的输出。
dot-product attention相比较additive attention的优势是计算速度更快一些, 但是对于
d
k
d_k
dk的值比较大时,对于dot-product attention效果不好,所以要进行scaled(缩放,这边是指进行除以参数缩小),原因见为什么 dot-product attention 需要被 scaled?
回到Multi-Head Attention层,进入scaled dot-product的Q,K,V是经过处理的,例如Q的size对应为(batch_size, seq_len, hidden_size),在Multi-Head Attention层设置的层为num_head层,那么Q将变化为(batch_size, num_head, seq_len,hidden_size)(先做分割,然后transpose),那么就要求hidden_size一定要能被num_head整除,即hidden_size%num_head==0,使用多头的原因是能富含比较丰富的语言、语法信息,然后经过将num_head层进行组合起来,经过一个线性层得到多头注意力模型的输出。
add&Norm层
相当于是一个残差网络,对multi-head attention层的输出是进行了残差网络和归一化,归一化的目的是在网络层上面的数据尽量对应输入数据的分布,残差网络的目的是为了预防梯度消失或者梯度爆炸。
Feed Forward层
全连接层的公式比较简单,就是进入了两个全连接层,然后max函数相当于试用的激活函数是ReLU:
F
F
N
(
x
)
=
max
(
0
,
x
W
1
+
b
1
)
W
2
+
b
2
FFN(x) = \max(0, xW_1 + b_1)W_2 + b_2
FFN(x)=max(0,xW1+b1)W2+b2
论文中描述的FFN的作用如下图,但是我没看明白,也没找到辅助的文章让我理解和证明这句话的具体含义,姑且认为是对每个位置进行区别和统一。(捉急的英文理解)还有就是第一个全连接层将最后一维特征转化为4*hidden_size大小,第二个连接层再将最后一维特征转化为hidden_size。
整体bert的网络结构就介绍到这边,然后就把bert任务的相关介绍简单描述一下吧:
二、NLP的下游任务
在词向量输出的基础上做下游任务,包括很多相关的任务,类似于文本分类,QA问答,情感分析等等;这边内容很多,就后续一步一步补充吧
1. BERT的预训练任务
bert的预训练任务包括两个任务,一个MaskLM,另一个是NSP。
Masked LM
在MaskLM中,输入的是一个句子,然后每个字都有15%的概率被选中用作mask任务;被选中的字有80%的概率被标记为[MASK],10%的概率被标记为它本身,10%的概率被标记为随机词,目的是为了增加扰动,不要过分依赖于[MASK]。
然后选中概率为什么是15%?
因为1/0.15≈7,比较符合CBOW或者Skip-gram的窗口大小设置,所以这就是15%的原因。一般我们选用是10%-20%相对比较合理。
NSP
NSP的全称是next sentence predict,对下一个句子的预测;在NSP中,输入是两个句子,使用token_type_id做区分,代表不同的两个句子,样例的生成是当前句子,后面跟随的,有50%的概率是它的下一句,50%的概率是任意一句其它的随机语句,使用的是最后一层[CLS] 进行二分类输出。
2. 分类任务
一般输入和预训练任务的输入基本一致,然后模型中 最后一层[CLS] 进行二分类作为输出。
为什么使用cls作为作为分类任务的输出?
因为cls不携带字词的信息,对于语句而言最为公平,且研究者发现cls携带的语言语义信息在句子中也是最丰富的。
关于其它的任务,序列标注,QA等等之类的后续再补充吧,下一篇简单的介绍一下bert的源码,就这样了,水平有限,有错误的地方,希望大家指出,帮我进步,3q!