【旋转位置编码RoPE的一些个人理解】

并非科普而是个人记录!

前人的解释和介绍

如果不明白RoPE的前置知识可以看看下面两篇文章,本文也主要受其启发。
https://mp.weixin.qq.com/s/grayNg0IvAmILTF1dCEWTA
https://spaces.ac.cn/archives/9675

##RoPE旋转矩阵
RoPE旋转矩阵

RoPE实际计算方法

RoPE实际计算方法
究竟为啥要选这个样子咱也不懂咱也管不了,在这里大致分享一下一种另类的理解方式吧。

进制转换的理解

苏神(苏剑林)是按照进制表示来理解的,我觉得这个理解有一点点问题就是了,进制表示这玩意会退位。从下面看从右往左第二位从原来10进制的4变到了现在的13,大小反而变大了,而其中计算公式是 c o s ( k θ i ) = c o s ( k 1000 0 − 2 i / d ) cos(k{\theta}_i)=cos(k10000^{-2i/d}) cos(kθi)=cos(k100002i/d) ,只看里面的 k 1000 0 − 2 i / d k10000^{-2i/d} k100002i/d,假设说相同的 i i i的情况下,把 10000 10000 10000变为 40000 40000 40000,按道理来说除的越多得到的值就越小嘛。但是如果按照进制表示由于有退位,反而可能会出现变大的情况。
进制转换

旋转矩阵直观体现

那些符号什么的太麻烦啦,看的头昏眼花的,不如直接代数进去看看究竟是怎么样的计算吧
RoPE的cos公式部分

我们就只看 c o s ( k θ i ) = c o s ( k 1000 0 − 2 i / d ) = c o s ( k 1000 0 2 i / d ) cos(k{\theta}_i)=cos(k10000^{-2i/d})=cos(\frac{k}{10000^{2i/d}}) cos(kθi)=cos(k100002i/d)=cos(100002i/dk)这一部分, s i n sin sin的部分其实差不多,也暂时只看里面的 1000 0 − 2 i / d = 1 1000 0 2 i / d 10000^{-2i/d}=\frac{1}{10000^{2i/d}} 100002i/d=100002i/d1

我们讨论5种 i i i 的情况(注意 0 < i < d / 2 0<i<d/2 0<i<d/2):

  1. i = 0 d i=0d i=0d : 这时候 1 1000 0 0 / 1 = 1 \frac{1}{10000^{0/1}}=1 100000/11=1
  2. i = 1 8 d i=\frac{1}{8}d i=81d :这时候 1 1000 0 1 / 4 = 1 10 \frac{1}{10000^{1/4}}=\frac{1}{10} 100001/41=101
  3. i = 2 8 d = 1 4 d i=\frac{2}{8}d=\frac{1}{4}d i=82d=41d :这时候 1 1000 0 2 / 4 = 1 100 \frac{1}{10000^{2/4}}=\frac{1}{100} 100002/41=1001
  4. i = 3 8 d i=\frac{3}{8}d i=83d :这时候 1 1000 0 3 / 4 = 1 1000 \frac{1}{10000^{3/4}}=\frac{1}{1000} 100003/41=10001
  5. i = 4 8 d = 1 2 d i=\frac{4}{8}d=\frac{1}{2}d i=84d=21d :这时候 1 1000 0 4 / 4 = 1 10000 \frac{1}{10000^{4/4}}=\frac{1}{10000} 100004/41=100001

我们把上面的括号里面的公式放倒并且把数带入进去:
RoPE的cos公式代入直观表述
向量的蓝色部分1/4是除以一个1 ~ 10的数,向量的绿色部分1/4是除以一个10 ~ 100的数,向量的橙色部分1/4是除以100 ~ 1000的数,向量的红色部分1/4是除以一个 1000 ~ 10000的数。

让我们看看当在计算token相对位置时,不同大小的相对距离( k = m − n k=m-n k=mn)会是怎么样。

当相对距离 1 < k < 10 1<k<10 1<k<10的时候,经过除法蓝色部分大约等于1,而其他部分都比较小,绿色橙色红色的数量级分别为0.1,0.01,0.001,接近于0,而我们知道在深度学习过程中值的大小都要在一个范围内会比较好,最经典的就是 [ 0 , 1 ] [0,1] [0,1]区间还有 [ − 1 , 1 ] [-1,1] [1,1] 。所以我们是否可以认为此时是蓝色部分的向量发挥作用,而其他部分的向量不发挥作用呢?

同样的,当相对距离 10 < k < 100 10<k<100 10<k<100的时候,经过除法绿色部分大约等于1,而左边蓝色的部分数量级为10左右,有点过大;而右边的部分在0.1和0.01,比较小。所以可以认为此时是绿色部分的向量发挥作用。

同样的,当相对距离 100 < k < 1000 100<k<1000 100<k<1000的时候,经过除法橙色部分大约等于1,而左边蓝色的部分数量级为100左右,太大了;绿色部分数量级在10左右,也比较大;而右边的红色部分在0.1,比较小。所以可以认为此时是橙色部分的向量发挥作用。

最后一种情况,当相对距离为 1000 < k < 10000 1000<k<10000 1000<k<10000的时候,经过除法红色部分大约等于1,而左边蓝色的部分数量级为1000左右,太大了;绿色部分数量级在100左右,也比较大;橙色部分数量级在10左右。所以可以认为此时是红色部分的向量发挥作用。

改进版本的对数相对距离embedding

这样一看我们想到了前人在相对位置表示上的另一种方法,相对距离位置嵌入。原先是每个距离都对应一个相对距离位置嵌入,比如相对距离从最小的0到最大的512,对应512个位置嵌入,这样其实是有一些缺点的,一个就是较远距离位置嵌入由于训练数据较少,比较难以训练的问题;还有其实在距离比较长的时候,相邻之间的区分度不是那么大了,就比如相对距离为100还是101重要吗?看起来不是很重要,远不如6和7的相对距离之间重要。

但RoPE这里采用的其实是对数排列的方式,前1/4对应1 ~ 10的相对距离;1/4 ~ 1/2 对应10 ~ 100的相对距离;1/2 ~ 3/4 对应100 ~ 1000的相对距离;而最后1/4则对应1000 ~ 10000的相对距离,这很好,解决了上面传统相对距离嵌入的问题。在距离小的时候区分度大,在距离大的时候区分度小。

旋转位置编码的长度扩展

我们按照 直观体现的旋转位置矩阵改进版本的对数相对距离嵌入 去理解不同种长度扩展方式带来的影响。
RoPE的cos公式代入直观表述

直接外推

假设说,我们训练数据大多是在1~1000范围内,我们相对距离旋转位置矩阵计算之后,为1的地方大多数落在蓝色、绿色、橙色这三个区域,所以对应这三个区域的参数可以认为被训练的很好了(由于训练数据占比通常是短的多,长的少,所以其实可以认为蓝色、绿色、橙色这三个部分的训练完成度是 蓝色 > 绿色 > 橙色, 蓝色部分得到了很好的训练,其次是绿色,再其次是橙色

那么问题来了,来了个长度为5k的文本,在相对距离旋转位置矩阵计算后,为1的地方落在红色部分,怎么办?没怎么见过,对应的参数没训练过啊!更何况如果来的长度是50k的文本呢?那为1的地方红色部分都落不下了,得落到红色部分的右边了。这可以解释为什么在超出一定长度的时候模型性能下降的问题。

线性内插

线性内插,说穿了其实是对计算公式 c o s ( k θ i ) cos(k{\theta}_i) cos(kθi)中的 k k k进行缩放。假设说我要将原来的1 ~ 1000的范围缩放到1 ~ 2000,也就是所有的 k k k都要除以2。那相对距离为10的,除一下就变成了5,也就是原先使用10这个位置对应的参数,现在使用5这个位置对应的参数,影响还是比较大的,所以需要进一步的微调。

假设说1 ~ 1000的范围缩放到1 ~ 1500,那么也就是10变成了大约7的样子,相对变化较小,还是可以接受的,因此证实了小范围扩展的可用性。

假设说1 ~ 1000的范围缩放到1 ~ 10000,那么原来对应10直接变成了现在对应1,距离近的词之间缩放的太厉害了,这种变化是非常致命的,就好像原先主语和宾语之间大致是10个词左右,现在直接距离被认为是1,这就是形容词和名词之间的处理距离了;或者可以认为是句子和句子之间距离为10个词左右,变为同句子词语之间相对距离1左右,肯定会有大问题的。因此不合适大规模扩展。

说到底,其实就是线性缩放不适应原来的对数分布的相对距离旋转位置矩阵。

NTK扩展

NTK扩展其实就是把线性内插的线性缩放改成了对数缩放的形式

具体做法是对计算公式中 c o s ( k θ i ) = c o s ( k 1000 0 − 2 i / d ) cos(k{\theta}_i)=cos(k10000^{-2i/d}) cos(kθi)=cos(k100002i/d)中的 10000 10000 10000上做文章,比如说把 10000 10000 10000换成 160000 160000 160000 。这会造成什么影响呢?我们把这个变化带入原先的计算数当中。
RoPE的cos公式代入直观表述
RPE2
还是假设原来的训练数据长度大多数在1 ~ 1000之内。(再次重申)因此在相对距离旋转位置矩阵计算之后,原先是大多数落在了蓝色、绿色、橙色之内,因此这些区域对应的参数训练的很好,在1 ~ 1000范围以外的比如说5000是落在了红色区域,没训练到所以结果很差。

但是,经过 10000 10000 10000换成 160000 160000 160000的缩放,原来的5000距离从原先的落入红色区域,变成了现在的落入橙色区域,使用的是原先橙色区域训练好的参数,因此效果比较好。(为什么明明距离5000使用1000的参数效果会好呢?下一节会给出可能的解释)那么经过这样的缩放模型的适用距离从原来的1 ~ 1000变到了多少呢?应该是橙色区域现在对应的最大相对距离,我猜应该是1 ~ 8000。

但为什么效果不会像线性内插一样变差呢?线性内插效果变差的原因是相对距离近的词缩放的太厉害了,我们看看NTK扩展下距离近的词的缩放情况怎么样。

假设距离为10,在原来 10000 10000 10000的情况下,除完之后等于1的位置是蓝色区域最右边,也就是从左往右 1 / 4 1/4 1/4处,因此可以认为使用到的参数是这个位置对应的参数;在 160000 160000 160000的情况下,解方程 10 ∗ 16000 0 − 2 i / d = 1 10*160000^{-2i/d}=1 101600002i/d=1,解得 2 i / d = 0.1923 ≈ 0.2 = 1 / 5 2i/d=0.1923\approx0.2=1/5 2i/d=0.19230.2=1/5,所以 i = d / 10 i=d/10 i=d/10,又 i i i 的范围为 0 < i < d / 2 0<i<d/2 0<i<d/2,所以此时1落在整个光谱的从左往右 1 / 5 1/5 1/5处。 1 / 5 1/5 1/5 1 / 4 1/4 1/4 之间相差不多,因此在相对距离比较小的时候影响并不大。

所以相对距离的对数缩放,恰合了原来对数分布的相对距离旋转位置矩阵。对于相对距离小的词影响很小,而相对距离很大原来落在红色区域的,又能够用橙色区域的参数来处理。不需要太多微调也能够进行处理。

整个NTK扩展我觉得其实是有点像传统的相对距离位置嵌入解决过长相对距离没有训练到导致的问题。

传统的做法是这样:
假设说我们的相对距离位置嵌入一共有512个,对应从0 ~ 512,那么如果相对距离大于512呢?那就直接拿512对应的相对距离位置嵌入就可以了。

NTK这里其实我觉得也是想实现这样一个效果,用对数缩放达到了类似的效果。

为什么明明距离5000使用1000的参数效果会好?

为什么距离5000的相对距离使用1000的参数效果会好?旋转矩阵直观体现中,我们将整个旋转矩阵表示分成了4份,产生了5个分割点,这5个分割点的1、10、100、1000、10000又代表着什么意思呢?

我尝试从语言学的角度来粗略的给一个可能的解释。

1 ~ 10这个数量级,一般都是同一个句子中,不同的词之间相对距离所在的数量级。通常我们的一句话(把复杂句拆成多个从句这样看)的词语的数目都是10词数量级,因此同一个句子内部词和词之间的距离也就满足大部分在1 ~ 10之间这个要求。例如:一句话中词和词的关系,比如形容词和名词,主语和谓语,谓语和宾语……这些关系通常都是在1 ~ 10这个距离区间内的。

10 ~ 100这个数量级,一般都是同一个段落中,不同句子的词和词相对距离所在数量级。上面也说了,一句话词的数目是10这个数量级,而一段话的词的数量是100这个数量级(小时候老师告诉我们要分段,不要一段写完整篇文章!一段大概是200个字左右,高考作文800字分4、5、6、7段,也就是100 ~ 200个字)。因此跨句子,但是不跨段落的词之间的相对距离,也就在10 ~ 100这个区域。例如:一句话前面提及一个新的事物,后面的句子很可能就是围绕着这个新事物展开叙述。不同句子之间可以有句子之间独特的对应关系。

100 ~ 1000这个数量级,一般都是同一篇文章/同一章节,不同段落的词和词之间的相对距离所在的数量级。就像上面提到的,高考作文通常是800字,因此一篇文章或者一部作品的一个章节所包含的字数通常是在1000个这个数量级。而段落包含的字数通常在100这个数量级。所以跨段落但是不跨文章/章节的词之间的相对距离,也就在100 ~ 1000这个区域。例如:前面一个段落是首段,后面就不要再傻傻的开头了,就应该进入正文开始议论部分了(议论文)。不同段落之间可以有段落之间独特的对应关系。

再往上嘛,1000 ~ 10000这个范围,上万字的作品,基本上只有中长篇小说才会有这么多字了,很少的说,另外模型不能直接训练得到一个比较好的结果可想而知这些样本的稀少程度了,再对其进行语言学对应关系似乎没多少意义了,章节和章节之间是没有很明显的独特的对应关系的,有对应关系也应该在段落和段落,句子和句子之间多次出现过。就比如说推理小说《白夜行》不同章节之间的可能存在的对应关系,比如说前面章节藏了铃铛的响声之类的伏笔,后面再次提到了,但其实这种伏笔完全可以在短片小说(1000字这个数量级)找到很多。因此章节跨度的对应关系应该没多少独特性。

既然那么长的相对距离的对应关系没有多少独特性,我们就直接将段落和段落之间(100 ~ 1000)的对应关系直接拿来用就可以了。

一些改进的想法

虽然按照NTK这样对数缩放的形式,确实是能够起到不错的作用,但是不管怎么说1 ~ 10、10 ~ 100、100 ~ 1000这些范围内相较于缩放之前,还是或多或少存在错配的问题,原本对应的参数位置多少出现了偏移,我感觉或多或少会对原本的性能产生影响。

那么问题来了怎么办呢?既然按照上一节分析的,5000可以直接使用1000对应的参数的话,直接把相对距离设置一个上限就行了?比如说设置上限为1000,超过这个距离的就把他设置为1000就行了。当相对距离大于1000的时候,都使用1000这个位置对应的参数。或者可以做精细一点,只对超过1000的进行对数缩放,在1000以内的则不变。

而相对距离小于1000的词之间,对应的位置和所使用的参数之间完全没有变化,一点都不会影响到相对距离小于1000词之间的关系。

我感觉很不错,自我感觉良好。

别忘了cos!

前面我们武断的说只有当 k 1000 0 − 2 i / d k10000^{-2i/d} k100002i/d大致等于1的时候才是有效的,当值约等于0.1的时候会被忽略掉这比较好理解,但是值很大(10、100)的时候不就会计算之后数量太大直接爆炸吗?

这时候我们想起之前忽略的cos和sin了,三角函数将值限制在 [ − 1 , 1 ] [-1, 1] [1,1]之间,使得不会出现计算后数量太大爆炸的问题。而cos和sin达到最大值的时候是 n ∗ π / 2 n*\pi/2 nπ/2这些位置,因此在公式里面的k做一点点缩放就行,不影响结论,更何况 π / 2 ≈ 1.57 \pi/2\approx1.57 π/21.57,差的也不是特别多。

至于cos在1这里大致取0,哈哈,这个问题确实,也许这个时候要看sin呢,sin可是这个时候大概取1呢。

有些人又会问了,由于cos的周期性,所以当k=555之类比较大的时候,也不是只有100 ~ 1000这个区域会等于1啊,并不像你之前说的一样只有这块区域有效/活跃啊,有些k会刚好使得前面的区域也会等于1啊,比如说k=555的时候,不仅是100 ~ 1000区域会有一个地方等于1,还有1 ~ 10这个区域某个值会等于1,还有10 ~ 100这个区域的某个值也会等于1。那这怎么办,会不会由于前面也有内容被激活了,导致引入不必要的短距离的影响呢?(就比如说在分析段和段之间词的关系呢,把句子内部词的关系也引入进来了)长距离下引入短距离的差别属实没什么必要,你会纠结距离为100和200之间的差别,但是从100变到101,这似乎确实没什么差别了,长距离下需要忽略由于周期性导致的短距离区域的激活,就好像我们之前讨论的一样,橙色区域激活之后,蓝色和绿色区域似乎就没看的必要了,具体到cos和sin上,超过一周期,也就是一圈之后就没必要看了。

按这样分析确实会有可能会在长距离的时候受到短距离区域激活的的影响,但我估计模型自己学习了一定的方法来防止这一问题,就比如说只看最高位,较大数量级区域影响权重更大一些?

传统的相对距离embedding是否可以按照上面一样进行改造也能起到一样的效果呢?

我也想知道,但我没钱没卡没数据,要是有大佬看了这个思路受了可能的启发搞了波大的能不能带带我🤣(属实是有点太高看自己了,大抵这篇文章也没人看😭)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值