Sinusoidal 位置编码追根溯源

2021-05-13 17:46:36 浏览数 (1)

这篇文章主要是介绍自己对 Google 在《Attention is All You Need》中提出来的 Sinusoidal 位置编码

begin{equation}left{begin{aligned}&boldsymbol{p}_{k,2i}=sinBig(k/10000^{2i/d}Big)\ &boldsymbol{p}_{k, 2i 1}=cosBig(k/10000^{2i/d}Big) end{aligned}right. tag{1}end{equation}

的新理解,其中 boldsymbol {p}_{k,2i},boldsymbol {p}_{k,2i 1} 分别是位置 kk 的编码向量的第 2i,2i 1 个分量,d 是向量维度

作为位置编码的一个显式解,Google 在原论文中对它的描述却寥寥无几,只是简单提及了它可以表达相对位置信息,后来知乎等平台上也出现了一些解读,它的一些特点也逐步为大家所知,但总体而言比较零散。特别是对于 “它是怎么想出来的”、“非得要这个形式不可吗” 等原理性问题,还没有比较好的答案。因此,本文主要围绕这些问题展开思考

泰勒展开

假设我们的模型为 f (cdots,boldsymbol {x}_m,cdots,boldsymbol {x}_n,cdots),其中标记出来的 {x}_m, {x}_n 分别表示第 m,n 个输入。像 Transformer 这样的纯 Attention 模型,它是全对称的,即对于任意的 m,n,都有

begin{equation}f(cdots,boldsymbol{x}_m,cdots,boldsymbol{x}_n,cdots)=f(cdots,boldsymbol{x}_n,cdots,boldsymbol{x}_m,cdots)tag{2}end{equation}

这就是我们说 Transformer 无法识别位置的原因 —— 全对称性,简单来说就是函数天然满足恒等式f (x,y)=f (y,x),以至于我们无法从结果上区分输入到底是 [x,y][x,y] 还是 [y,x][y,x]

换句话说,"xx 你好 xx" 和 "xx 好你 xx" 大概率具有一样的输出,这在 NLP 里面显然是不合理的

因此,我们要做的事情,就是打破这种对称性,比如在每个位置都加上一个不同的编码向量:

begin{equation}tilde{f}(cdots,boldsymbol{x}_m,cdots,boldsymbol{x}_n,cdots)=f(cdots,boldsymbol{x}_m boldsymbol{p}_m,cdots,boldsymbol{x}_n boldsymbol{p}_n,cdots)tag{3}end{equation}

一般来说,只要每个位置的编码向量不同,那么这种全对称性就被打破了,即可以用 f~tilde {f} 代替 ff 来处理有序的输入。但现在我们希望能进一步分析位置编码的性质,甚至得到一个显式解

为了简化问题,我们先只考虑 m,nm,n 这两个位置上的位置编码,将它视为扰动项,泰勒展开到二阶:

begin{equation}tilde{f}approx f boldsymbol{p}_m^{top} frac{partial f}{partial boldsymbol{x}_m} boldsymbol{p}_n^{top} frac{partial f}{partial boldsymbol{x}_n} frac{1}{2}boldsymbol{p}_m^{top} frac{partial^2 f}{partial boldsymbol{x}_m^2}boldsymbol{p}_m frac{1}{2}boldsymbol{p}_n^{top} frac{partial^2 f}{partial boldsymbol{x}_n^2}boldsymbol{p}_n underbrace{boldsymbol{p}_m^{top} frac{partial^2 f}{partial boldsymbol{x}_m partial boldsymbol{x}_n}boldsymbol{p}_n}_{boldsymbol{p}_m^{top} boldsymbol{mathcal{H}} boldsymbol{p}_n}tag{4}end{equation}

可以看到,第 1 项与位置无关,第 2 项到第 5 项都只依赖于单一位置,它们都是存粹的绝对位置信息,第 6 项是第一个同时包含 boldsymbol {p}_m,boldsymbol {p}_n 的交互项,我们将它记为 boldsymbol {p}_m^{top} boldsymbol {mathcal {H}} boldsymbol {p}_n

补充一下二元函数泰勒展开知识: f(x h,y k)=f(x, y) hfrac{partial f}{partial x} kfrac{partial f}{partial y} frac{1}{2!}(hfrac{partial f}{partial x} kfrac{partial f}{partial y})^2 cdots

相对位置

我们先从简单的例子入手,假设 boldsymbol {mathcal {H}}=boldsymbol {I} 是单位阵,此时 boldsymbol {p}_m^{top} boldsymbol {mathcal {H}} boldsymbol {p}_n = boldsymbol {p}_m^{top} boldsymbol {p}_n = langleboldsymbol {p}_m, boldsymbol {p}_nrangle 是两个位置编码的内积,我们希望在这个简单的例子中该项表达的是相对位置信息,即存在某个函数 g 使得

begin{equation}langleboldsymbol{p}_m, boldsymbol{p}_nrangle = g(m-n)tag{5}end{equation}

这里的 boldsymbol {p}_m,boldsymbol {p}_n 是 d维向量,这里我们从最简单的 d=2 入手

对于 2 维向量,我们借助复数来推导,即将向量 [x,y] 视为复数 x ytext {i},根据复数乘法的运算法则,我们不难得到:

begin{equation}langleboldsymbol{p}_m, boldsymbol{p}_nrangle = text{Re}[boldsymbol{p}_m boldsymbol{p}_n^*]tag{6}end{equation}

其中boldsymbol {p}_n^*boldsymbol {p}_n 的共轭复数,text {Re}[] 代表复数的实部。

举个栗子:[3,5] 对应的复数为 3 5text {i},[1,6] 对应的复数为 1 6text {i},其共轭复数为 [3,5]⋅[1,6]⊤=33[3,5]cdot [1,6]^{top}=33,而(3 5text {i})(1-6text {i})=33-13text {i},且 text {Re}[33-13text {i}]=33

为了满足式 (5),我们可以假设存在复数 boldsymbol {q}_{m-n} 使得

begin{equation}boldsymbol{p}_m boldsymbol{p}_n^* = boldsymbol{q}_{m-n}tag{7}end{equation}

这样两边取实部就得到了式 (5)。为了求解这个方程,我们可以使用复数的指数形式,即设 boldsymbol {p}_m=r_m e^{text {i}phi_m}, boldsymbol {p}_n^*=r_n e^{-text {i}phi_n}, boldsymbol {q}_{m-n}=R_{m-n} e^{text {i}Phi_{m-n}} 得到

begin{equation}r_m r_n e^{text{i}(phi_m - phi_n)} = R_{m-n} e^{text{i}Phi_{m-n}}quad\Rightarrowquad left{begin{aligned}&r_m r_n = R_{m-n}\ & phi_m - phi_n=Phi_{m-n}end{aligned}right.tag{8}end{equation}

这里补充一下复数的指数形式: 根据定义有复数的三角形式 r (costheta text {i}sintheta),又由于欧拉公式 costheta text{i}sintheta=e^{text{i}theta} 上式两端同乘以 r (r>0),得 r(costheta text{i}sintheta)=re^{text{i}theta} 这说明复数可以用指数形式 re^{itheta} 来表示。实际上,复数的代数形式、三角形式和指数形式之间有下面的关系 a btext{i}=r(costheta text{i}sintheta)=re^{text{i}theta}

对于第一个方程,带入 n=m 得r_m^2=R_0,即r_m 是一个常数,简单起见这里设为 1

对于第二个方程,带入0n=0 得 phi_m-phi_0=Phi_m,简单起见设 phi_0=0,那么phi_m=Phi_m

对于第二个方程,带入 n=m-1(在 NLP 中,这个式子的含义相当于两个词的位置是相邻的)得 phi_m-phi_{m-1}=Phi_1=phi_1,那么 {phi_m} 只是一个等差数列,通解为 mtheta,因此我们就得到二维情形下的位置编码的解为:

begin{equation}boldsymbol{p}_m = e^{text{i}mtheta}quadLeftrightarrowquad boldsymbol{p}_m=begin{pmatrix}cos mtheta \ sin mthetaend{pmatrix}tag{9}end{equation}

由于内积满足线性叠加性,所以更高维的偶数维位置编码,我们可以表示为多个二维位置编码的组合:

begin{equation}boldsymbol{p}_m = begin{pmatrix}e^{text{i}mtheta_0} \ e^{text{i}mtheta_1} \ vdots \ e^{text{i}mtheta_{d/2-1}}end{pmatrix}quadLeftrightarrowquad boldsymbol{p}_m=begin{pmatrix}cos mtheta_0 \ sin mtheta_0 \ cos mtheta_1 \ sin mtheta_1 \ vdots \ cos mtheta_{d/2-1} \ sin mtheta_{d/2-1} end{pmatrix}tag{10}end{equation}

它同样满足式 (5)。当然,这只能说是式 (5) 的一个解,但不是唯一解,对于我们来说,求出这一个简单的解就行了

远程衰减

基于前面的假设,我们推导出了位置编码的形式 (10),它跟标准的 Sinusoidal 位置编码 (1) 形式基本一样了,只是 sin,cos 的位置有点不同。一般情况下,神经网络的神经元都是无序的,所以哪怕打乱各个维度,也是一种合理的位置编码,因此除了各个 theta_i 没确定下来外,式 (10) 和式 (1) 并无本质区别

式 (1) 的选择是theta_i=10000^{-2i/d},这个选择有什么意义呢?事实上,这个形式有一个良好的性质:它使得随着 |m−n| 的增大,langleboldsymbol {p}_m, boldsymbol {p}_nrangle 有着趋近于零的趋势。按照我们的直观想象,输入句子中相对距离越大的两个单词,其相关性应该越弱,因此这个性质是符合我们的直觉的。只是,明明是周期性的三角函数,为什么会呈现出衰减的趋势呢?

这的确是个神奇的现象,源于高频振荡积分的渐近趋零性。具体来说,我们将内积写为

begin{equation}begin{aligned} langleboldsymbol{p}_m, boldsymbol{p}_nrangle =&, text{Re}left[e^{text{i}(m-n)theta_0} e^{text{i}(m-n)theta_1} cdots e^{text{i}(m-n)theta_{d/2-1}}right]\ =&, text{Re}left[sum_{i=0}^{d/2-1}e^{text{i}(m-n)theta_i}right]\ =&,text{Re}left[frac{d}{2}cdotfrac{1}{d/2}cdotsum_{i=0}^{d/2-1} e^{text{i}(m-n)10000^{-i/(d/2)}}right]\ sim&, frac{d}{2}cdottext{Re}left[int_0^1 e^{text{i}(m-n)cdot 10000^{-t}}dtright] end{aligned}tag{11}end{equation}

对于式 (11),将 d/2 看成一个整体 n,于是就变为: text{Re}left[ncdotfrac{1}{n}sum_{i=0}^{n-1}e^{text{i}(m-n)10000^{-frac{i}{n}}}right] 根据定积分的定义,即 lim limits_{nto infty} frac{1}{n}sum_{i=1}^{n}f(frac{i}{n})=int_0^1 f(x)dx 于是即可推导出式 (11)

这样问题就变成了积分 int_{0}^1 e^{text {i}(m-n)theta_t} dt 的渐进估计问题了。对我们来说,最直接的方法就是通过 Mathematica 把积分结果的图像画出来

代码语言:javascript复制
[Theta][t_] = (1/10000)^t;
f[x_] = Re[Integrate[Exp[I*x*[Theta][t]], {t, 0, 1}]];
Plot[f[x], {x, -128, 128}]

从图像中我们可以看出确实具有衰减趋势

那么问题来了,必须是theta_t=10000^{-t} 才能呈现出远程衰减趋势吗?当然不是。事实上,对于我们这里的场景,"几乎" 每个值域在 [0,1] 上的单调光滑函数 theta_t,都能使得积分 int_0^1e^{text {i}(m-n)theta_t} dt 具有渐近衰减趋势,比如幂函数 theta_t=t^{alpha}。那么 theta_t=10000^{-t} 有什么特别的吗?我们来比较一些结果(下面两张图分别是短距离和长距离时的趋势)

这样看上去,除了 theta_t=t 比较异常之外(与横轴有交点),其他都没有什么明显的区分度,很难断定孰优孰劣,无非就是幂函数在短距离降的快一点,而指数函数则在长距离降的快一点。如此来看 theta_t=10000^{-t} 也只是一个折中的选择,没有什么特殊性,要是笔者来选,多半会选 theta_t=1000^{-t}。还有一个方案是,直接让theta_i=10000^{-2i/d} 作为各个 theta_i 的初始化值,然后将它设为可训练的,由模型自动微调,这样也不用纠结选哪个了

一般情况

前面两节中,我们展示了通过绝对位置编码来表达相对位置信息的思想,加上远程衰减的约束,可以 "反推" 出 Sinusoidal 位置编码,并且给出了关于 θitheta_i 的其他选择。但是别忘了,到目前为止,我们的推导都是基于 boldsymbol {mathcal {H}}=boldsymbol {I} 这个简单情况的,对于一般的 boldsymbol {mathcal {H}},使用上述 Sinusoidal 位置编码,还能具备以上的良好性质吗?

如果 boldsymbol {mathcal {H}} 是一个对角阵,那么上面的各个性质可以得到一定的保留,此时

begin{equation}boldsymbol{p}_m^{top} boldsymbol{mathcal{H}} boldsymbol{p}_n=sum_{i=1}^{d/2} boldsymbol{mathcal{H}}_{2i,2i} cos mtheta_i cos ntheta_i boldsymbol{mathcal{H}}_{2i 1,2i 1} sin mtheta_i sin ntheta_itag{12}end{equation}

由积化和差公式得到

begin{equation}sum_{i=1}^{d/2} frac{1}{2}left(boldsymbol{mathcal{H}}_{2i,2i} boldsymbol{mathcal{H}}_{2i 1,2i 1}right) cos (m-n)theta_i frac{1}{2}left(boldsymbol{mathcal{H}}_{2i,2i} - boldsymbol{mathcal{H}}_{2i 1,2i 1}right) cos (m n)theta_itag{13} end{equation}

可以看到它也是确实包含了相对位置 m-n,只不过可能会多出 m n 这一项,如果不需要它,模型可以让 boldsymbol {mathcal {H}}_{2i,2i} = boldsymbol {mathcal {H}}_{2i 1,2i 1} 来消除它。在这个特例下,我们指出的是 Sinusoidal 位置编码赋予了模型学习相对位置的可能,至于具体需要什么位置信息,则由模型的训练自行决定

特别地,对于上式,远程衰减特性依然存在,比如第一项求和,类比前一节的近似,它相当于积分

begin{equation}sum_{i=1}^{d/2} frac{1}{2}left(boldsymbol{mathcal{H}}_{2i,2i} boldsymbol{mathcal{H}}_{2i 1,2i 1}right) cos (m-n)theta_i sim int_0^1 h_t e^{text{i}(m-n)theta_t}dttag{14}end{equation}

其实式 (14) 没有严格的推导,sim 的意思是 "类比","相当于",就是说我们要分析 sum_i a_ib_i 的性态,大致上相当于分析 int a (x) b (x) dx 的性态。读者不要一味的钻牛角尖想办法证明两者相等

同样地,振荡积分的一些估计结果(参考《Oscillatory integrals》、《学习笔记 3 - 一维振荡积分与应用》等)告诉我们,该振荡积分在比较容易达到的条件下,有 |m-n|toinfty 时积分值趋于零,因此远程衰减特性是可以得到保留的

如果 boldsymbol {mathcal {H}} 不是对角阵,那么很遗憾,上述性质很难重现。我们只能寄望于 boldsymbol {mathcal {H}} 的对角线部分占了主项,这样一来上述性质还能近似保留。对角线部分占主项,意味着 dd 维向量之间任意两个维度的相关性比较小,满足一定的解耦性。对于 Embedding 层来说,这个假设还是有一定的合理性的,笔者检验了 BERT 训练出来的词 Embedding 矩阵和位置 Embedding 矩阵的协方差矩阵,发现对角线元素明显比非对角线元素大,证明了对角线元素占主项这个假设有一定的合理性

问题讨论

有读者会反驳:"就算你把 Sinusoidal 位置编码说的无与伦比,也改变不了直接训练的位置编码比 Sinusoidal 位置编码效果要好的事实",的确,有实验表明,在像 BERT 这样经过充分预训练的 Transformer 模型中,直接训练的位置编码效果是要比 Sinusoidal 位置编码好些,这个并不否认。本文要做的事情,只是从原理和假设出发,推导 Sinusoidal 位置编码为什么可以作为一个有效的手段,但并不代表它就一定是最好的位置编码方式

推导是基于一些假设的,如果推导出来的结果不够好,那么就意味着假设与实际情况不够符合。那么,对于 Sinusoidal 位置编码来说,问题可能出现在哪呢?我们可以逐步来反思下

第一步,泰勒展开,这个依赖于 boldsymbol {p} 的值比较小,笔者也在 BERT 中做了检验,发现词 Embedding 的平均模长要比位置 Embedding 的平均模长大,这说明 boldsymbol {p} 的值比较小在某种程度上是合理的,但是多合理也说不准,因为 Embedding 模长虽然更大但也并不是压倒性的

第二步,假设 boldsymbol {mathcal {H}} 是单位阵,因为上一节我们分析了它很可能是对角线占主项的,所以先假设单位阵也没什么太大的问题

第三步,假设通过两个绝对位置向量的内积来表达相对位置信息,这个直觉上来说是合理的,绝对位置的交互应当有能力表达一定程度的相对位置信息

最后一步,通过自动远程衰减的特性来确定 theta_i,这个本身应该也是好的,但就是这一步变数太大,因为可选的 theta_i 形式太多,甚至还有可训练的 theta_i,很难挑出最合理的,因此如果说 Sinusoidal 位置编码不够好,这一步是最值得反思的

Reference
  • 《BERT 为何使用学习的 position embedding 而非正弦 position encoding?》
  • Transformer 升级之路:1、Sinusoidal 位置编码追根溯源

0 人点赞