大模型训练原理(09)|Transformer 凭什么知道“狗咬人”和“人咬狗”不一样?——从位置编码到 RoPE

大模型训练原理(09)|Transformer 凭什么知道“狗咬人”和“人咬狗”不一样?——从位置编码到 RoPE
上一课我们终于把文字送进了神经网络真正熟悉的世界。一段文字先经过 Tokenizer被拆成 Token再变成 Token IDToken ID 去 Embedding Matrix 里找到对应的一行最后得到一个高维 Vector向量。于是Text→Token→Token ID→Embedding→Vector到这里我们已经解释清楚了一件很重要的事Token ID 只是地址真正进入 Transformer 参与计算的是 Vector。但第八课结束时我故意停在了一个地方。因为当每一个 Token 都变成 Vector 以后一个看起来很简单、实际上非常致命的问题出现了这些 Vector 自己哪里写着谁是第一个、谁是第二个这就是今天要解决的问题。而且这一课如果真正想明白后面很多看起来很玄的东西——RoPE、Long Context、YaRN、百万 Token 上下文——都会突然变得顺理成章。一、先别想 Transformer先看一句小学语文有两句话狗咬人。和人咬狗。如果只统计出现了哪些词两句话完全一样狗、咬、人。甚至每个词都只出现了一次。但没有任何人会觉得这两句话表达的是同一件事。为什么因为语言不是一个“词的集合”。语言是一个Sequence序列。谁在前谁在后本身就是信息。再比如小明打了小李。和小李打了小明。只交换两个名字的位置施事者和受事者就完全反过来了。所以一个语言模型如果只能知道这里有“小明”“打”“小李”三个 Token。却不知道谁排在前面谁排在后面。那它连最基本的句法关系都无法稳定表达。问题来了。上一课我们已经把每个 Token 都变成 Embedding 了。假设“狗”的 Embedding 是e狗那么“狗”出现在狗咬人的第一个位置时是这条向量。它出现在人追狗的第三个位置时刚进入模型时仍然可以是同一条e狗因为 Embedding Lookup 做的事情只是根据 Token ID找到这个 Token 对应的向量。它回答的是我是谁却没有自动回答我在哪里这就是今天整节课真正的起点。二、一个特别容易想错的问题数组不是本来就有第 1 行、第 2 行吗很多人第一次学 Position Encoding位置编码时都会产生这个疑问。假设一句话已经变成X [x1x2x3]那程序不是明明知道(x_1) 是第一行(x_2) 是第二行(x_3) 是第三行吗为什么还要额外告诉 Transformer 位置这里有一个非常关键的区别程序知道数据存在哪里不等于模型的数学计算已经获得了“位置”这个特征。举个简单例子。假设我们对每一个 Token 都做同样的线性变换hixiW第一行乘的是 (W)。第二行乘的还是 (W)。第三行仍然是同一个 (W)。这个 (W) 不会因为“你现在处理的是第 37 个 Token”突然自动换一套参数。所以“第几行”虽然存在于程序的数据结构里却不代表它已经变成模型能够利用的 Representation表示。可以把它理解成这样Excel 里一条员工记录位于第 300 行。程序当然知道这是第 300 行。但如果“第 300 行”这个信息从来没有作为 Feature特征交给模型那么模型不会仅仅因为它存储在第 300 行就自动学会“这个员工和第 299 行员工有某种特殊关系。”所以真正需要解决的问题不是计算机知不知道 Token 的数组下标而是怎样把 Position 变成神经网络能够利用的数学信息这才是 Position Encoding 存在的原因。三、最直觉的办法直接告诉模型“你坐第几号位”假设一句话是我 喜欢 人工智能三个 Token 经过 Embedding 后得到e0,e1,e2现在我们另外准备三个和位置有关的 Vectorp0,p1,p2然后让xieipi于是第 0 个 Tokenx0e0p0第 1 个 Tokenx1e1p1第 2 个 Tokenx2e2p2现在送进 Transformer 的东西就不再只有“我是谁”还混入了“我现在在哪个位置”这个想法其实一点都不神秘。Embedding 可以理解为 Token 的“身份信息”。Position 可以理解为 Token 的“座位信息”。一个 Token 最终进入模型时我们希望它不仅有身份证还拿着座位号。这就是最朴素的位置编码思想。四、Absolute Position先从“我是第几个”开始最容易想到的位置概念叫Absolute Position绝对位置。例如今天 天气 很 好我们直接编号Token位置今天0天气1很2好3那么“好”的 Absolute Position 就是 3。这和电影院座位非常像。你告诉我我坐第 12 排。这就是绝对位置。因为你直接告诉了我你位于整个坐标系统的哪里。于是我们很容易想到一种实现。上一课不是已经有 Token Embedding Matrix 了吗E∈ℝV× d其中 (V) 是 Vocabulary Size词表大小(d) 是 Embedding Dimension嵌入维度。那我们再造一张 Position Embedding Matrix 不就好了P∈ℝL× d这里的 (L) 表示支持的位置数量。如果某个 Token 在第 17 个位置就查P[17]然后xE[Token ID]P[17]于是同一个“狗”出现在第 2 个位置时E[狗]P[2]出现在第 100 个位置时E[狗]P[100]Token 没变。但是因为位置不同进入后续网络的 Representation 已经不同。这就是一种非常直觉的Learned Positional Embedding可学习位置嵌入。五、第一处矛盾出现了如果位置是一张表超出表怎么办假设模型准备了8192 个 Position Embedding。也就是P[0],P[1],P[2],…,P[8191]训练的时候没有问题。但现在用户突然输入了一段 12000 Token 的内容。第 10000 个 Token 要找P[9999]结果呢根本没有这一行。这时候就暴露出一个很自然的问题如果每一个 Position 都依赖一条独立学习出来的 Vector那么位置范围就和这张表直接绑在一起了。于是下一种思路就非常自然既然“位置”本质上是0、1、2、3、4……这样有规律的数字我们为什么非要让模型把每一个位置单独背下来能不能给我一个 Position我直接算出它的表示也就是从Position→Lookup变成Position→Function这就引出了经典 Transformer 里的另一个著名设计Sinusoidal Positional Encoding正弦位置编码。六、为什么偏偏是 Sin 和 Cos先别看公式想象很多只速度不同的钟这是我认为理解位置编码最重要的一个直觉。先不要看任何公式。想象桌子上摆着很多只钟。第一只钟转得非常快。第二只慢一点。第三只更慢。第四只更慢。……现在 Token 从 Position 0 移动到 Position 1。所有钟都转动一点。从 Position 1 到 Position 2所有钟又继续转一点。于是每一个 Position都对应这一刻所有钟表指针的组合状态。单独看第一只钟可能会重复。因为钟会转圈。但是如果同时看很多只转速完全不同的钟它们组合起来就可以形成非常丰富的位置模式。这就是“多 Frequency频率”的直觉。现在再看经典公式就会好理解很多PE(pos, 2i) sinpos100002i/dPE(pos, 2i1) cospos100002i/d第一次学这两个公式完全没有必要背。真正要看懂的是三个东西。(pos)当前是第几个位置。(i)现在处理的是哪组维度。(d)整个 Representation 的维度。真正重要的设计是不同维度使用不同 Frequency。有些变化得快。有些变化得慢。于是一个位置不再只用“317”这个孤零零的数字来表示而是变成一组跨不同尺度的位置特征。七、为什么一定要很多不同 Frequency假设我们只使用一个sin(pos)问题马上就来了。Sin 是周期函数。转一圈以后又回到原来的状态。也就是说单独一条周期信号很容易出现重复。还是用钟来想。如果我只告诉你秒针指向哪里秒针现在指向 12。你无法知道现在到底是10:00:0010:01:00还是 10:02:00。因为秒针每分钟都会重复。但是如果同时告诉你时针的位置分针的位置秒针的位置组合起来以后状态的区分能力就强得多。位置编码的多 Frequency 思想本质上也是类似的用多个不同变化速度的信号共同描述 Position。这个概念一定要记住。因为等一下进入 RoPE旋转位置编码以后你会发现 Frequency 仍然是核心。八、到这里还没结束因为“我是第几个”可能根本不是最重要的问题现在看一句更真实的话小明把一本书借给小李几天以后小李把书还了回来。假设模型处理第二个“小李”。真正有价值的信息仅仅是“这个 Token 位于第 23 个位置。”吗显然不是。更重要的可能是它距离前面的“小李”有多远再比如代码。前面定义user_count几百个 Token 以后再次出现user_count对于后面的 Token 来说模型真正关心的往往不是我是第 800 个 Token。而是我和那个相关 Token 相隔多远这时候位置问题发生了一次非常重要的升级。前面的问题叫Absolute Position绝对位置。现在的问题叫Relative Position相对位置。九、Absolute Position 和 Relative Position差别到底有多大假设 Token A 位于m100Token B 位于n103它们的绝对位置是100 和 103。但它们的相对距离是n-m3现在把这整段内容往后移动。A 来到m5000B 来到n5003绝对位置已经完全改变100 → 5000103 → 5003但n-m3没有改变。这个观察非常重要。因为自然语言中的很多结构本来就具有这种性质。例如“形容词在名词前面一个位置”这种关系可能出现在句首也可能出现在一篇 5000 Token 文章的中间。真正重要的并不一定是它位于整个 Sequence 的第 1738 个位置。而可能是它和另一个 Token 相隔几个位置。如果你想通这一点就已经走到了 RoPE 出现的门口。十、RoPE 真正聪明的地方不是“用了 Sin 和 Cos”RoPE 全名Rotary Position Embedding旋转位置编码。很多教程讲到这里会马上甩出一堆复数、旋转矩阵和公式。然后读者记住了一个结论“现在的大模型一般都用 RoPE。”但完全不知道它为什么漂亮。其实 RoPE 真正值得学的只有一个问题有没有办法让每个 Token 根据自己的绝对位置发生变化但两个 Token 相互比较的时候最终出现的是它们之间的相对位置如果可以做到这一点就非常适合语言。RoPE 给出的答案是Rotation旋转。十一、先在二维世界里理解“旋转”假设有一个二维向量v [xy]现在把它旋转一个角度 (θ)。对应的 Rotation Matrix旋转矩阵是R(θ) [cosθ-sinθsinθcosθ]旋转后的 Vectorv′R(θ)v如果原来v [10]它相当于一根朝右的箭头。旋转 90° 后v′ [01]箭头变成朝上。这里有个很漂亮的性质旋转改变方向但不会改变 Vector 的长度。所以 Position 不一定要表现成给 Vector 硬加一个“第 100 位”的数字。它还可以表现成根据 Position改变 Vector 在空间里的方向。这就是 RoPE 的几何直觉。十二、最关键的一步让 Position 决定旋转多少假设 Token 位于第 (m) 个位置。我们让它旋转mω这里的 (ω) 可以理解成某一组 Angular Frequency角频率。于是Position 0R(0ω)Position 1R(1ω)Position 2R(2ω)Position 100R(100ω)Position 不再只是一串0、1、2、3……而是变成不同的旋转角度。也就是Position→Rotation但这还不是 RoPE 最精彩的地方。真正值得“恍然大悟”的一步现在才开始。十三、两个 Token 一比较神奇的事情发生了假设有两个 Token。一个位于位置m另一个位于位置n它们有两个向量q和k先别纠结 q、k 是什么。下一课正式进入 Attention 时我们会知道它们分别对应 Query查询和 Key键。今天只把它们看成两个需要比较的 Vector。位置 (m) 上的 q 根据自己的 Position 旋转q′mR(mω)q位置 (n) 上的 k 也旋转k′nR(nω)k现在我们比较两个 Vector。计算(q′m)Tk′n代进去(R(mω)q)T(R(nω)k)继续整理qTR(mω)TR(nω)k而 Rotation Matrix 有一个非常漂亮的性质R(θ)TR(-θ)于是得到qTR(-mω)R(nω)k旋转角度可以相加R(−mω) · R(nω) R((n−m)ω)最后变成(q′m)Tk′n qTR((n−m)ω)k先别继续。盯着最后一个东西n-m发现了吗开始的时候一个 Token 知道自己的位置 (m)。另一个知道自己的位置 (n)。可当它们真正发生关系计算时最后留下来的却是n-m也就是相对位置。这就是 RoPE 最漂亮的地方。十四、真正应该记住的不是公式而是这句话RoPE 对每一个 Token 做的是根据 Absolute Position绝对位置进行旋转。但两个 Token 相互比较以后关系中自然出现Relative Position相对位置。所以如果一定要用一句话解释 RoPE我更愿意写成RoPE 用绝对位置决定旋转却让 Token 之间的交互自然感知相对距离。这句话比“RoPE 是一种通过复数实现的位置编码。”重要得多。因为后一句只是实现层面的描述。前一句才告诉你它到底解决了什么问题。十五、用一个小到不能再小的例子把它钉死假设q [10]k [10]开始时两根箭头完全同方向。假设ω30°现在 q 所在 Token 位于 Position 2。所以它旋转2×30°60°k 所在 Token 位于 Position 5。所以它旋转5×30°150°两根箭头真正相差150°-60°90°注意。Position 2 和 Position 5 本身不是最终最关键的东西。真正进入两者相对几何关系的是5-23现在把两个 Token 一起向后平移 100 个位置102 和 105。两者仍然相隔105-1023它们的相对旋转关系仍然保持同样的结构。如果你能从这个例子理解 RoPE后面的公式基本就只是把这个思想推广到高维。十六、LLM 有几百维难道真的把整个 Vector 在一个空间里旋转真实模型当然不是只处理二维向量。但方法没有想象中复杂。可以把维度两两分组(x0,x1)是一组二维平面。(x2,x3)又是一组。(x4,x5)再是一组。以此类推。然后每一组都可以做刚才那个二维 Rotation。如果某个向量有 128 维从理解上可以把它想成64 组二维平面。真正有意思的地方在于这些二维平面并不一定使用同一个 Frequency。而是ω0,ω1,ω2,…有的旋转得快有的旋转得慢。于是同一个 Position (m)在不同维度组上形成mω0mω1mω2……这就是为什么我们前面一定要先讲“很多只不同速度的钟”。RoPE 不是突然冒出来的一套魔法。它仍然在使用Multi-Frequency多频率的位置表示。只是它不再单纯把这些 Sin/Cos 数值当 Position Vector 加进去而是把它们真正变成了 Rotation。十七、一个很容易学歪的地方高频负责短距离、低频负责长距离可以拿这个说法帮助入门理解但不要把它理解得过于机械。Frequency 高Position 稍微变化一点角度就变化得比较明显。Frequency 低Position 要移动更远角度才慢慢改变。所以从直觉上可以理解成不同 Frequency 提供了不同尺度的 Position Pattern。但真实神经网络不是一张人工设计好的 Excel第 116 维短距离语法。第 1732 维长距离依赖。并不是这样。更准确的说法是不同 Frequency 共同构成一套多尺度的位置几何结构模型再通过训练学习如何利用它。这和上一课讲 Distributed Representation分布式表示其实是同一个思想。不要总想着某一维到底代表什么很多时候真正有意义的是整组 Representation 如何共同参与计算。十八、现在你应该能看懂为什么 RoPE 会放在 Attention 的 Q 和 K 上这里我们提前碰一下下一课的内容但只讲必要的部分。Attention 后面要解决的问题是当前 Token 应该关注哪些 Token其中一个核心步骤就是比较Query查询和Key键之间的关系。所以如果我们希望两个 Token 的位置关系会影响它们之间的匹配一个非常自然的办法就是在 Q 和 K 被拿去比较之前先根据各自 Position 应用 RoPE。于是数据流可以先记成Attention 前的位置处理数据流Token→Embedding→Hidden Representation隐藏表示→生成 Q、K→对 Q、K 应用 RoPE→比较 Q、K→Attention这一点很重要。因为 RoPE 不是简单地说“我把 Token Embedding 整体旋转一下。”更准确地说在典型的 RoPE Transformer 中它主要被用于 Attention 中与位置关系计算直接相关的 Q/K Representation。为什么恰恰是 Q 和 K等下一课真正理解Query 到底在问什么Key 到底在提供什么之后你甚至不需要背这个结论。它会变得非常自然。十九、走到这里再回头看三种 Position 思路现在我们终于可以把前面的路线放在一起。第一种Learned Absolute Position核心问题我是第几个办法给每个 Position 学一条 Vector。第二种Sinusoidal Position Encoding核心问题Position 能不能不用一条条背而是直接计算办法用不同 Frequency 的 Sin/Cos 生成 Position Signal位置信号。第三种RoPE问题进一步升级成Token A 和 Token B 相互比较时能不能自然感知“我们相隔多远”办法让 Position 控制 Rotation再利用 Rotation 的几何性质让 Token InteractionToken 之间的交互中自然出现n-m如果按照这个顺序理解RoPE 根本不难。真正难的是很多教程一上来就告诉你eimθ然后开始讲复数。数学没有错。教学顺序错了。因为一个技术最应该先回答的是为什么非得有它而不是论文公式长什么样二十、然后一个更大的坑出现了有 RoPE是不是 Context 想多长就多长这是今天一定要提前堵住的误区。你可能已经发现RoPE 的角度来自mω那 (m) 是 Position。Position 是 100可以算。Position 是 10000也可以算。Position 是 1000000Sin 和 Cos 照样可以计算。那是不是意味着使用 RoPE 的模型天然支持无限 Context不是。这里一定要记住一句非常重要的话数学上算得出来不代表模型训练出来以后会用。英文可以叫Mathematical Computability ≠ Learned Capability数学可计算性不等于模型已经获得对应能力。假设模型训练期间主要接触的是08191这些 Position。现在突然让它处理100000的位置。三角函数当然不会报错。Rotation Matrix 也可以照常计算。但模型后面的参数有没有学会处理这种位置范围下的 Pattern这是另一回事。二十一、这就是 Position Extrapolation位置外推假设训练期间主要覆盖0≤ pos8192推理时突然进入pos50000甚至pos500000这时候我们面对的就是Position Extrapolation位置外推。“外推”是什么意思你可以把它理解成训练的时候你只做过 0100 的题。考试突然给你 10000。公式形式可能没变但你已经远远走出了训练时熟悉的区域。对于 RoPE 来说也是如此。Position 越来越大不同 Frequency 上的 Rotation 会继续变化。数学没有坏。但模型看到的是越来越偏离原训练分布的位置模式。所以一个模型在配置文件里能够写出很大的 Position不等于它在那个长度上真的拥有稳定、有效的 Long Context长上下文能力。这两个概念千万不要混。二十二、以后你会遇到 YaRN、RoPE Scaling它们其实都在接今天的问题等以后开始学 Long Context你会看到很多名词RoPE ScalingPosition InterpolationNTK-aware ScalingYaRN……第一眼看起来像完全不同的技术。但如果今天真正学懂了你会发现它们都逃不出一个最根本的问题原本模型只在某一段 Position 范围里学过如果现在要把 Context 拉得更长怎样重新安排 Position 和 Frequency 的关系才能让模型更平稳地进入更远的位置所以后面学这些技术的时候不要重新从零开始。你只需要回到今天这条链后续 Long Context 技术的知识链Position→Frequency→Rotation→Relative Position→Training Range→Extrapolation就能重新找到它们的位置。这也是为什么我一直强调不要背名词。要建立知识树。二十三、不过这里必须再严谨一点没有 Position EncodingTransformer 就完全不知道顺序吗很多入门文章会直接写Transformer 没有任何顺序概念所以一定必须加入 Position Encoding。拿来入门不算离谱。但如果以后真正开始读论文这句话就显得太绝对了。尤其 Decoder-only Transformer 里还有一个东西Causal Mask因果掩码。它会限制当前 Token 只能访问自己以及前面的 Token不能看到未来。所以模型的计算过程并不是完全对前后位置毫无区别。研究领域也存在 NoPE也就是不显式使用传统 Position Encoding 的路线。因此更严谨的理解应该是标准 Attention 的内容匹配机制本身没有天然提供一个完整的位置坐标系统因此现代 Transformer 通常需要某种机制让网络能够利用顺序和相对位置结构。RoPE 是其中非常重要的一种设计。这句话可能没有“Transformer 完全不懂顺序”那么抓眼球。但它更准确。技术文章真正长期有价值的地方就在这里。简单可以。不能为了简单把概念讲错。二十四、现在终于可以重新回答开头的问题为什么狗咬人和人咬狗进入 Transformer 以后不会只是同样三个 Token因为模型需要处理的从来不只是Token IdentityToken 身份。还包括Position Structure位置结构。Embedding 告诉模型我是“狗”。Position Mechanism 告诉模型我出现在这里。而像 RoPE 这样的设计进一步让后续 Token 之间进行关系计算时能够利用我距离另一个 Token 有多远。所以真正的数据世界已经从上一课的Symbol→Vector进一步发展成Symbol→Vector→Position-aware Representation也就是输入进入 Transformer 的完整路径文字→Token→Token ID→Embedding→Vector→Position→Transformer第八课完成的是我是谁。第九课补上的是我在哪里以及我和别人相隔多远。到这里输入端似乎终于完整了。但你仔细想一下会发现一个更麻烦的问题马上出现。二十五、知道“我在哪里”还是不知道“我应该看谁”看一句话小明把电脑交给小李因为他第二天要出差。假设现在模型处理他这个 Token。经过前九课它已经拥有很多东西它知道我是“他”。也知道我现在位于 Sequence 的这个位置。甚至能够利用自己和前面 Token 之间的相对位置。但是这些仍然没有直接回答最关键的问题“他”到底应该和“小明”建立强关系还是应该和“小李”建立强关系再看代码前面user_count calculate_users(data)很久以后print(user_count)后面的user_count应该去哪里找与自己有关的信息仅仅知道前面有 3000 个 Token。没用。仅仅知道某个 Token 距离我 837 个位置。也不够。模型真正还缺一个能力面对当前 Token从整个 Context上下文里寻找最值得拿过来的信息。这才是 Transformer 真正开始变厉害的地方。它需要一个动态的信息路由机制。英文叫Contextual Information Routing上下文信息路由。而这个机制有一个你一定听过的名字Attention注意力。二十六、第九课真正需要带走的是这一条因果链今天其实没有必要记住多少公式。真正应该留下来的是Embedding 解决What am I我是谁但语言有顺序于是需要Where am I我在哪里这产生Absolute Position绝对位置。但语言里的很多关系真正关心Where am I relative to you我和你相隔多远于是进入Relative Position相对位置。然后我们希望每个 Token 根据自己的位置发生变化但两个 Token 互相比较的时候能够自然得到相对距离。于是Position→Rotation最终让m,n在关系计算中变成n-m这就是 RoPE 最值得理解的地方。如果你现在能真正说清楚为什么旋转能够把绝对位置转化成相对位置关系那你已经不是“知道 RoPE 这个名词”了。你是真的开始理解它为什么被设计出来。二十七、最后检查一下这些问题你能不能自己解释不用背定义。试着顺着自己的理解回答为什么 Token ID 相同的 Token在不同位置仍然需要额外的位置机制为什么“数据在数组第 3 行”不等于“模型已经知道自己位于 Position 3”Absolute Position 和 Relative Position 的区别到底是什么为什么 Sin/Cos 位置编码需要多种 Frequency而不是只用一个周期函数RoPE 为什么选择 Rotation为什么R(mω)T R(nω)最后会和n-m发生关系为什么这件事对 Token 之间的关系建模特别有价值为什么 RoPE 在数学上可以计算极大的 Position却不代表模型天然拥有无限 Context如果这些问题都能自己解释出来这一课就算真正学懂了。因为你已经完成了从Embedding到Position再到Relative Position最后到RoPE的完整推导。而不是记住了几个缩写。下一课别急着背 Q、K、V我们先回答一个更根本的问题——模型到底怎么从上下文里“找东西”到现在为止每一个 Token 已经拥有了两个非常重要的信息它知道我是谁。也知道我在哪里。但 Transformer 真正的难题才刚刚开始我现在需要什么信息前面谁手里有我需要的信息如果很多 Token 都和我有关我应该各拿多少这三个问题一旦抽象出来你会发现 Query、Key、Value 根本不是三个莫名其妙的字母。它们几乎是被问题本身“逼”出来的。所以第十课我们暂时不从Attention(Q, K, V) softmaxQKT√dV开始。我们会先搞清楚一件更重要的事Attention 到底是在解决什么问题当这个问题真正想通以后Q、K、V 才会从三个需要背诵的术语变成三个你觉得“原来就应该这么设计。”的东西。

最新新闻

日新闻

周新闻

月新闻