了解 Transformer 模型,并基于 Transformer 模型实现在机器翻译任务上的应用!
Transformer 介绍
基于循环或卷积神经网络的序列到序列建模方法是现存机器翻译任务中的经典方法。然而,它们在建模文本长程依赖方面都存在一定的局限性。
为了更好地描述文字序列,谷歌的研究人员在 2017 年提出了一种新的模型 Transformer
Transformer 视频讲解
它摒弃了循环结构,并完全通过注意力机制完成对源语言序列和目标语言序列全局依赖的建模。在抽取每个单词的上下文特征时,Transformer 通过自注意力机制(self-attention)衡量上下文中每一个单词对当前单词的重要程度
Transformer 的主要组件包括编码器 (Encoder)、解码器 (Decoder) 和注意力层。其核心是利用多头自注意力机制(Multi-Head Self-Attention)
// 关于 Transformer的20题
layer
- sublayer
- multi-head self-attention
- positionwise feed-forword network
嵌入表示层
输入文本序列,生成词向量 + 位置编码
为了得到不同位置对应的编码,Transformer 模型使用不同频率的正余弦函数如下所示
P
E
p
o
s
,
2
i
=
sin
(
p
i
s
/
1000
0
2
i
/
d
)
PE_{pos, 2i}=\sin(pis/10000^{2i/d})
PEpos,2i=sin(pis/100002i/d)
P
E
p
o
s
,
2
i
+
1
=
cos
(
p
i
s
/
1000
0
2
i
/
d
)
PE_{pos, 2i+1}=\cos(pis/10000^{2i/d})
PEpos,2i+1=cos(pis/100002i/d)
注意力层
**自注意力(Self-Attention)**操作是基于 Transformer 的机器翻译模型的基本操作,在源语言的编码和目标语言的生成中频繁地被使用以建模源语言、目标语言任意两个单词之间的依赖关系
给定由单词语义嵌入及其位置编码叠加得到的输入表示
{
x
i
∈
R
d
}
i
=
1
t
\{x_{i} \in R^{d}\}_{i=1}^{t}
{xi∈Rd}i=1t
为了实现对上下文语义依赖的建模,进一步引入在自注意力机制中涉及到的三个元素:查询
q
i
(
Q
u
e
r
y
)
q_{i}(Query)
qi(Query) ,键
k
i
(
K
e
y
)
k_{i}(Key)
ki(Key) ,值
v
i
(
V
a
l
u
e
)
v_{i}(Value)
vi(Value)
通过位置
i
i
i 查询向量与其他位置的键向量做点积得到匹配分数
q
i
⋅
k
1
,
q
i
⋅
k
2
,
.
.
.
,
q
i
⋅
k
t
q_{i}\cdot k_{1},q_{i}\cdot k_{2},...,q_{i}\cdot k_{t}
qi⋅k1,qi⋅k2,...,qi⋅kt
Z
=
A
t
t
e
n
t
i
o
n
(
Q
,
K
,
V
)
=
S
o
f
t
m
a
x
(
Q
K
T
d
)
V
Z=Attention(Q,K,V)=Softmax(\frac{QK^{T}}{\sqrt{d}})V
Z=Attention(Q,K,V)=Softmax(dQKT)V
其中
Q
∈
R
L
×
d
q
Q \in R^{L\times d_{q}}
Q∈RL×dq,
K
∈
R
L
×
d
k
K \in R^{L\times d_{k}}
K∈RL×dk,
V
∈
R
L
×
d
v
V \in R^{L\times d_{v}}
V∈RL×dv 分别表示输入序列中的不同单词的
q
,
k
,
v
q,k,v
q,k,v 向量拼接组成的矩阵,L 表示序列长度,
Z
∈
R
L
×
d
v
Z \in R^{L\times d_{v}}
Z∈RL×dv 表示自注意力操作的输出,
d
\sqrt{d}
d 表示稳定优化的放缩因子
//????
前馈层
前馈层接受自注意力子层的输出作为输入,并通过一个带有 Relu 激活函数的两层全连接网络对输入进行更加复杂的非线性变换
F
F
N
(
x
)
=
R
e
l
u
(
x
W
1
+
b
1
)
W
2
+
b
2
FFN(x)=Relu(xW_{1}+b_{1})W_{2}+b_{2}
FFN(x)=Relu(xW1+b1)W2+b2
其中
W
1
,
b
1
,
W
2
,
b
2
W_{1},b_{1},W_{2},b_{2}
W1,b1,W2,b2 表示前馈子层的参数。另外,以往的训练发现,增大前馈子层隐状态的维度有利于提升最终翻译结果的质量,因此,前馈子层隐状态的维度一般比自注意力子层要大。
//????
残差连接与层归一化
Transformer 结构组成的网络结构通常都是非常庞大而复杂,这就导致模型的训练比较困难。研究者们在 Transformer 块中进一步引入了残差连接与层归一化技术以进一步提升训练的稳定性。
具体来说,残差连接主要是指使用一条直连通道直接将对应子层的输入连接到输出上去,从而避免由于网络过深在优化过程中潜在的梯度消失问题
x
l
+
1
=
f
(
x
l
)
+
x
l
x^{l+1}=f(x^l)+x^l
xl+1=f(xl)+xl
其中
x
l
x^l
xl 表示第
l
l
l 层的输入,
f
(
⋅
)
f(\cdot)
f(⋅) 表示一个映射函数
此外,为了进一步使得每一层的输入输出范围稳定在一个合理的范围内,层归一化技术被进一步引入每个 Transformer 块的当中:
L N ( x ) = α ⋅ x − μ σ + b LN(x)=\alpha \cdot \frac{x-\mu}{\sigma} + b LN(x)=α⋅σx−μ+b
其中 μ \mu μ 和 σ \sigma σ 分别表示均值和方差,用于将数据平移缩放到均值为 0,方差为 1 的标准分布, a a a 和 b b b 是可学习的参数。层归一化技术可以有效地缓解优化过程中潜在的不稳定、收敛速度慢等问题。
编码器和解码器结构
相比于编码器端,解码器端要更复杂一些。具体来说,解码器的每个 Transformer 块的第一个自注意力子层额外增加了注意力掩码,对应图中的掩码多头注意力(Masked Multi-Head Attention)部分
在翻译的过程中,编码器端主要用于编码源语言序列的信息,而这个序列是完全已知的,因而编码器仅需要考虑如何融合上下文语义信息即可。而解码端则负责生成目标语言序列,这一生成过程是自回归的,即对于每一个单词的生成过程,仅有当前单词之前的目标语言序列是可以被观测的,因此这一额外增加的掩码是用来掩盖后续的文本信息,以防模型在训练阶段直接看到后续的文本序列进而无法得到有效地训练。
此外,解码器端还额外增加了一个多头注意力(Multi-Head Attention)模块,使用交叉注意力(Cross-attention)方法,同时接收来自编码器端的输出以及当前 Transformer 块的前一个掩码注意力层的输出
//????
基于 task2 的 baseline 修改代码
主要修改模型结构部分的代码:
# 位置编码
class PositionalEncoding(nn.Module):
def __init__(self, d_model, dropout=0.1, max_len=5000):
super(PositionalEncoding, self).__init__()
self.dropout = nn.Dropout(p=dropout)
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0).transpose(0, 1