详解谷歌机器翻译模型:Transformer
1. 模型框/架
Transformer 是谷歌提出的机器翻译模型。其包括了一个编码器Encoder和Decoder,这是一个翻译的模型,将源语言input进编码器,然后通过解码器输出模型 。可以表示为如下
输入编码器是一系列的编码器的集合,这个编码器是,论文中包括了六个编码器(六个并没有特殊的要求),同样,解码器就是也是由六个编码器堆叠而成的如图2。
六个编码器都是一样的结构(尽管他们并不共享权重),每一个都可以分解为如下的两个子层,即子注意力。
输入首先经过一个Self-Attention层作为输入,这一层在编码一个句子中指定的单词的时候可以帮助观察到其他的单词,输出。
Self-Attention的输出被送入前馈神经网络,并且一个句子的每个单词在送入前馈神经网络中都是独立的,不会交叉输入。
解码器也有这些层,但是在自注意层和前馈层还有一个Encoder-Decoder Attention 层,并且在堆叠的这些编码器的顶部通往每一个,堆叠的解码器中的每一个Encoder-Decoder Attention 层。
2. 具体的步骤
2.1 Embedding algorithm
一般都会把每一个单词使用embedding algorithm编码成一个向量,这种编码发生在编码器最底部的输入之前。如下是把其编码成了512个维度:
在上图我们可以看到一个句子的输入会在自己对应的位置开始输入,一般会设置一个输入的最长的长度如N=1000即每次最多能输入和翻译1000个单词。
2.2 使用单词进行具体说明
对于下面这句话:
The animal didn't cross the street because it was too tired. 中的 it 指的是什么,自注意力就可以把它和 animal 相关联。
2.3 三个向量的细节
step 1 后面的计算position都以为标准
第一步是根据每一个输入的向量中计算出三个向量: , 这些向量通过原始输入乘法上三个矩阵(在训练中学习到的)生成。注意到这些新的的维度要比原始的输入的维度小很多,只有64(假设)。
step 2
第二步是计算一个 ,按照比如第一个单词:
step3
把这些,从而获得更为稳定的梯度。然后使用Softmax进行概率的计算。来得到每一个单词的在这个位置(position)的占比或重要程度。
接着把每一个进行加权求和(权重为),来得到这一位置的最后输出向量。
2.4 向量化表示,三个向量的矩阵话运算表示
可以从上图看出,输入的横向量堆砌而成的矩阵,经过和三个变换矩阵的乘积然后得到
这三个矩阵,然后经过一系列运算得到最终的
2.5 Multi-Headed
我们希望能够生成多组 从而更好的提升模型的表达效果
对于生成的各组z我们也会通过增广矩阵的形式并乘上一个权重矩阵从而得到最后的 ,如下图所示
2.6 位置编码 Positional Encoding
这里方法用到的理念:把这些只跟位置相关的值加入到后,把他们投影到后就可以在过程中提供有效的距离。
原文提出了两种方式:一种是训练出一个位置编码,第二种是用原文使用的三角函数编码的方式,其具体公式如下:
# 具体的编码代码实现,可以了解一下
class PositionalEncoding(nn.Module):
"Implement the PE function."
def __init__(self, d_model, dropout, max_len=5000):
super(PositionalEncoding, self).__init__()
self.dropout = nn.Dropout(p=dropout)
(
# Compute the positional encodings once in log space.
pe = torch.zeros(max_len, d_model) # (max_words_nums,d_model)维度矩阵
position = torch.arange(0, max_len).unsqueeze(1) # 生成一个[0,1...max_len-1]的列向量,维度为(max_len,1)
div_term = torch.exp(torch.arange(0, d_model, 2) *
-(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)
self.register_buffer('pe', pe) #使用这个函数 是为了不放入模型的self.parameters(),而是注册一个缓冲区进行保存
def forward(self, x):
x = x + Variable(self.pe[:, :x.size(1)],
requires_grad=False)
return self.dropout(x)
2.7 残差块
在Encoder之间会有残差连接,具体可以如下:由上图可以看出残差连接会从下面的一个Self-Attention的输入连接到Self-Attention的输出进行操作,具体如下图所示:
同时解码器也有同样的结构,具体的可以用下图来表示:
2.8 解码器工作
编码器以处理输入序列作为开始,最顶端的编码器输出的会送入解码器的每一个层,从而能让解码器注意到适当的位置。
由上图可以看出,解码器的工作方式和编码器有些不同,解码器每一步输出一个元素,并重复这个过程直到输出一个特定的符号来表示一个翻译的结尾。,每一步的输出在下一次运算时被送入底部的解码器,并且项编码器一样被加入了位置信息。
Decoder中的Self-Attention层和Decoder中的有一些的区别,在Decoder中,self-attention layer 仅仅能访问之前输出的Output,这是通过在self-attenion 计算过程中Softmax步骤之前就把后面的位置填充为符号来实现的。
2.9 最后的Linear 和Softmax Layer
解码器把输出堆叠为浮点型向量,这个向量通过Linear层后跟Softmax layer 来实现的。通过Softmax layer算的对数概率,最后输出概率最大的那个单词。
3. 训练的一些细节
在训练过程中,可以把标注和输出进行监督学习.为了可视化这个过程,假设输出词汇仅包含六个单词(“a”, “am”, “i”, “thanks”, “student”, and “<eos>(eos是句子的结束符号)” ).
没有训练的输出可以比较杂乱无章, 他们之间的就可以用一些交叉熵和KL散度等其他的方式来计算.
在经历过多次的迭代优化后,可以让其在对应的位置达到很高的概率.
4.
- 读 Attention Is All You Need 这一篇论文, the Transformer blog post (Transformer: A Novel Neural Network Architecture for Language Understanding), and the Tensor2Tensor announcement.
- 观看 Łukasz Kaiser’s talk 从而获得模型和细节
- 实战操作 Jupyter Notebook provided as part of the Tensor2Tensor repo
- 探索 Tensor2Tensor repo.
后续的一些工作:
- Depthwise Separable Convolutions for Neural Machine Translation
- One Model To Learn Them All
- Discrete Autoencoders for Sequence Models
- Generating Wikipedia by Summarizing Long Sequences
- Image Transformer
- Training Tips for the Transformer Model
- Self-Attention with Relative Position Representations
- Fast Decoding in Sequence Models using Discrete Latent Variables
- Adafactor: Adaptive Learning Rates with Sublinear Memory Cost