行是知之始,知是行之成。这篇文章主要讲述Transforme结构:位置编码 | Transformer Architecture: The Positional Encoding相关的知识,希望能为你提供帮助。
注意:本文大多采用义译,确保原文意思不变,但不保证用词和原作完全一致。:sunglasses:
@[toc]
使用正弦函数为模型添加位置信息Transformer是只基于自注意力机制的序列到序列架构。因为并行计算能力以及高性能。使得它在NLP领域中大受欢迎。
现在常见的几个深度学习框架都实现了transformer,这让很多学生都能够方便使用到transformer。但是这也存在一个弊端,他会让我们忽略模型的一些细节。
在本文中我,不打算研究它的整体结构,毕竟现在已经有很多优秀的文章介绍其结构了。在本文中我仅对transformer结构的一部分进行探讨,就是位置编码。
当我阅读论文原文^[Attention Is All You Need]的时候,我的脑海里浮现出来一些问题,但是不幸的是,原文中没有提供足够的信息解答我的疑惑,所以在本文中,我想尝试将位置编码单拎出来,看看它是如何工作的。
注意:为了理解本文,请确保你在阅读本文之前已经熟悉了Transformer的基本架构。
文章图片
什么是位置编码?为什么我们需要位置编码。对任何语言来说,句子中词汇的顺序和位置都是非常重要的。它们定义了语法,从而定义了句子的实际语义。RNN结构本身就涵盖了单词的顺序,RNN按顺序逐字分析句子,这就直接在处理的时候整合了文本的顺序信息。
但Transformer架构抛弃了循环机制,仅采用多头自注意机制。避免了RNN较大的时间成本。并且从理论上讲,它可以捕捉句子中较长的依赖关系。
由于句子中的单词同时流经Transformer的编码器、解码器堆栈,模型本身对每个单词没有任何位置信息的。因此,仍然需要一种方法将单词的顺序整合到模型中。
想给模型一些位置信息,一个方案是在每个单词中添加一条关于其在句子中位置的信息。我们称之为“信息片段”,即位置编码。
第一个可能想到的想法是为每个时间步添加一个$[0,1]$范围内的数字,其中0表示第一个单词,1表示最后一个单词。
这会导致什么问题?
问题之一是你无法计算出在特定范围内有多少个单词。换句话说,时间步长$δ$在不同的句子中含义不一致。
另一个想法是为每个时间步按一定步长线性分配一个数字。 也就是说,第一个单词是“1”,第二个单词是“2”,依此类推。
这种方法的问题在于,随着句子变长,这些值可能会变得特别大,并且我们的模型可能会遇到比训练时更长的句子,此外,我们的模型可能会忽略某些长度的样本。这会损害模型的泛化。
理想情况下,应满足以下标准:
- 每个时间部都有唯一的编码。
- 在不同长度的句子中,两个时间步之间的距离应该一致。
- 模型不受句子长短的影响,并且编码范围是有界的。(不会随着句子加长数字就无限增大)
- 必须是确定性的。
首先,它不是单独某个数字,它是一个d维向量,其中包含句子中特定位置的信息。其次,这种编码并没有集成到模型本身中,该向量用于为每个单词提供有关其在句子中位置的信息。
也就是说,其修改了模型的输入,添加了单词的顺序信息。
令
- $t$ 是句子中某词汇的位置。
- $\\overrightarrowp_t \\in \\mathbbR^d$ 是其encoding。
- $d$是encoding的维度(其中$d \\equiv _2 0$ )
$$
\\overrightarrowpt^(i)=f(t)^(i):= \\begincases\\sin \\left(\\omegak \\cdot t\\right), & \\textifi=2 k \\ \\cos \\left(\\omega_k \\cdot t\\right), & \\textifi=2 k+1\\endcases
$$
其中 $\\omega_k=\\frac110000^2 k / d$
从函数定义可以推导出,频率沿向量维数递减。因此它在波长上形成了一个从$2 \\pi$到$10000 · 2 \\pi$的几何级数。
你也可以把$\\overrightarrowpt$ 想象成一个sin和cos交替的向量($d$可以被2整除 ):
$$
\\overrightarrowpt=\\left[\\beginarrayc
\\sin \\left(\\omega1 \\cdot t\\right) \\
\\cos \\left(\\omega1 \\cdot t\\right) \\
\\sin \\left(\\omega2 \\cdot t\\right) \\
\\cos \\left(\\omega2 \\cdot t\\right) \\
\\vdots \\
\\sin \\left(\\omegad / 2 \\cdot t\\right) \\
\\cos \\left(\\omegad / 2 \\cdot t\\right)
\\endarray\\right]_d \\times 1
$$
The intuition你可能想知道,正余弦组合怎么能代表一个位置/顺序?
其实很简单,假设你想用二进制格式表示一个数字:
文章图片
你可以看到不同位置上的数字交替变化。最后一位数字每次都会0、1交替;倒数第二位置上两个交替一次,以此类推。
但是在浮点数的世界中使用二进制值是对空间的浪费,所以我们可以用正弦函数代替。事实上,正弦函数也能表示出二进制那样的交替。此外随着正弦函数频率的降低,也可以达到上图红色位到橙色位交替频率的变化。
下图使用正弦函数编码,句子长度为50(纵坐标),编码向量维数128(横坐标)。可以看到交替频率从左到右逐渐减慢。
文章图片
其他细节前面我们只提到了位置编码是给句子中的单词添加位置信息的,但具体是怎么实现的呢?
在论文原文中是直接将词嵌入向量和位置编码进行相加,即对于句子$[w_1 \\dots w_n]$中的每个词$w_t$, 最终的输入如下:
$$
\\psi^\\prime\\left(wt\\right)=\\psi\\left(wt\\right)+\\overrightarrowp_t
$$
- $\\overrightarrowp_t$ 位置编码
- $\\psi\\left(w_t\\right)$ 词嵌入
$$
d\\text word embedding =d\\text postional embedding
$$
相对位置正弦位置编码的另一个特点是,可以让模型获取相对位置。以下是原文中的一段话:
We chose this function because we hypothesized it would allow the model to easily learn to attend by relative positions, since for any fixed offset $k$,$PEpos+k$ can be represented as a linear function of $PEpos$.
但为什么这一说法成立?为了充分理解原因,可以看一下这篇文章^[Linear Relationships in the Transformer’s Positional Encoding](点右上角参考)。不看也可以,我在这里总结了一个简短一点的版本:
对于对应频率$\\omegak$的每个正余弦对,有一个线性变换$M \\in \\mathbbR^2 \\times 2$ (独立于$t$ ),使下列等式成立:
$$
M .\\left[\\beginarrayl
\\sin \\left(\\omegak \\cdot t\\right) \\
\\cos \\left(\\omegak \\cdot t\\right)
\\endarray\\right]=\\left[\\beginarrayl
\\sin \\left(\\omegak \\cdot(t+\\phi)\\right) \\
\\cos \\left(\\omega_k \\cdot(t+\\phi)\\right)
\\endarray\\right]
$$
证明:
令$M$ 是一个 $2 \\times 2$的矩阵,我们想得到$u1, v1, u2$ and $v2$ 使下式成立:
$$
\\left[\\beginarrayll
u1 & v1 \\
u2 & v2
\\endarray\\right] \\cdot\\left[\\beginarrayl
\\sin \\left(\\omegak \\cdot t\\right) \\
\\cos \\left(\\omegak \\cdot t\\right)
\\endarray\\right]=\\left[\\beginarrayl
\\sin \\left(\\omegak \\cdot(t+\\phi)\\right) \\
\\cos \\left(\\omegak \\cdot(t+\\phi)\\right)
\\endarray\\right]
$$
使用三角函数的定理,我们可以将等式右边展开如下:
$$
\\left[\\beginarrayll
u1 & v1 \\
u2 & v2
\\endarray\\right] \\cdot\\left[\\beginarrayl
\\sin \\left(\\omegak . t\\right) \\
\\cos \\left(\\omegak . t\\right)
\\endarray\\right]=\\left[\\beginarrayl
\\sin \\left(\\omegak . t\\right) \\cos \\left(\\omegak . \\phi\\right)+\\cos \\left(\\omegak . t\\right) \\sin \\left(\\omegak . \\phi\\right) \\
\\cos \\left(\\omegak . t\\right) \\cos \\left(\\omegak . \\phi\\right)-\\sin \\left(\\omegak . t\\right) \\sin \\left(\\omegak . \\phi\\right)
\\endarray\\right]
$$
普通的矩阵乘法运算将其拆开:
$$
\\beginaligned
& u1 \\sin \\left(\\omegak . t\\right)+v1 \\cos \\left(\\omegak . t\\right)=\\cos \\left(\\omegak . \\phi\\right) \\sin \\left(\\omegak . t\\right)+\\sin \\left(\\omegak . \\phi\\right) \\cos \\left(\\omegak . t\\right) \\
& u2 \\sin \\left(\\omegak \\cdot t\\right)+v2 \\cos \\left(\\omegak . t\\right)=-\\sin \\left(\\omegak . \\phi\\right) \\sin \\left(\\omegak . t\\right)+\\cos \\left(\\omegak . \\phi\\right) \\cos \\left(\\omegak . t\\right)
\\endaligned
$$
通过求解上述方程我们可以得到:
$$
\\beginarrayll
u1=\\cos \\left(\\omegak \\cdot \\phi\\right) & v1=\\sin \\left(\\omegak \\cdot \\phi\\right) \\
u2=-\\sin \\left(\\omegak \\cdot \\phi\\right) & v2=\\cos \\left(\\omegak \\cdot \\phi\\right)
\\endarray
$$
所以最终的变换矩阵$M$ 是:
$$
M\\phi, k=\\left[\\beginarraycc
\\cos \\left(\\omegak \\cdot \\phi\\right) & \\sin \\left(\\omegak \\cdot \\phi\\right) \\
-\\sin \\left(\\omegak \\cdot \\phi\\right) & \\cos \\left(\\omega_k \\cdot \\phi\\right)
\\endarray\\right]
$$
通过上述推到可以看到,最终的转换不依赖于$t$。注意,可以发现矩阵$M$与旋转矩阵非常相似。
类似地,我们可以为其他正余弦对找到$M$,最终我们可以将$\\overrightarrowpt+\\phi$表示为任何固定偏移量$\\phi$的$\\overrightarrowpt$的线性函数。这一特性使模型很容易学到相对位置信息。
正弦位置编码的另一个特性是相邻时间步之间的距离是对称的,并随时间衰减。
下图是所有时间步位置编码的点乘积可视化:
【Transforme结构(位置编码 | Transformer Architecture: The Positional Encoding)】
文章图片
FAQ 为什么位置编码是和词嵌入相加而不是将二者拼接起来?
我找不到这个问题相关的理论依据。求和(与拼接相比)保存了模型的参数,现在我们将初始问题改为“在单词中添加位置嵌入有缺点吗?” 。这我会回答,不一定!
首先,如果我们回想一下上边的第一张可视化图,我们会发现位置编码向量的前几个维度用于存储关于位置的信息(注意,虽然我们的示例很小只有128维,但论文中的输入维度是512)。由于Transformer中的嵌入是从头开始训练的,所以设置参数的时候,可能不会把单词的语义存储在前几个维度中,这样就避开了位置编码。
因此我认为最终的Transformer可以将单词的语义与其位置信息分开。此外,也没有理由支撑将二者分开拼接有什么好处。也许这样相加为模型提供比较好的特征。
更多相关信息可以看:
- Why add positional embedding instead of concatenate? #1591 ^[Why add positional embedding instead of concatenate? #1591]
- Discussion:Positional Encoding in Transformer^[ Discussion:Positional Encoding in Transformer]
Transformer里加了残差连接,所以模型输入的信息可以有效地传播到其它层。
为什么同时使用正弦和余弦?
个人认为,只有同时使用正弦和余弦,我们才能将$sine(x+k)$和$cosine(x+k)$表示为$sin(x)$和$cos(x)$的线性变换。好像不能只用正弦或者只用余弦就能达到这种效果。如果你能找到单个正余弦的线性变换,可以在评论区补充。
总结感谢阅读,希望这篇文章能对你有用。如果有问题欢迎批评指正。
引用格式:
@articlekazemnejad2019:pencoding,
title= "Transformer Architecture: The Positional Encoding",
author= "Kazemnejad, Amirhossein",
journal = "kazemnejad.com",
year= "2019",
url= "https://kazemnejad.com/blog/transformer_architecture_positional_encoding/"
原文信息原文链接:Transformer Architecture: The Positional Encoding
文章图片
作者信息:
文章图片
References
推荐阅读
- 翻译翻译什么是适配器模式()
- 全网最全JSR303参数校验与全局异常处理(从理论到实践别用if判断参数了)
- 一款超牛逼的 Linux 终端复用神器(附安装使用教程)
- 字节跳动算法工程师面试总结,头条抖音后端技术3面题(Linux)
- 实战案例 : Tomcat9 利用memcached1.6实现会话Cluster (同一主机no sticky 模式)
- 001如何访问Linux系统
- 002UNIX/Linux特征简介
- 这次我会结合我前面所发的搭建DHCP服务,dns服务和HTTP服务,中核做一个实验有什么不懂得,可以评论区交流一下,也可以私信我,葱鸭!
- Swift进阶黄金之路