字幕组双语原文:
英语原文:
翻译:雷锋字幕组()
多头自注意力开销很大,这已经不是什么秘密了——序列长度的o(n²)复杂度意味着不太可能让经典的transformer模型处理超长文本序列。在过去的两年里,nlp社区已经开发出了名副其实的缝合怪方法来应付这种复杂性,但这篇文章将重点介绍在大规模下更有前景的方法。
稀疏transformers
自适应transformers
transformer-xl
压缩transformers
reformer
寻觅式 transformer
多头注意力对序列长度的伸缩性很差,原因有二: 首先是计算注意力矩阵所需的flops按序列长度的平方暴增,导致对单个序列的自注意力操作的计算复杂度为o(hdn²),其中h是注意力头数,d是key和query的维度,n是文本序列的长度。
第二点是,点积自注意力操作的空间复杂度也按序列长度的平方增大。 计算注意力矩阵的空间复杂度为o(hdn hn²)——第一项是存储key和query所需的内存,第二项是每个头得出的注意力标量值。
让我们向bert-base代入具体的数字来了解哪些项的开销占大头。 bert-base使用的序列长度为512,隐藏层大小为768,12个头,这意味着每个头的维度为64(768 / 12)。 在这种设置下,需要393216 floats(约1.5mb)(头12个*头大小64*序列长度512)来存储键和值,而存储所有头的注意力标量所需的空间为3145,728 floats (12*512*512)即约12mb的内存——几乎10倍于键存储的空间开销,这还仅仅是仅仅512个上下文词符。
由于在训练过程中必须缓存激活,以便进行梯度计算(除非使用梯度检查点这种激活再计算策略),因此仅存储这些12层的bert-base注意力矩阵,每个样本就要消耗约150mb的内存。 当序列长度为1024时,这就上升为约600mb,而序列长度为2048时,每个样本仅存储注意力矩阵就已经消耗了约2.4gb的内存。这意味着训练时的批处理尺寸(batch size)更小,并行性更差,进一步阻碍了模型利用长距离上下文的能力。
"generating long sequences with sparse transformers" 由 rewon child, scott gray, alec radford 和 ilya sutskever 通过离散化(factorization)方法解决了自注意力的时间和空间复杂度中的o(n²)项问题。
在一个典型的自注意力操作中,输入序列中的每一项都会关注到输入序列中的所有其他项,从而形成如下的注意力模式:
典型的自回归设置下的自注意力连接模式。深蓝色方块代表 "查询(query)",浅蓝色方块代表 "键(key)"
经典自注意力带来的益处是,其高连通性使得信息在词符之间很容易传递——只需要一层注意力就可以聚合任意两个词符的信息。 但如果我们放宽这一约束,保证两层内信息可以在任意两个词符之间传递即可的话,就可以大幅降低按序列长度增长的复杂度。稀疏transformer通过利用固定注意力模式的自定义核来实现这一目标。
固定的稀疏transformer。深蓝色方块代表查询,中浅蓝色方块代表奇数层注意力键索引,最浅蓝色的方块代表偶数层关注的关键索引。
一半的头只关注短的局部上下文,而另一半则预分配均匀分布在整个序列中的索引。
通过这些聚合索引来传递信息,网络就能够从较远的词符获取信息并利用长距离上下文,同时将时间和空间复杂度降低到o(n√n)。最重要的一点是,只需要两层隐藏层,任意词符就都可以整合来自其他词符的信息。
重要的是,离散化注意力结构似乎不会对语言模型的性能产生负面影响,它的每字符比特数比enwiki8上的密集注意力(令人惊讶地)更高,且可以在高达12228个词符的上下文上产生有效的注意力。
可以看到,稀疏transformer的注意结构之所以有效,部分原因是因为这种注意力模式与真正习得的密集注意力并没有什么不同。 kevin clark, urvashi khandelwal, omer levy, 和 christopher d. manning在他们的 "what does bert look at? an analysis of bert’s attention" 一文中探究了密集注意力所习得的模式,试图弄明白注意力在transformer模型中承载了什么功能。他们发现注意力头倾向于关注紧接在前的词符(类似于稀疏注意力中的局部注意力模式),以及如[sep]和句号的特定词符。所以,也许稀疏transformer的注意力模式中包含的归纳偏差是有用而非有害的。
例子: bert习得的注意力模式
如果想在自己的项目中采用固定注意力核,可以查看openai的以及作者发布的配套示例。
sainbayar sukhbaatar, edouard grave, piotr bojanowski, 和 armand joulin 在他们的文章 "adaptive attention span in transformers" 中对复杂性问题采取了不同的方法. 他们与 "what does bert look at?" 的作者得到了同样的观察,并指出虽然密集注意力允许每个头关注完整的上下文,但许多注意力头只关注局部上下文,而剩下的头才会关注整个文本序列。 他们建议使用某种自注意力来利用这一现象,以此让模型可以选择其上下文尺寸。
自适应窗口transformer通过对序列进行遮罩,使每头习得的上下文之外的词符贡献迅速消失。 遮罩(m)与softmax操作的对数相乘,使某些词符对当前隐状态x的贡献归零,其中超参数r控制最小窗口(span)大小。
"adaptive attention span in transformers"所用的软遮罩函数。图片来自论文所附的facebook ai博文
为鼓励模型只在有益的地方使用额外上下文,对习得的z值施加了ℓ1惩罚。
在这些限制条件下,大部分的头都会选择关注<100个字符的上下文,只有少数的头(主要是在网络的后几层)会选择顶着ℓ1ℓ1的惩罚来关注>1000个字符的上下文。
除了巧妙的缓存机制,这种对长上下文的惩罚使得自适应窗口高达8k个字符,同时仍然保持模型的整体计算成本可控。此外,它在基线上的性能仍然很高——在enwiki8上达到了0.98比特/字符,text8数据集上达到了1.07比特/字符。
然而,可变窗口大小在便于并行方面并不理想,我们通常希望密集的、尺寸规整的矩阵来实现最佳性能。虽然这种方法可以大幅减少预测时前向计算所需的flops数量,但作者只提供了模糊的性能估计,并表示自适应跨度的实现能够以2048个上下文词符的固定上下文大小模型的速度最高处理8192个词符 。
facebook ai research还开源了他们的工作——代码和预训练的模型可以在github.com/facebookresearch/adaptive-spans上获得。
比起让密集注意力操作的成本更低廉,zihang dai, zhilin yang, yiming yang, jaime carbonell, quoc v. le和 ruslan salakhutdinov 则从rnns中获得灵感,并在transformer中引入了除自关注机制外的循环机制。 他们的文章"transformer-xl: attentive language models beyond a fixed-length context",引入了两个新颖的概念——第一个是将之前 "段(segments)"的隐状态作为输入反馈给当前段层的组件,另一个是促进这一策略的相对位置编码方案。
使用具有固定上下文大小的标准变换器,处理长输入时需要将输入分割成块(或称段)分别处理。然而,这种方法有一个局限,即前一段的信息与当前段的词符无关。 这种段独立性在某种程度上是有益的,因为它让我们能分批地有效处理每一段,但如果目标保持是长序列的一致性,这就会成为一个很大的限制。
带密集注意力的自回归transformer的词符注意力结构来自transformer-xl。
transformer-xl通过强制进行分段串联来克服这一限制。 在第一段之后,后续段中的词符将始终保持512个词符的上下文尺寸,之前段的激活作为上下文传递给后续段的注意力操作。 这意味着来自nn上下文大小*ll层外的信息可以传播到一个给定的令牌。 假设上下文尺寸为640,模型有16层,理论上transformer-xl可以纳入10,240个词符的信息。
transformer-xl原文中的词符注意力模式。
为了避免存储所有段的激活,作者阻止了梯度流向之前的段。
transformer-xl还引入了一种新颖的位置编码方案,称为 "相对位置编码"。 不是简单地将内容和绝对位置嵌入的和输入网络,而是将每层的注意力操作分解为基于内容的部分和基于相对位置的部分——如果一个段中的第512个词符要关注第511个词符,它的相对位置嵌入就是-1。
为了使相对位置编码的使用变得简单,他们将从键和查询中产生注意力权重的操作进行了分解。对于一个典型的密集注意力操作,pre-softmax注意力权重可以如下分解:
上式中,exi是词符在位置i的基于内容的嵌入,uj是词符j的位置嵌入。
(a) 将查询的内容与键的内容相关联
(b) 将查询的内容与键的位置相关联
(c) 将查询的位置与键的内容相关联
(d) 将查询的位置与键的位置相关联
当使用相对位置嵌入时,作者将式子改成如下形式:
在b)和d)中,uj已经被它的相对位置嵌入ri-j替换.
对于包含查询位置的项,我们将矩阵uiui替换为两个新学习参数uu和vv。这些向量可以理解为两个不依赖于查询具体细节的偏置——cc鼓励多关注一些项,dd鼓励多关注相对位置。 作出这种替换是因为对自身的查询其相对位置保持不变。
要想让transformer-xl模型利用这样的长程上下文,每一层至少有一个头要利用其注意力跨度的全部上下文。 平均注意力权重图显示,每一层都有头主要关注先前的位置。
transformer-xl论文中的平均注意力权重图
此外transformer-xl论文还测量了有效上下文长度对困惑度的影响,并发现增大上下文长度至~900个词符时会产生更好的困惑度得分——这进一步证明了循环机制在实践中的有效性,而非仅仅停留于理论。
kimi young的github提供了源代码,huggingface的实现可以帮助你搭建自己的transformer-xl项目。
列表上的下一个模型是transfromer,它建立在transformer-xl架构的基础上,但通过压缩损失扩展了该方法,以便纳入更长的文本序列。在来自deepmind的jack w. rae、anna potapenko、siddhant m. jayakumar和timothy p. lillicrap的文章 "compressive transformers for long-range sequence modelling "中,详细介绍了一种能够关注与全书长度的序列模型架构。
" compressive transformers for long range sequence modeling "中的压缩记忆(compressed memory)示意图
按照transformer-xl的做法,当前序列可以关注已存储的前段的激活。此外,在同样的多头注意操作中,当前段中的词符可以关注存储在 "压缩记忆 "中的第二组状态。
在每一步中,最早的压缩记忆被丢弃,压缩记忆向后移动一个索引。 然后,来自正常记忆段中最早的nn个状态进行压缩,然后转移到压缩记忆新空出来的槽中。
deepmind博客上的一个gif很好地说明了这个过程:
将过去的记忆逐渐压缩成压缩记忆——图片由 deepmind 博客提供
deepmind团队尝试了多种压缩操作(包括平均池化、最大池化和学习卷积等等),但最终决定训练一个二级网络来重建缩记忆中基于内容的注意力矩阵。
换句话说,他们学习了一个函数fc,通过最小化压缩记忆的注意力(c-1=fc(mold))和正被压缩的正常记忆状态的注意力之差,将n个最早的记忆状态压缩为一个压缩记忆状态。:
他们没有将这种压缩操作与主语言模型联合训练,而是选择在一个单独的优化循环中更新压缩网络。因为让注意力状态容易被压缩,对降低语言模型的损失会起到反作用。
在他们的实验中,压缩记忆的尺寸为512,正常记忆尺寸为512,窗口尺寸为512,压缩率为2——意味着在压缩步骤中,最早的2个记忆状态将被压缩为1个状态。在这个设置下,他们在wikitext-103上实现了17.1的sota困惑度。
由于利用较长序列长度的收益通常是长尾的,他们特别研究了不同词频下的困惑度,发现在最稀有的词符上的收益尤其显著:
按词频分类的困惑度。图片由deepmind博客提供
虽然他们还没有公开源码,但deepmind已经开放了pg-19的源码,这是他们在研究压缩transformer时开发的数据集。pg-19是project gutenberg的衍生品,旨在进一步研究长期注意力。
接下来是nikita kitaev, łukasz kaiser, anselm levskaya 的文章"reformer: the efficient transformer". reformer在增大序列长度方面采取了不同的策略——他们没有引入循环机制或压缩记忆,而是选择通过使用局部敏感哈希(lsh)技术来缩小每个词符的注意力范围.
局部敏感哈希是一系列将高维向量映射到一组离散值(桶/簇)的方法。它常常用在近似最近邻搜索中。
reformer的作者对注意力操作的键和查询使用了同一个投影,并使用基于随机旋转的局部敏感哈希方法将共享的键/查询分到最多几百个词符的不同桶中。下图是该方法的一个示例:
reformer论文中的角度化lsh。该图展示了一个有3次旋转的4桶哈希设置。下方图中的三个向量已经映射到同一个哈希桶中,因为其的原始向量就很接近,而上方的第一个图和最后一个展示了向量被映射到不同的哈希桶中。
它们计算每个桶内的注意力矩阵,然后取对应值的加权和。 由于只关注一个给定的桶内的元素,所以如果桶的大小选择得当,这可以将注意力操作的整体复杂度从o(n2)降低到o(nlogn)。由于分桶是随机的,而且旋转映射向量也是随机的,所以他们计算了多个哈希值,以确保具有相似的共享键-查询嵌入的词符最终以高概率落入同一个桶中。
他们还采用了 " the reversible residual network: backpropagation without storing activations "中介绍的技术来控制训练时的空间消耗。可逆残差层使用巧妙的架构结构,允许从层输出中轻松重构层输入,并在网络深度不变的情况下以空间复杂度降低了计算量。
通过局部敏感的哈希技巧来降低计算成本,以及可逆残差来降低内存消耗,reformer架构能够在单个加速器上处理长达64000个词符的序列。
虽然在enwiki-8上得出的1.05比特/字符的得分落后于我们在这篇文章中所研究的其他一些模型,但reformer是一个令人耳目一新的独特机制,我很期待看到这种方法如何继续扩大规模。
如果你有兴趣进一步探索reformer架构,可以看看我最近关于这个主题的博文 "a deep dive into the reformer"。 在google/jax github仓库中,有一个reformer的开源实现示例。 phil wang也维护了一个pytorch版本。
我原打算在这里就结束本文,但在aran komatsauzaki的建议下,我加入了最后一篇论文。aurko roy、mohammad taghi saffar、david grangier和ashish vaswani的第二篇iclr 2020的论文 "efficient content-based sparse attention with routing transformers "与前述的reformer有一些异曲同工之处。他们将问题框定为路径问题,旨在学习选择稀疏词符聚类簇si和内容x的函数。
作者的在下图中说明了他们的方法。 他们不是只关注局部元素或第n个元素来增加稀疏性,而是学习了(图c中用彩色表示的)需要关注的聚类。重要的是这些簇是每个键和查询的内容的函数,而不仅仅与绝对或相对位置相关。
routing attention与local和strided attention的比较,来自routing transformer论文
在确保每个键和查询向量都单位化后,他们使用尺寸为(dk,dk)的随机正交权重的共享矩阵来投影键和查询的值,其中dk是键和查询的隐藏维度。
然后,根据一组k-means中心将r中的向量分组到k个簇中,每个k-means中心通过每批使用k-means更新来习得,与梯度下降过程无关。
在一个给定的聚类簇ci内,它们使用标准的加权求和方法计算了一组新的上下文嵌入,其中每个注意力值ai都是使用标准的点积自注意力计算的。
由于密集注意力中的注意力模式通常由少数关键元素主导,而且聚类分配过程需要将具有高注意力权重的键和查询归入同一个聚类中,作者认为这个机制能够有效告知我们x′i进行了高开销的密集操作。
最后,他们选择了一些接近√n的聚类簇,这样基于稀疏内容的注意力机制的整体复杂度就变成了o(n√n)。 为了使整个过程易于并行化和统一矩阵尺寸,作者最接近每个中心点的top-k个项来代替真正的k-means聚类。
除了基于内容的路径注意力, 路径注意力transformer还在尺寸为256的上下文上执行局部注意力。
routing transformer在计算效率上的提升也使得其在wikitext-103这个词级语言建模基准测试上的困惑度得到提升,它们的性能明显超过了之前描述的transformer-xl模型。
wikitext-103测试集上的困惑度结果,来自routing transformer论文。
在enwiki-8上,routing transformer的表现也相当不错,不过他们的结果略微落后于adaptive span transformer。
enwiki-8的测试集的每个字符比特数结果。
我本来没找到routing transformer的实现,但aurko roy很好心地给我了一份他们源码的压缩包,这份源码是提交给iclr审阅的版本。
如果你对在transformer中加入长程上下文的其他方法感兴趣,那你还可以读一下:
雷锋字幕组是一个由 ai 爱好者组成的翻译团队,汇聚五百多位志愿者的力量,分享最新的海外ai资讯,交流关于人工智能技术领域的行业变革与技术创新的见解。
团队成员有大数据专家、算法工程师、图像处理工程师、产品经理、产品运营、it咨询人、在校师生;志愿者们来自ibm、avl、adobe、阿里、百度等知名企业,北大、清华、港大、中科院、南卡罗莱纳大学、早稻田大学等海内外高校研究所。
如果,你也是位热爱分享的ai爱好者。欢迎与雷锋字幕组一起,学习新知,分享成长。
雷锋网雷锋网