语言模型与架构模块三 · Transformer 结构组成公式代码约 18 分钟
位置编码与 RoPE 旋转位置编码
注意力本身「看不见顺序」,位置信息得额外注入
学完这节你能:
- 解释为什么需要位置编码
- 区分绝对/相对/旋转位置编码
- 看懂 RoPE 的旋转公式与代码填空
注意力对输入是「置换等变」的——打乱词序,每个词算出的注意力不变。所以必须额外告诉模型每个 token 在第几位。这就是位置编码。
- 绝对位置编码:给每个位置一个向量(正弦函数或可学习),加到词向量上。
- 相对位置编码:直接建模两个 token 的相对距离,外推更好。
- RoPE(旋转位置编码):把 Q、K 按位置「旋转」一个角度,用乘法把位置融进注意力,是当前主流(Llama、DeepSeek 等在用)。
对每一对维度 (even, odd),角度 :
这就是二维旋转矩阵——RoPE 本质是把每对分量按位置旋转一个角度。
RoPE 核心(对应样题的代码填空:符号别写反)
freqs = 1.0 / (10000 ** (torch.arange(0, d, 2).float() / d))
angles = pos.unsqueeze(-1) * freqs # (seq, d/2)
cos, sin = angles.cos(), angles.sin()
q_even, q_odd = q[..., 0::2], q[..., 1::2]
# 旋转:注意第一行是减号、第二行是加号
q_rot_even = q_even * cos - q_odd * sin
q_rot_odd = q_even * sin + q_odd * cos▪ 把一对分量旋转 90°
取一对分量 (x_even, x_odd) = (1, 0),某位置角度 θ=90°:cos=0, sin=1
x'_even = 1×0 − 0×1 = 0
x'_odd = 1×1 + 0×0 = 1
→ (1,0) 旋转成 (0,1);不同位置转不同角度,位置信息就编进了 Q、K
自测RoPE 对 Query 的旋转变换,正确的是:
自测变式(换数字再算):把一对分量 (x_even, x_odd)=(0, 1) 旋转 90°(cos=0, sin=1),结果是:
// 带走一句话
注意力看不见顺序→需位置编码;RoPE 用「按位置旋转 Q/K」的乘法注入位置,公式=二维旋转(先减后加)。
独立练习
做到这些,才算完成本节
- 手算一个二维向量旋转 0、π/2、π 后的结果,并检查范数是否保持。
- 实现 RoPE 后验证相对位置相同的两组 token 得到一致的相对旋转关系。
- 不看正文重写公式,并逐项说明符号、形状和单位。
- 改变一个条件,判断公式结果应增大、减小还是不变。
- 在本地运行代码,打印每个关键张量的 shape。
- 关闭示例后从空文件重写核心部分,并补一个异常或边界测试。
学习记录
记录本节阅读进度
建议先独立回答自测。读完记录不等于已经掌握。