LongCut logo

Transformer论文逐段精读

By 跟李沐学AI

Summary

Topics Covered

  • Part 1
  • Part 2
  • Part 3
  • Part 4
  • Part 5

Full Transcript

大家好 今天是我们论文精读系列的第三篇文章 我们将讲的是Transformer这个模型 也就是大家投票分数最高的一篇模型 这篇文章可以认为是最近三年以内 深度学习里面最重要的文章之一 它可以认为是开创了继 MLP cl和RNN之后的第四大类模型

在上个月 斯坦福联合了100多名作者 写了一篇200多页的综述文章 也就是讲Transformer模型和它之后的一些变种 他们甚至提议说将这一类模型啊 叫做基础模型哈 可以见它对整个领域的影响力是有多大 首先我们看一下标题 标题是说Attention Is All You Need 就是说你就需要注意就行了 当然在英语中

这也是一句合法的话 就是说对小孩说啊 集中一下注意力啊 不要东看西看 然后这个标题啊成为了一个梗 就是说 什么什么is all you need 然后在后续出了很多很多篇文章 然后你就把这个词换成任何你想要的词 只要你换成这个词 基本上你的文章能够上头条 然后我们来看一下作者 这里面有八个作者 作者绝大部分都是在google

然后有两个作者当中不在google 它做了一个注释 注释上面写的是这个是这两位作者在google 应该是实习的时候完成的工作 比较有意思的是 这篇文章每一个作者后面都打了一个星号 星号在论文里面我们一般叫做同样贡献 就是说一般来说我们会把前面一两个三个作者说 你这前面三个作者对这篇文章的贡献是差不多的

因为在机器学习这一块 我们一般会按照作者对文章的贡献 从大排到小 排序 也就是说第一作者通常对文章的贡献是比较大的 很多时候在绝大部分文章里面 第一作者贡献了80%的事情 有一些情况是说 第一个第二个第三个作者有同样贡献 这个也是常见的 但是说你整个文章八个作者 对整个文章的贡献都是均等啊

这个情况是比较少见的 但我们可以看一下这个星号写的是什么东西 当你跳到这个文章第一页的末尾的时候 它有长长的一段话来解释说 是怎么样贡献的 就是说 Listing order is random 我整个作者的排名是比较随机的 我们知道第一作者通常会拿到整篇文章最大的credit 大家都觉得这一篇文章是第一作的功劳

当你说我的作者是随机的话 当然是第一作者放在那个地方是赚的 然后他就解释说啊 谁 Jakob 然后说我提出了要把RNN换成self-attention 然后后面说我实现了第一个模型 然后呢后面又有几个人来做了一些实验啊 最后写了文章呀 然后

把 甚至是说后面的两个作者是把整个tensor2tensor 也就是这篇文章的一个开源实现整个代码 重构了一遍 就是说他把每个作者放的贡献写在这个地方 这个当然是一个比较好的做法 当你一篇文章有比较多作者的时候 能把每个作者对这个文章的贡献 明明白白写出来 其实是一件很好的事情

这也是告诉大家说 我们这个名字也不是 随便挂名的 然后每个人确实需要明明白白给这篇文章做出贡献 才能挂名 这个摘要的第一句话是说 在主流的序列转录模型里面 所谓的序列转录模型就是说给你一个序列 你生成另外一个序列 机器翻译说给一句英文 甚至一句中文 当然是一个序列转录模型

这样子模型啊主要是依赖于比较复杂的循环 或者是卷积神经网络 然后呢它一半是用一个叫做encoder和decoder的架构 当然这句话意思是说你 多多少少知道这个模型的 encoder decoder的架构什么样子 然后当CNN是RNN还是什么样子 当然你得假设你知道 然后第二句话是说 在性能最好这些模型里面

通常也会在你的编码器和解码器之间呢 使用一个叫做注意力机制的东西 基本上就是说这篇文章 讲的是我要做序列到序列的生产 但是现在主流的模型是干什么东西 第三句话是说我这篇文章 提出了一个新的简单的架构啊 所以现在比较有意思的是

之前我们都说我们提供一个novel 就是比较有意思的架构 现在基本上因为我们的模型其实现在都挺复杂的 如果你能做一个simple的架构 其实也挺好了 只要你的结果好 大家其实还是挺喜欢简单的架构 我们之前讲的Resnet 其实也是一个比较简单的架构 所以大家挺喜欢的 这个也是整个研究氛围的一个转变

我们说simple这个词不再是一个贬义词 而是一个褒义词这样的结果 好 它说这个模型的名字叫Transformer 中文翻译叫做变形金刚 这个也是比较有意思的取名方法 你当然可以说我把我的模型取得一些 大家很熟知的一些名词 就很容易被记住 但是你这个问题是说 如果你的文章没有出名 大家去搜你文章的时候 根本就搜不到你的文章

还是搜到的是变形金刚 取名字也是一个非常重要的事情 好的文章啊 一般有一个比较好的名字 我们之前讲过的Resnet Resnet这个名字其实挺好的 叫resnet 很好记对吧 然后我们讲到第一篇文章Alexnet 其实那篇文章根本就没有提到Alexnet这个名字 他根本没有给自己的文章取个名字 估计作者也没想到自己会那么火 所以他说我们做了一个神经网络

因为这篇文章是开创性的工作 大家重复你的结果的时候 总要给你的模型取个名字 然后 提到你的时候最好有个名字 所以大家给了你一个名字叫做Alexnet Alex来自与第一作者的名字 所以对后面文章的作者来讲啊 如果不想让别人给你取名字的话 当然给自己取一个比较好的名字比较重要 然后它接着说 我这个模型仅仅依赖于注意力机制

而没有用之前的循环或者是卷积 这就是它的贡献了 它提出了一个新的模型啊 简单 然后跟之前 大家表现很好的模型的架构都长得不一样 接下来说我做了两个机器翻译的实验 显示这个模型在性能上特别好 他说可以并行度更好

然后许用更少的时间来训练 他说我的模型达到了28.4的BLEU BLEU是在机器翻译里面大家经常用的一个衡量标准啊 如果你不做机器翻译的话 你可能不一定明白BLEU score是干什么事情 但是没关系 它说我我这个是在英语到德语的一个翻译工作 它说我们比目前的最好的结果 好了两个BLEU

然后在一个英语到法语的翻译的任务上面啊 他们做了一个单模型 比所有的模型都要效果要好 然后它只在八个GPU上训练了3.5天 最后他说我的Transformer架构能够泛化到一些别的任务上面都很好 那基本上你可以看到是说我提出了一个新的模型 主要用在是什么呢

在机器翻译这个任务上面 所以这篇文章一开始写的时候是针对机器翻译这个小任务写的 所以他整个写作的时候 他去假设你前面是知道的 然后提出一个模型 然后我 就主要在我的机器翻译上 结果很好 这个也是比较有意思的工作 他一开始做的是机器翻译 这个比较相对来说小一点的领域上面 之所以说小

是因为你会发现机器翻译也就那么几家公司关心 对吧 你能够提供 动机翻译的那些服务的公司啊 其实全世界范围来讲也就那么多家 但是随着之后bert呀gbt 把这个架构用在更多的 在源处理的任务上的时候呢 整个这个工作要出圈了 然后最近当然大家都知道用在了图片上面 用在了video上面 几乎上什么东西都能用

所以这个版本它是真正的火出圈在这个地方 但是呢你第一次读这个文章的时候 你可能看到机器翻译这一块 你可能不那么感兴趣 当然了 现在我们知道这篇文章非常重要 我们就还是继续往下读 我们接下来直接跳到我们的结论啊 跟我们之前的做法是一样的 结论的第一句话是说我们介绍了Transformer这个模型 这是第一个做

序列转录的模型 然后仅仅使用注意力 它把之前所有的循环程啊 全部换成了multi-headed self-attention 全部换成了multi-headed self-attention 基本上可以看到这篇文章主要用的是提出了是这样一个层 第二句话是说 在机器翻译这个任务上面 Transformer能够训练的 比其他的架构都要快很多

而且呢在实际的结果上确实是效果比较好 然后第三段是说他对于 这种纯基于注意力机制的模型感到非常的激动 他想把它用在一些别的任务上面 他觉得可以用在文本以外的数据上啊 包括了 啊 图片啊 语音啊 video啊 然后他说使得生成不那么时序化 也是另外一个研究的方向

其实现在看起来作者多多少少是预测的未来对吧 Transformer真的在 各种别的数据上以及这一块做的是比较好 虽然这些工作基本上都不失于本篇文章 作者完成的 都是由别人完成的 但是本文的作者啊基本上是看准了大方向的 最后一句话是说 这篇文章所有代码放在tensor2tensor这个库里面 这也是比较有意思的写法

他把整个代码放在了结论的最后 但是现在我们知道如果你有代码的话 通常你会把这个代码放在你摘要的最后一句话 因为现在神经网络的文章里面细节通常是比较多的 啊 简简单单的一篇文章 很难把所有的细节写清楚 所以你最好第一时间公布你的代码 让别人能够很方便的重复你的文章 然后这样能扩大你文章的影响力

好接下来我们来看第一段导言 这里的导言写的是比较短的 基本上可以认为是他前面摘要的前面一半的一个扩充 我们来看一下 他第一段话是说 在时序模型里面呢 当然当前最常用的是RNN 这是2017年啊 然后它包括了LSTM呐GRU啦 然后接下来他当然是说

嗯在这里面呢有两个比较主流的模型 一个叫做语言模型 另外一个是当你的输出结构化信息比较多的时候 大家会用一个叫做编码器和解码器的架构 第二段话是讲RNN的特点是什么 同样也是它的缺点是什么 在RNN里面啊 给你一个序列的话 它的计算是把这个序列从左往右移一步一步往前做

假设你的一个序列是一个句子的话 它就是一个词一个词的看 对第t个词 它会计算一个输出叫做ht 也叫它的隐藏状态 然后呢它的ht是由 前面一个词的隐藏状态 叫ht-1和当前第t个词本身决定的 这样子的话它就可以把前面学到的历史信息呢

通过ht-1放到当下 然后和当前的词做一些 计算 然后得到输出 这也是RNN如何能够有效处理时序信息的一个 关键之所在 它把之前的信息全部放在隐藏状态里面 然后一个一个放下去 但它的问题也来自于这里 第一个说它是一个时序 就是一步一步计算的过程 它比较难以并行

就是说你在算第t个词的时候 算ht的那个出处的时候呢 你必须要保证第前面那个词的ht-1输入完成了 假设你的句子有100个词的话 那么就是说你得时序地上100步 导致说你在这个时间上呀 你无法并行 现在在主流的GPU和那些 加速器 比如说TPU一样的 大家都是成千上万个线程

你无法在这个上面并行的话 导致你的并行度比较低 使得你在计算上性能比较差 第二个也是因为这个原因 你的历史信息呢是一步一步的往后传递的 如果你的时序比较长的话 那么你在很早期的那些时序信息啊 在后面的时候可能会丢掉 如果你不想丢掉的话 那你可能得要ht要比较大 就说你得做一个比较大的ht 但是这个的问题是说

如果你做比较大的ht 你在每一个时间不都得把它存下来 导致你的内存开销是比较大的 当然他也提到过啊 这一块其实大家在过去这些年做了非常多的改进啊 不管是并行的改进啊 以及做一些分解的 方法使得我们能够提升并行度啊 但是呢本质上还是没有解决太多问题 第三段啊

他其实讲是attention在RNN上的应用 在这篇文章之前 attention已经被成功地用在编码器的解码器里面了 它主要是用在 怎么样把 编码器的东西很有效的传给解码器 主要是用到这一块 就是说你跟RNN是一起使用的啊 这个其实是讲这一段的事情 最后一段讲的是这篇文章提出来的Transformer 这是一个新的模型

不再使用之前被大家使用的循环神精层 而是纯基于注意力机制了 他说我这个东西因为是可以变形的 因为之前你 攻击的就是时序神经网络 主要是 要 按时序地做运算 现在你做了attention之后 你可以完全做并行 因为它现在纯用的attention 所以它的并行度是比较高的啊 这样子的话它能够在

比较短的时间之内呢 做到一个跟之前可能更好的结果 这就是导言干的事情 总体来看这个导言是写的比较短的 可以认为就是摘要的前面几句话的一个稍微的扩充版本 对自己提出的 也就是一句话带过了 啊这么写的原因啊 我觉得应该是因为这篇文章提出来的东西是比较多的 它是一个比较不一样的一个网络

里面有一些核心的东西在里面 然后呢是发表在NeurIPS上面 NeurIPS是一个篇幅比较短的一个会议啊 它是一个单列的 然后啊也就八页吧 所以导致说你要在这么一个短的 模板里面写下很多东西是很难的 那你就得压缩掉一些东西 第二节是相关工作 首先他第一段提的是如何使用卷积神经网络

来替换掉你的循环神经网络 使得减少你的时序的计算 他提到了这个工作啊 他又提到是说 这些工作主要的问题是说 用卷积神经网络 对于比较长的序列难以建模 这是因为我们知道卷积做计算的时候 每一次它去看一个一个比较小的一个窗口 比如说看一个3x3的一个像素块

如果你两个像素隔得比较远的话呢 你得需要用很多层卷积 一层一层上去 才能够最后把这两个隔得远的像素给你融合起来 但是他说如果使用Transformer里面的注意力机制的话 每一次我能看到所有的像素 我一层就能够把整个序列给你看到 相对来说就没有这个问题 但是他又提到说卷积它的一个比较好的地方是说

可以做多个输出通道 一个输出通道可以认为是它可以去识别不一样的模式 所以他说我也想要这样子的多输出通道的效果 所以他提出了一个叫做Muti-Headed Attention 就是多头的注意力机制 所以可以模拟卷积神经网络多输出通道的一个效果 接下来第二段他讲的是自注意力机制啊

其实这个是Transformer里面一个关键性的点呢 但是他说啊这个工作其实之前已经有人提出来了 并不是我这个工作的创新 所以但是所以我这个地方需要给大家说明白一下 啊另外他又提到一个叫做memory networks的东西 这个在17年的时候也算是一个研究的重点吧 如果大家不知道的话 我们可以跳过 在我们best knowledge里面啊

我们的Transformer是第一个只依赖于自注意力 来做这种encode到decode的架构的模型 这就是相关工作的章节 关键是说你要讲清楚 跟你论文相关的那些论文是谁 跟你的联系是什么 以及说你跟他们的区别是什么 好接下来是第三章 模型架构 我们知道深度神经网络的论文里面最重要的就是这一章了

那一章怎么讲 你这个神经网络长什么样子 我们来看一下 第一句话说这些序列模型里面 现在比较好的是一个叫做编码器和解码器的架构 然后他解释一下什么是编码器解码器 就对编码器来讲呢 它会将一个输入啊 就是一个长为n的一个x1一直到xn的一个东西 假设你是一个句子的话 有n个词的话呢

那么第xt就表示你的第t个词 他说将这个序列呢编码器会把它表示一个也是长为n 但是呢其中每一个zt啊 它对应的是xt的一个向量的表示 假设你是一个句子的话呢 那么zt就表示你第t个词的一个向量的表示 这就是你的编码器的输出 就是这样一些 原始的一些输入呢变成一个

机器学习可以理解的一系列的向量 那对解码器来讲 我会拿到编码器的输出 然后它会生成一个长为m的一个序列 首先注意到n和m是不一样长的 可以一样可以不一样 比如说你英文句子翻译中文句子的话 那么两个句子很有可能是不一样长的 他跟 编码器的一个大的不一样 是说在解码器里面 你的

这个词是一个一个生成的 因为对编码器来讲 你很有可能是一次性能看全整个句子 就是说做翻译的时候 我可以把整个英语的句子给你 但是你在解码的时候呢 只能一个一个的生成啊 这个东西叫做一个叫做自回归 叫做auto-regressivet的一个模型 在这个里面啊 你的输入又是你的输出啊 具体的看一下 是说 在最开始我给定的z

那么你要去生成第一个输出 叫做y1 在拿到y1之后 我就可以去生成我的y2 然后一般来说你要生成yt的话 你可以把之前所有的y1到yt-1全部拿到 也就是说你在翻译的时候 你是一个词一个次地往外蹦 所以就是说你在过去时刻的输出 也会作为你当前时刻的输入 所以这个叫做自回归

再就是第一段讲的事情 然后它又很简单地来了一句说 Transformer是使用了一个 编码器解码器的架构 具体来说它是将一些自注意力和point-wise fully connected layers 然后把一个一个堆在一起的 他说啊 我们在下面的统一给大家展现这个架构 这个图如果你讲Transformer的话 很有可能你就是把这个图复制一下

然后放到你的ppt里面给大家讲 这就意味着说 如果你写论文的话 有一张比较漂亮的 能够把整个全局画清楚的图是非常重要的 因为很有可能别人讲你的论文的时候 就是把这个图搬过去 如果你的图画的不够好的话 别人可能还花半天来讲这些东西 如果你画的很好的话 就是一张图能够搞定所有东西 所以就是说在神经网络年代 会画图是一个很基础的技能

但具体到这篇文章的话 这张图画的是挺好的 但是如果你就读到这个地方的话 你会发现其实看不懂这个图的 因为你什么东西都不知道 什么东西没解释这个东西是什么东西 当然我们可以现在可以做一个事后诸葛亮 给大家来讲一下这个到底是在干什么事情 当然每个模块我们在后面会讲到 首先你看到是一个它是一个 编码器和解码器的架构啊 这个东西是你的编码器啊

这一块是你的解码器 这是编码器的 输入就是比如说你中文翻英文的话 那么这就是你的中文的句子 然后这是你解码器的输入 在解码器在做预测的时候是没有输入的 实际上它就是解码器在之前时刻的一些 输出作为输入在这个地方 所以这个地方写的是一个output啊 然后他说shifted right就是一个一个往后往右移

然后看到是你的输入进来呢 先进入一个嵌入层 那可是大家都要干的事情 就是说你进来是一个一个词 我要把它表述成一个向量 那这个地方加了一个叫做positional encoding 我们等会再来讲 这个地方就是你的核心的一个 编码器的架构了 这个n是说你这个层啊有n个 就是n个这样层摞在一起 比如说你在讲Resnet的时候

我们说的一个残差块是一个块 然后你把n个块摞在一起 最后摞成了你的东西 在这个地方呢你可以认为这个叫做啊Transformer block 也是Transformer的一个块 具体你进去看的话 你会发现是说第一个一个叫做Multi-headed Attention 然后再有一个前馈神经网络 然后他有一个什么这个东西 这个东西大家知道这个就是一个残差的连接

然后这个norm我们等会儿再讲 基本上可以看到是说一个啊注意力层 再加上一个 基本就是一个MLP吧 然后在中间有一点的残差连接 然后再有一些的normalization 然后你的编码器的输出啊 就会作为你的解码器的一个输入 在这个地方放进来 这个是比较有意思的一个东西 解码器的话跟编码就有点像

但是呢这地方 所以这一块是一样的 但是它多了一个叫做Masked的一个多头注意力机制 当然我们等会会来讲啊 同样道理的话 你可以基本上可以认为就是解码器其实就是这三块组成一个块 然后把它重复n次 会得到你最后的一个解码器 最后你的输出进入一个输出层 然后做一个softmax就会得到你的输出啊

这个是这一块 就是标准的神经网络的做法 它确实是一个比较标准的编码器解码器的架构只是说你中间的每一块啊 跟之前是一个不一样的地方 在里面 但还有一个是说你怎么样 这个东西怎么过来 也是有一点的不一样的啊 接下来我们看一下每一个具体模块是怎么实现的 其实下面的文章跟上面写的很像 就是非常的简洁 所以你第一次读的话

很有可能会遇到一些困难 但没关系 我们这里会给大家仔细的讲一下 首先他给大家介绍了一下它的编码器 从编码器它是用一个 n等于六个的一个完全一样的层啊 也就是之前我们画的这一块啊 给大家看一下 就是说 他把这个东西叫做layer 然后再用 啊重复六个layer出来 他说每个layer里面呢会有两个sub-layers

就是一个子层 第一个sub-layer叫做multi-head self-attention 这个词已经出现很多次了 但是现在没有解释 他在之后才会解释 第二个子层呢是用的 名字很长啊 他说是simple 然后是position-wise fully connected feed-forward network 后面这个词是一个词啊 它说白了就是一个MLP 然后所以他为什么加一个simple 这里就是一个MLP

但是他为了显得 fancy一点呢 就把名字搞得特别长 但我们之后再来解释 他说对每一个子层 他用了一个残差连接 但我们上一期已经讲过残差连接了 他说最后我们在使用一个叫做 layer normalization的东西 解释完这一些之后 他说我这个子层啊 其实它的公式要写出来就是长成这个样子的 给大家画个线

就是说你的输入x进来 然后先进入你的那个子层 你是自注意力也好 mp也好 然后因为是残差连接啊 他就把输入和输出加在一起 最后进入他的LayerNorm 然后说他说为了简单起见啊 啊因为我的残差连接需要残差 需要你的输入和输出是一样大小 如果不一样大小的话 你得做投影 从而为了简单起见呢

我就把每一个层它的输出的维度变成512 也就是说你对每一个词啊 你不管在哪一层 我都做了 是512的这个 长度的表示这个我们之前讲的CNN是不一样的 或者我们之前做MLP的时候 经常会把维度啊往要么是往下减 要么CNN的话是空间维度往下减 但是channel维度往上拉

但是这个地方呢其实它就是固定长度来表示 使得这个模型相对来说是比较简单的 然后调参也就调一个参就行了 另外一个参数说你要复制多少块 所以这个简单设计影响到后面一系列网络啊 他说 bert怎么样GBT怎么样 实际上也就是两个操场是可以调的 你就要多少层 然后每一层里面那个维度有多大 也就是这两个参数

接下来给大家解释一下什么是LayerNorm 可能你不做这一块的话 可能之前是不知道LayerNorm LayerNorm也是因为Transformer 这篇文章啊被大家广为知道 再给大家解释一下 另外一个是说如果你写篇文章的话 你说我用了别人的 东西 最好在文章里面 真的讲一下它是什么东西 你不能真的指望别人都知道所有的细节啊

能能够花几句话讲清楚是不错 不然的话别人还得去点开那个链接去看一下到底 是什么东西 是给大家带来了困难 接下来我们通过跟batch norm来对比来解释一下什 么是layernorm 以及说为 什么我们在这些变长的应用里面不使用batchnorm 所以我们考了一个最简单的二维输入的情况啊 二维输入的话我就是输入是一个矩阵

然后呢我的每一行是一个样本 这是我的x 这个是我的batch 然后我的每一列呢是我的一个特征 那么这写的就是一个feature batchnorm的时候干的事情 就是说每一次啊 我去把我的每一个列 就是每一个特征 把它在一个小mini-batch里面 它的均值变成0方差变成1 你怎么把一个向量变成均值为零 方差为一呢

这是你把它的这个向量本身的均值减掉 然后再除以它的方差就行了 这个地方你算均值的时候呢 是在每一个小批量里面啊 就这条向量里面算出它的一个均值 算出它的一个方差 这个是在训练的时候 你可以做小批量 在在预测的时候呢 你会把一个全局的一个均值给算出来 这个你认为是以整个啊 整个数据扫一遍之后呢

在所有数据上那些平均的那个均值方差存起来 在预测的时候再使用 当然呢batchnorm还会去学一个 能把它一个伽马出来啊 就是说我可以把这个向量通过学习可以放成一个 任意方差为某个值 均值为某个值的一个东西 layernorm跟batch norm在很多时候是几乎是一样的啊 除了他做的

方法有点不一样之外 还如果同样的是我这一个二维输入的话呢 layernorm干的事情就是对每个样本啊 他做了 normalization 而不是对每个特征做了 就之前我是把每一个列它的均值变0方差变1 现在是我把每一个行变成 均值为零 方差为1 这个行就表示的是一个样本 所以你可以认为这个layernorm就是整个把 数据转置一下

放到batchnorm里面出来的结果 再转置回去一下 基本上可以得到自己的东西了 啊这个是你当你的输入是二维的时候 最简单的情况 但是在我们的Transformer里面 或者说正常的RNN里面 它的输入是一个三维的东西 因为它 输的是一个序列的样本 就是每一个样本其实是里面有很很个元素对吧 它是一个序列 你给一个句子里面有n个词 所以每个词有个向量的话

还还有一个batch的话 那么就是个3D的东西 我们把它画出来 就是长成这个样子的这个地方 还是你的batch 还是你的样本 列不再是我的特征了 而是我的那个序列的长度 我们 写成sequence 然后对每一个sequence就是对每个词啊 我当然是有自己的向量嘛 那我再画一个额外的维度画在这个地方

这个就是我的feature了 如果在之前的话呢 Transformer里面这个地方就是长 这个东西长的就是啊n 那feature呢就是d d在刚刚我们设成了512 那么如果你还是用batchnormalization的话呢 你每次是取一根特征 然后呢把它的每个样本里面所有的元素啊 这那个序列的元素啊 以及它的整个batch全部搞出来

把他的均值变成零 方差变成1就是说我这么切一下 切一块出来 把它拉成个向量 然后跟之前作一样的运算 如果是layernorm的话 那么就是对每个样本就是 就是啊这么切一下我用黄色来表示啊 就那就是用这么切一下 这么横着切一下 就这两种切法不一样 但说切法不一样

它是会带来不一样的结果 具体来说为什么layer norm用的多一点 一个原因是说 在 持续的这些序列模型里面 你的每个样本的长度可能会发生变化 比如说我们这个地方 我们可能会我们的样本是一个 第一个样本的长度是呃这样长的 第二个样本可能会长一点 第三个样本可能会短一点 第四个样本是中间长 可能是

长度是这样子变换的 那些没有的东西 一般我们是把它放上零进去啊 那我们看一下这两种切法会有不一样什么的结果 如果是用batchnorm的话 我切出来效果就是一个啊跟画出来结果一样 对每一个特征你切出来东西会是一个这样子的东西 剩下的东西当然是填的是零了 如果是 layernorm的话他其实会 就第一个样本

它切出来长度是一个这样子的长度 第二个样本当然会长一点啊 是这样子的长度 第三个是短一点 啊第四个是中等长度 这里的主要的问题是在算均值和方差的上面 对于batchnorm来说 我算均值的时候其实是通过这样子来算的对吧 但是我画线阴影的区域的只是有效值 别的值的话其实没什么太多用

你会发现你的如果你的样本长度变化比较大的时候 你每次做 小批量的时候 你算出来的均值方差 它的抖动相对来说是比较大的 而且这个另外一个问题是说 因为我们记得我们在做预测的时候 我们要把这个全局的均值和方差记录下来 那么这个全局的均值方差 如果碰到一个新的预测样本 如果特别特别长 怎么办

我碰到一个那么那么长的东西 那么 我是不是在训练的时候没见过那么伸出去那么多 那么我在之前算的均值和方差 很有可能是不那么好用的 但反过来讲 对layernorm相对来说没有太多 这个问题线 是因为它是每个样本自己来算 我的均值和方差 我也不需要存在一个全局的一个均值方差

因为这东西是对每个样本来做的 所以相对来说你不管样本是长还是短 反正我算均值是在你自己里面算的啊 这样子的话相对来说它稳定一些 这也是layernorm大家去看那篇文章的时候 他是给 大家这么解释的 但实际上来说我们知道哈一个很 好用的一个东西呢 原文写的东西可能和之后大家的理解是不一样的 在

在之后又有一篇文章来解释为什么layernorm 有效是更多是从一个啊对梯度呀 对于事物的那些normalization 然后呢提升它的啊常数来解释的 再讲完编码器的架构之后 我们来看一下解码器 解码器跟编码是一个很像的东西 首先它跟编码器角一样是由n等于六个 同样的层构成的

每个层里面呢跟编码器有两个一样的子层 但是不一样的在于说 解码器里面用了一个第三个子层啊 它同样是一个多头的注意力机制 他说跟编码器一样我们同样的用了残差连接我们用 的log 另外一个是我们知道在解码器的时候 他做的是一个自回归 也就是说你当前的输出

的输入集是上面一些时刻的输出 意味着是说你在做预测的时候 你当然不能看到之后的那些时刻的输出 但是我们知道在注意力机制里面 他每一次能看到整个完整的输入 所以这个地方我们要避免这个情况发生 也就是说在解码器训练的时候 再预测第t个时刻的

输出的时候你不应该看到t时刻以后的那些输入 它的做法是通过一个带掩码的注意力机制 如果你回过头来看这个图的话 你会发现这个地方是有一个masked的 你别的那些黄色的块都是多头的注意力 但是这个地方是有个masked 保证你输入进来的时候 在t时间呢是不会看到t时间以后的那些输入

从而保证你训练和预测的时候行为是一致的 好在看完我们的编码器和解码器的架构之后 我们来看一下每一个子层具体是怎么定义的 当然我们先要看到的是注意力层 第一段话就是一个对注意力的一个非常一 般化的介绍啊 属于你 懂的话 你看完之后就懂了 如果你不懂的话 你开完之后可能还是不懂 但不管怎么样

我们就按照这一段话给大家来解释一遍 首先他说 注意力函数呢是一个将一个query 和一些key-value对映射成一个输出的一个函数 这里面所有的query呀key value和output 它都是一些向量

具体来说你的output是你的valve的一个加权和 所以就导致说你的 输出的维度跟你的value的维度是一样的 另外一个是说这个权重是怎么来的呢 对于每一个value的权重啊 它是这个value对应的key 和你这个查询这个query 的相似度算来的 这个相似度

或者叫做compatibility function 不同的注意力机制有不同的算法 如果我们画一个简单示意图 可以长成这样子 假设我有三个value和三个对应的key 假设我们现在给一个query 这个query呢跟第一个第二个key比较近 就是放在这个地方 那么你的输出呢就是

这三个v的相加 但是呢这个地方的权重会比较大一点 这个地方权重也可能比较大 但是这个地方的权重就会比较小一点 因为这个权重是等价于你的 query和你对应的key的那个相似度同样道理 我假设再给你一个query 但是他是跟最后那一个key比较像的话

那么这样子你再去算他的v的时候呢 就会发现它对后面的权重会比较高一点啊 中间权重也还不错 最后的权重是比较小一点 就会得到一个新的输出 虽然你的key value并没有变 但是随着你query的改变 因为权重分配不一样 导致你的输出会有不一样 这就是注意力机制

因为不同的相似函数导致不一样的注意力的版本 所以接下来这一章就讲的是Transformer 自己用到的这一个注意力 是什么样子计算的 他取的名字叫做scaled dot-product attention 虽然名字比较长啊 实际上是最简单的注意力机制了 他说我这个里面呢我的query和key 它的长度是等长的 都等于dk

因为你可以不等长 不正常是有别的办法算的 然后它的value它的是dv 当然你的输出也一样的是dv了 他说我具体计算的是说 我对我每一个query和我的key呀做累积 然后把它作为相似度 你可以认为两个向量作了一积的事儿 如果这两个向量的long是一样的话 那么你的内积的值越大 就是它的余弦值

那么就表示这两个向量的相似度就越高 如果你的内积比如零了 那就等于是两个向量正交的 就是没有相似度 然后算出来之后 他再除以根号dk 就是你这个向量的长度 然后再用一个soft max来得到你的权重 因为你给一个query 假设给n个key value pair的话 那么就会算出n个值对吧

因为这个query会跟每个key做内积 算出来之后再放进soft max就会得到n个非负的 而且加起来和等于一的一个权重 对于权重我们觉得当然是非负啊加起来等于一 依旧是比较好的权重 然后我们把这些权重作用在我们的value上面 就会得到我们的输出了 在实际中当然 我们不能一个一个这么做 运算算起来比较慢

所以他下面给了一个在实际中的时候 我们应该怎么样算的 他说我的query啊可以写成一个矩阵 就是我其实可能不止一个query 我有n个query 那我们画出来就是一个假设 是一个 Q是这个地方 那么你就嗯行 然后你的维度呢是等于dk的 同样道理的话你的k啊

也是一个同样的东西 但你的可能会长一点或者短一点都没关系 假设你是m 就是你的query 个数和你的key value的个数可能是不一样的 但是它的长度一定是一样的 这样子我才能做内积 然后给定这两个矩阵啊 我把它一乘就会得到一个 n乘以m的一个东西对吧 所以这个东西里面它的每一行啊

就这个蓝色的线就是一个query 对所有key的那一个内积值 然后我们再再除以这个根号 dk 在做soft max 所谓的soft max就是对每一行做soft max 然后每行一行之间是独立的 这样子就会得到我的权重 然后再乘以我的v 我的v是有一个叫m行的

然后它的列数是dv的一个矩阵则是v 然后这两个矩阵乘的话就会得到一个 啊成为n乘以dv的一个东西对吧 我们写的这个地方n乘以dv 那么这个地方每一行啊 它就是我们要的一个输出了 所以这里你可以看到是说对于组key value对啊 和你n个query的话

我可以通过两次矩阵乘法来把整个计算 做掉这些query啊 key啊value啊在实际中对应的就是我的序列 所以这样导致说我 基本上可以并行的计算里面每个元素 因为矩阵乘法是一个非常好并行的东西 接下来一段他说我提出来的注意力机制啊跟别的 的区别是什么样子

他说一般有两种比较常见的注意力机制 一种叫做加型的注意力机制 它可以处理你的 query和你的key不等长的情况 另外一个叫做点积的注意力机制 他说点积的注意力呢跟我的机制是一样的 除了我这里除了一个这个数之外 所以你可以看到它的名字 它叫做 scaled就是除了那个东西

然后是点积注意力机制 接下来他说这两种注意力机制啊 其实 都差不多 但是它选用的是点乘 这是因为这个实现起来比较简单 而且会比较高效 因为这就是两次矩阵乘法就能算好 当然你需要解释一下 你为什么不直接用最简单的点乘注意力 你为什么要这里要出一个根号dk 他说呀

当你的dk不是很大的时候 其实你出不出都没关系 但是当你的dk比较大的时候 也就是说两个向量啊 它的长度比较长的时候 那么你做点积的时候 这些值呢可能就会比较大 但也可能是比较小了 当你的值相对来说比较大的时候呢 你之间的相对的那些差距啊就会变大

就导致说你值最大的那一个值做出来 soft max就会更加靠近于1 剩下那些值呢就会更加靠近于零 就是你的值就会更加像两端靠拢 当你出现这样子的情况的时候 你算梯度的时候 你会发现梯度比较小 因为soft max最后的结果是什么 最后的结果就是我希望我的预测值啊 置信的地方尽量靠近1

不置信的地方尽量靠近零 这样子的时候 我说我的收敛就差不多了 这时候你的梯度就会变得比较小 那你就会跑不动 所以他说啊我们在Transformer里面一般用的 dk比较大 之前说过是512 所以除以一个根号dk是一个不错的选择 整个这个注意力的计算呢 他在上面有张图给大家画了出来

可以看到你在里面要两个矩阵 一个是query一个是key做矩阵乘法 然后再除以根号dk 这个地方我们一会儿讲 然后再做soft max 做出来结果最后跟你的值的那个矩阵做 矩阵乘法就会得到你的输出了 这个是通过计算图来展示你这个是怎么做的 另外一个我们要讲到是怎么样做mask

mask主要是为了避免 你在第t时间的时候看到以后时间的东西 具体来说 我们假设我们的query和key是等长的 他们长度都为n 而且在时间上是能对应起来的 然后对第t时间课的qt啊 这是我的query 那么我在做计算的时候

我应该只是看k1一直到kt-1 而不应该去看了kt和他之后的东西 因为kt在当前时刻还没有 但是我们知道在注意力机制的时候 其实你会看到所有 你qt会跟所有k里面的东西全部做运算 就是kt一直算算算算到kn 那这个时候怎么办

就是说我们发现其实你算还是可以算的 就是说你把这些值全部给你算出来 啊 然后呢在算出来之后 我们只要保证说在计算权重的时候 就是算输出的时候呢 我们 不要用到后面的一些东西就行了 具体来说他就在你这个地方呢加了一个mask mask的意思是说

对于qt和kt和他之后的计算那些值 我给你换成一个非常大的负数 比如说一一负的一一十次方 那么这一个那么大的负数在 进入soft max做指数的时候 它就会变成零 所以导致soft max之后出来的这些东西啊 它的它对应的那些权重都会变成零

而只会前面这些值出效果 啊这样子的话我在算我的output的时候 我只用了v 对应的v1一直到vt-1的结果就用上了它 而后面的东西我没有看 所以这个mask效果是在我训练的时候 我让你t个时间的query 只看我对应的前面那一些的keyvalue pair

使得我在做预测的时候 我跟现在这个是能够一一对应上的 在讲完注意力机制的计算之后呢 我们来看一下multi-head是在干什么事情 我们首先还是回到我们的文字那部分啊 他这里说与其我做一个单个的注意力函数 不如说我把整个query呀,keyvalue呀投影到一个低维 投影h次 然后再做h次的

注意力函数 然后每一个函数的输出 我把它并在一起 然后再投影来会得到我的最终的输出 他说我们在图二给大家演示这个效果 那我们就跳回图二看一眼它是怎么做的 然后他说这个是我们原始的value啊 key啊 query啊 然后在这地方呢我们 进入一个线性层

线性层就是把你投影的比较低的维度 然后再做一个 scaled dot-product attention 就是这个东西了 全部放进来 然后我们这里做h次 会得到h的输出 我们再把自己这些向量啊全部 合并在一起 最后做一次线性的投影 会回到我们的multi-head attention 所以为什么要做多头注意力机制呢 如果我们回过头来看这个

dot-product的注意力的话 你会发现里面没有什么可以学的参数 你的 具体函数啊就是你的内积 但有时候我为了识别不一样的那些模式 我希望你可能有一些不一样的计算像素的办法 如果你用的是加性 attention的话 这里没有提到的 那里面其实还是有一个权重 你来学的 你也许可以学到这些东西 他说那我不用那个 那我用这个的话

我的一个做法是我先让你 投影到一个低维 这个投影的w是可以学的 也就是说我给你h次会 希望你能学到不一样的投影的方法 使得在那个投影进去的那个度量空间里面 能够去匹配不同模式 它需要的一些相似函数 然后最后把这些东西回来 最后再做一次投影啊

所以跟我们之前说到的有点点像 在卷积网络里面 你有多个输出通道的感觉 然后我们看一下这个东西的具体的公式是怎么算的 那你会发现是在Multi-Head的情况下 你还是以前的Q,K,V 但是呢你的输出啊已经是你不同的头的 那一个输出的做concat起来

再投影到一个WO里面的 对每一个头啊 他就是把你的qkv 然后通过一个不同的可以学习的WQ,WK,WV 投影到一个dv上面 在做我们之前提到过的注意力函数 然后再出来就行了 这个地方你可以说每一个里面当时怎么算的 他们在实际上来说 他用的h是等于8的 就是用8个头

而且我们知道你的注意力的时候 因为有残差连接的存在 使得你的输入和输出的维度 至少是一样的 所以它的做法是说你投影的时候 它投影的就是你的输出的维度啊 除以h 因为我们之前我的输出维度是512 所以除以八之后呢 就是每一次我们把它投影到一个64维 的一个维度

然后在上面算你的注意力函数 然后再 并起来再投影回来 虽然这个地方你看到是非常多的小矩阵的乘法 实际上你在实现的时候也可以通过一次 的矩阵乘法来实现 这个可以作为一个练习题 大家去看一下怎么样实现它 在讲完多头注意力是如何实现了之后 在3.2章的最后个小节里面讲的是

在Transformer这个模型里面是如何使用注意力的 他这里讲了三种使用的情况啊 我们最简单的方法是回到我们之前那个架构图 看一看它到底是怎么被用的 我们回到我们的架构图啊 我们看到的是黄色 这个东西表示的是注意力的层啊 这个地方一共有三种不一样的注意力层 首先我们看一下我们的编码器的注意力是在干什么事情

然后我们分别来看一下每一个注意力层 它的输入和输出分别是什么 这个其实对应的是刚刚我们那一小节里边的 三段话 首先我们来看一下我们的编码器的注意力是在干什么事情 我们知道编码器的输入啊 这个地方啊 假设你的句子长度是n的话呢 它的输入其实是一个n个长为d的向量啊 假设我们的pn大小设成1了 我们把它画出来

就是每一个输入它的词 对应的是一个长为d的向量 然后我们这里一共有n个这样子的东西 然后我们来看一下注意力层啊 它有三个输入 他分别表示的是 key value 和query 然后这个地方是你一根线过来 然后他复制成了 三下意思就是说 同样一个东西 我既作为key 也作为value 也作为query

所以这个东西叫做自注意力机制 就是说你的key value和query其实就是一个东西 就是自己本身 然后我们知道 那么这个地方我们输入了n个query 那么每个query我会拿到一个输出 那么意味着我会有n个输出 而且这个输出和value 因为长度是一样的话 那么我的输出的维度其实也是那个d

就是意味着我的输入和输出的大小其实是一个东西 但我们也可以把它画出来啊 画出来的话 其实你就是你的输出也是跟它长度一样长 长为n的一个东西 对于每一个query 我会计算一个这样子的输出 因为我们知道这个输出啊 其实就是你的value的一个加权和 权重呢是来自于query和key的一些东西 但它本身是一个东西

那么就意味着说 他的这个东西呢 实际上本身就是你的输入的一个加权的一个和 然后这个绿色线代表权重的话 因为这个权重其实本身就是这一个向量 这个向量跟每一个输入的别的向量计算相似度 那么他跟自己算肯定是最大的 就是说你这根线肯定是最初的 假设这个线跟你啊最这边这个向量也

相似度比较高的话 那么这个权重也会稍微高一点 假设我们不考虑多头啊和有投影的情况 你的输出呢其实就是你的输入的一个加权和 你的权重来自于你自己本身啊 跟 各个向量之间的一个相似度 但如果我们说过有多头的话 因为有投影 其实我们在

这个地方会学习h个不一样的距离空间出来 使得你出来的东西当然是会有一点点不一样了 这个就是第一个 注意力层是如何用的 然后你看到嗯 解码器解码器是一回事 它这个地方一样的 是一个东西过来 然后复制成了三次 然后解码器的输入也是一样的 只是长度可能变成了一个长为m的样子

然后你的维度其实也是一样的 所以它跟编码器是一样的 自注意力 唯一不一样的是 这里有个masked这个东西 我们之前有解释过 在解码器的时候啊 比如说你算这一个query它对应的输出的时候呢 它是不应该看后面那些东西 所以意味着是说在解码器的时候 你的这些后面的东西要设成零 我们用黄色的线表示一下

就是说后面这些东西呢这些权重你要设成零 在解码器的时候 这就是masked它的一个作用 然后我们看第三个注意力层 也就是在这个地方 这个地方你看到是他不再是自注意力了 而是 你的key和你的value来自于你的 编码器的输出 然后你的

query呢是来自于你下解码器下一个attention的输入 我们知道你的编码器最后一层的输出 就是n个长为d的向量 我们把它画在这个地方还是 那么你的解码器的masked attention啊 就最下面那个attention它的输出是 m个也是长为d的向量 我们也把它画在这个地方

这里你的编码器的输出作为value和key进来 然后你的解码器下一层的输出呢作为query进来 意味着是说对解码器的每一个输出呢 作为query我要算一个我要的输出啊 假设我用蓝色的表示的话 那么你的输出是我们知道是来自于value的一个加权和 那我就是来自于你的

编码器它的输出的加权和我如果把它划过来 就是有一个这样子的东西过来 一些权重过来 这个权重它的粗细程度啊 就是取决于 我这个query 跟这个东西的相似度 假设我这个东西跟这个东西相似度比较高的话 那么我的权重这个地方就会大一点 如果相似度比较低的话 权重就会小一点

那意味着是说在这个attention干的事情 其实就是去有效的把你的 编码器里面的一些输出啊 根据我想要的东西给它拎出来 举个具体的例子 假设你是在做英文翻译中文啊 我假设第一个词是hello 对应的向量是这个东西 然后我第二个词是hello world的话

那么你的中文他就是第一个 当是你对吧 你好 所以你会知道说在算 好的时候 如果它作为query的时候 那么呢去看 hello的这个向量应该是会相近一点 给它一个比较大的权重 但是world 这个是后面的次相关 我发现到word这个词跟我这个query 相关度没那么高 在计算你的相似度的时候

那么就是说在算好的时候呢 我会给它一个比较大的权重 在这一个上面 但是我在后面如果还有你好 世界的话 如果是个世的话 那么在这个query的时候 我再去算它的输出这个东西的时候呢 它那么就会给第二个向量 给一个比较大的一个权重出来

意味着是说根据你在解码器的时候 你的输入的不一样 那么我会去 根据你的当前的那一个向量 去在编码器的输出里面去挑我感兴趣的东西 也就是你 注意到你感兴趣的东西 那些没有跟你不那么感兴趣的东西 你就可以忽略掉它 这个也是说attention是如何在

编码器和解码器之间传递信息的时候 起到的一个作用 这样我们就讲完了 Transformer里面三个attention 他到底是在干什么事情 那么接下来我们要去讲蓝色这个feed forward 是在干什么东西 3.3节讲的就是这个名字很长的point-wise feed forward network 他说他其实就是一个fully connected feed-forward network 他就是一个MLP了

但是他不一样的是说他是applied to each position seperately and identically position是什么东西呢 就是你输入的那一个序列啊 不是有很多很多个词吗 每个词它就是一个点 他就是那一个position 然后他就是把一个MLP对每一个词作用一次 然后对每个词作用的是同样一个MLP 所以这个就是point wise的意思

它说白了就是MLP只是作用在最后一个维度 具体来看一下它是怎么写的 这个东西大家认识对吧 就是一个线性层 max0到这个东西就是一个Relu的激活层 然后再有一个线性层 我们知道在我们的注意力层 它的输入啊 就每一个query它对应的那一个输出 它是常为512 那么就是说这个xg呢就是一个512的一个向量

他说 w1我会把512投影成2048 这个维度就等于是我把它的维度扩大了四倍 因为最后你有一个残差连接 你还得投影回去 所以W2呢又把2048投影回了512 所以这个东西说白了就是一个 单隐藏层的MLP 然后中间隐藏层 把你的输入扩大四倍 最后输出的时候也回到你输入的大小

说白了就是啊你用pytorch来实现的话 它其实就是把两个线性层呢放在一起 你都不需要改任何参数 因为pytorch去当你的输入是一个3d的时候 它默认就是在最后一个维度做计算 为了更好的理解 我们用图把他跟 你的attention这个东西给大家画一下 以及说它跟我们之前的rn它的区别在什么地方

我们这里还是考虑一个最简单的情况 就是没有残差连接 也没有lay alone 然后你的attention呢也是一个单头 然后没有投影 我们知道我们的输入啊就是一个 长为n的一个一些向量 我们画在这个地方 在进入attention之后 啊就是attention之后 我们就会得到同样长度的一些输出 在这个地方

在最简单的情况的attention 其实说白了就是对你的输入 做一个加权的和对吧 然后加权和之后我们进入我们的MLP 就是那个point wise的 l MLP 我们把它画在这个地方 我们写个MLP 虽然我们画了几个东西 但其实它就一个就是说每一个 红色的方块之间的权重是一样的

然后每个MLP对每一个输入的点呢做运算 会得到一个输出 最后就得到了整个 Transformer块的一个输出是这样子 虽然它的输入和输出都是 大小都是一样的 所以这个地方你看到的是说 attention起的作用是什么东西 他就是把整个序列里面的信息抓取出来 做一次汇聚aggregation

所以这个东西已经就有了我序列中感兴趣的东西 信息已经抓取出来了 以至于我在做投影啊 在做MLP的时候 映射成我更想要的那个语义空间的时候 因为这个东西已经含有了我的序列信息 所以每个MLP只要在对每个点独立做就行了 因为这个地方啊历史信息 因为这个地方序列信息已经被汇聚完成

所以这个地方是可以分开做的 也就是整个Transformer是如何抽取 序列信息 然后把这些信息加工成我最后要的那个语义空间那个 向量的过程 作为对比啊 我们看一下rn是怎么做的 我们知道rn的输入跟你是一样啊 就是一些向量 然后对于第一个点呢 说白了你也就是做一个线性层

我们做一个最简单的就是一个 啊 没有隐藏层的MLP就是一个纯线性的层 第一个点就是直接做出去就完事了 对于下一个点 我是怎么样利用我的序列信息的呢 我还是用之前这个MLP它的权重跟之前是一样的 但是呢我的时序信息啊 我用绿色表示

它就是把这个东西它的上一个时刻的输出 放回来 作为跟输入一起并入进去 这样子我就完成了我信息的一个传递 然后用 绿色的线表示的是之前的信息啊 蓝色的线当时表示的是我当前的信息 这样子我会得到一个当前的一个输出 历史信息就是上一次的那个输出作为历史信息进来

然后得到我当前的一个输出 所以可以看到是说rn呢跟Transformer是一样的 都是用一个线性层 或者说一个MLP 来做一个语义空间的一个转换 但是不一样的是你如何传递序列的信息 rn是把上一个时刻的信息 输出传入下一个时候做输入 但是在Transformer里面

它是通过一个attention层 然后再全局的去拉到整个序列里面信息 然后再 用MLP做语义的转换 这个是两个模式之间的区别 但是它的关注点 都是在你怎么有效的去使用你的序列的信息 好这样我们就只剩最后两个层了啊 第一个层是叫做embedding 后面一个层叫做positional encoding 这embedding大家都知道

因为我的输入是一个个的词 或者一个叫词源 叫token 那我需要把它映射成一个向量 embedding就是说给任何一个词 我学习一个长为d的一个向量来表示它 这个d 当然这个地方你可以认为就是等于512了 他这里是说你的编码器要一个embedding 你的解码器的输入也要有个embedding 这货在你的soft max前面那个线性啊 也需要一个embedding

他说我这三个是 一样的权重 这样子我训练起来会简单一点 另外一个有意思的是说他把权重啊 乘了一个根号d d就是512 为什么做这个事情是因为 你在学embedding的时候呢 多多少少会把每一个向量啊 它的l2long 学成 相对来说比较小的 比如说学成1吧 就不管你的维度多大的话 最后你的值都会等于1

那就是说 你的维度一大呢 你学的一些权重值就会变小 但是你之后我要加上这个东西 加这个东西的时候 它不会随着你的长度变成了它把你的long固定住 所以它成了它之后 使得 这么两个相加的时候 再一个 scale上大家都差不多 就是他做了一个hat 下面一个东西叫做positional encoding 你为什么有这个东西 是因为你发现

attention这个东西是不会有时序信息的 你想一想你的输出是什么东西 你的输出是你的value的一个加权和 你这个权重 是query和key的之间的那个距离 它跟你的序列信息是无关的 就我根本就不会去看你那个key value里面那些对啊在那个 序列里面哪个地方 所以意味着说我给你一句话

我把顺序任何打乱之后 我attention出来结果都是一样的 顺序会变 但是值不会变 这个当然是有问题的对吧 在处理时序数据的时候 我给你一句话 假设我把里面的词给你完全打乱 那么在 你语义肯定会发生变化 但是你的attention不会处理这个情况 所以我需要把时序信息加进来 rn是怎么加呢 而是说上一个时刻的输出

作为下一个时刻的输入来传递我的历史的信息 所以它本来就是一个时序的一个东西 但是要attention不是 他的做法是说我在我的输入里面加入时序信息 就是说你这一个词啊 他在一个位置i i这个位置这个数字12345啊 加到你的输入里边 所以这个东西叫做positional encoding

具体来说呢他后面给了一个公式 它是具体是怎么算的 我就不给大家完全讲个公式给大家讲一下啊 大概的思路是什么样子 在计算机里面我们怎么表示一个数字 假设我用一个32位的整数来表示数字的话 那就是用32个bit 每个bit上面有不同的值来表示 012345678 你可以认为就是说我一个数字是用一个

长为32的一个向量来表示的 现在 我一个词在嵌入层 会表示成一个长为512的向量 同样我用一个长为512的向量来 表示一个数字 表示你这个位置012345678 具体那些值是怎么算出来的 是用周期不一样的sin和cos函数的值来算出来的 所以导致说

我任何一个值 可以用一个长为512的一个向量来表示它 然后呢这个长为512的 记录了时序信息的一个东西啊 跟你的嵌入层相加就会完成了 我把时序信息加进我的数据的一个做法 如果我们回到之前的架构图的话 你可以看到我的输入进来 进入embedding层之后

那么对每个词都会拿到那个向量 长为512的一个向量 然后positional encoding 就是你这个词在我这个句子中的位置 告诉他 他返回给你一个长为512的一个向量 表示这个位置 让把这两个加起来就行了 这个东西因为是cos和sin的一个函数 它是在正1负1之间抖动的 所以这个东西成了一个根号d

使得每个数字呢也是在差不多的正1到负1之间 这个数值区间里面 然后进去之后 那么我就完成了 在输入里面加入了信息啊 这是因为我后面整个这一块啊是 顺序不变呢 就是说我的输入的序列 不管我怎么打乱我的顺序 进去之后 我的输出那些值是不变的 最多是 我的顺序发生了相应的变化

所以他就把顺序信息直接在数据里面那个 值给加进去了 好这样我们就讲完了 第三章也就是整个Transformer模型的架构 你看一下第三章其实写的并不长啊 就那么几页 但是你真的要讲的话 其实你需要花比较长的时间 这也给大家带来了很多困扰 如果你第一次读这篇文章 而且对这个模型 不那么了解的话 你可能读下来发现啊

很多细节你都没有搞明白是怎么回事 第四章是大概解释一下为什么要用自注意力 你发现读到这里为止啊 整个这篇文章是告诉你我这个模型长什么样子 并没有告诉你说我为什么要这么做啊 以及我整个设计理念是怎么回事 但这个地方大家给你稍微讲了一下 我为什么要这么做

它主要说的是相对于你用循环层或者卷积层的时候 我用自注意力有多么好 但是整个来说这篇文章呀 对整个模型的解释其实是比较欠缺的 然后整个这一段话呢 他解释的其实就是我们这一个表 我们就直接给大家讲一下这个表是在干什么

他说我们比较了四种不一样的层啊 第一个当然是他们关注的自注意力 然后是循环层 卷积层 另外一个是它构造出来一个受限的自注意力 它呢有三列做比较 第一列是说我的计算复杂度当然是越低越好 第二个是说我的顺序的计算 越少越好 顺序的计算

就是说你下一步计算必须要等前面多少步计算完成 在算一个Layer的时候 你越不要等那么你的并行度就越高 最后一个是说 一个 信息从一个数据点走到另外一个数据点要走多远 这也是越短越好 我们分别来看一下每一个层它代表的数值 是什么意思 首先我们来看自注意力啊

n这个地方是你序列的长度 d是你向量的长度 我们知道整个自注意力的话 其实说白了就是几个矩阵做运算啊 其中一个矩阵是你的 query的矩阵乘以你的key的矩阵 你的query矩阵 你的是有n行 你的n个query 然后你的列数是d 就是你的维度是d 然后你的key呢也是一样的 也是n乘d 所以两个矩阵一乘的话 那么算法复杂度就是n的平方乘以d

另外当然还有一些别的矩阵运算 但是它的复杂度都是一样的 所以是有个on平方d的这个地方 然后你的 sequential operation呢 因为你就是那么几个矩阵乘法 矩阵里面它可以认为是并行度比较高的 所以这个地方是一个O(1)的 最大的长度是说 你从一个点的信息想跳到另外一个点要走多少步 我们知道在attention里面

就是一个query可以跟所有的key去做运算 而且你的输出啊是你所有value的一个加权和 所以就是说任何 query跟任何一个很远的一个key value pair 我只要一次就能过来 所以呢这个长度是比较短的 然后看一下循环层 循环层呢是我们知道就是 如果你的序列是乘了n的话 它就一个一个做运算

每个里面呢它的主要的计算就是一个n乘以n的一个矩阵 一个 就是一个dense layer 然后再乘以你一个成为d的一个输入 所以它是一个n平方 然后要做n次 所以是n乘d的平方 然后你对比一下这两个东西啊 是有一定区别的 就真的取决于是n大还是d大 如果你n大的话 当然它过一点 你d大的话是下面一个过一点 实际上来说你的d这个地方是512

你的n呢 也差不多是几百的样子吧 现在当然是说 比较大的模型的话 d可以做到2048呀 甚至更大 你的n呢相对来说也会做的比较 也是几千的样子 所以你其实现在看起来这两个东西都差不多 就是n和d的 其实在差不多的数据上面 所以啊这两个都差不多 但是在循环的时候呢

因为你是要一步一步做运算 当前时间刻的那个词啊 需要等待前面那个东西完成 所以导致你是一个成为n的一个序列化的操作 在并行上是比较吃亏的 我们之前提到过 另外一个是说你最初点的那个历史信息啊 需要到最后那一个点的话 需要走过n步才能过去 所以他这个地方的最长是O(n)

所以大家会批评 RNN说你对特别长的序列的时候做的不够好 因为你的信息一开始走啊走啊走 就走丢了 而不像attention一样 就可以直接一步就能过去 然后看一下卷积啊 卷积我们 大家也没有特别解释卷积在序列上怎么做 具体做法是它用一个ed的卷积 所以他的kernel啊它就是个k 所以就是不是k平嘛

就是k n是你的长度 然后d呢就是你的输入的通道数和输出的通道数吧 所以这个地方是k乘n乘d的平方 k一般也不大啊 k一般就三啊五啊 几 所以这个东西你也可以认为是常数 所以导致说卷积的复杂度和RNN的复杂度其实是差不多的 但是卷积的好处是说 你就是一个卷积操作就完成了 里面的并行度很高

所以卷积呢做起来通常比RNN要快一点 另外一个是说卷积每一次一个点是有 一个成为k的一个窗口来看呢 所以他一次一个信息在 k距离内是能够一次就能传递 如果呢你超过k了的话 他要传递信息的话 他要通过多层一层一层上去 但是它是一个log的一个操作 所以这个东西也不亏

最后一个东西他是说当我做注意力的时候啊 我的query只跟我 最近的r个邻居去做运算 这样子的话我就不用去算n平方这个的东西了对吧 但他的问题是说 这样子的话有两个比较长的远的一个点啊 需要走几步才能过来啊 所以他就损失了这个东西 一般来说在实际上来说呢 啊我们

用attention主要是关心说啊 特别长的序列 你真的能够把整个信息揉的比较好一点 所以在实际过程中啊 这一块感觉上用的不是那么多啊 大家都是用最原始的版本 不用太做受限了 所以呢基本上就是考虑这三个 所以基本上可以看起来是说就实际中啊 就是当你的序列的长度啊 和你的整个模型的宽度啊差不多的时候

而且大家深度都一样的话 基本上这三个模型的算法复杂都是差不多的 当然是说你的attention和卷积相对来说计算会好一点啊 另外一个是说attention在信息的糅合性上会好一点 所以你可能认为这个地方还是能影响一些东西了 所以你看上去是说用了self-attention之后 是不是你的感觉上对长数据处理更好

而且可能算得也 不快就不会慢对吧 但实际上其实也不是这样子的啊 实际上是说attention对你整个模型的假设做了更少 导致说你需要更多的数据和更大的模型才能训练出来 跟你的RNN和CNN同样的效果 所以导致现在基于Transformer的模型呢 都是特别大特别贵

好在讲完模型之后 我们接下来讲一下实验 第五章是讲你训练的一些设置是怎么样的 首先他说我的训练数据集和我的batching怎么做的 他用了两个人物 一个是英语翻德语 他用的是标准的WMT 2014的数据啊 它这个里面有4.5万个句子的对 他说他用的是byte-pair encoding 就是bpe啊

大概的思想是说 你不管是英语还是德语啊 其实一个词里面有很多种变化 就是什么加ing啊 加es呀 但是你如果直接把每一个词做成一个token的话呢 你会导致你的字典里面的东西会比较多 而且一个动词的可能有几种变化形式 你做成不一样的词的时候 他们之间的区别模型是不知道了

bpe相对来说就是把你那些词根给你提出来啊 这样好处是说它可以把整个字典这样的比较小 它这个地方用的是 37000个token的一个字典 而且它是在英语和德语之间是共享的 就是说我们不再为英语构造一个字典 不再为德语构造一个字典 这样的好处是说 我整个编码器和解码器的一个embedding 就可以用一个东西了

而且整个模型变得更加简单 也就是他之前所谓的我的编码器 解码器那个embedding它是共享权重的 另外一个英语到法语的话 他用了一个更大的一个数据集 在接下来的硬件和schedule部分 他说我训练使用了八个P100的GPU 啊这个是比较有意思的 就是说在三年前啊 google的工作还是大量使用gpu的 但是

这个之后基本上就很少见了 因为在这个之后 google让内部的员工尽量使用tpu 限制你们使用gpu 这篇文章多多少少也是推动这个进展 这是因为 Transformer里面我们知道基本就是一些比较大的矩阵 做乘法 tpu这种东西啊 就是特别适合做大的矩阵乘法 以致于Google说 你们其实挪到tpu也没有太多问题

可能性能还更好一些 他说我们的base模型呢是用的一个小一点的参数 他每一个bench训练的时间是0.4秒 然后我们一共训练了10万步 一共就是在我的八个gpu上训练了12个小时 就基本上一台机器训练12个小时 也是不错的一个性能啊 他说我一个大的模型啊

这样一个batch训练需要一秒钟 然后他一共训练了30万步啊 最后是一台机器3.5天 那其实也是一个可承受的范围啊 但是这个朋友之后的那些 之后的工作基本上是属于大家几乎不能承受的 时间成本了 在训练器上面 他们用的是Adam 他们用的是Adam 这是它的参数 β2 我觉得可能不是最常用的 β2我记得应该是0.99还是0.999

所以他选了一个稍微少一点的值 然后他的学习率是用这个公式算出来的 有意思的是他的学习率是根据你的模型的那个 宽度的-0.5次方 就是说当你的模型越宽的时候 就是你学的那些向量越长的时候 你的学习率要低一点 另外一个是它有啊 他有一个warmup 就是从一个小的值慢慢地爬到一个高的值 爬到之后呢

再根据你的步数啊 按照0.5次方衰减 最后他说我的warmup是4000 有意思的是 基本可以看到说这个地方没有东西可以调的 就是你的学习力几乎是不用调的 取决于第一adam对学习率确实不那么敏感 第二个是说他这个地方也是把整个 他就两个模型对吧 这个东西已经考虑进来了啊 这个这个schedule就已经也算是不错的schedule了 所以在学习率是不需要调的

然后在5.4的时候讲的 他使用的正则化 他用了三个正则化呀 第一个是他用的是一个叫做residual dropout 说白了就是说对每一个子层 子层就是包括了你的多头的注意力层 和你之后的MLP 在每个层的输出上 在他进入残差连接之前和在进入layer alone之前

他使用了一个dropout 他的dropout率是0.1 也就是说 把这些输出的10%的那些元素只乘0.1 剩下的那些只能乘以1.1 另外一个他在输入加上你的词嵌入 再加上你的positional enconding的时候呢 在它上面也用了一个dropput 也就是把10%的元素值乘了一个

有意思的是说你基本看到对每一个带权重的乘啊 他在输出上都使用的dropout 用的是比较狠的 虽然这个 dropout率并不是特别高 但是它使用了大量的dropout的层 来对它的模型做正则化 然后另外一个他使用的是一个label smoothing 这个技术是在 inception v3让大家官方的知道啊 啊意思是说我们用softmax

去学一个东西的时候 我的标号是 正确的是1 错误的是0 就是我用 对于正确的那一个label的softmax的值 去逼近于1 但我们知道softmax 是很难逼近于1的 因为它里面是一个指数 它是一个很soft的一个东西 就是说 它需要你的输出接近无限大的时候 才能逼近于1啊 这个使得训练比较难 一般的做法是说你不要让

搞成那么特别难的零和一 你可以把那个一的值往下降一点 比如说降成0.9啊 但这个地方他降得比较狠啊 他是降成了0.1 就是说对于正确的那个词 我只需要我的softmax的输出 是到0.1就行了 叫置信度是0.1就行了 不需要做的很高啊 剩下的那些值呢就可以是0.9除以你的 字典的大小

他说这里会损失你的 perplexity perplexity你的log lost做指数 基本上可以认为是你的模型补缺行动 因为你这个地方让你学说我正确答案 我也只要给个10%是对的就行了 所以当然你的不确信度会增加 所以你这个值会变高 但是他说我的模型会不那么确信 会提升我的精度和我的BLUE的分数

因为精度和blue的分数才是我们关心的重点 所以这个地方他说觉得没关系 那我们接下来看第二个表 第二个表表示的是不同的超参数之间的一些对比 我们可以看一下有哪些超参数啊 就回忆一下n是什么 n是你要 堆多少层 d是你这个模型的宽度 就是一个token进来要表示成一个多长的向量

dff表示的是你拿MLP中间那个隐藏层的输出的大小 h是你的头的个数 就是你注意力层的头的个数 dk dv分别是你一个头里面那个 啊key和那个value那个维度 你的P是你dropout 是你的丢弃的率 以及这个是说你最后 label smoothing的时候 你这个要学的那个label的真实值是等于多少

最后一个是说你要训练多少个batch 然后可以看一下它的base模型啊 base模型我们知道是说他用了六个层 然后每一层的宽度是512 然后这个东西基本上就是它的四倍了 然后 头的数乘以你的维度数是等于他的 就是8乘64 等于500兆 啊dropout率是0.1 然后这个是0.1 然后最后是训练了10万步

另外一个是他的big模型 基本上可以看到是说 这个东西没有变 但是呢模型的宽度乘了两倍 然后啊这个东西也当然是跟着翻倍了 他也把这个头的个数乘了两倍 然后这个东西就不用变了 另外一个是你的模型更加复杂了 所以他用了一个比较大的 丢弃率0.3 而且模型更加复杂了 收敛会慢一点 因为你的学习率是变低了的

这个地方他训练的30万个批量大小 所以基本上可以看到是 整个模型参数相对来说还是比较简单的啊 基本上你能调的就是一个 要多少个层 然后你的模型有多宽 以及说你要多少个头 剩下的这些东西基本上都是可以按比例算过来的啊 这个也是Transformer架构的一个好处 虽然你看上去那个模型啊 比较复杂 但是也没有太多东西可以调啊

这个设计上来说让后面的人更加方便一点 比如说bert它其实就是把这个价格拉过去 然后把这个把这几个参数改了一下啊 gpt也就是 基本上就是靠比过去 然后稍微调一下就行了 让后面的人的工作变得简单了很多 最后一个表是另外一个啊 NLP任务上大家不熟的话 我们就可以跳过来 他也 你放一个也挺好的 你不放其实也没关系

就是他是说我的结果还不错 就是不仅仅是在机器翻译上还行啊 我又找了一个另外一个人 我说 哎 效果也还挺好的 就是这个要表达的一个观点 好这就是我们实验的部分 我们很快速的给大家过了一遍 好最后我们来评价一下这篇文章啊 我们首先看一下它的写作啊 这篇文章的写作是非常简洁的 因为就是说 他每一句话就基本上在讲一件事情

你看那么短短的一篇文章 我们读下下来大概就花了一个半小时 也能理解是说你有那么多东西 你要塞到那么短的一个篇幅里面 你只能用这么写 另外一个是说他没有用太多的写作技巧 基本上就是说啊你看我提出一个什么东西 这个模型长什么样子啊 跟CNN和RNN比是什么样子 最后的结论是 最后的实验结果是什么东西 这个不是那么推荐的一种写法 因为对一篇文章来说

你需要在讲一个故事 让你的读者有代入感 能够convince读者 但是我也能理解说 你要在一篇文章里面发现那么多东西的话 也没那么多篇幅来讲一个很好的故事 啊一般的建议是说 假设你写篇文章的话 你可以选择把你的东西减少一点 甚至把一些东西 不那么重要的东西放到你的附录里面 但是在正文的时候 你还是最好讲个故事 说你为什么做这个事情

你的一些啊设计的理念是什么样子的 你的对整个文章的一些思考是什么样子的 这个东西让大家会觉得你的文章更加有深度一些 接下来我们评论一下Transformer这个模型本身啊 我们现在当然可以看到Transformer模型不仅仅是用在机器翻译上面 它也能够用在几乎所有的NLP的任务上面 在后续的工作

bert gpt 让大家能够 训练很大的易训的模型 能够极大的提升所有 NLP里面的任务的性能 这个有点像CNN在对整个计算机视觉的改变 我们能够训练一个大的CNN的模型 使得别的人物也能够从中受益 另外一个是说 CNN给整个计算机视觉的研究者 提供了一个同样的一个框架

使得我只要学会CNN就行了 而不需要去管以前跟任务相关的那么多的 专业的知识 比如说做特征提取啊 对整个任务怎么建模 Transformer也是一样的 之前我们要做各种各样的数据文本的预处理 然后我要根据NLP的任务 给你设计不一样的架构 现在不需要了 我们用整个transform这个架构

就能够在各个任务上做得非常好的成绩 而且他预设的模型也让大家的训练变得更加简单 当然我们还看到的是Transformer 现在不仅仅是用在在源上面 也在图片上啊 语音上 media上取得了很大的进展 这个是一个非常有影响力的一件事情 这是因为之前计算机视觉的研究者是用CNN 而在原处理你用RNN 然后别的人用别的模型

现在是说大家发现同样一个模型能够在所有领域 都能用 就是让大家的语言变成一样了 就以前你用python 我用java 现在我说大家都用python了 那你任何一个领域的研究者做的一些突破 能够很快的在别的领域被使用 能够极大的减少一个新的技术在机器学习里面 各个领域被应用的那个时间 另外一块的话我们知道人对世界的感知是 多模态的

我们看见图片 我们读文字 我们听到语音 现在Transformer能够把这些所有的不同的数据给你融合起来 因为大家都用一个同样的架构抽取特征的话 那么那么他可以抽到一个同样的语义空间 使得我们可以用文本 图片啊 语音啊 啊视频啊能训练更好更大的模型啊 也可以看到这一块应该是现在和未来的 一个研究重点

但反过来讲啊 虽然Transformer这些模型啊 取得了非常好的实验性的结果 但是我们对它的理解还在比较初级的阶段 第一个是说这篇文章的标题叫做啊 你只需要attention就行了 但是最新的一些结果表明 attention 只是在Transformer里面起到一个作用 它的主要作用是把整个序列的信息给大家聚合起来 但是后面的MLP呀

以及你的残差连接是缺一不少了 如果你把这些东西去掉的话 attention 基本上什么东西的训练不出来 所以呢你这个模型attention 也不是说你只需要它就行了 第二个是说 attention根本 attention根本 就不会去对你这个数据的那个顺序做建模 他为什么能够打印RNN呢 而能够显示的建模这个 序列信息理论上应该比你的mlp效果更好

现在大家觉得他使用了一个更广泛的归纳偏置 使得他能处理一些更一般化的信息 这也是为什么说 而attention并没有做任何空间上的一些假设 它也能够跟CNN甚至是比CNN取得更好的一些结果 啊但是它的代价是说因为它的假设更加一般呢 所以他对数据里面抓取信息的能力变差了 以至于说你需要

使用更多的数据 使用更大的模型 才能训练出你要的效果 这也是为什么现在Transformer模型一个比一个大训练 一个比一个贵 另外最后要提到一点是说 Attention也给了研究者一些鼓励 说原来在CNN和RNN之外也会有新的模型 能打败他们 能打败他们 现在有很多工作说我 就用MLP或者就用一些更简单的架构 也能够在

图片上面在文本上面取得很好的结果 所以我觉得在未来肯定会有更多新的架构出现 让整个这个领域啊让更加有意思 一线

Loading...

Loading video analysis...