transformer 订阅
TRANSFORMER,作词:Kenzie(韩文),T-Crash(中文),作曲: Kenzie / Jonathan Yip /Jonathan Yip / Ray Romulus / Ray McCullough,演唱:EXO。 展开全文
TRANSFORMER,作词:Kenzie(韩文),T-Crash(中文),作曲: Kenzie / Jonathan Yip /Jonathan Yip / Ray Romulus / Ray McCullough,演唱:EXO。
信息
歌曲时长
3分47秒
歌曲原唱
EXO
中文名称
变形女
发行时间
2015年3月30日
谱    曲
Kenzie,Jonathan Yip,Jonathan Yip,Ray Romulus,Ray McCullough
外文名称
TRANSFORMER
所属专辑
EXODUS\LOVE ME RIGHT
歌曲语言
韩语,中文
填    词
Kenzie(韩文),T-Crash(中文)
TRANSFORMER基本信息
歌名:TRANSFORMER作词:Kenzie(韩文)T-Crash(中文)作曲: Kenzie / Jonathan Yip /Jonathan Yip / Ray Romulus / Ray McCullough演唱:EXO
收起全文
精华内容
下载资源
问答
  • Transformer

    2021-01-06 14:16:54
    Transformer 在之前的章节中,我们已经介绍了主流的神经网络架构如卷积神经网络(CNNs)和循环神经网络(RNNs)。让我们进行一些回顾: CNNs 易于并行化,却不适合捕捉变长序列内的依赖关系。 RNNs 适合捕捉长距离...
  • transformer

    2021-02-25 14:55:22
    Transformertransformer模型结构:attention机制ref3transformer总结李宏毅课程 参考资料: 1 模型原理详解:https://zhuanlan.zhihu.com/p/44121378 2 attention机制:https://zhuanlan.zhihu.com/p/43493999 3 详解...


    参考资料:

    1 模型原理详解:https://zhuanlan.zhihu.com/p/44121378
    2 attention机制:https://zhuanlan.zhihu.com/p/43493999
    3 详解transformer子结构的计算方式:https://zhuanlan.zhihu.com/p/59629215
    4 算法流程:https://baijiahao.baidu.com/s?id=1651219987457222196&wfr=spider&for=pc
    5 李宏毅课程PPT:https://blog.csdn.net/frank_ljiang/article/details/104382282
    课程:https://www.bilibili.com/video/BV1J441137V6?from=search&seid=16273963478069518947
    6 transformer在计算机视觉的应用:http://www.360doc.com/content/21/0116/16/32196507_957302113.shtml

    前景:https://www.thepaper.cn/newsDetail_forward_10820015

    文章:《Attention is all you need》

    学习过程:
    先学ref5李宏毅的课程,了解基础
    通过ref2简单了解attention和rcnn的机制
    ref1对模型(网络结构)进行了简介
    ref3对子结构有详细的描述,偏学术
    ref4详细地说明了算法流程,易懂

    transformer模型结构:

    在这里插入图片描述

    attention机制

    在这里插入图片描述

    在这里插入图片描述
    其中h 是编码器每个step的输出,z是解码器每个step的输出,计算步骤是这样的:
    先对输入进行编码,得到h
    开始解码了,先用固定的start token也就是 z最为Q,去和每个h (同时作为K和V)去计算attention,得到加权的c
    用c作为解码的RNN输入(同时还有上一步的z),得到 z并预测出第一个词是machine
    再继续预测的话,就是用 z作为Q去求attention:
    在这里插入图片描述

    ref3

    selfattention计算过程
    多头注意力机制
    使用位置编码表示序列顺序
    残差连接
    解码器
    linear层和softmax层

    transformer总结

    Transformer 与 RNN 不同,可以比较好地并行训练。

    Transformer 本身是不能利用单词的顺序信息的,因此需要在输入中添加位置 Embedding,否则 Transformer 就是一个词袋模型了。

    Transformer 的重点是 Self-Attention 结构,其中用到的 Q, K, V矩阵通过输出进行线性变换得到。

    Transformer 中 Multi-Head Attention 中有多个 Self-Attention,可以捕获单词之间多种维度上的相关系数 attention score。

    transformer在计算机视觉中是靠CNN提取特征,它完成目标检测和分割的任务

    李宏毅课程

    RNN无法被平行化,而CNN的视野有限
    self_attention 通过q,k,v习得相互关系、语序等,得到预测结果
    self_attention主要解决平行化和加速的问题
    不同head关注点不同
    注意区分layer norm和batch norm的区别

    目前存在的疑问:
    qkb怎算出来?

    前景:
    CNN用于提取特征,transformer完成推理并生成预测
    目前主要是将用于NLP的transformer结构套在视觉任务上

    展开全文
  • 图解Transformer

    万次阅读 多人点赞 2018-12-12 17:04:46
    原文标题:The Illustrated Transformer 原文链接:https://jalammar.github.io/illustrated-transformer/ 论文地址:https://arxiv.org/abs/1706.03762 前言 Transformer在Goole的一篇论文Attention is All ...

    原文标题:The Illustrated Transformer

    原文链接:https://jalammar.github.io/illustrated-transformer/

    论文地址:https://arxiv.org/abs/1706.03762


    前言

         Transformer在Goole的一篇论文Attention is All You Need被提出,为了方便实现调用Transformer Google还开源了一个第三方库,基于TensorFlow的Tensor2Tensor,一个NLP的社区研究者贡献了一个Torch版本的支持:guide annotating the paper with PyTorch implementation。这里,我想用一些方便理解的方式来一步一步解释Transformer的训练过程,这样即便你没有很深的深度学习知识你也能大概明白其中的原理。

    A High-Level Look

           我们先把Transformer想象成一个黑匣子,在机器翻译的领域中,这个黑匣子的功能就是输入一种语言然后将它翻译成其他语言。如下图:

    掀起The Transformer的盖头,我们看到在这个黑匣子由2个部分组成,一个Encoders和一个Decoders。

    我们再对这个黑匣子进一步的剖析,发现每个Encoders中分别由6个Encoder组成(论文中是这样配置的)。而每个Decoders中同样也是由6个Decoder组成。

    对于Encoders中的每一个Encoder,他们结构都是相同的,但是并不会共享权值。每层Encoder有2个部分组成,如下图: 

    每个Encoder的输入首先会通过一个self-attention层,通过self-attention层帮助Endcoder在编码单词的过程中查看输入序列中的其他单词。如果你不清楚这里在说什么,不用着急,之后我们会详细介绍self-attention的。

    Self-attention的输出会被传入一个全连接的前馈神经网络,每个encoder的前馈神经网络参数个数都是相同的,但是他们的作用是独立的。

    每个Decoder也同样具有这样的层级结构,但是在这之间有一个Attention层,帮助Decoder专注于与输入句子中对应的那个单词(类似与seq2seq models的结构)

    Bringing The Tensors Into The Picture

          在上一节,我们介绍了Transformer的网络结构。现在我们以图示的方式来研究Transformer模型中各种张量/向量,观察从输入到输出的过程中这些数据在各个网络结构中的流动。

          首先还是NLP的常规做法,先做一个词嵌入:什么是文本的词嵌入?

          我们将每个单词编码为一个512维度的向量,我们用上面这张简短的图形来表示这些向量。词嵌入的过程只发生在最底层的Encoder。但是对于所有的Encoder来说,你都可以按下图来理解。输入(一个向量的列表,每个向量的维度为512维,在最底层Encoder作用是词嵌入,其他层就是其前一层的output)。另外这个列表的大小和词向量维度的大小都是可以设置的超参数。一般情况下,它是我们训练数据集中最长的句子的长度。

         上图其实介绍到了一个Transformer的关键点。你注意观察,在每个单词进入Self-Attention层后都会有一个对应的输出。Self-Attention层中的输入和输出是存在依赖关系的,而前馈层则没有依赖,所以在前馈层,我们可以用到并行化来提升速率。

        下面我用一个简短的句子作为例子,来一步一步推导transformer每个子层的数据流动过程。

    Now We’re Encoding!

           正如之前所说,Transformer中的每个Encoder接收一个512维度的向量的列表作为输入,然后将这些向量传递到‘self-attention’层,self-attention层产生一个等量512维向量列表,然后进入前馈神经网络,前馈神经网络的输出也为一个512维度的列表,然后将输出向上传递到下一个encoder。

         如上图所示,每个位置的单词首先会经过一个self attention层,然后每个单词都通过一个独立的前馈神经网络(这些神经网络结构完全相同)。

    Self-Attention at a High Level

          Self attention这个单词看起来好像每个人都知道是什么意思,但实质上他是算法领域中新出的概念,你可以通过阅读:Attention is All You Need 来理解self attention的原理。

          假设下面的句子就是我们需要翻译的输入句:

    The animal didn't cross the street because it was too tired

          这句话中的"it"指的是什么?它指的是“animal”还是“street”?对于人来说,这其实是一个很简单的问题,但是对于一个算法来说,处理这个问题其实并不容易。self attention的出现就是为了解决这个问题,通过self attention,我们能将“it”与“animal”联系起来。

          当模型处理单词的时候,self attention层可以通过当前单词去查看其输入序列中的其他单词,以此来寻找编码这个单词更好的线索。

          如果你熟悉RNNs,那么你可以回想一下,RNN是怎么处理先前单词(向量)与当前单词(向量)的关系的?RNN是怎么计算他的hidden state的。self-attention正是transformer中设计的一种通过其上下文来理解当前词的一种办法。你会很容易发现...相较于RNNs,transformer具有更好的并行性。

    如上图,是我们第五层Encoder针对单词'it'的图示,可以发现,我们的Encoder在编码单词‘it’时,部分注意力机制集中在了‘animl’上,这部分的注意力会通过权值传递的方式影响到'it'的编码。

    更多细节可以查看 Tensor2Tensor notebook 

    Self-Attention in Detail

        这一节我们先介绍如何用向量的方式来计算self attention,然后再来看看它是如何使用矩阵来实现的。

         计算self attention的第一步是从每个Encoder的输入向量上创建3个向量(在这个情况下,对每个单词做词嵌入)。所以,对于每个单词,我们创建一个Query向量,一个Key向量和一个Value向量。这些向量是通过词嵌入乘以我们训练过程中创建的3个训练矩阵而产生的。

         注意这些新向量的维度比嵌入向量小。我们知道嵌入向量的维度为512,而这里的新向量的维度只有64维。新向量并不是必须小一些,这是网络架构上的选择使得Multi-Headed Attention(大部分)的计算不变。

    我们将X_{1}乘以W^{Q}的权重矩阵得到新向量q_{1}q_{1}既是“query”的向量。同理,最终我们可以对输入句子的每个单词创建“query”,
    “key”,“value”的新向量表示形式。

    对了..“query”,“key”,“value”是什么向量呢?有什么用呢?

    这些向量的概念是很抽象,但是它确实有助于计算注意力。不过先不用纠结去理解它,后面的的内容,会帮助你理解的。

          计算self attention的第二步是计算得分。以上图为例,假设我们在计算第一个单词“thinking”的self attention。我们需要根据这个单词对输入句子的每个单词进行评分。当我们在某个位置编码单词时,分数决定了对输入句子的其他单词的关照程度。

           通过将query向量和key向量点击来对相应的单词打分。所以,如果我们处理开始位置的的self attention,则第一个分数为q_{1}k_{1}的点积,第二个分数为q_{2}k_{2}的点积。如下图

    第三步和第四步的计算,是将第二部的得分除以8\sqrt{d_{k}})(论文中使用key向量的维度是64维,其平方根=8,这样可以使得训练过程中具有更稳定的梯度。这个\sqrt{d_{k}}并不是唯一值,经验所得)。然后再将得到的输出通过softmax函数标准化,使得最后的列表和为1。

    这个softmax的分数决定了当前单词在每个句子中每个单词位置的表示程度。很明显,当前单词对应句子中此单词所在位置的softmax的分数最高,但是,有时候attention机制也能关注到此单词外的其他单词,这很有用。

    第五步是将每个Value向量乘以softmax后的得分。这里实际上的意义在于保存对当前词的关注度不变的情况下,降低对不相关词的关注。

    第六步是 累加加权值的向量。 这会在此位置产生self-attention层的输出(对于第一个单词)。

    总结self-attention的计算过程,(单词级别)就是得到一个我们可以放到前馈神经网络的矢量。 然而在实际的实现过程中,该计算会以矩阵的形式完成,以便更快地处理。下面我们来看看Self-Attention的矩阵计算方式。

    Matrix Calculation of Self-Attention

    第一步是去计算Query,Key和Value矩阵。我们将词嵌入转化成矩阵X中,并将其乘以我们训练的权值矩阵(W^{Q},W^{K},W^{V}

    X矩阵中的每一行对应于输入句子中的一个单词。 我们看到的X每一行的方框数实际上是词嵌入的维度,图中所示的和论文中是有差距的。X(图中的4个方框论文中为512个)和q / k / v向量(图中的3个方框论文中为64个)

    最后,由于我们正在处理矩阵,我们可以在一个公式中浓缩前面步骤2到6来计算self attention层的输出。

     

    The Beast With Many Heads

    本文通过使用“Multi-headed”的机制来进一步完善self attention层。“Multi-headed”主要通过下面2中方式改善了attention层的性能:

    1. 它拓展了模型关注不同位置的能力。在上面例子中可以看出,The animal didn't cross the street because it was too tired,我们的attention机制计算出“it”指代的为“animal”,这在对语言的理解过程中是很有用的。

    2.它为attention层提供了多个“representation subspaces”。由下图可以看到,在self attention中,我们有多个个Query / Key / Value权重矩阵(Transformer使用8个attention heads)。这些集合中的每个矩阵都是随机初始化生成的。然后通过训练,用于将词嵌入(或者来自较低Encoder/Decoder的矢量)投影到不同的“representation subspaces(表示子空间)”中。

        通过multi-headed attention,我们为每个“header”都独立维护一套Q/K/V的权值矩阵。然后我们还是如之前单词级别的计算过程一样处理这些数据。

        如果对上面的例子做同样的self attention计算,而因为我们有8头attention,所以我们会在八个时间点去计算这些不同的权值矩阵,但最后结束时,我们会得到8个不同的Z矩阵。如下图:

        瞧瞧,这会给我们后续工作造成什么问题?

        我们知道在self-attention后面紧跟着的是前馈神经网络,而前馈神经网络接受的是单个矩阵向量,而不是8个矩阵。所以我们需要一种办法,把这8个矩阵压缩成一个矩阵

        我们怎么做? 

       我们将这8个矩阵连接在一起然后再与一个矩阵W^{O}相乘。步骤如下图所示:

    这样multi-headed self attention的全部内容就介绍完了。之前可能都是一些过程的图解,现在我将这些过程连接在一起,用一个整体的框图来表示一下计算的过程,希望可以加深理解。

          现在我们已经触及了attentionheader,让我们重新审视我们之前的例子,看看例句中的“it”这个单词在不同的attention header情况下会有怎样不同的关注点。

          如图:当我们对“it”这个词进行编码时,一个注意力的焦点主要集中在“animal”上,而另一个注意力集中在“tired” 

    但是,如果我们将所有注意力添加到图片中,那么事情可能更难理解:

     

    Representing The Order of The Sequence Using Positional Encoding

    # 使用位置编码表示序列的顺序

    我们可能忽略了去介绍一个重要的内容,就是怎么考虑输入序列中单词顺序的方法。

    为了解决这个问题,transformer为每个输入单词的词嵌入上添加了一个新向量-位置向量。

    为了解决这个问题,变换器为每个输入嵌入添加了一个向量。这些位置编码向量有固定的生成方式,所以获取他们是很方便的,但是这些信息确是很有用的,他们能捕捉大奥每个单词的位置,或者序列中不同单词之间的距离。将这些信息也添加到词嵌入中,然后与Q/K/V向量点击,获得的attention就有了距离的信息了。

    为了让模型捕捉到单词的顺序信息,我们添加位置编码向量信息(POSITIONAL ENCODING)-位置编码向量不需要训练,它有一个规则的产生方式。

    如果我们的嵌入维度为4,那么实际上的位置编码就如下图所示:


    那么生成位置向量需要遵循怎样的规则呢?

    观察下面的图形,每一行都代表着对一个矢量的位置编码。因此第一行就是我们输入序列中第一个字的嵌入向量,每行都包含512个值,每个值介于1和-1之间。我们用颜色来表示1,-1之间的值,这样方便可视化的方式表现出来:

    这是一个20个字(行)的(512)列位置编码示例。你会发现它咋中心位置被分为了2半,这是因为左半部分的值是一由一个正弦函数生成的,而右半部分是由另一个函数(余弦)生成。然后将它们连接起来形成每个位置编码矢量。
     

    位置编码的公式在论文(3.5节)中有描述。你也可以在中查看用于生成位置编码的代码get_timing_signal_1d()。这不是位置编码的唯一可能方法。然而,它具有能够扩展到看不见的序列长度的优点(例如,如果我们训练的模型被要求翻译的句子比我们训练集中的任何句子都长)。

    The Residuals

    这一节我想介绍的是encoder过程中的每个self-attention层的左右连接情况,我们称这个为:layer-normalization 步骤。如下图所示:

     

     

    在进一步探索其内部计算方式,我们可以将上面图层可视化为下图:

     Decoder的子层也是同样的,如果我们想做堆叠了2个Encoder和2个Decoder的Transformer,那么它可视化就会如下图所示:

    The Decoder Side

         我们已经基本介绍完了Encoder的大多数概念,我们基本上也可以预知Decoder是怎么工作的。现在我们来仔细探讨下Decoder的数据计算原理,

         当序列输入时,Encoder开始工作,最后在其顶层的Encoder输出矢量组成的列表,然后我们将其转化为一组attention的集合(K,V)。(K,V)将带入每个Decoder的“encoder-decoder attention”层中去计算(这样有助于decoder捕获输入序列的位置信息)


    完成encoder阶段后,我们开始decoder阶段,decoder阶段中的每个步骤输出来自输出序列的元素(在这种情况下为英语翻译句子)。

    上面实际上已经是应用的阶段了,那我们训练阶段是如何的呢?

    我们以下图的步骤进行训练,直到输出一个特殊的符号<end of sentence>,表示已经完成了。 The output of each step is fed to the bottom decoder in the next time step, and the decoders bubble up their decoding results just like the encoders did. 对于Decoder,和Encoder一样,我们在每个Decoder的输入做词嵌入并添加上表示每个字位置的位置编码

    Decoder中的self attention与Encoder的self attention略有不同:

           在Decoder中,self attention只关注输出序列中的较早的位置。这是在self attention计算中的softmax步骤之前屏蔽了特征位置(设置为 -inf)来完成的

         “Encoder-Decoder Attention”层的工作方式与"Multi-Headed Self-Attention"一样,只是它从下面的层创建其Query矩阵,并在Encoder堆栈的输出中获取Key和Value的矩阵。

     

    The Final Linear and Softmax Layer

             Decoder的输出是浮点数的向量列表。我们是如何将其变成一个单词的呢?这就是最终的线性层和softmax层所做的工作。

    线性层是一个简单的全连接神经网络,它是由Decoder堆栈产生的向量投影到一个更大,更大的向量中,称为对数向量

          假设实验中我们的模型从训练数据集上总共学习到1万个英语单词(“Output Vocabulary”)。这对应的Logits矢量也有1万个长度-每一段表示了一个唯一单词的得分。在线性层之后是一个softmax层,softmax将这些分数转换为概率。选取概率最高的索引,然后通过这个索引找到对应的单词作为输出。

     上图是从Decoder的输出开始到最终softmax的输出。一步一步的图解。

    Recap Of Training

    现在我们已经讲解了transformer的训练全过程了,让我们回顾一下。

    在训练期间,未经训练的模型将通过如上的流程一步一步计算的。而且因为我们是在对标记的训练数据集进行训练(机器翻译可以看做双语平行语聊),那么我们可以将模型输出与实际的正确答案相比较,来进行反向传播。

    为了更好的理解这部分内容,我们假设我们输出的词汇只有(“a”,“am”,“i”,“thanks”,“student”和“<eos>”(“句末”的缩写))

    在我们开始训练之前,我们模型的输出词汇是在预处理阶段创建的。

    一旦我们定义了输出的词汇表,那么我们就可以使用相同宽度的向量来表示词汇表中的每个单词。称为one-hot编码。例如,我们可以使用下面向量来表示单词“am”:

                                                               示例:我们的输出词汇表的one-hot编码

    下一节我们再讨论一下模型的损失函数,我们优化的指标,引导一个训练有素且令人惊讶的精确模型。

    The Loss Function

    假设我们正在训练一个模型,比如将“merci”翻译成“谢谢”。这意味着我们希望模型计算后的输出为“谢谢”,但由于这种模式还没有接受过训练,所以这种情况不太可能发生


    这是因为模型的参数(权重)都是随机初始化的,因此(未经训练的)模型对每个单词产生的概率分布是具有无限可能的,但是我们可以通过其余实际我们期望的输出进行比较,然后利用反向传播调整所有模型的权重,使得输出更接近所需的输出。

    那么如何比较算法预测值与真实期望值呢?

    实际上,我们对其做一个简单的减法即可。你也可以了解交叉熵Kullback-Leibler散度来掌握这种差值的判断方式。

    但是,需要注意的是,这只是一个很简单的demo,真实情况下,我们需要输出一个更长的句子,例如。输入:“je suis étudiant”和预期输出:“I am a student”。这样的句子输入,意味着我们的模型能够连续的输出概率分布。其中:

    • 每个概率分布由宽度为vocab_size的向量表示(在我们的示例中vocab_size为6,但实际上可能为3,000或10,000维度)
    • 第一概率分布在与单词“i”相关联的单元处具有最高概率
    • 第二概率分布在与单词“am”相关联的单元格中具有最高概率
    • 依此类推,直到第五个输出分布表示' <end of sentence>'符号,意味着预测结束。


    上图为:输入:“je suis étudiant”和预期输出:“I am a student”的期望预测概率分布情况。

    在算法模型中,虽然不能达到期望的情况,但是我们需要在训练了足够长时间之后,我们的算法模型能够有如下图所示的概率分布情况:

        现在,因为模型一次生成一个输出,我们可以理解为这个模型从该概率分布(softmax)矢量中选择了具有最高概率的单词并丢弃了其余的单词。            

       现在,因为模型一次生成一个输出,我们可以假设模型从该概率分布中选择具有最高概率的单词并丢弃其余的单词。

    这里有2个方法:一个是贪婪算法(greedy decoding),一个是波束搜索(beam search)。波束搜索是一个优化提升的技术,可以尝试去了解一下,这里不做更多解释。

    Go Forth And Transform

    如果你想更深入了解,可以尝试下面几个步骤:

    后续工作:

    如果感觉有用,留个赞吧~~

    QQ:470581985

    微信:lsq960124

    打赏一下作者:

    赞赏名单:

    • Pengyu  10颗小?
    • 大饼 李    5颗小?
    • 张晓刚     5颗小?
    • 肖同尧     5颗小?
    • lz             1颗小?
    • 小丽的明天  5颗小?
    • ....

    感谢赞赏:

    展开全文
  • 图解Transformer(完整版)

    万次阅读 多人点赞 2019-01-17 23:45:25
    审校:百度NLP、龙心尘 翻译:张驰、毅航、Conrad 原作者:Jay Alammar 原链接:https://jalammar.github.io/illustrated-transformer/ 编者按:前一段时间谷歌推出的BERT模型在11项NLP...谷歌的Transformer模型...

    作者: 龙心尘
    时间:2019年1月
    出处:https://blog.csdn.net/longxinchen_ml/article/details/86533005

    审校:百度NLP、龙心尘
    翻译:张驰、毅航、Conrad
    原作者:Jay Alammar
    原链接:https://jalammar.github.io/illustrated-transformer/

    编者按:前一段时间谷歌推出的BERT模型在11项NLP任务中夺得SOTA结果,引爆了整个NLP界。而BERT取得成功的一个关键因素是Transformer的强大作用。谷歌的Transformer模型最早是用于机器翻译任务,当时达到了SOTA效果。Transformer改进了RNN最被人诟病的训练慢的缺点,利用self-attention机制实现快速并行。并且Transformer可以增加到非常深的深度,充分发掘DNN模型的特性,提升模型准确率。在本文中,我们将研究Transformer模型,把它掰开揉碎,理解它的工作原理。

    正文

    Transformer由论文《Attention is All You Need》提出,现在是谷歌云TPU推荐的参考模型。论文相关的Tensorflow的代码可以从GitHub获取,其作为Tensor2Tensor包的一部分。哈佛的NLP团队也实现了一个基于PyTorch的版本,并注释该论文。

    在本文中,我们将试图把模型简化一点,并逐一介绍里面的核心概念,希望让普通读者也能轻易理解。

    Attention is All You Need:https://arxiv.org/abs/1706.03762

    从宏观的视角开始

    首先将这个模型看成是一个黑箱操作。在机器翻译中,就是输入一种语言,输出另一种语言。

    那么拆开这个黑箱,我们可以看到它是由编码组件、解码组件和它们之间的连接组成。

    编码组件部分由一堆编码器(encoder)构成(论文中是将6个编码器叠在一起——数字6没有什么神奇之处,你也可以尝试其他数字)。解码组件部分也是由相同数量(与编码器对应)的解码器(decoder)组成的。

    所有的编码器在结构上都是相同的,但它们没有共享参数。每个解码器都可以分解成两个子层。

    从编码器输入的句子首先会经过一个自注意力(self-attention)层,这层帮助编码器在对每个单词编码时关注输入句子的其他单词。我们将在稍后的文章中更深入地研究自注意力。

    自注意力层的输出会传递到前馈(feed-forward)神经网络中。每个位置的单词对应的前馈神经网络都完全一样(译注:另一种解读就是一层窗口为一个单词的一维卷积神经网络)。

    解码器中也有编码器的自注意力(self-attention)层和前馈(feed-forward)层。除此之外,这两个层之间还有一个注意力层,用来关注输入句子的相关部分(和seq2seq模型的注意力作用相似)。

    将张量引入图景

    我们已经了解了模型的主要部分,接下来我们看一下各种向量或张量(译注:张量概念是矢量概念的推广,可以简单理解矢量是一阶张量、矩阵是二阶张量。)是怎样在模型的不同部分中,将输入转化为输出的。

    像大部分NLP应用一样,我们首先将每个输入单词通过词嵌入算法转换为词向量。

    每个单词都被嵌入为512维的向量,我们用这些简单的方框来表示这些向量。

    词嵌入过程只发生在最底层的编码器中。所有的编码器都有一个相同的特点,即它们接收一个向量列表,列表中的每个向量大小为512维。在底层(最开始)编码器中它就是词向量,但是在其他编码器中,它就是下一层编码器的输出(也是一个向量列表)。向量列表大小是我们可以设置的超参数——一般是我们训练集中最长句子的长度。

    将输入序列进行词嵌入之后,每个单词都会流经编码器中的两个子层。

    接下来我们看看Transformer的一个核心特性,在这里输入序列中每个位置的单词都有自己独特的路径流入编码器。在自注意力层中,这些路径之间存在依赖关系。而前馈(feed-forward)层没有这些依赖关系。因此在前馈(feed-forward)层时可以并行执行各种路径。

    然后我们将以一个更短的句子为例,看看编码器的每个子层中发生了什么。

    现在我们开始“编码”

    如上述已经提到的,一个编码器接收向量列表作为输入,接着将向量列表中的向量传递到自注意力层进行处理,然后传递到前馈神经网络层中,将输出结果传递到下一个编码器中。

    输入序列的每个单词都经过自编码过程。然后,他们各自通过前向传播神经网络——完全相同的网络,而每个向量都分别通过它。

    从宏观视角看自注意力机制

    不要被我用自注意力这个词弄迷糊了,好像每个人都应该熟悉这个概念。其实我之也没有见过这个概念,直到读到Attention is All You Need 这篇论文时才恍然大悟。让我们精炼一下它的工作原理。

    例如,下列句子是我们想要翻译的输入句子:

    The animal didn’t cross the street because it was too tired

    这个“it”在这个句子是指什么呢?它指的是street还是这个animal呢?这对于人类来说是一个简单的问题,但是对于算法则不是。

    当模型处理这个单词“it”的时候,自注意力机制会允许“it”与“animal”建立联系。

    随着模型处理输入序列的每个单词,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码。

    如果你熟悉RNN(循环神经网络),回忆一下它是如何维持隐藏层的。RNN会将它已经处理过的前面的所有单词/向量的表示与它正在处理的当前单词/向量结合起来。而自注意力机制会将所有相关单词的理解融入到我们正在处理的单词中。

    当我们在编码器#5(栈中最上层编码器)中编码“it”这个单词的时,注意力机制的部分会去关注“The Animal”,将它的表示的一部分编入“it”的编码中。

    请务必检查Tensor2Tensor notebook ,在里面你可以下载一个Transformer模型,并用交互式可视化的方式来检验。

    从微观视角看自注意力机制

    首先我们了解一下如何使用向量来计算自注意力,然后来看它实怎样用矩阵来实现。

    计算自注意力的第一步就是从每个编码器的输入向量(每个单词的词向量)中生成三个向量。也就是说对于每个单词,我们创造一个查询向量、一个键向量和一个值向量。这三个向量是通过词嵌入与三个权重矩阵后相乘创建的。

    可以发现这些新向量在维度上比词嵌入向量更低。他们的维度是64,而词嵌入和编码器的输入/输出向量的维度是512. 但实际上不强求维度更小,这只是一种基于架构上的选择,它可以使多头注意力(multiheaded attention)的大部分计算保持不变。

    X1与WQ权重矩阵相乘得到q1, 就是与这个单词相关的查询向量。最终使得输入序列的每个单词的创建一个查询向量、一个键向量和一个值向量。

    什么是查询向量、键向量和值向量向量?

    它们都是有助于计算和理解注意力机制的抽象概念。请继续阅读下文的内容,你就会知道每个向量在计算注意力机制中到底扮演什么样的角色。

    计算自注意力的第二步是计算得分。假设我们在为这个例子中的第一个词“Thinking”计算自注意力向量,我们需要拿输入句子中的每个单词对“Thinking”打分。这些分数决定了在编码单词“Thinking”的过程中有多重视句子的其它部分。

    这些分数是通过打分单词(所有输入句子的单词)的键向量与“Thinking”的查询向量相点积来计算的。所以如果我们是处理位置最靠前的词的自注意力的话,第一个分数是q1和k1的点积,第二个分数是q1和k2的点积。

    第三步和第四步是将分数除以8(8是论文中使用的键向量的维数64的平方根,这会让梯度更稳定。这里也可以使用其它值,8只是默认值),然后通过softmax传递结果。softmax的作用是使所有单词的分数归一化,得到的分数都是正值且和为1。

    这个softmax分数决定了每个单词对编码当下位置(“Thinking”)的贡献。显然,已经在这个位置上的单词将获得最高的softmax分数,但有时关注另一个与当前单词相关的单词也会有帮助。

    第五步是将每个值向量乘以softmax分数(这是为了准备之后将它们求和)。这里的直觉是希望关注语义上相关的单词,并弱化不相关的单词(例如,让它们乘以0.001这样的小数)。

    第六步是对加权值向量求和(译注:自注意力的另一种解释就是在编码某个单词时,就是将所有单词的表示(值向量)进行加权求和,而权重是通过该词的表示(键向量)与被编码词表示(查询向量)的点积并通过softmax得到。),然后即得到自注意力层在该位置的输出(在我们的例子中是对于第一个单词)。

    这样自自注意力的计算就完成了。得到的向量就可以传给前馈神经网络。然而实际中,这些计算是以矩阵形式完成的,以便算得更快。那我们接下来就看看如何用矩阵实现的。

    通过矩阵运算实现自注意力机制

    第一步是计算查询矩阵、键矩阵和值矩阵。为此,我们将将输入句子的词嵌入装进矩阵X中,将其乘以我们训练的权重矩阵(WQ,WK,WV)。

    x矩阵中的每一行对应于输入句子中的一个单词。我们再次看到词嵌入向量 (512,或图中的4个格子)和q/k/v向量(64,或图中的3个格子)的大小差异。

    最后,由于我们处理的是矩阵,我们可以将步骤2到步骤6合并为一个公式来计算自注意力层的输出。

    自注意力的矩阵运算形式

    “大战多头怪”

    通过增加一种叫做“多头”注意力(“multi-headed” attention)的机制,论文进一步完善了自注意力层,并在两方面提高了注意力层的性能:

    1.它扩展了模型专注于不同位置的能力。在上面的例子中,虽然每个编码都在z1中有或多或少的体现,但是它可能被实际的单词本身所支配。如果我们翻译一个句子,比如“The animal didn’t cross the street because it was too tired”,我们会想知道“it”指的是哪个词,这时模型的“多头”注意机制会起到作用。

    2.它给出了注意力层的多个“表示子空间”(representation subspaces)。接下来我们将看到,对于“多头”注意机制,我们有多个查询/键/值权重矩阵集(Transformer使用八个注意力头,因此我们对于每个编码器/解码器有八个矩阵集合)。这些集合中的每一个都是随机初始化的,在训练之后,每个集合都被用来将输入词嵌入(或来自较低编码器/解码器的向量)投影到不同的表示子空间中。

    在“多头”注意机制下,我们为每个头保持独立的查询/键/值权重矩阵,从而产生不同的查询/键/值矩阵。和之前一样,我们拿X乘以WQ/WK/WV矩阵来产生查询/键/值矩阵。

    如果我们做与上述相同的自注意力计算,只需八次不同的权重矩阵运算,我们就会得到八个不同的Z矩阵。

    这给我们带来了一点挑战。前馈层不需要8个矩阵,它只需要一个矩阵(由每一个单词的表示向量组成)。所以我们需要一种方法把这八个矩阵压缩成一个矩阵。那该怎么做?其实可以直接把这些矩阵拼接在一起,然后用一个附加的权重矩阵WO与它们相乘。

    这几乎就是多头自注意力的全部。这确实有好多矩阵,我们试着把它们集中在一个图片中,这样可以一眼看清。

    既然我们已经摸到了注意力机制的这么多“头”,那么让我们重温之前的例子,看看我们在例句中编码“it”一词时,不同的注意力“头”集中在哪里:

    当我们编码“it”一词时,一个注意力头集中在“animal”上,而另一个则集中在“tired”上,从某种意义上说,模型对“it”一词的表达在某种程度上是“animal”和“tired”的代表。

    然而,如果我们把所有的attention都加到图示里,事情就更难解释了:

    使用位置编码表示序列的顺序

    到目前为止,我们对模型的描述缺少了一种理解输入单词顺序的方法。

    为了解决这个问题,Transformer为每个输入的词嵌入添加了一个向量。这些向量遵循模型学习到的特定模式,这有助于确定每个单词的位置,或序列中不同单词之间的距离。这里的直觉是,将位置向量添加到词嵌入中使得它们在接下来的运算中,能够更好地表达的词与词之间的距离。

    为了让模型理解单词的顺序,我们添加了位置编码向量,这些向量的值遵循特定的模式。

    如果我们假设词嵌入的维数为4,则实际的位置编码如下:


    尺寸为4的迷你词嵌入位置编码实例

    这个模式会是什么样子?

    在下图中,每一行对应一个词向量的位置编码,所以第一行对应着输入序列的第一个词。每行包含512个值,每个值介于1和-1之间。我们已经对它们进行了颜色编码,所以图案是可见的。

    20字(行)的位置编码实例,词嵌入大小为512(列)。你可以看到它从中间分裂成两半。这是因为左半部分的值由一个函数(使用正弦)生成,而右半部分由另一个函数(使用余弦)生成。然后将它们拼在一起而得到每一个位置编码向量。

    原始论文里描述了位置编码的公式(第3.5节)。你可以在 get_timing_signal_1d()中看到生成位置编码的代码。这不是唯一可能的位置编码方法。然而,它的优点是能够扩展到未知的序列长度(例如,当我们训练出的模型需要翻译远比训练集里的句子更长的句子时)。

    残差模块

    在继续进行下去之前,我们需要提到一个编码器架构中的细节:在每个编码器中的每个子层(自注意力、前馈网络)的周围都有一个残差连接,并且都跟随着一个“层-归一化”步骤。

    层-归一化步骤:https://arxiv.org/abs/1607.06450

    如果我们去可视化这些向量以及这个和自注意力相关联的层-归一化操作,那么看起来就像下面这张图描述一样:

    解码器的子层也是这样样的。如果我们想象一个2 层编码-解码结构的transformer,它看起来会像下面这张图一样:

    解码组件

    既然我们已经谈到了大部分编码器的概念,那么我们基本上也就知道解码器是如何工作的了。但最好还是看看解码器的细节。

    编码器通过处理输入序列开启工作。顶端编码器的输出之后会变转化为一个包含向量K(键向量)和V(值向量)的注意力向量集 。这些向量将被每个解码器用于自身的“编码-解码注意力层”,而这些层可以帮助解码器关注输入序列哪些位置合适:

    在完成编码阶段后,则开始解码阶段。解码阶段的每个步骤都会输出一个输出序列(在这个例子里,是英语翻译的句子)的元素

    接下来的步骤重复了这个过程,直到到达一个特殊的终止符号,它表示transformer的解码器已经完成了它的输出。每个步骤的输出在下一个时间步被提供给底端解码器,并且就像编码器之前做的那样,这些解码器会输出它们的解码结果 。另外,就像我们对编码器的输入所做的那样,我们会嵌入并添加位置编码给那些解码器,来表示每个单词的位置。

    src="https://v.qq.com/txp/iframe/player.html?vid=m13563cy49o" allowfullscreen="true" width="600" height="400">

    而那些解码器中的自注意力层表现的模式与编码器不同:在解码器中,自注意力层只被允许处理输出序列中更靠前的那些位置。在softmax步骤前,它会把后面的位置给隐去(把它们设为-inf)。

    这个“编码-解码注意力层”工作方式基本就像多头自注意力层一样,只不过它是通过在它下面的层来创造查询矩阵,并且从编码器的输出中取得键/值矩阵。

    最终的线性变换和Softmax层

    解码组件最后会输出一个实数向量。我们如何把浮点数变成一个单词?这便是线性变换层要做的工作,它之后就是Softmax层。

    线性变换层是一个简单的全连接神经网络,它可以把解码组件产生的向量投射到一个比它大得多的、被称作对数几率(logits)的向量里。

    不妨假设我们的模型从训练集中学习一万个不同的英语单词(我们模型的“输出词表”)。因此对数几率向量为一万个单元格长度的向量——每个单元格对应某一个单词的分数。

    接下来的Softmax 层便会把那些分数变成概率(都为正数、上限1.0)。概率最高的单元格被选中,并且它对应的单词被作为这个时间步的输出。

    这张图片从底部以解码器组件产生的输出向量开始。之后它会转化出一个输出单词。

    训练部分总结

    既然我们已经过了一遍完整的transformer的前向传播过程,那我们就可以直观感受一下它的训练过程。

    在训练过程中,一个未经训练的模型会通过一个完全一样的前向传播。但因为我们用有标记的训练集来训练它,所以我们可以用它的输出去与真实的输出做比较。

    为了把这个流程可视化,不妨假设我们的输出词汇仅仅包含六个单词:“a”, “am”, “i”, “thanks”, “student”以及 “”(end of sentence的缩写形式)。

    我们模型的输出词表在我们训练之前的预处理流程中就被设定好。

    一旦我们定义了我们的输出词表,我们可以使用一个相同宽度的向量来表示我们词汇表中的每一个单词。这也被认为是一个one-hot 编码。所以,我们可以用下面这个向量来表示单词“am”:


    例子:对我们输出词表的one-hot 编码

    接下来我们讨论模型的损失函数——这是我们用来在训练过程中优化的标准。通过它可以训练得到一个结果尽量准确的模型。

    损失函数

    比如说我们正在训练模型,现在是第一步,一个简单的例子——把“merci”翻译为“thanks”。

    这意味着我们想要一个表示单词“thanks”概率分布的输出。但是因为这个模型还没被训练好,所以不太可能现在就出现这个结果。

    因为模型的参数(权重)都被随机的生成,(未经训练的)模型产生的概率分布在每个单元格/单词里都赋予了随机的数值。我们可以用真实的输出来比较它,然后用反向传播算法来略微调整所有模型的权重,生成更接近结果的输出。

    你会如何比较两个概率分布呢?我们可以简单地用其中一个减去另一个。更多细节请参考交叉熵和KL散度。

    交叉熵:https://colah.github.io/posts/2015-09-Visual-Information/

    KL散度:https://www.countbayesie.com/blog/2017/5/9/kullback-leibler-divergence-explained

    但注意到这是一个过于简化的例子。更现实的情况是处理一个句子。例如,输入“je suis étudiant”并期望输出是“i am a student”。那我们就希望我们的模型能够成功地在这些情况下输出概率分布:

    每个概率分布被一个以词表大小(我们的例子里是6,但现实情况通常是3000或10000)为宽度的向量所代表。

    第一个概率分布在与“i”关联的单元格有最高的概率

    第二个概率分布在与“am”关联的单元格有最高的概率

    以此类推,第五个输出的分布表示“”关联的单元格有最高的概率


    依据例子训练模型得到的目标概率分布

    在一个足够大的数据集上充分训练后,我们希望模型输出的概率分布看起来像这个样子:

    我们期望训练过后,模型会输出正确的翻译。当然如果这段话完全来自训练集,它并不是一个很好的评估指标(参考:交叉验证,链接https://www.youtube.com/watch?v=TIgfjmp-4BA)。注意到每个位置(词)都得到了一点概率,即使它不太可能成为那个时间步的输出——这是softmax的一个很有用的性质,它可以帮助模型训练。

    因为这个模型一次只产生一个输出,不妨假设这个模型只选择概率最高的单词,并把剩下的词抛弃。这是其中一种方法(叫贪心解码)。另一个完成这个任务的方法是留住概率最靠高的两个单词(例如I和a),那么在下一步里,跑模型两次:其中一次假设第一个位置输出是单词“I”,而另一次假设第一个位置输出是单词“me”,并且无论哪个版本产生更少的误差,都保留概率最高的两个翻译结果。然后我们为第二和第三个位置重复这一步骤。这个方法被称作集束搜索(beam search)。在我们的例子中,集束宽度是2(因为保留了2个集束的结果,如第一和第二个位置),并且最终也返回两个集束的结果(top_beams也是2)。这些都是可以提前设定的参数。

    再进一步

    我希望通过上文已经让你们了解到Transformer的主要概念了。如果你想在这个领域深入,我建议可以走以下几步:阅读Attention Is All You Need,Transformer博客和Tensor2Tensor announcement,以及看看Łukasz Kaiser的介绍,了解模型和细节。

    Attention Is All You Need:https://arxiv.org/abs/1706.03762

    Transformer博客:https://ai.googleblog.com/2017/08/transformer-novel-neural-network.html

    Tensor2Tensor announcement:https://ai.googleblog.com/2017/06/accelerating-deep-learning-research.html

    Łukasz Kaiser的介绍:https://colab.research.google.com/github/tensorflow/tensor2tensor/blob/master/tensor2tensor/notebooks/hello_t2t.ipynb

    接下来可以研究的工作:

    Depthwise Separable Convolutions for Neural Machine Translation

    https://arxiv.org/abs/1706.03059

    One Model To Learn Them All

    https://arxiv.org/abs/1706.05137

    Discrete Autoencoders for Sequence Models

    https://arxiv.org/abs/1801.09797

    Generating Wikipedia by Summarizing Long Sequences

    https://arxiv.org/abs/1801.10198

    Image Transformer

    https://arxiv.org/abs/1802.05751

    Training Tips for the Transformer Model

    https://arxiv.org/abs/1804.00247

    Self-Attention with Relative Position Representations

    https://arxiv.org/abs/1803.02155

    Fast Decoding in Sequence Models using Discrete Latent Variables

    https://arxiv.org/abs/1803.03382

    Adafactor: Adaptive Learning Rates with Sublinear Memory Cost

    https://arxiv.org/abs/1804.04235

    注:
    本文系大数据文摘与百度NLP联合出品系列文章第一篇。百度NLP以“理解语言,拥有智能,改变世界”为使命,开展包括自然语言处理、机器学习、数据挖掘在内的技术研究和产品应用工作,引领着人工智能技术的发展。

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,501
精华内容 5,800
关键字:

transformer