LLM 架构专题:RoPE 位置编码、长上下文扩展与 MoE 稀疏化

· 约 7 分钟 ·
本文目录(8 节)

阅读大模型架构报告时,RoPE、长上下文和 MoE 经常一起出现,但它们解决的问题不同:位置表示、长序列处理,以及参数与计算量的分配。下面把这几条线分开讲,再看它们如何组合,避免把模型能力归因于某一个组件。

这篇把三个主题串起来讲——它们表面独立,实则都在解决「scale」的不同侧面。

前置阅读:建议先读 Transformer 详解、ViT 与 CLIP。

一、位置编码:注意力本身是「瞎」的

自注意力有个先天缺陷:它是集合运算,不包含顺序信息——「狗咬人」和「人咬狗」的注意力矩阵完全一样。必须显式注入位置。

正弦绝对编码(原始 Transformer):给每个位置算一个固定的正弦向量加到 embedding 上。问题:模型学的是「绝对位置编号」,文本超过训练长度后位置没见过,直接崩。

RoPE(旋转位置编码)——现在的绝对主流(LLaMA/Qwen/DeepSeek 全系)的思路转变:不编码「我在哪」,编码「我们俩离多远」。把 Q、K 向量的每两维看成一个复数,按位置做旋转;点积时旋转角度差自然变成相对距离的信息。直觉:与其告诉每个人「你是 3 号」,不如在计算时体现「他比你早来两个位置」。

import torch

def apply_rope(x: torch.Tensor, pos: torch.Tensor, base=10000):
    # x: (B, L, heads, dim),dim 必须偶数
    d = x.shape[-1]
    inv_freq = 1.0 / (base ** (torch.arange(0, d, 2).float() / d))
    # freqs: (L, d/2) —— 位置 × 频率
    freqs = torch.outer(pos.float(), inv_freq)
    cos, sin = freqs.cos(), freqs.sin()
    x1, x2 = x[..., 0::2], x[..., 1::2]   # 偶数位/奇数位配对
    rot = torch.stack([-x2, x1], dim=-1).flatten(-2)  # 旋转 90° 的配对
    return x * cos.repeat_interleave(2, -1)[None, :, None, :] + \
           rot * sin.repeat_interleave(2, -1)[None, :, None, :]

RoPE 的实际优点:相对位置天然融入、无需学习参数、衰减特性让模型自然更关注近处(符合语言直觉)。代价:位置被「旋转频率」编码,最大频率限定了外推能力——训练时最长 4K,推理直接喂 32K,高频分量的位置表示就乱了,这就是长上下文问题的根源。

二、长上下文:让 4K 训练的模型读 128K

上下文长度 = 模型能「同时考虑」的 token 数,它决定能不能喂整本书、整库代码。注意力 O(n²) 的计算成本是一难,RoPE 的位置外推失败是更本质的一难。主流解法沿着「调整旋转频率」展开:

方法思路代价
位置插值(PI)把长位置线性压缩进训练范围(32K 的位置除以 8 当 4K 用)高频信息被压缩,短距离分辨力略降
NTK 缩放高频少缩、低频多缩(保留近处分辨率)免微调可用,但有上限
YaRNNTK + 温度修正 + 分频段处理当前主流,Qwen/LLaMA 系采用
长文本微调直接在长文本上继续训练效果最好,成本最高

工程现实:「宣称 128K」不等于「128K 都好用」。中间位置的注意力衰减是真实存在的——「lost in the middle」实验表明模型对长文档开头和结尾的内容利用最好,中间最差。RAG 场景把关键文档放开头或结尾、别埋中间,就是这个结论的直接应用。

另一个方向是改架构本身:滑动窗口注意力(每层只看近处 4K,信息层层传递)、Mamba 等线性复杂度状态空间模型。但 2026 年的现实是全注意力 + RoPE 扩展仍是绝对主流,替代品还没证明能在大规模上全面胜出。

三、MoE:参数翻倍、计算不变的魔法

稠密模型每个 token 激活全部参数——7B 模型每个 token 都过 70 亿参数。MoE(Mixture of Experts)的思路:把 FFN 层换成 N 个「专家」小 FFN,每个 token 由一个路由器挑 top-k 个专家来算。

# MoE 前向的骨架(每个 token 独立路由)
router_logits = router(x)                    # (n_tokens, n_experts)
topk_experts, topk_weights = router_logits.topk(k=2, dim=-1)
topk_weights = softmax(topk_weights)
output = sum(w_i * expert_i(x) for i, w_i in zip(topk_experts, topk_weights))

Mixtral 8x7B:8 个专家、每 token 选 2 个——总参数 47B,但每 token 只激活约 13B。用 13B 的推理成本买 47B 的知识容量,这就是 DeepSeek-V3(671B 总参、37B 激活)和 Qwen-MoE 系列的核心算术。

代价在暗处:

  1. 显存不省:推理快但总参数要全装下——Mixtral 需要 ~90GB 显存(FP16),省算力不省显存。
  2. 负载均衡:路由器可能「偏心」——少数专家被疯狂选中,多数饿死。训练时加 load balancing loss 惩罚不均匀;推理时专家容量(capacity factor)满了直接丢 token。
  3. 微调更难:路由的不稳定性让 MoE 微调比稠密模型娇气(LoRA 篇里冻结路由器是常用技巧)。
  4. 通信开销:分布式部署时专家分散在不同卡上(专家并行),token 在卡间搬运,网络成为瓶颈。

三者合观:scale 的三条战线

回头看,这三个主题是一条主线的三个侧面——如何在可控成本下扩大模型能力:

  • RoPE/位置编码:让「序列维度」的信息表示不拖后腿;
  • 长上下文:扩展序列维度的 scale(4K → 1M);
  • MoE:扩展参数维度的 scale(13B 成本 ↔ 671B 容量)。

读任何新模型架构报告,先找这三个答案:位置编码用的什么、上下文怎么扩展的、稠密还是 MoE——架构的骨架就抓住了,剩下的都是细节调优。

踩坑排查

现象原因解法
微调后长文本输出乱码RoPE base 未随训练长度调整长文本微调要调 rope_theta 或开 YaRN
32K 文档中间内容被忽略lost in the middle关键信息放首尾;或分段+重排
MoE 模型推理显存爆了只看激活参数量估显存总参数全加载,按总参数量估显存
MoE 微调 loss 不降反升路由器被一起训坏冻结 router,用更小 lr
位置插值后短文本效果变差PI 压缩了高频,近距分辨力下降NTK/YaRN 替代线性 PI

练习

  1. 用文中的 RoPE 代码对一个随机向量应用不同位置的旋转,验证「点积只依赖位置差」——两个位置同时 +10,点积不变。
  2. 找一个开源小模型(Qwen2.5-0.5B),对比它对「关键句在开头/中间/结尾」三种布局的 10K 文档问答准确率,亲手复现 lost in the middle。
  3. 加载 Mixtral 或 Qwen-MoE 模型,用 output_router_logits=True 观察不同 token 的专家选择分布——标点、名词、动词各去哪类专家?
  4. 估算题:一个 8 专家 top-2 的 MoE,单专家 7B,问总参数、激活参数、FP16 显存需求各是多少?和同激活量的稠密模型比推理 FLOPs。

面试常问

Q:RoPE 相比绝对位置编码的优势? ① 相对位置内禀:点积只含位置差,符合「语言关心相对距离」的直觉;② 无需学习参数,不占用训练容量;③ 远程衰减特性自然形成局部性偏好;④ 配合缩放技术(NTK/YaRN)可外推到更长上下文。代价:外推不是免费的,超训练长度仍需干预。

Q:长上下文的主要技术路线和取舍? 位置编码扩展(PI/NTK/YaRN,便宜但有损)、长文本续训(效果好但贵)、注意力近似(滑窗/稀疏,省算力但丢全局)、外挂检索(RAG 绕开问题)。实践组合:YaRN 调频 + 少量长文本微调是性价比之选;超长(1M)场景目前靠工程妥协(分段、检索、重排)。

Q:MoE 为什么省计算不省显存? 计算按「激活参数」计——每 token 只过 top-k 专家,FLOPs 与激活量成正比;显存按「总参数」计——所有专家权重都要驻留显存以备被路由选中。所以 MoE 的甜蜜点是「推理算力受限但显存充裕」的场景(比如单卡大显存服务);显存紧张时反而不如稠密小模型。

Q:MoE 的负载均衡为什么重要? 路由是学出来的,若不加约束会塌缩:少数专家赢者通吃(被选多→被训多→更强→被选更多),其余专家退化,模型等效容量大跌。辅助损失(load balancing loss)惩罚专家使用率的方差;router z-loss 防 logits 过大;推理侧 capacity factor 限制单专家最大 token 数。DeepSeek-V3 还用了「无辅助损失的偏置调整」策略。

Q:注意力复杂度 O(n²) 的实际影响多大? 标准注意力在 128K 上下文时,注意力矩阵 128K×128K = 164 亿元素——光存它就 FP16 32GB。所以推理侧有 KV Cache 优化(推理优化篇)、训练侧有 FlashAttention(不实体化 N×N 矩阵,分块在线 softmax,把显存降到 O(n))——FlashAttention 是「不省 FLOPs 但省显存和访存」的工程奇迹,它让长上下文训练从不可能变成日常。

相关阅读

架构演进史读多了会发现规律:每个「革命性」创新都是对某个具体瓶颈的精准手术。RoPE 手术位置外推,MoE 手术参数成本——先看清瓶颈,再欣赏手术刀。

💬 评论

这套方案在哪一步卡住了?也欢迎补充你的实现方式或踩坑经验。

正在连接评论服务,首次访问可能需要几秒…