分类: 学习

  • MoE:沉睡三十年,醒来已是大模型标配

    1991 年,一篇论文提出了”多个专家协同工作”的构想。三十多年后,这个构想成为大语言模型的主流架构。这篇文章聊聊 MoE(Mixture of Experts,混合专家模型)的来龙去脉——它的起源、原理、关键里程碑,以及一个有趣的问题:为什么一项 1991 年就提出的技术,直到 2023 年才真正爆发?是理论太超前,还是科技发展太缓慢?最后,展望 MoE 的未来:它会被什么架构替代,又可能进化成什么形态?

    MoE 是什么

    MoE 的核心思想可以用一句话概括:模型很大,但每次只用一小部分

    传统大模型(Dense 模型)处理每个 Token 时,所有参数都会参与计算。MoE 则不同——它把模型拆成多个”专家”(通常是多个结构相同的前馈神经网络),再配一个”路由器”(门控网络),让路由器根据输入内容动态选择最合适的几个专家来处理。

    打个比方:一家综合医院有上百位医生,但每位患者只需要看其中几位专科医生。MoE 就像这个医院的分诊台——患者来了,分诊台判断该看哪几个科室,而不是让所有医生都来会诊。

    特性Dense 模型MoE 模型
    总参数量NN(可达 Dense 的数倍)
    每次激活参数Nn(通常仅 5%-10%)
    推理计算量低(接近同等激活参数的 Dense 模型)
    知识容量受限于激活参数受益于巨大的总参数池
    Dense 模型 vs MoE 模型对比

    起源:1991 年的超前构想

    1991 年,加拿大滑铁卢大学的 Robert Jacobs、Michael Jordan 和几位同事发表了一篇论文:Adaptive Mixtures of Local Experts。这篇论文的核心想法是:与其训练一个大而全的神经网络,不如训练多个”专家”网络,每个专家只擅长处理输入空间的一个子区域,再用一个”门控网络”来决定每个输入应该交给哪个专家处理。

    这个想法在当时是超前的。1991 年的神经网络还处于”寒冬”的尾声——支持向量机(SVM)和随机森林才是机器学习的主角,神经网络因训练不稳定、缺乏大规模数据而被边缘化。MoE 的数学框架虽然优美,但缺乏实践的土壤。

    论文: Adaptive Mixtures of Local Experts, Jacobs et al., Neural Computation, 1991


    沉寂三十年:不是被遗忘,是在等待

    从 1991 年到 2017 年,MoE 在学术界的引用量一直不温不火。这三十年间,它并没有完全消失——在语音识别、手写识别等小众领域,偶尔有研究者尝试 MoE 的变体。但总体而言,MoE 处于”理论正确,工程不可行”的状态。

    为什么?因为 MoE 要真正运转起来,需要三个前置条件同时成熟:

    条件一:足够的算力。 MoE 的”大参数量”特性意味着模型总参数可能是同性能 Dense 模型的数倍,这对 GPU 显存和集群通信带宽提出了极高要求。2017 年之前,主流 GPU(如 GTX 1080)只有 8GB 显存,连训练一个普通 Transformer 都吃力,更别提承载 MoE 的庞大参数池。

    条件二:一个标准化的骨干网络。 MoE 需要”挂载”在一个成熟的架构上才能发挥作用。1991 年没有 Transformer,也没有后来的 CNN、RNN 流行范式。直到 2017 年 Transformer 横空出世,MoE 才找到了最理想的宿主——它可以直接替换 Transformer 中的 FFN(前馈神经网络)层,实现”即插即用”。

    条件三:对”规模”的信仰。 2020 年之前,主流研究追求的是”小模型高精度”——用更少的参数达到更好的效果。MoE 的”大参数量”反而是缺点。直到 OpenAI 的 Scaling Law 被发现(2020 年左右),业界才开始相信”参数规模本身就是通往智能的关键路径”。MoE 作为”廉价扩容”方案,终于有了刚需。

    这就像 19 世纪的蒸汽机图纸——原理完全正确,但要等到钢铁冶炼、精密加工、铁路系统全部就位,蒸汽机才能真正改变世界。


    深度学习融合:Google 的三次关键突破

    2017 年到 2021 年,Google Brain/DeepMind 团队将 MoE 从学术概念推向工程可行,完成了三次关键突破。

    第一次突破:稀疏门控(2017)

    Noam Shazeer(Transformer 论文的共同作者之一)在论文 Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer 中,首次将 MoE 嵌入深度神经网络。他提出了两个关键创新:

    • 稀疏门控:用一个可学习的门控网络对所有专家打分,然后只选择得分最高的 Top-K 个专家参与计算,其余专家”休眠”。
    • 噪声 Top-K:在门控分数上加入随机噪声,防止所有输入都涌向少数”热门专家”,保证负载均衡。

    这篇论文证明了 MoE 可以在深度网络中稳定训练,并且能以极低的计算成本显著扩大模型容量。

    论文: Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer, Shazeer et al., ICLR 2017

    第二次突破:分布式分片(2020)

    MoE 的参数量动辄数百亿,单卡根本装不下。Google 的 GShard 论文解决了这个问题:它提出了自动分片策略,把不同专家分布在不同的 GPU/TPU 上,通过高效的通信协议协调计算。GShard 首次将 MoE 模型扩展到 6000 亿参数级别,证明了大规模分布式 MoE 训练的可行性。

    论文: GShard: Scaling Giant Models with Conditional Computation and Automatic Sharding, Lepikhin et al., 2020

    第三次突破:极简路由(2021)

    Switch Transformer 论文做了一件反直觉的事:把 Top-K 路由简化为 Top-1——每个 Token 只选择一个专家。这个简化大幅降低了通信开销和实现复杂度,同时引入了专家容量因子(Capacity Factor)来控制每个专家能处理的 Token 数量上限。Switch Transformer 首次触及万亿参数级别,成为后续所有 LLM-MoE 的直接蓝本。

    论文: Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity, Fedus et al., JMLR 2022


    开源引爆:Mixtral 让 MoE 走进大众视野

    2021 年的 Switch Transformer 和 2022 年的 GLaM(Google 的另一个 MoE 语言模型)虽然轰动学术界,但有一个致命问题:不开源。普通开发者只能看论文,无法亲手体验 MoE 的威力。大众对 MoE 的印象停留在”巨头的玩具”。

    这一切在 2023 年 12 月被彻底改变。法国创业公司 Mistral AI 发布了 Mixtral 8x7B——一个权重完全开放、性能强劲的 MoE 语言模型。它只有约 120 亿激活参数,但在多数基准测试中击败了 Llama 2 70B(一个 700 亿参数的稠密模型)。

    Mixtral 的冲击是多维度的:

    • 性能震撼:直观展示了 MoE”小算力办大事”的能力。
    • 门槛极低:能在消费级显卡(双 3090/4090)上运行,普通开发者第一次亲手跑起了 MoE。
    • 生态爆发:发布后数天内,HuggingFace 上涌现出大量量化版本、微调版本和部署教程。

    大众的认知在这一刻发生了转折:”原来不用堆满 700 亿参数也能有这么强的效果?”MoE 从论文走向工程实践,从”听说过”变成”用起来”。

    论文: Mixtral of Experts, Jiang et al., Mistral AI, 2024


    中国力量接力:DeepSeek 让 MoE 成为信仰

    如果说 Mixtral 让大众”知道”了 MoE,DeepSeek 则让大众”信服”了 MoE 可以比 Dense 更好。

    2024 年 5 月,DeepSeek 发布了 DeepSeek-V2,提出了两个关键创新:

    • MLA(Multi-head Latent Attention,多头潜在注意力):通过低秩压缩大幅减少 KV Cache 的显存占用,让长序列推理更加高效。
    • 辅助损失免调优:传统 MoE 需要精心调节辅助损失函数来平衡专家负载,DeepSeek-V2 提出了一种自适应机制,省去了这个超参数调优的痛苦。

    DeepSeek-V2 证明了 MoE 不仅能做 Dense 的”平替”,还能通过架构创新实现超越同级 Dense 模型的性价比。在国内,DeepSeek-V2 引发了一波 MoE 跟进潮——Qwen-MoE、GLM-4-MoE 等相继发布,MoE 从”海外新奇事物”变为”国产大模型标配选项”。

    2024 年底的 DeepSeek-V3 更进一步:引入 FP8 混合精度训练、Multi-Token Prediction、无辅助损失负载均衡,以极低的算力成本达到顶级性能,成为 MoE 工程化的标杆。

    论文: DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model, DeepSeek-AI, 2024


    全面普及:从另类选择到默认选项

    2025 年,MoE 迎来了”巨头背书”的时刻。Meta 在 Llama 4 系列中正式采用 MoE(Maverick 为 128 个专家的 MoE 架构),阿里发布 Qwen3-MoE。当开源领袖都选择 MoE 时,这项技术完成了从”挑战者架构”到”行业默认选项”的身份转变。

    MoE 的发展脉络可以用一条时间线来概括:

    MoE 关键技术演进时间线

    原理解析:大而稀疏的智慧

    MoE 的核心可以拆解为三个组件:

    MoE 核心架构:路由器 + 专家网络 + 加权聚合

    专家网络(Experts)

    通常由多个结构相同的前馈神经网络(FFN)组成。每个专家独立学习数据分布的不同子空间——某些专家可能擅长代码,某些擅长多语言翻译,某些擅长数学推理。这种”术业有专攻”的设计,让模型总容量远超单个 FFN 所能承载的极限。

    路由器/门控网络(Router/Gating Network)

    路由器是 MoE 的”大脑”,负责决定每个输入 Token 应该被发送给哪些专家。它的核心机制是 Top-K 选择:对所有专家计算一个亲和度分数(通常是线性变换 + Softmax),然后只选择得分最高的 K 个专家(通常 K=1 或 K=2),其余专家不参与计算。这就是”条件计算”(Conditional Computation)的精髓——根据输入内容动态决定计算路径。

    负载均衡是路由器设计中最棘手的问题。如果所有 Token 都涌向少数”热门专家”,其他专家就会闲置,模型退化为一个更小的 Dense 模型。传统方案是引入辅助损失函数(Auxiliary Loss)来惩罚负载不均,但这个损失需要精心调节。DeepSeek-V2 提出的”无辅助损失负载均衡”是目前最先进的方案。

    加权聚合

    被选中的 K 个专家分别对输入进行独立计算,最终输出是这 K 个专家输出的加权和,权重由路由器的 Softmax 分数决定。这个设计保证了梯度可以顺畅地从输出回传到路由器和专家网络,使整个系统可以端到端训练。

    打个比方:想象一个咨询公司有 100 位顾问(专家),每位顾问专精不同领域。客户来了(输入 Token),前台(路由器)根据客户需求匹配最合适的 2 位顾问。两位顾问各自给出方案,最后按匹配度加权融合成最终建议。公司总共有 100 位顾问的知识储备,但每次咨询只需要 2 位参与,成本极低。


    为何落地这么久:理论太先进还是科技太慢

    回到文章开头的问题:1991 年提出的 MoE,为什么直到 2023 年才真正爆发?是理论太超前,还是科技进步太缓慢?

    答案是:两者都不是,而是技术落地需要”时代的对齐”

    MoE 的核心机制——门控网络 + 多专家协作——在 1991 年就是完备的。但一项技术从”数学概念”变成”工程可行”再到”产业主流”,需要同时满足三个条件:

    1. 基础设施就绪:GPU 集群、高速互联(NVLink/InfiniBand)、分布式训练框架(PyTorch FSDP、DeepSpeed)——这些是 MoE 的”钢铁和铁路”。
    2. 架构载体出现:Transformer 是 MoE 最理想的宿主,它的 FFN 层可以无缝替换为 MoE 层。没有 Transformer,MoE 就像没有轮子的蒸汽机。
    3. 需求驱动:Scaling Law 的发现让”参数规模”成为通往智能的核心路径,MoE 作为”廉价扩容”方案才有了刚需。2020 年之前,业界追求”小模型高精度”,MoE 的”大参数量”反而是缺点。

    中间三十年并非空白。2017-2022 年间,Google 内部一直在迭代 MoE(GShard → Switch → GLaM → ST-MoE),只是多数成果未及时开源或发表,外界感知滞后。MoE 不是”被遗忘了 30 年”,而是等待了 30 年

    一项技术的落地速度,取决于它何时与时代的算力、架构和需求完成对齐。MoE 的故事,是这个规律的完美注脚。


    未来展望:MoE 会被替代吗

    MoE 不太可能被单一架构完全”替代”。更可能的走向是与其他架构深度融合,最终形成一种新的统一范式。以下是几个值得关注的方向:

    SSM + MoE:已经发生的融合

    状态空间模型(SSM,如 Mamba)以其线性推理复杂度成为 Transformer 的有力竞争者。但 SSM 不会替代 MoE,而是与 MoE 结合。AI21 Labs 的 Jamba(2024)是第一个大规模落地的 Transformer-Mamba-MoE 混合模型——它交替堆叠 Transformer 块和 Mamba 块,并在部分层加入 MoE,单卡即可装下 520 亿参数模型,支持 256K 上下文。MoE-Mamba 进一步验证:将 MoE 叠加到纯 Mamba 上,训练效率提升 2.35 倍,同时保持 Mamba 的推理优势。

    SSM 与 Attention 的理论统一

    Tri Dao 和 Albert Gu 的 Mamba-2(2024 ICML)提出了 State Space Duality (SSD) 框架,证明 SSM 和 Attention 本质上是同一类数学结构的两个视角。这意味着 MoE 作为”计算容量扩展”的通用手段,未来可以无缝绑定到这个统一框架上,无论底层是 Attention 还是 SSM 层。

    RWKV:线性复杂度 RNN 的复兴

    RWKV 结合了 Transformer 的并行训练能力和 RNN 的 O(1) 推理复杂度,已扩展到 140 亿参数。它的设计天然适合与 MoE 结合——用 MoE 扩展 RWKV 的 FFN 层,可以在不增加推理复杂度的前提下大幅扩展模型容量。

    MoE 自身的极致演进

    MoE 内部也在深刻进化。DeepSeekMoE 提出了细粒度专家切分(把 N 个专家拆成 mN 个,激活 mK 个,实现更灵活的组合)和共享专家隔离(抽取专门捕获公共知识的专家,消除路由专家间的冗余)。未来的方向包括:动态专家数量激活(不同 Token 激活不同数量的专家)、专家间层次化组织(树状/图状路由而非扁平路由)。

    稀疏注意力与动态网络

    稀疏注意力(如 Ring Attention、Flash Attention)更像是一种工程优化而非架构替代,它让标准 Transformer 能处理更长上下文,削弱了 SSM 在长序列上的独占优势。动态网络/条件计算则超越了 MoE 的”选专家”范式,走向更细粒度的 Token-level 路由——每一层甚至每个子模块都可以动态决定计算量和路径。这可以理解为 MoE 的自然推广。

    方向替代 MoE?与 MoE 融合?短期可行性
    SSM/Mamba❌ 不替代✅ 已验证 (Jamba, MoE-Mamba)
    RWKV❌ 不替代✅ 理论可行
    SSM+Attention 统一 (Mamba-2)❌ 不替代✅ 统一框架上叠加 MoE中高
    稀疏注意力❌ 不替代✅ 互补优化
    动态网络/条件计算⚠️ 可能演化 MoE✅ 是 MoE 的超集

    核心判断:MoE 不会被替代,而是会作为容量扩展的通用原语融入所有新兴架构中。 真正的演进方向是:Mamba-2/SSD 统一框架 + MoE 动态容量 + 稀疏注意力精确检索的三层融合体。Jamba 已经是这个方向的早期实例。

    MoE 未来融合架构:SSM + MoE + 稀疏注意力

    全景回顾

    1991 ──────────────────────────────────────────────────────── 2025+
     │                                                            │
     │  理论诞生                                                   │
     │  (Jacobs et al.)                                           │
     │       │                                                    │
     │       ▼                                                    │
     │  ┌─────────────────┐                                       │
     │  │   沉寂期 (26年)   │  缺少:算力、Transformer、Scaling Law │
     │  └─────────────────┘                                       │
     │       │                                                    │
     │       ▼                                                    │
     │  稀疏门控 (2017) ──→ 分布式分片 (2020) ──→ 极简路由 (2021)   │
     │       │                    │                    │          │
     │       ▼                    ▼                    ▼          │
     │  ┌─────────────────────────────────────────────────────┐   │
     │  │          Google 内部迭代期 (2017-2022)                │   │
     │  └─────────────────────────────────────────────────────┘   │
     │       │                                                    │
     │       ▼                                                    │
     │  开源引爆 (2023 Mixtral) ──→ 中国力量 (2024 DeepSeek)      │
     │       │                              │                     │
     │       ▼                              ▼                     │
     │  ┌─────────────────────────────────────────────────────┐   │
     │  │              全面普及 (2025 Llama 4)                  │   │
     │  └─────────────────────────────────────────────────────┘   │
     │       │                                                    │
     │       ▼                                                    │
     │  ┌─────────────────────────────────────────────────────┐   │
     │  │     未来:MoE + SSM + 稀疏注意力 融合架构              │◄──┘
     │  └─────────────────────────────────────────────────────┘

    MoE 的故事是一个关于”等待”的故事。1991 年的那篇论文像一粒种子,落在了贫瘠的土壤里。三十年间,算力在增长,Transformer 在孕育,Scaling Law 在被发现——这些看似无关的技术进步,最终在 2023 年完成了”时代的对齐”。种子破土而出,迅速长成参天大树。

    未来,MoE 大概率不会被替代,而是会像”稀疏激活”这个思想本身一样,融入所有新兴架构的血液中。它可能不再被单独称为”MoE”,但”按需激活、动态路由”的理念,将成为下一代 AI 系统的底层直觉。

  • 16GB 显卡跑 9B 大模型:量化选型与 K-quants 原理

    在一块 16GB 显存的消费级显卡上加载 9B 参数的 BF16 大模型,日志直接报出 OUT_OF_RESOURCES——光权重就占了 18GB,物理上就放不下。这篇文章聊聊量化(Quantization)是怎么把大模型塞进小显存的,Q8_0、Q6_K、Q4_K_M 这些后缀各自代表什么,K 和 M 又是什么意思,以及在有限显存下该怎么选模型版本。

    一个典型的翻车现场

    用 llama.cpp 加载 Qwythos-9B-Claude-Mythos-5-1M-BF16.gguf,日志里出现这样的报错:

    failed to fit params to free device memory
    level_zero backend failed with error: 40 (UR_RESULT_ERROR_OUT_OF_RESOURCES)

    原因很简单:BF16 精度下,每个参数占 2 字节,9B × 2 = 18GB,仅模型权重就已经超出 16GB 显卡的物理极限。再加上 KV Cache(随上下文长度线性增长的缓存区)和运行时开销,OOM 是必然结果。

    解法办法是换量化版本。


    量化:把蓝光压成流媒体

    打个比方,原始的 BF16 模型就像一张 4K 蓝光原盘,画质完美但体积巨大。量化就是对这张原盘做压缩——降低每个参数的存储精度,用更少的 bit 表示权重值,从而大幅减小文件体积和显存占用。

    BF16 用 16 位浮点存储权重,量化过程将其映射到 8 位、6 位甚至 4 位的离散值。精度越低,压缩越狠,体积越小,质量损失也越大。关键问题是:损失多少?


    精度阶梯:从蓝光到 480p

    以 BF16 为 100% 基准,PPL(困惑度,Perplexity)劣化幅度反映模型”智力”的保留程度。PPL 越低代表模型预测越准确,量化后的 PPL 上升幅度越小,说明质量保留越好。以下是 9B 级别模型在各量化等级下的社区实测均值:

    版本文件大小显存需求保留原版智力PPL 劣化形象类比
    BF1617.9 GB~19-20 GB100%0%4K 蓝光原盘
    Q8_09.8 GB~11-12 GB99.5%+0.3~0.5%高码率 4K 流媒体
    Q6_K7.4 GB~8.5-9.5 GB98.5%+1.2~1.8%优质 1080p
    Q5_K_M~6.5 GB~7-8 GB97%+2.5~3.5%标准 1080p
    Q4_K_M5.6 GB~6.5-7.5 GB95%+4.0~5.5%720p 视频
    Q3_K_M~4.5 GB~5-6 GB89%+9~12%480p 视频

    PPL 数据基于 Llama-3/Qwen2.5 等 9B 级别模型的社区大规模评测均值,不同微调版本间浮动极小。

    量化精度阶梯

    Q8_0 的 0.3% 劣化,在绝大多数对话、代码生成、逻辑推理任务中无法被人类察觉。Q6_K 损失约 1.5%,主要体现在长文本连贯性略微下降,日常使用感知不到。Q4_K_M 的 5% 损失开始影响多步推理链条的稳定性,但 95% 的智力水平仍足以胜任编程助手、写作润色等绝大多数场景。


    K 是什么,为什么 Q8_0 没有 K

    Q8_0 和 Q6_K 的后缀差异不是命名随意,背后是两种完全不同的量化策略。

    Q8_0:均匀量化

    Q8_0 采用传统线性量化,对所有参数一视同仁,使用相同的缩放因子映射到 8 位离散值(256 个取值)。8 位精度本身已经足够高,即使这种”傻瓜式”均匀量化的误差也极小(<0.5%)。引入更复杂的算法带来的质量提升微乎其微(可能只有 0.05%),收益不值得成本。所以 0 就是"第 0 种标准方案"——不需要花哨的后缀。

    Q6_K:K-means 智能量化

    K 代表 K-quants(K-means 量化),是 llama.cpp 社区开发的非均匀量化算法。

    打个比方:均匀量化就像给全校所有科目统一用同一套评分标准——语文和体育按同一个百分制打分。K-means 量化则像因材施教——识别出哪些权重对模型输出更关键(比如注意力层的投影矩阵),给它们分配更高精度;哪些权重不那么敏感(比如部分前馈网络层),就用更低精度压缩。好钢用在刀刃上。

    在 6 位及以下精度时,这种差异化分配的价值急剧放大。没有 K-means 的传统 Q6 量化会比 Q6_K 差 3-5%,而 Q4 级别如果没有 K-means 几乎不可用——K 是”能用与不能用”的分水岭。

    后缀中的 _M 代表 Medium(中等压缩策略),此外还有 _S(Small,更激进压缩)和 _L(Large,更保守压缩)变体。

    特性Q8_0Q6_K
    量化方法均匀线性量化K-means 聚类非均匀量化
    精度分配所有层/通道相同根据重要性动态分配
    8 位时质量差距K-means 仅提升 ~0.05%(可忽略)
    6 位时质量差距传统 Q6 会比 Q6_K 差 3-5%K-means 弥补了低精度损失
    均匀量化 vs K-means 智能量化

    总结:Q8_0 没有 K,是因为 8bit 精度下均匀量化就已经够好了;Q6_K 有 K,是因为 6bit 精度必须靠”聪明地”分配比特才能保住质量。


    MTP 版本:多 Token 预测加速

    模型文件列表中有一类带 MTP 后缀的版本,例如 Qwythos-9B-...-MTP-Q6_K.gguf

    MTP(Multi-Token Prediction,多 Token 预测) 是一种推测解码技术:模型在生成当前 token 的同时,额外预测未来 1~N 个 token。如果预测命中,就能一次输出多个 token,理论上提升 20%-50% 的生成速度。

    代价是文件体积比同级标准版大约 200-300MB,且需要较新版本的 llama.cpp(2026 年 5 月之后)才能支持。如果 llama.cpp 版本不支持 MTP,加载该文件可能报错或退化为普通推理。此外,MTP 在不同硬件后端上的兼容性参差不齐,第三方微调模型的 MTP 头是否被正确识别也存在不确定性。不确定的话,用标准版最稳妥。


    mmproj:让大模型”看图”的视觉编码器

    文件列表中还有两个 mmproj 开头的文件,约 918MB。这是多模态视觉编码器(Multimodal Vision Encoder)的权重文件。

    大模型本身只懂”文字语言”——输入 token,输出 token。要让它理解图片,需要一个”翻译官”先把图片翻译成它能理解的语言。这个翻译官就是多模态视觉编码器。

    具体来说,视觉编码器一般基于 ViT(Vision Transformer) 架构,负责从原始像素中提取高层语义特征,输出一组”视觉 token”。这些视觉 token 经过投影层(projection layer)映射到与文字 token 相同的向量空间后,就能和文字一起被语言模型处理。整个流程:

    图片 → 视觉编码器 (ViT) → 视觉 token → 投影层 → 映射到文字 embedding 空间 → 语言模型理解图片
    多模态视觉编码器工作流程

    mmproj 文件就包含了视觉编码器和投影层的权重。纯文本对话不需要它,不加载可节省约 900MB 显存,只有通过 --mmproj 参数显式指定时才会加载。文件列表中的两个 mmproj 文件内容相同(哈希一致),只是命名不同,任选一个即可。


    16GB 显卡的选型实战

    回到最初的问题:16GB 显卡能跑什么?

    显存预算需要同时覆盖三部分:模型权重、KV Cache、运行时开销。其中 KV Cache 随上下文长度线性增长——模型名中的 “1M” 标注的是训练时支持的最大上下文长度,不是实际硬件能跑满的长度。以 Q4_K_M (5.6GB) 为例:

    上下文长度KV Cache 估算总显存需求能否运行
    4K~1.5 GB~7 GB✅ 宽裕
    16K~5 GB~11 GB✅ 可用
    32K~9 GB~15 GB⚠️ 接近极限
    128K~35 GB~40 GB❌ 不可能
    16GB 显卡显存预算

    对于 16GB 显卡,推荐的选型路径:

    • 质量至上,上下文 ≤8K:Q8_0(99.5% 质量,16G 刚好能跑)
    • 均衡首选,上下文 8K-16K:Q6_K ✅(98.5% 质量 + 充足显存余量)
    • 速度/长度优先,上下文 >16K:Q4_K_M(95% 质量,最快响应)

    Q6_K 在 16GB 显卡(以测试的这台笔记本集显)上大约能跑出 12-15 t/s 的生成速度,略快于人类阅读速度(约 5-8 t/s),日常对话和代码生成完全够用。如果追求更流畅的体验,降级到 Q4_K_M 可提升至 18-25 t/s。

    一个容易忽略的点:稳定运行 > 理论精度。一个 99.5% 质量的 Q8_0 如果因为显存溢出而频繁卸载到 CPU 做混合推理,实际体验远不如 98.5% 质量但全程 GPU 加速的 Q6_K。


    全景回顾

    从 BF16 到 Q4_K_M,本质上是一条精度与实用性之间的权衡链:

    BF16 (100%) → Q8_0 (99.5%) → Q6_K (98.5%) → Q4_K_M (95%)
     18GB          10GB           7.4GB          5.6GB
     原盘           流媒体          1080p          720p

    对于消费级显卡,量化不是妥协,而是让大模型真正落地的必要手段。9B 模型用 Q6_K 跑在 16GB 显卡上,日常使用几乎感受不到与 BF16 的区别——但在显存账本上,省下的那 10GB 决定了模型能不能跑起来。

  • 大模型推理:为什么只缓存 KV,不缓存 Q?

    做过大模型推理优化的同学,应该都听过 KV Cache 这个概念。这里有一个问题:Attention 计算明明涉及 Q、K、V 三个矩阵,为什么只有 KV 需要缓存,Q 却被”抛弃”了?

    这不是设计上的偷懒,而是由自回归生成的本质决定的。


    自回归生成的时序特性

    大模型生成文本的过程是一个 Token 接一个 Token 往外蹦的,这叫自回归(Autoregressive)。当大模型生成第 t 个 Token 时,需要”回头看”前面所有 0 到 t-1 个 Token,和它们做 Attention 计算。

    自回归生成过程
    自回归生成过程

    这个过程中,Q 和 KV 承担的角色截然不同:

    KV 是历史的累积。 前面每个 Token 的 Key 和 Value 在它出现的那一刻就算好了,而且数值永远不会变。到了第 t 步,这些历史 KV 还要被反复读取。如果不存起来,每生成一个新 Token 就得把前面所有 Token 的 KV 重算一遍——复杂度直接从 O(N) 爆炸到 O(N²)。

    Q 是当下的查询。 生成第 t 个 Token 时,只有当前这个 Q 参与计算。算完这一步,Q 的使命就结束了。下一步生成 t+1 时,会产生一个全新的 Q,旧的 Q 完全不会再被用到。


    从公式看数据流向

    Attention 的核心公式:

    $$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d}}\right)V$$

    Attention 计算数据流
    Attention 计算数据流

    在第 t 步推理时:

    • Q_t 的形状是 (1, d),只有一个向量——当前 Token
    • K_{0:t} 和 V_{0:t} 的形状是 (t, d),包含了从开头到当前的所有历史 Token

    K 和 V 是”被查阅的资料库”,会随着序列变长不断膨胀,必须持久化存储;Q 是”查阅者”,用完即弃,缓存它对后续计算没有任何帮助。


    如果强行缓存 Q 会怎样?

    两个字:浪费。

    KV Cache vs QKV Cache 显存对比
    KV Cache vs QKV Cache 显存对比

    显存白白多占 50%。 本来存 KV 两份,现在变成存 QKV 三份,但没有任何计算收益。

    旧 Q 是”死数据”。 Attention 机制里不存在 Q × Q 或 K × Q_old 这样的运算,历史的 Q 缓存下来也无人问津。

    可以打个比方:去图书馆查资料,每次都要带上自己的问题(Q),但图书馆的藏书(KV)是一直在那里、不断累积的。每次问的是新问题,上一次的问题留不留着都无所谓。


    哪些场景会涉及 Q 的”缓存”?

    虽然标准自回归解码不缓存 Q,但有些场景确实会暂存 Q:

    不同场景下的缓存策略
    不同场景下的缓存策略

    Prefill(预填充)阶段。 处理用户输入的 Prompt 时,所有 Token 是并行计算的,Q、K、V 都是批量生成的中间激活值。有些框架为了内存布局优化可能会短暂暂存 Q,但这属于计算过程中的临时状态,不是跨步复用的 Cache。

    非自回归 / Encoder 模型。 像 BERT 这类双向模型,所有 Token 同时参与注意力计算,不存在”历史 vs 当前”的区别,不涉及 KV Cache 的概念。

    Speculative Decoding(投机采样)。 验证阶段可能同时评估多个候选 Token,会有多个 Q 并存,但本质是为当前验证步骤服务,而非持久化的历史记忆。

    Linear Attention / RNN-like 架构。 Mamba、RWKV 这类新架构把历史信息压缩成固定大小的 State,传统的 KV Cache 概念本身就在被重构,这属于另一套范式了。


    DeepSeek 的”缓存命中率”是什么?

    聊完 KV Cache,再延伸一个实际问题:DeepSeek API 返回的”缓存命中率”,指的是什么?

    答案是:就是 KV Cache 的命中。

    Prefix Caching 工作原理
    Prefix Caching 工作原理

    更准确地说,它指的是 Prefix Caching(前缀缓存) 技术中对 KV Cache 的复用程度。当 API 报告”缓存命中 800 tokens”时,意味着这 800 个 Token 对应的 KV Cache 已经存在于显存中,系统直接加载复用,跳过了这些 Token 的 Prefill 计算。

    需要注意,这里的”缓存”不是简单的文本字符串匹配,而是张量级别的 KV 状态复用。即使两段文本内容相同,如果分词结果或位置编码不同,KV Cache 也无法命中。

    这也解释了为什么 DeepSeek 的定价里,缓存命中的 Token 价格只有未命中的 1/4 到 1/10——因为命中意味着省去了 Prefill 的算力开销。


    总结

    Q vs KV 核心差异
    Q vs KV 核心差异
    特性Query (Q)Key-Value (KV)
    角色当前的提问者历史的资料库
    生命周期单步有效,用完即弃全程有效,逐步累积
    是否被后续复用❌ 否✅ 是
    缓存价值极高(避免 O(N²) 重算)

    一句话:KV Cache 缓存的是”过去”,因为过去会被反复回顾;Q 代表的是”现在”,而现在转瞬即逝,无需为未来保存。

  • 从 ViT 到 SigLIP:多模态大模型视觉底座的进化之路

    本文聊聊多模态大模型(MLLM)里那个最关键的”眼睛”——视觉编码器——是怎么一步步从 ViT 走到 SigLIP 的。我们会讲清楚每个技术为什么出现、解决了什么问题、又留下了什么遗憾。关于”为什么 LLaVA 不直接用 ResNet”或者”CLIP 和 SigLIP 到底差在哪”,这篇文章应该能给一个完整脉络。


    2020:ViT 证明了一件事——图像不需要卷积

    2020 年 10 月,Google Research 发布了一篇标题极具挑衅性的论文:An Image is Worth 16×16 Words(Dosovitskiy et al., 2020)。这篇论文做的事情很简单粗暴:把一张图片切成 16×16 的小块(Patch),每块当作一个 Token,扔进标准的 Transformer Encoder,就完了。

    在此之前,视觉领域是 CNN 的天下。从 AlexNet 到 ResNet,卷积神经网络统治了将近十年。CNN 有两个根深蒂固的归纳偏置:局部性(相邻像素关系更紧密)和平移不变性(猫在左上角和右下角是同一个猫)。这些偏置让 CNN 在小数据集上表现很好,但也像一副有色眼镜——模型永远在用”局部窗口”看世界。

    值得一提的是,CNN 时代有一个著名的发现:微软研究院在 2015 年训练 56 层的网络时,发现它的训练误差和测试误差都比 20 层的网络更差——不是过拟合,而是更深层的网络反而更难训练。这催生了残差连接(Residual Connection):让信息可以通过一条”捷径”直接跳过中间层传到后面,解决了深层网络的退化问题。ViT 的 Transformer Encoder 每一层内部都内置了残差连接,这使得堆叠几十甚至上百层成为可能。可以说,没有残差连接,就没有后来 ViT-Base(12层)、ViT-Large(24层)、ViT-Huge(32层)的递进式扩展。

    ViT 把 CNN 的有色眼镜摘了。它用全局自注意力取代了卷积,每个 Patch 都能直接”看到”图片里的所有其他 Patch。代价是什么?计算量是序列长度的平方 $O(N^2)$,而且缺乏归纳偏置,在数据量不够大的时候反而不如 CNN。原论文的结论很诚实:只有在 JFT-300M 这样的超大数据集上预训练后,ViT 才能全面碾压 CNN。

    打个比方:CNN 像一个用放大镜逐块检查壁画的考古学家,每看一小块就记录一次;ViT 则像退后三步、一览全局的鉴赏家——但前提是他面前的壁画得足够多、足够丰富,不然他反而不知道该看哪里。

    ViT 的意义远不止一个新模型

    ViT 的真正价值不在于”比 ResNet 高了几个点”,而在于它证明了 Transformer 架构可以成为视觉的通用语言。在 ViT 之前,NLP 和 CV 用的是两套完全不同的架构。ViT 之后,大家开始意识到:也许我们可以用同一种架构同时处理图像和文本。

    需要澄清一个常见的混淆:ViT 是一种架构(怎么把图像变成向量),而后面要讲的 SigLIP 是一种训练范式(怎么训练这个架构让它跟语言对齐)。SigLIP 的视觉编码器就是 ViT——架构没变,变的是训练方法。就像同一辆车,装了不同的镜头,看到的世界就完全不同。理解这一点,才能理解为什么”从 ViT 到 SigLIP”并不是一条替代链,而是一条从”怎么看”到”看什么”的进化线。而正是 ViT 证明了 Transformer 可以成为视觉的通用语言,才直接催生了后面全部的故事。

    论文: An Image is Worth 16×16 Words: Transformers for Image Recognition at Scale,Dosovitskiy et al., ICLR 2021。arXiv: 2010.11929(2020.10.22)


    2021 年初:两条路线几乎同时出发

    2021 年 2 月到 3 月,在不到两个月的时间里,两篇论文先后出现在 arXiv 上,分别代表了”视觉 Transformer + 语言”的两种截然不同的思路:

    • 2021.02.05:ViLT(Kim et al.)—— 把图像和文本的 Token 拼在一起,用一个 Transformer 统一处理
    • 2021.02.26:CLIP(Radford et al., OpenAI)—— 图像和文本各用一个 Transformer,通过对比学习把它们拉到同一个语义空间

    它们几乎同时出现并非巧合。2020 年底,ViT 已经证明 Transformer 能处理图像,GPT-3 证明了大规模预训练的威力,接下来自然而然的问题就是:怎么把视觉和语言结合起来?

    ViLT:最朴素的融合尝试

    ViLT 的全称是 Vision-and-Language Transformer(Kim et al., ICML 2021)。它的思路直觉上非常自然:既然 Transformer 既能处理图像 Token 又能处理文本 Token,那为什么不直接把它们拼在一起?

    在 ViLT 之前,多模态模型(比如 VilBERT、LXRT)的做法是用一个预训练好的目标检测器(Faster R-CNN)从图片里提取出”区域特征”——先识别出”这里有一只猫””那里有一张桌子”,然后把这些区域特征和文本一起送进 Transformer。这个方案有个致命问题:Faster R-CNN 本身就很大、很慢,而且它需要预先在目标检测数据集上训练,整个流程极其笨重。

    ViLT 砍掉了这个检测器。它用 ViT 的 Patch Embedding(一个简单的线性层)直接从原始图像中提取视觉 Token,然后把视觉 Token 和文本 Token 拼接成一个长序列,送入单个 Transformer。训练目标也很直白:掩码语言建模(MLM)和图文匹配(ITM)。

    效果呢?推理速度比基于区域特征的模型快了 60 倍以上。这个数字在当时相当惊人。

    但 ViLT 遇到了一个结构性的瓶颈。图像被切成 14×14 = 196 个 Patch,加上一段文本的 Token,整个序列长度轻松突破 200。Transformer 的 $O(N^2)$ 复杂度意味着注意力计算量随序列长度急剧膨胀。更麻烦的是,196 个 Patch 只能覆盖 224×224 的分辨率——稍微复杂一点的图表、带有小字的文档图片,对 ViLT 来说就是一片模糊。

    打个比方:ViLT 就像让一个人同时阅读一本书的文字和盯着一幅画,然后试图在脑子里把它们”对齐”。这在信息量不大的时候能行,但一旦文字变长、图片变复杂,脑子就不够用了。

    ViLT 今天已不再是主流 MLLM 的选择,但它提出了一个正确的问题:我们能不能用统一的架构处理多模态信息? 这个问题后来被 LLM 用另一种方式回答了。

    论文: ViLT: Vision-and-Language Transformer Without Convolution or Region Supervision,Kim et al., ICML 2021。arXiv: 2102.03334(2021.02.05)


    CLIP:先对齐,再理解

    CLIP 的全称是 Contrastive Language-Image Pre-training(Radford et al., OpenAI, 2021)。如果说 ViLT 的思路是”把图文塞进一个模型硬融”,那 CLIP 的思路就是”别急着融合,先让图像和文本学会说同一种语言”。

    CLIP 的架构是经典的双塔结构:一个 Image Encoder(通常是 ViT)负责把图片编码成一个向量,一个 Text Encoder(Transformer)负责把文本编码成一个向量。训练目标极其简洁——在一个 Batch 里,让匹配的图文对的余弦相似度尽量高,不匹配的尽量低。这就是所谓的对比学习(Contrastive Learning)。

    $$ \mathcal{L} = -\frac{1}{N} \sum_{i=1}^{N} \log \frac{\exp(sim(I_i, T_i)/\tau)}{\sum_{j=1}^{N} \exp(sim(I_i, T_j)/\tau)} $$

    CLIP 真正让人震惊的不是架构,而是数据和能力。OpenAI 从互联网上收集了 4 亿个图文对(WebImageText),用这个数据集训练出来的模型展现出了前所未有的 Zero-shot 能力:你只需要给它一个文本描述,它就能判断图片里有没有对应内容——完全不需要任何微调。

    想象一下:你是一个从未见过猫的人,但有人告诉你”这种毛茸茸的四条腿动物叫猫”。下次你再看到类似的东西,你就能认出来——尽管从来没有人手把手教过你。这就是 Zero-shot 的魔力,而 CLIP 之所以能做到这一点,是因为它在 4 亿个图文对上学到了一个通用的”视觉-语言联合词典”。

    CLIP 的软肋

    但 CLIP 有一个根本性的局限:它只学到了”全局语义对齐”。它知道”这张图里有猫”,但不知道”猫在桌子左边”或”猫是黑色的、正在睡觉”。这是因为双塔架构在预训练阶段只做了向量级别的匹配,没有做 Token 级别的细粒度交互。

    另外,CLIP 的损失函数用的是 Softmax(InfoNCE),计算依赖一个 $N \times N$ 的相似度矩阵。在多机分布式训练时,必须做 All-Gather 通信来聚合整个 Batch 的负样本。Batch Size 越大,通信开销越大,扩展性越来越差。CLIP 原论文用了 32,768 的 Batch Size——这已经是工程上的极限了。

    尽管如此,CLIP 开创了一个范式:先对齐,再融合。具体来说,先用对比学习把视觉特征和语言特征映射到同一个语义空间(对齐),然后再通过一个轻量级的投影层送进 LLM 做更精细的理解(融合)。现代多模态大模型几乎全部沿用了这个思路。

    论文: Learning Transferable Visual Models From Natural Language Supervision,Radford et al., ICML 2021。arXiv: 2103.00020(2021.02.26)


    2023:SigLIP 换了一根引线

    2023 年 3 月,Google Research 的 Zhai、Beyer 等人发表了 Sigmoid Loss for Language-Image Pre-training(简称 SigLIP)。这篇论文做的事情用一句话概括就是:保留 CLIP 的全部架构,只换掉损失函数

    把 Softmax 换成了 Sigmoid。

    就这么简单?就这么简单。但效果是颠覆性的。

    为什么换一个损失函数就能有这么大区别?

    CLIP 的 Softmax 损失是一个多分类问题:对于每张图片,要从整个 Batch 的所有文本中找到唯一匹配的那一个。这意味着分母必须遍历所有负样本,也就是必须知道整个 Batch 的全局信息。

    SigLIP 把它变成了 $N \times N$ 个独立的二分类问题:对于每一对(图片, 文本),只需要判断”它们配不配”。配就标 1,不配就标 0,用 Sigmoid 函数(本质上是二分类的交叉熵损失):

    $$ \mathcal{L} = -\frac{1}{N} \sum_{i=1}^{N} \sum_{j=1}^{N} \left[ y_{ij} \log(\sigma(z_{ij})) + (1-y_{ij}) \log(1-\sigma(-z_{ij})) \right] $$

    关键区别在于:每个”配不配”的判断是局部独立的。不需要等所有卡上的数据汇总在一起才能算出分母。这意味着在分布式训练中,各卡可以各算各的,最后只需要同步梯度——通信开销大幅降低。

    继续用考试的比喻:CLIP 像是一场全校统考,每道题的答案必须跟全年级所有人的答案做比较才能打分,年级越大(班级越多)打分越慢。SigLIP 像是每个班的老师只负责判断自己班的卷子配不配对,互不干扰,最后汇总。后者天然适合并行,班级数量可以轻松扩大。

    实际效果是什么?在同等算力下,SigLIP 的 Zero-shot ImageNet Top-1 准确率比 CLIP 高约 2-3 个百分点。换一种说法:达到同等性能,SigLIP 所需的训练计算量大约只有 CLIP 的一半到六成。

    不只是效率,还有质量

    SigLIP 的 Sigmoid 损失还有一个容易被忽视的优势:它对”难负样本”的梯度更稳定。什么是难负样本?就是那些看起来很像正例但实际上是负例的样本——比如一张金毛猎犬的图片配文本”拉布拉多”。在 Softmax 框架下,这类样本的梯度信号容易被其他”简单负样本”淹没(因为 Softmax 的分母要照顾所有负样本的贡献)。而在 Sigmoid 框架下,每一对样本的损失是独立计算的,难负样本能得到更充分的梯度信号。

    这直接导致 SigLIP 学到的视觉特征与文本空间对齐得更精细。对于多模态大模型来说,这意味着视觉编码器输出的特征质量更高,后续 LLM 处理起来更轻松。

    SigLIP 的具体实践

    Google 开源的 SigLIP 权重中,最广泛使用的是 SigLIP-SO400M/14-384——一个 4 亿参数、Patch 大小为 14、输入分辨率为 384 的 ViT 模型。它在 WebLI 数据集(约 100 亿图文对,多语言)上训练,质量远超同规模的原版 CLIP。

    论文: Sigmoid Loss for Language-Image Pre-training,Zhai et al., ICCV 2023 Oral。arXiv: 2303.15343(2023.03.27)


    为什么 SigLIP 能成为事实标准?

    到 2024 年,几乎所有新发布的顶级多模态大模型都转向了 SigLIP 作为视觉编码器。这不是跟风,而是工程上的理性选择。

    公开使用 SigLIP 的多模态大模型

    以下是我们目前能找到的公开文档中明确标注使用 SigLIP 作为视觉编码器的代表性模型:

    模型机构SigLIP 变体备注
    PaliGemma / PaliGemma 2Google DeepMindSigLIP-So400M/14Google 自家模型,自然首选 SigLIP
    Idefics2 / Idefics3HuggingFaceSigLIP-SO400M/14经过系统性对比后选择了 SigLIP
    LLaVA-NeXT(部分配置)UW-Madison / ByteDanceSigLIP-SO400M/14提供 CLIP-ViT-L 和 SigLIP 两种配置
    Phi-3-VisionMicrosoftSigLIP-SO400M/14微软的小型多模态模型
    Moondream2开源社区SigLIP-SO400M/14轻量级多模态模型
    Qwen2-VL / Qwen2.5-VL阿里巴巴SigLIP 相关变体Qwen 系列的视觉底座

    另外值得注意的是,Google 的 Gemini 系列虽然闭源,但考虑到开发 SigLIP 的就是同一个团队(Zhai、Beyer、Kolesnikov 等人),业内普遍推测 Gemini 使用了 SigLIP 或其内部变体作为视觉编码器。

    SigLIP 胜出的三个核心原因

    第一,特征质量更好。 前面提到 Sigmoid 损失对难负样本的梯度更稳定,这让 SigLIP 的视觉特征空间与语言空间对齐得更精细。对于多模态大模型来说,视觉编码器输出的特征就像是”原材料”——原材料质量越高,LLM 这个”加工厂”做出来的理解就越准确。

    第二,高分辨率成为可能。 训练效率的提升使得 384px 甚至 512px 分辨率上的预训练变得可行。原版 CLIP 的默认分辨率是 224px,在这个分辨率下,图表上的小字、文档里的细节、远处的物体都看不清。SigLIP 的 384px 版本直接提升了 MLLM 对这些细节的理解能力。

    第三,生态已经成熟。 Google 开源了高质量的预训练权重,HuggingFace 生态全面支持,社区经过大量验证。对于一个新的 MLLM 项目来说,选用 SigLIP 基本上不需要额外的验证成本——直接拿来用就行。


    SigLIP 并不完美:已知的短板

    尽管 SigLIP 已经成为事实标准,但它并非没有缺陷。这些问题在实际使用中已经暴露出来。

    缺乏空间定位能力

    SigLIP 继承了 CLIP 的全局对比学习范式,本质上是在做”这张图整体上配不配这段文本”的判断。这意味着它学到的视觉特征缺乏精细的空间信息。具体来说:

    • 它知道”图里有一只猫”,但不知道”猫在桌子左边”
    • 它擅长识别”这是什么”,但难以回答”在哪里有几个”

    在需要空间推理的任务上(比如”图中左边第三个物体是什么”),SigLIP 的表现远不如 DINOv2——后者通过自监督学习获得了更丰富的空间特征。实际上,已有研究表明,自监督方法(DINO/DINOv2/MAE)学到的 ViT 特征在语义分割、深度估计等密集预测任务上显著优于对比学习方法。

    多语言和公平性问题

    SigLIP 主要在 WebLI 数据集上训练,这个数据集虽然号称多语言,但实际上以英语为主。对于中文、日文、阿拉伯文等非拉丁语系语言,SigLIP 的图文对齐质量明显下降。这在处理多语言文档、非英语网页截图等场景时会成为瓶颈。

    分辨率仍然受限于 Patch 网格

    虽然 SigLIP 的主流版本是 384px(比 CLIP 的 224px 高了不少),但它本质上仍然是固定分辨率、固定宽高比的。一张 1920×1080 的截图被压缩到 384×384 后,细节丢失是不可避免的。更根本的问题是,ViT 的 Patch 数量由分辨率决定——384px / 14 = 27,即 27×27 = 729 个 Token。如果要支持更高分辨率,Token 数量会迅速膨胀。

    Sigmoid 损失的理论局限

    Sigmoid 损失的一个微妙缺陷在于:每一对样本的判断是独立的,缺乏全局归一化。Softmax 损失天然提供了全局的竞争性归一化——一张图片的所有负样本文本互相竞争。而 Sigmoid 损失中,每个”配不配”的判断是孤立的,这在极端情况下可能导致特征空间的聚类质量不如 Softmax 版本。不过,SigLIP 2 的论文指出,这个问题可以通过其他辅助损失来弥补。


    之后呢:SigLIP 2 和更远的方向

    2025 年 2 月,Google DeepMind 发布了 SigLIP 2(arXiv: 2502.14786),直接回应了上述大部分短板。SigLIP 2 在保留 Sigmoid 损失的基础上,引入了三大改进:

    1. 多目标训练:除了图文对比损失,还加入了图像描述生成(captioning)损失和自监督损失(自蒸馏 + 掩码预测),这让模型同时学到了细粒度的空间特征和全局语义
    2. 原生支持多分辨率和可变宽高比:不再把所有图片强行压缩到正方形
    3. 多语言和去偏:通过更平衡的多语言训练和去偏策略,改善了非英语场景的表现

    从更大的视角来看,图像 Transformer 作为多模态大模型的视觉底座,正在朝几个方向演进:

    • 对比学习 + 自监督融合:SigLIP 2 已经开始把 CLIP/SigLIP 的对比损失和 DINO/MAE 的自监督损失合并训练。未来可能不再有”对比学习”和”自监督”的明确分界,而是统一在一个多目标框架下
    • 动态分辨率:Qwen2-VL 等模型已经在探索原生支持任意分辨率的视觉编码器,让”看不清小字”不再是瓶颈
    • 更高效的注意力机制:线性注意力、Flash Attention 等技术正在缓解 $O(N^2)$ 的计算瓶颈,让高分辨率输入变得实际可行
    • 数据质量的回归:Meta 的 MetaCLIP 研究表明,数据筛选策略可能比损失函数的选择更重要。Apple 的 DFN(Data Filtering Networks)在 2024 年达到了 84.4% 的 ImageNet Zero-shot 准确率,Meta 的 Perception Encoder 在 2025 年更是达到了 85.4%,主要靠的就是更精细的数据策划

    全景回顾

    让我们拉远镜头,看看这条进化链:

    2020.10  ViT — 证明 Transformer 能看图
             ↓
    2021.02  ViLT — 试图把图文硬融进一个 Transformer(快但受限)
    2021.02  CLIP — 另一条路:先对齐再融合(强但慢)
             ↓
    2023.03  SigLIP — 换掉损失函数,CLIP 全面升级
             ↓
    2025.02  SigLIP 2 — 加入自监督和生成目标,弥补空间定位短板

    在今天,当我们使用 LLaVA、Qwen-VL、PaliGemma 这些多模态大模型”看图说话”的时候,图像首先经过的那双”眼睛”,大概率就是 SigLIP 的 ViT。这双眼睛看到的世界不是一个一个孤立的像素,而是一个与语言共享的语义空间——猫不再只是一团像素,而是同时是”cat””猫””feline”以及所有与猫相关的概念。

    从 2020 年 ViT 证明”Transformer 能看图”,到 2023 年 SigLIP 证明”一个好的损失函数能让 Transformer 看得更好”,再到 2025 年 SigLIP 2 试图让 Transformer “看得更细”——这条路还在继续。下一步,也许是完全统一的多模态 Transformer,不再需要独立的视觉编码器;也许是某种我们还没想到的新范式。但不管怎样,ViT 打开的那扇门,SigLIP 让它开得更大了。

  • 想象参数自省带来的总总误差下降

    一、什么是”参数自省”?

    神经网络里的参数自省,即得到一次总总误差之后怎么做整条线上的参数自省?

    神经网络训练的核心,就是一次又一次地”犯错 → 自省 → 修正”的循环。这里提到的”参数自省”,在专业术语里叫反向传播(Backpropagation)。

    流水线上的甩锅与认错

    想象一家工厂,有一条几百人的流水线,每个人负责一道工序。最后质检员发现产品不合格——这时候老板不会只骂最后一个人,而是从后往前挨个追责:

    • 最后一步工人:”我拧螺丝拧歪了,但这是因为上一步给我的零件本身就是歪的。”——他算出自己的责任,同时把”锅”往前甩。
    • 中间步骤工人:”我切割切歪了,是因为上一步给我的钢板尺寸就不对。”——继续算自己的责任,继续往前甩。
    • 第一步工人:”没法怪别人了,是我一开始选料就选错了。”——承担全部责任。

    等每个人都清楚了自己”责任有多大”,大家再一起按照责任大小,稍微调整一下自己的手法。这就是参数自省

    数学上怎么做的

    假设一个三层网络:输入 x → 隐藏层(权重 W₁)→ 输出层(权重 W₂)→ 预测值 ŷ → 总误差 L。

    第一步:算出总误差(前向传播)

    数据从前往后跑一遍,得到预测值 ŷ,和真实值 y 对比,算出总误差 L。

    第二步:从输出层开始自省

    输出层直接面对误差,它要算:”我的权重 W₂ 对总误差 L 有多大影响?”——数学上就是求偏导数 ∂L/∂W₂,然后把 W₂ 往减小误差的方向挪一小步。

    第三步:把误差传给隐藏层(链式法则)

    隐藏层看不见总误差,只能看到输出层传回来的”抱怨”。它利用链式法则计算:

    ∂L/∂W₁ = ∂L/∂ŷ × ∂ŷ/∂W₁

    然后根据这个梯度,把 W₁ 也往减小误差的方向挪一小步。

    第四步:继续往前传

    如果网络有几百层,这个”传话 + 算责任”的过程就会一直重复,直到算出第一层参数的梯度。

    自省之后:参数更新

    等整条线上的参数都拿到了各自的梯度,就开始修正:

    新参数 = 旧参数 – 学习率 × 梯度

    • 梯度:告诉我们该往哪个方向调、调多大幅度。
    • 学习率(Learning Rate):控制每次”自省后改正”的步子大小。步子太大容易跨过最优解来回震荡,步子太小自省得太慢收敛不了。

    神经网络就是通过几万次、几百万次这样的”犯错 → 整条线集体自省 → 集体微调”的循环,最终把误差降到最低的。


    二、几百层的网络,自省还能传回去吗?

    假设有几百层的神经网络,反向传播也能得到正确的梯度下降方向吗?不太理解,怎么想象。

    这个担忧非常合理。

    数学上它是绝对正确的

    把反向传播想象成推倒一排几百块的多米诺骨牌。最后一块骨牌倒下(算出误差),它撞击倒数第二块的力量是确定的;倒数第二块再撞击倒数第三块,力量也是确定的。只要骨牌的摆放位置(网络结构)和质量(激活函数)是确定的,第一块骨牌受到的撞击力(梯度)在数学上就是唯一且精确的。

    但历史上它差点”翻车”

    在2012年之前,神经网络确实很难超过几层,因为遇到两个致命问题:

    • 梯度消失:如果每一层传递误差时都要乘以一个小于1的数字(比如0.1),传了10层就变成 0.1¹⁰ ≈ 0.0000000001。前面的层根本收不到自省信号,直接躺平。
    • 梯度爆炸:反过来,如果每一层乘以大于1的数字(比如10),传了10层就变成 10¹⁰,参数直接被炸飞,网络崩溃。

    那时候用的激活函数是 Sigmoid 和 Tanh——它们会把所有信号压缩到一个很小的区间里,就像一条漏水的管道,误差传着传着就没了。

    现代的三大救命法宝

    为了让几百层的网络能稳定训练,工程界发展出了三套关键机制。今天的主流大模型(LLaMA、Qwen、GPT-4 等)全部在用。


    三、激活函数:从”漏水管道”到”智能水闸”

    早期的困境(2012年以前)

    最早使用的激活函数是 Sigmoid(把信号压缩到 0~1 之间)和 Tanh(压缩到 -1~1 之间)。它们的共同问题是饱和——当输入值稍微大一点或小一点,函数曲线就变得极其平坦,导数趋近于零。

    打个比方:想象在一个山谷里走路,Sigmoid 把我们卡在了山谷的缓坡上。使劲迈步,但坡太缓了,几乎原地不动。这就是梯度消失的根源。

    ReLU 的革命(2012年左右)

    2012年,ReLU(Rectified Linear Unit)横空出世,公式极其简单:f(x) = max(0, x)。正数原样输出,负数直接变成0。

    这就像把漏水的管道换成了直通水管——正数区间导数恒为1,梯度可以毫无衰减地往后传。正是这个简单到令人发指的改进,让训练几十层的网络成为可能。

    但 ReLU 有一个致命缺陷:它不传播负数。当输入为负时,输出为0,梯度也为0。如果某个神经元在训练中”走背运”,对所有样本的计算结果都是负数,那它就彻底”死”了——永远输出0,永远收不到梯度,永远无法更新参数。这就是所谓的”神经元死亡”问题。

    ReLU 是深度学习发展史上一个极其关键的过渡英雄:它解决了梯度消失,但留下了神经元死亡的隐患。

    当前的主流:GELU 与 SiLU/SwiGLU

    今天的大语言模型几乎不再使用 ReLU,取而代之的是两种更聪明的激活函数:

    GELU(Gaussian Error Linear Unit)——被 BERT、GPT-2/3 等模型采用。

    GELU 不是简单地把负数”一刀切”归零,而是用一条平滑的曲线来决定每个值该保留多少。直觉上,它像一个”智能筛子”:值越大,通过的比例越高;值越小(甚至为负),通过的比例越低,但不会完全截断。

    SiLU / SwiGLU——被 LLaMA、Qwen、Mistral 等当代主流大模型采用。

    SiLU 的公式是 f(x) = x · σ(x),其中 σ(x) 是 Sigmoid 函数。它全程光滑可导,负数区域也能让信号微弱通过。SwiGLU 则是 SiLU 的”升级版”,在 Transformer 的前馈网络层中配合门控机制使用,效果更好。

    它们为什么比 ReLU 好?打个比方:

    • ReLU 像一个生锈的铁闸门:要么全开(正数通过),要么死死关住(负数归零)。闸门一旦锈死(神经元死亡),再也打不开。
    • GELU / SiLU 像一个智能调光玻璃:信号强的地方完全透明,信号弱的地方微微透光,但永远不会完全遮死。每个神经元都能持续接收到微弱的训练信号,永远不会”躺平”。

    而且,GELU/SiLU 的负数区域不会像老式 Sigmoid 那样把信号压缩到一个极小的区间——它们的导数在大部分区域都不会远小于1,所以梯度消失的问题也不存在了。

    这就是现代大模型敢于堆到几百层甚至上千层的底气之一。


    四、残差连接:给信息修一条高速公路

    核心思想

    残差连接(Residual Connection)最初由 ResNet 提出,核心公式非常简洁:

    y = F(x) + x

    意思是:某一层的输出,不仅包含这一层计算的结果 F(x),还要直接加上这一层的输入 x

    这看起来不起眼,但解决了一个困扰深度学习多年的反直觉现象:56层的网络训练误差反而比20层的网络更高——不是因为过拟合,而是因为网络太深时,优化器很难学到”恒等映射”(即什么都不做)。

    残差连接让网络至少能做到 F(x) = 0,即”跳过这一层”,从而保证深层网络的性能不会低于浅层。

    直观想象

    在流水线的比喻里,残差连接就像在每几层楼之间修了一条直达电梯。普通的层是楼梯——得一层层爬,可能走错方向。但有了直达电梯,即使中间的楼梯全部走不通,信息也能通过电梯直接传递到终点。

    反向传播时,梯度可以通过这条电梯直接”嗖”地一下传回去,不受中间层的任何干扰。

    当代大模型怎么用

    原始 ResNet 的残差连接是”先计算,再归一化,最后加回来”。当代 Transformer 架构普遍采用前置残差(Pre-Norm Residual):先做归一化,再做计算,最后加回残差。这样训练更稳定,几百层的 Transformer 也不会发散。


    五、归一化:流水线上的稳压器

    为什么需要归一化

    随着前面层的参数不断更新,后面层接收到的数据分布也在不断变化——这个问题叫内部协变量偏移。就像流水线上,前一道工序做出来的零件忽大忽小,后面每一道工序都得不断调整自己的工具来适应,效率极低。

    归一化层的作用就是:不管上一道工序送来的东西有多参差不齐,都先把它们统一校准到一个标准范围内,再交给下一道工序。

    批归一化(Batch Normalization)

    简称 BN,最早由 Google 提出。做法是:对当前这一批数据(Batch)的同一个特征通道,跨所有样本做标准化——减均值、除标准差。

    打个比方:批归一化是竖着切——把一批数据中,同一个特征对齐。比如在图像识别中,把所有图片的”红色通道”拉到同一尺度。

    它的问题:

    • 强依赖 Batch Size。Batch 太小,统计量不准,效果急剧下降。
    • 不适合变长序列。NLP 中句子长度不一,需要 padding,padding 位置会污染统计量。
    • 推理阶段需要缓存训练时的滑动平均值。

    层归一化(Layer Normalization)

    简称 LN。做法完全不同:对单个样本的所有特征维度做标准化。

    打个比方:层归一化是横着切——把单个样本内部的所有特征对齐。不管这一批有多少样本,每个样本自己管自己。

    它的好处:

    • 完全不依赖 Batch Size,Batch=1 也能正常工作。
    • 天然适合变长序列,每个样本独立计算。
    • 推理时直接用当前样本实时计算,无需缓存。

    这就是为什么 Transformer 几乎都用层归一化:自注意力机制使得每个 token 的特征高度依赖上下文,跨样本对齐同一位置的特征没有明确语义;加上大模型训练时 Batch Size 往往受显存限制较小,BatchNorm 统计不稳定。

    当代主流:RMSNorm

    今天的主流大模型(LLaMA、Qwen、Mistral 等)已经从 LayerNorm 进化到了 RMSNorm(Root Mean Square Normalization)。

    RMSNorm 做了一个大胆的简化:去掉均值中心化,只保留方差归一化

    LayerNorm 的做法是:减去均值,再除以标准差。

    RMSNorm 的做法是:直接除以均方根(Root Mean Square),省掉了”减均值”这一步。

    为什么能这么做?研究发现,LayerNorm 起作用的关键在于”把数值拉到同一尺度”,而”把均值移到零”这个操作对最终效果贡献不大,反而增加了计算量。RMSNorm 就像一个更精简的稳压器——少了一个零件,但稳压效果几乎一样,速度快了不少。


    六、”传播负数”到底有什么问题?

    ReLU 不传播负数吗?传播负数会有什么问题?

    这两个追问恰好串联起了激活函数的整个进化史。

    “不传负数”是 ReLU 的取舍

    ReLU 不传负数——这是事实。它用”负区间完全截断”换来了正区间的无损梯度和极简计算。代价是神经元死亡风险。

    那如果允许负数通过呢?

    这正是2012年以前的困境。当时用的 Sigmoid 和 Tanh 就是”传播负数”的函数,结果引发了四个连锁灾难:

    一、梯度消失——负数连乘的指数级衰减。 反向传播是把每一层的导数连乘起来。Sigmoid 的导数最大值只有 0.25,假设每层导数平均 0.25,传过10层就变成 0.25¹⁰ ≈ 0.00000095,传到第20层时梯度已经小到计算机浮点数无法表示。前面的层收不到任何自省信号。

    二、非零均值输出——优化路径走”之字形”。 Sigmoid 的输出永远为正,导致下一层接收到的输入全部同号。结果所有权重的梯度要么全正、要么全负,只能同时增大或同时减小,无法独立调整。优化器走不了直线,只能沿着低效的之字形路径慢慢震荡。

    三、计算效率低下。 Sigmoid/Tanh 涉及 eˣ 指数运算,当网络从几层扩展到几百层时,激活函数的计算开销会被放大数百倍。

    四、饱和区陷阱。 当输入绝对值较大时,Tanh/Sigmoid 的曲线变得极度平坦,导数趋近于零。权重初始化稍大,数据就落入饱和区,训练还没开始就”卡死”了。

    旧路不通,新路怎么走

    问题的根源不是”传播负数”本身,而是老式函数”为了传播负数而引入的非线性压缩”——把信号挤压到一个极小的区间里,导致连乘衰减。

    现代的 GELU / SiLU 也传播负数,但它们走了一条完全不同的路:

    时代方案效果
    2012年以前Sigmoid / Tanh传负数 → 梯度消失 + 饱和 + 慢,行不通
    2012年左右ReLU不传负数 → 梯度畅通 + 快,但有神经元死亡风险
    当前GELU / SiLU / SwiGLU用平滑曲线传负数 → 兼顾梯度畅通与信息完整

    GELU/SiLU 的负数区域是一条平滑且不趋近于零的曲线——信号可以微弱通过,梯度不会指数级衰减,也不会像 Sigmoid 那样把信号压缩到一个极小的区间。它们从根本上解决了”传负数会出问题”这个困扰深度学习十几年的难题。


    七、把所有法宝组装起来

    回到最初的问题:一次总总误差,怎么在几百层的网络里做参数自省?

    答案是,今天的几百层乃至上千层大模型,就像一个高度现代化的超级工厂:

    • 传送带是智能的(GELU / SiLU / SwiGLU):信号不会被硬截断,负数也能微弱通过,每个神经元都永远不会”躺平”。
    • 车间之间有直达电梯(残差连接):误差可以通过跳跃通道直接传回去,不被中间层衰减。
    • 每个车间都装了稳压器(RMSNorm):不管上游送来的数据分布怎么变,都先校准到标准尺度再处理。
    • 质检员的警报是无损传播的(链式法则 + 现代梯度流设计):从最后一层到第一层,每个工人都能清楚地收到”自己该往哪个方向调、调多少”的精确指令。

    当最后质检员发现一个次品(总误差),他按下警报。这个警报通过直达电梯、智能传送带、无损通道,瞬间传达到每一个车间、每一个工人。每个人都能精确地知道自己该怎么调整。调整之后,再生产下一批产品,再质检,再自省,再调整——经过几百万次这样的循环,误差被一步步压到最低。

    这就是参数自省的全貌。

  • RoPE 旋转位置编码详解

    一、一句话概览

    绝对位置编码是「加法」——把位置向量加到 token 上;RoPE 是「旋转」——用位置角度去旋转每一层 Attention 的 Q 和 K 向量。

    二、绝对位置编码的回顾

    2.1 原版 Transformer 的 Sin/Cos 编码

    对位置 pos 和维度索引 i(0 ≤ i < d/2):

    PE(pos, 2i)   = sin(pos / 10000^(2i/d))
    PE(pos, 2i+1) = cos(pos / 10000^(2i/d))

    然后将 PE(pos) 加到 token embedding 上:

    x_pos = Embedding(token) + PE(pos)

    2.2 问题

    问题原因
    破坏语义位置信号直接加到语义向量上,两者混在一起
    外推差训练时只见过 0~2047 的位置,推理到 4096 时参数模型没学过
    相对位置是间接的需要模型自己从 sin/cos 加法公式里推导相对关系

    三、RoPE 的设计思路

    3.1 目标约束

    找到一个函数 f(q, k, m, n),使得 Attention Score 只依赖相对位置 (n-m),且不破坏语义向量。

    写成数学形式:

    Attention_Score(m, n) = <g(q_m, m), g(k_n, n)>
                            其中 g 是只依赖位置的变换
                         = 只依赖于 (n-m)

    3.2 推导过程

    第 1 步:将位置信息施加在 Q/K 上,而非输入的 embedding 上

    q_m' = g(q_m, m)
    k_n' = g(k_n, n)

    这样语义向量本身不受影响,位置信号只在 Attention 计算时生效。

    第 2 步:假设变换是线性的(乘以矩阵)

    q_m' = R_m · q_m
    k_n' = R_n · k_n
    
    内积 = (R_m·q_m)^T · (R_n·k_n) = q_m^T · R_m^T · R_n · k_n

    为了让内积只依赖 (n-m),需要:

    R_m^T · R_n = R(n-m)

    第 3 步:寻找满足条件的矩阵

    2D 旋转矩阵完美满足:

    R(θ) = [cos θ  -sin θ]
           [sin θ   cos θ]
    
    性质:R(θ_m)^T · R(θ_n) = R(θ_n - θ_m)

    验证:

    R(θ_m)^T · R(θ_n) = R(-θ_m) · R(θ_n) = R(θ_n - θ_m)

    如果让 θ_pos = pos × ω(角度与位置成正比),那么:

    R_m^T · R_n = R(n·ω - m·ω) = R((n-m)·ω)    ← 只含 n-m

    第 4 步:推广到高维

    Q 和 K 不是二维的(通常 128 维)。解决方案:把 d 维向量切成 d/2 个二维块,每块独立旋转:

    [ q0, q1, q2, q3, q4, q5, ..., q126, q127 ]
     └─┬─┘ └─┬─┘ └─┬─┘         └───┬───┘
      对0    对1    对2           对63
    
    每对在自己的 2D 平面内独立旋转

    每个块的旋转角和频率:

    对 i 的旋转角 = pos × θ_i
    其中 θ_i = 10000^(-2i/d)

    频率设计直接复用了原始 Transformer sin/cos 编码的参数。

    第 5 步:验证内积确实只剩相对位置

    Score = (R(m)·q_m)^T · (R(n)·k_n)
          = Σ_i [q_m^(2i), q_m^(2i+1)] · R((n-m)·θ_i) · [k_n^(2i), k_n^(2i+1)]^T

    每个块的旋转角度只依赖 (n-m)·θ_i,与绝对位置 m、n 无关。

    四、发现过程:从问题到方案的完整叙事

    前面第三节展示了 RoPE 的数学推导步骤,但只列步骤不看动机,就像读答案不看草稿——看不出设计者的思考过程。本节还原完整的发现历程。

    4.1 当时的研究困境(2020-2021)

    RoPE 诞生前,位置编码方案已经探索了好几年:

    方案代表原理致命缺陷
    绝对位置(可学习)BERT,GPT-1每个位置一个向量,当 embedding 训练位置数固定,外推 = 零
    Sin/Cos 绝对位置原版 Transformer用三角函数算固定值外推差,相对位置是间接的
    相对位置偏置T5,Transformer-XL在 Attention 矩阵上加偏置项无法外推,偏置表尺寸受限
    ALiBi论文 “Train Short, Test Long”按距离加线性衰减简单但精度不如 RoPE
    可学习相对位置DeBERTa加可学习的相对位置嵌入参数量大,外推差

    各方案的共同困境:要么破坏语义(加法类),要么不能外推(偏置类),要么计算量大(可学习类)。

    4.2 核心诉求

    作者(苏剑林等)把需求提炼成一个精确的数学命题:

    是否存在一种变换,使得 Attention Score 天然只含相对位置,同时:
    1. 不修改 token embedding(保持语义纯度)
    2. 不增加可学习参数(泛化到任意长度)
    3. 计算效率高(可融入现有 Attention 流程)

    4.3 为什么选择在 Q/K 上做变换?

    这是第一个关键决策。前人都在两个地方加位置:

    选项 A:加在 x(embedding)上 → 破坏语义
    选项 B:加在 Attention 矩阵上(偏置项)→ 不能外推

    作者选择了一个前人没试过的第三条路

    选项 C:加在 Q 和 K 上(Attention 计算前一步)

    理由很巧妙——Attention Score 本身就是 q^T · k 的内积,如果在 Q 和 K 上分别施加位置相关的变换,内积就有可能天然产生相对位置。而且 Q/K 在每一层都重新计算,不绑定到输入层。

    4.4 为什么假设变换是线性的?

    g(q, pos) 出发,最自然的简化是假设它是某种线性变换(即乘以矩阵):

    q' = R(pos) · q

    为什么这么假设?

    • 可解析性:线性变换有丰富的数学工具可用(特征值、正交性、群论)
    • 计算效率:矩阵乘法是 GPU 最擅长的事
    • 已有的工作支撑:相对位置编码的论文已经暗示过”q 和 k 的某种变换可以编码位置”

    这一步没有天才的直觉——它就是逐次尝试最简单方案的自然选择。如果线性不成立,再考虑非线性。

    4.5 关键突破:发现旋转矩阵恰好满足约束

    代入线性假设后,内积变成:

    Score = q_m^T · R_m^T · R_n · k_n

    为了让 Score 只依赖 (n-m),需要:

    R_m^T · R_n = 某个只依赖 (n-m) 的矩阵

    现在问题变成了纯线性代数:什么样的矩阵满足 “相邻两个的乘积只依赖差”?

    这个条件等价于:

    R_m 构成一个群,且群运算是矩阵乘法
    R_m^T · R_n 只依赖 n-m

    在 2×2 矩阵中逐一排查:

    • 对角矩阵?D_m^T · D_n = D_m·D_n → 依赖 m+n,不满足
    • 三角矩阵?T_m^T · T_n → 结构复杂,不满足
    • 正交矩阵?O_m^(-1) · O_n → 依赖 n-m 当且仅当 O_pos 是旋转矩阵!

    这就是那一下”叮”的时刻——2D 旋转矩阵的转置等于逆矩阵,而两个旋转矩阵的乘积 = 角度相加。

    R(θ_m)^T · R(θ_n) = R(-θ_m) · R(θ_n) = R(θ_n - θ_m)

    旋转角相减 = 只剩下相对角度。只需要设定 θ_pos = pos × ω(角度与位置成正比),就完美得到:内积只依赖 pos_n - pos_m,即相对位置。

    4.6 为什么 n-m 直接落到内积里就够了?

    这其实是整个设计最精妙的一步。

    Attention 的语义是”当前词应该关注序列中的哪些词”。如果两个词的距离 n-m 直接编码在 Attention Score 中,那模型就不需要从绝对位置去推算距离——距离本身就是输入信号的一部分。

    类比:你不需要知道自己在屋子里的绝对坐标 (3.2, 5.7) 才能判断”门在你左边 2 米”——因为你直接感知的是相对距离。RoPE 让 Attention 同样直接感知相对距离。

    4.7 为什么是用复数旋转而不是其他正交变换?

    线性代数中,2D 空间的保距变换只有两类:纯旋转镜面反射

    反射矩阵虽然也满足 det=1 和正交性,但反射会改变向量的手性(左手系变右手系),对于语义向量的表示是不必要的扰动。旋转则不改变任何额外属性,是最干净的正交变换

    另外,旋转还有复数表示:

    R(θ) 等价于 e^(iθ) = cos θ + i sin θ

    这使得计算极其高效——直接在复数域上做逐元素乘法即可,不需要构造完整的 2×2 矩阵。现代实现(如 LLaMA 的 xformers)正是利用了这一点。

    4.8 推广到高维的巧思

    二维旋转搞定了,但 Q/K 是 128 维的,怎么推广?

    作者的做法简单到近乎粗暴:

    把 128 维切成 64 个二维块,每个块独立旋转。

    频率设计直接复用原版 Transformer 的 θ_i = 10000^(-2i/d)——这不是随手选的,而是为了让 RoPE 退化回 sin/cos 编码的频谱特性,保证和已有工作的兼容性。

    高低频分工的效果:

    • 低频维度转得快(θ_0 ≈ 1.0)→ 位置差 1 就会转 ~57°,向量变化剧烈 → 擅长分辨相邻词
    • 高频维度几乎不转 → 对位置不敏感 → 保留语义信息不被位置污染
    • 中间的维度 → 在局部和全局感知之间平滑过渡

    4.9 发现过程总结:关键决策点

    问题:如何让 Attention 只依赖相对位置?
      ├─ 前人试过 A "加在 x 上" → 破坏语义 ❌
      ├─ 前人试过 B "加在 Attention 矩阵上" → 不能外推 ❌
      └─ 作者选了 C "加在 Q/K 上" → 新路子 ✓
           ├─ 线性变换?先试最简单的——假设乘矩阵 ✓
           │    └─ 约束:R_m^T · R_n = R(n-m)
           │       ├─ 对角矩阵? → 不满足 ❌
           │       ├─ 三角矩阵? → 不满足 ❌
           │       └─ 旋转矩阵? → 恰好满足!!✓✓✓ (核心突破)
           ├─ 推广到高维?
           │    └─ d 维切成 d/2 对,每对独立旋转 ✓
           └─ 每对的频率?
                └─ 复用 sin/cos 的 10000^(-2i/d) ✓ (兼容现有工作)

    RoPE 之所以漂亮,不是因为某一步特别天才,而是因为每一步都是顺着问题约束自然推演——先定目标,再排除不行的方法,留下的那一条恰好是对的。

    五、为什么每层都要施加 RoPE?

    4.1 对比:施加的位置和层次

    绝对位置编码RoPE
    作用对象Token Embedding(只在输入层)Q 和 K 向量(每一层 Attention)
    位置信号加到语义向量上,混在一起通过旋转角度编码,不改变向量模长

    4.2 为什么 RoPE 每层都需要?

    Attention 是每一层独立计算的。如果第 i 层的 Q/K 不包含位置信息,这层的 Attention 就无法利用位置做推理。

    浅层 Q/K:关注局部语法、相邻词关系 → 旋转让它知道"谁在附近"
    深层 Q/K:关注全局语义、长距离依赖 → 旋转让它知道"谁离得远"

    位置信息通过所有层逐层传递和强化。

    4.3 每层的旋转矩阵值相同吗?

    R(pos) 只依赖位置索引 pos 和全局频率 θ_i,不依赖层数:

    R(pos) 对同一 token 在所有层中完全相同
    pos=0 时 R(0) = 单位矩阵,等于没有旋转(位置 0 作为原点)

    变的是被旋转的 Q/K 向量本身——每层的 W_Q/W_K 不同,输入 x 也不同。

    六、直观理解:频率分层

    5.1 为什么每对的旋转角度不同?

    维度对θ_ipos=2 时的旋转角直觉
    (0,1) 高频≈ 1.0≈ 115°转得猛 → 擅长感知”谁紧挨着我”
    (2,3) 中频≈ 0.05≈ 6°转得适中
    (63,64) 极低频≈ 0.00001≈ 0°几乎不转 → 对位置不敏感,专注语义

    5.2 类比:钟表

    秒针(高频):转得飞快 → 区分 t=0s 和 t=1s,捕捉瞬间变化
    时针(低频):几乎不动 → 区分 12:00 和 13:00,感知大范围位置
    ─────────────────────────────────────────────────────────
    两者同时看,就能精确得知当前时间

    同理:高频对负责感知局部邻居关系,低频对负责感知长距离段落位置,两者结合完整编码位置信息。

    七、为什么 RoPE 外推能力强?

    推理长度超过训练长度时,需要让模型适应没见过的大位置。RoPE 支持多种扩展策略:

    方法做法原理
    线性插值将所有位置除以缩放因子 s(pos’ = pos/s)把大位置映射回训练范围内,但高频信息丢失
    NTK-aware 插值低频维度多缩放,高频维度少缩放保留高频局部信息的同时扩展低频全局感知范围
    YaRNNTK + 温度调参在 NTK 基础上进一步优化,是目前效果最好的方案

    核心优势来自 RoPE 的相对位置本质——模型学到的是「两个 token 相距多远」,而不是「token 在第几个位置」。相对距离的概念是连续的、可泛化的。

    八、实现伪代码

    def apply_rope(q, k, position_ids, dim, theta=10000.0):
        """
        q, k: [batch, heads, seq_len, dim]
        position_ids: [seq_len]
        """
        # 计算每对维度的频率
        freq = 1.0 / (theta ** (torch.arange(0, dim, 2).float() / dim))
        # 每对维度的旋转角 = 位置 × 频率
        angles = position_ids.unsqueeze(-1) * freq.unsqueeze(0)  # [seq_len, dim/2]
        cos = angles.cos().unsqueeze(-1)  # [seq_len, dim/2, 1]
        sin = angles.sin().unsqueeze(-1)
    
        # 把 q, k 拆成 [..., dim/2, 2] 的形状,每对的 (d_2i, d_2i+1)
        q = q.view(*q.shape[:-1], -1, 2)
        k = k.view(*k.shape[:-1], -1, 2)
    
        # 2D 旋转: [x, y] → [x·cos - y·sin, x·sin + y·cos]
        q_rot = torch.stack([
            q[..., 0] * cos - q[..., 1] * sin,
            q[..., 0] * sin + q[..., 1] * cos
        ], dim=-1)
        k_rot = torch.stack([
            k[..., 0] * cos - k[..., 1] * sin,
            k[..., 0] * sin + k[..., 1] * cos
        ], dim=-1)
    
        return q_rot.flatten(-2), k_rot.flatten(-2)

    九、对比总结

    维度绝对位置编码 (Sin/Cos)RoPE
    操作方式x = emb + PE(加法,输入层)q' = R(pos)·q(旋转,每层 Attention)
    作用对象Token EmbeddingQ 和 K 向量
    对语义影响破坏语义向量旋转是正交变换,不改变向量模长
    位置编码性质绝对位置相对位置(旋转差 = n-m
    外推能力强,配合 NTK/YaRN 可扩至 128K
    代表模型原版 Transformer、BERT、GPT-1/2LLaMA 全系列、Qwen、DeepSeek、Mistral、ChatGLM