MIT 6.5940 | TinyML 与高效 AI 计算 | Fall 2026 | 笔记 | Lecture 12:Transformer and LLM

目录

    • 前言
    • [1. Lecture Plan](#1. Lecture Plan)
    • [2. Transformer Basics](#2. Transformer Basics)
      • [2.1 Before Transformers: RNNs and CNNs](#2.1 Before Transformers: RNNs and CNNs)
      • [2.2 Tokens, Embeddings and the Transformer Block](#2.2 Tokens, Embeddings and the Transformer Block)
      • [2.3 Self-Attention and Multi-Head Attention](#2.3 Self-Attention and Multi-Head Attention)
      • [2.4 FFN, LayerNorm and Positional Encoding](#2.4 FFN, LayerNorm and Positional Encoding)
    • [3. Transformer Design Variants](#3. Transformer Design Variants)
      • [3.1 Encoder-Decoder, BERT and GPT](#3.1 Encoder-Decoder, BERT and GPT)
      • [3.2 Relative Positional Encoding: ALiBi and RoPE](#3.2 Relative Positional Encoding: ALiBi and RoPE)
      • [3.3 KV Cache and Its Optimizations](#3.3 KV Cache and Its Optimizations)
      • [3.4 FFN Variants: SwiGLU](#3.4 FFN Variants: SwiGLU)
    • [4. Large Language Models](#4. Large Language Models)
    • [5. Advanced Topics](#5. Advanced Topics)
      • [5.1 Multimodal LLMs](#5.1 Multimodal LLMs)
      • [5.2 Mixture of Experts](#5.2 Mixture of Experts)
    • [6. Summary](#6. Summary)
    • 结语
    • 参考

前言

学习 MIT 韩松教授讲授的 MIT 6.5940: Tiny ML and Efficient AI Computing 课程,本篇文章记录 第十二讲:Transformer 和 LLM 的学习内容,和大家一起分享交流😄

Website:https://hanlab.mit.edu/courses/2026-fall-65940

Video:https://www.youtube.com/playlist?list=PLH7PIPKvCm38

1. Lecture Plan

今天我们要讲 Transformer 和大语言模型。我们只介绍 Transformer 架构以及大语言模型的一些应用;至于更细致的部署、后训练,以及如何把大语言模型用到各种应用中,会在后面的讲座里展开。所以今天 我们先深入整体架构,对 LLM 的架构及其应用做一个高层次的概览。

先说背景:大家都知道 ChatGPT 在 2022 年底问世,大语言模型聊天机器人变得非常普及、几乎人人可用。最开始它只是个聊天机器人,你可以输入一些简单问题,从当时的模型那里得到一些回答。后来,我们看到它被应用到越来越多的领域。

机器翻译大家都很熟悉,语言模型可以把一种语言的文本翻译成另一种语言,同时保留原意和上下文。随着语言模型越来越强,你可能会觉得如今的机器翻译比五年前、十年前好得多。

另一个很重要的应用是用大语言模型辅助编程 。GitHub Copilot 出现得非常早,甚至好几年前就有了。如今这类工具越来越多、越来越强,以几个月甚至几周一次的节奏在迭代:除了 GitHub Copilot,还有 Cursor、Codex、Claude Code、Antigravity 等等。有非常多强大的编程模型可以帮你完成日常编码任务。

大语言模型还扩展到了不同模态:有很多不同的多模态语言模型,用于图像理解、视频理解,以及多模态生成,比如图像生成、视频生成,还有世界模型之类的任务。它们不仅在 "文本进、文本出" 的任务上强大,在多模态---图像、视频、音频---上也非常强大。

今天的课我们会讲 Transformer 架构的基本概念,还会讲 Transformer 模型的几种变体,然后讨论大语言模型的组件和注意力架构,最后讲一些进阶话题,比如大语言模型的应用和多模态语言模型。

2. Transformer Basics

我们先从第一部分开始:Transformer 架构基础。先回顾一些 NLP 任务。

2.1 Before Transformers: RNNs and CNNs

自然语言处理任务大致分为两大类。一类是判别式任务:你有一个输入句子,要输出某种判断 ,比如这是正面还是负面反馈,或者说话的人是开心、生气还是难过等各种情绪,用语言模型在不同选项之间做判别。另一类非常重要的任务是生成式任务,这在如今的大语言模型用例中非常常见:你给一个句子、一个问题,语言模型输出一些 token、词、句子或段落,来回答你的问题、补全原文。

在 Transformer 流行之前,NLP 领域还有一些其他被广泛使用的架构,比如 RNN,也就是循环神经网络。RNN 有一个隐藏状态,充当固定大小的工作记忆,这让它在内存上很高效 :每当有新的输入 token,就把它编码进已有的记忆状态。所以内存消耗并不会随输入 token 增多、序列变长而线性增长。

但 RNN 的问题是,它很难在长序列上保留信息 。比如有些词或 token 出现得很早,而你想让最近的 token 关注到那些很遥远的 token,信息交换就很难。此外,顺序依赖也限制了训练和推理中的并行度,因为你必须逐个输入 token,在每一步维护状态。

卷积网络是另一个重要且适用的选择,用来对这类序列依赖建模。它在训练时也能更好地扩展,因为不同位置之间存在并行性:你可以像图像处理那样,把卷积核并行地应用到不同位置 。CNN 在语言建模中的局限通常是上下文长度有限:我们有一维的上下文窗口,卷积核的长度就是局部感受野。如果想要更大的感受野,你可能需要堆叠很多层,才能关注到很远的 token。

对于判别式任务,双向 RNN 可以利用前后文来编码输入;而对于生成式任务,单向 RNN 只能利用之前的状态,因为未来的 token 还没生成。这就是 RNN 或 LSTM 模型在不同语言任务中的区别:判别式和生成式。

正如前面讨论的,RNN 的第一个主要问题是长距离交互 :信息必须穿过序列长度那么多的 token 才能流到当前位置,让当前 token 与之前的 token 交互。比如我们想关注前面很远的 token,就得一层层、一步步地传状态。假设序列里一共有 N 个 token,在最后这个位置上要从最开始取信息,至少需要 N 步---这并不高效,也很难从很远的地方取回信息。

第二个问题是并行度有限 。比如我们想得到状态 2,就必须从第一个 token 出发得到状态 1,再得到状态 2、状态 3;要得到状态 N,就得一步步算 N 次。这对当今的并行处理器(比如 GPU)并不友好,在训练和推理过程中都很难充分利用 GPU 的强大算力。

2.2 Tokens, Embeddings and the Transformer Block

现在我们来看 Transformer 架构。它用一套新的处理流程---核心是注意力---解决了这些局限 。这为如今的大语言模型奠定了基础:所有这些令人惊叹的应用、强大的模型、强大的 agent,都建立在 Transformer 架构这个非常有原创性的起点上。

Transformer 的每一层里有一些关键组件。最开始我们有一个 tokenizer,把输入词、输入句子转换成若干 token,每个 token 再映射到不同的嵌入。比如在原始 Transformer 的编码器-解码器架构中,我们有两个不同的嵌入层:一个用于输入嵌入,另一个用于输出嵌入。经过这一步,输入 token 就变成了嵌入向量,深度学习模型可以很容易地处理。

之后我们会有多个编码器层或解码器层。每一层通常有这些模块:注意力模块、前馈网络、层归一化和残差连接 。注意力架构、前馈网络或 MLP 模块都有很多不同的变体和设计。除了这些模块,我们还有位置编码,注入与 token 在当前上下文中位置相关的信息。最后还有一个线性输出头,把模型的潜在空间映射到词的概率,从而得到最终预测。

我们先看 tokenizer。tokenizer 通常把词映射成一个或多个 token。

比如这段文字有 110 个词,会被编码成大约 162 个 token。不同的 tokenizer 得到不同数量的 token。有时一个词会被拆成多个 token,有时一个 token 可以包含多个词。粗略来说一个词对应一个 token,但这并不是严格限制,完全取决于你用的 tokenizer。一个重要的信息是:决定模型看到的序列长度的是 token 数,而不是词数 。所以,一段看起来很长、token 却很少的文本,可能反而比一段看起来更短、token 更多的文本处理起来更快。

分词之后,我们需要为每个 token 得到数值表示。我们比较一下 one-hot 表示和学习到的稠密嵌入。

one-hot 编码很简单,大家应该都很熟悉:词表中的每个词对应一个位置,用一个向量表示当前 token,向量长度、维度就是词表大小。这会非常大、非常稀疏,只有一个非零元素表示当前 token 。把它作为输入模型的表示并不是很高效。

为了解决这个问题,人们引入了嵌入层,通过查表把每个 token 映射成连续的词嵌入。嵌入权重矩阵的每一行就是当前 token 的嵌入向量 。不同 token 有不同的嵌入向量,代表它在嵌入空间中的不同位置。词嵌入可以随整个模型端到端地为下游任务训练;也有一些预训练词嵌入可选,比如 word2vec 和 GloVe。如果你感兴趣,可以自己搜索一下这些嵌入层是怎么训练出来的、词是怎么切成 token 的---有一些非常有趣的算法让整个过程非常高效。

2.3 Self-Attention and Multi-Head Attention

嵌入层之后,token 嵌入可以直接送入 Transformer 层,不管是编码层还是解码层。首先,我们通常有注意力层、自注意力层,它让每个 token 都能直接访问序列中的其他所有 token,于是同一个序列、同一个请求中的不同 token 之间可以交互。

这里是基本的自注意力架构。首先把嵌入或隐藏状态投影成不同的向量,通常称为查询(query)、键(key)和值(value),简称 QKV 。这非常像检索系统:查询相当于搜索框里的文本提示,键相当于标题、描述或视频、网页中的关键信息,值就对应视频内容或网页内容。搜索过程就是把查询与键做匹配,返回最匹配的那个值。

在 Transformer 中,这个思路非常相似,但实现方式有所不同。典型的注意力架构是:把查询向量与键向量相乘,得到内积,表示查询与键的相似度 ;再用 d \sqrt{d} d 归一化,d 是隐藏状态的维度。比如在单头注意力中,d 通常是模型的隐藏大小;在多头注意力中,d 通常是头维度,比如 128 或 256 等。这样归一化可以保证整体分布非常适合后续的 softmax---softmax 把相似度分数转换成概率,以便从不同的值向量中采样。

softmax 之后,我们得到注意力分数,把它与当前键对应的值向量相乘,再把所有加权后的值向量求和,就得到当前查询的注意力输出。由于注意力的计算模式,很容易知道注意力模块的计算复杂度是 O(N²)。

这是机器翻译任务注意力图的一个例子:颜色越白,表示注意力分数越高;颜色越深,分数越低。可以看到注意力图中有一些非常明显的模式,比如沿主对角线有对角线片段,还有一些反向片段。这说明在英法互译中,一些重要 token 会与另一种语言中对应的 token 有更高的注意力分数 ;有时注意力层还能识别不同语言中词序的不同,所以有时会出现反向片段。

单个注意力图只能表示一种交互模式,所以我们需要多头注意力来建模不同的东西 :多头注意力并行地学习多组查询、键、值投影,让不同的头捕捉不同的模式或关系,然后把各头的输出拼接起来,经过最终的线性投影合并。

具体来说,这里有一组查询、键、值,每个头都计算 Q 与 K 的转置之积(QKᵀ)得到注意力分数,再 softmax,再乘值向量,独立得到输出。多个头可以训练成关注不同的模式:有的关注局部模式,有的关注长距离建模等不同功能。

这是同一层中不同头的注意力图示例:注意力图在不同位置被高亮,呈现出不同的注意力模式,说明多头注意力给注意力模块更多自由去关注不同的东西。

注意力中另一个非常重要的设计是注意力掩码,尤其是因果掩码。全局注意力允许每个 token 看到完整序列。而因果注意力会掩蔽未来的 token,也就是说当前 token 只能关注自己和出现在它之前的 token 。在仅解码器(decoder-only)语言模型中,通常使用下三角因果掩码来做下一个 token 生成,就像这个例子。

在因果自注意力层中,每个 token 只能关注它之前(包括自己)的 token,看不到未来的 token。而在不掩码的全局注意力中,每个 token 都能看到其他所有 token。这个设计因应用而异,而因果掩码注意力在如今的生成任务和大语言模型应用中非常重要。

2.4 FFN, LayerNorm and Positional Encoding

注意力架构就讲到这里,接下来讲 Transformer 层的另一个重要部分:前馈网络 FFN,也有人叫它 MLP。

这是 FFN 模块最基本的设计:有两个投影层。第一个投影层把输入嵌入从维度 D 投影到 4D ,中间有激活函数,通常是 ReLU 或 GELU 等不同选择;激活之后,再用另一个投影层把模型的隐藏维度缩回原来的嵌入、隐藏状态大小,比如从 4D 投影回 D。这种 FFN 给每个 token 内部带来更多功能、更多非线性模式:注意力在不同 token 之间混合信息,FFN 则在每个 token 内部增加灵活性、增加非线性行为。

最后是层归一化和残差连接,包围在每个注意力和 FFN 层周围。这些组件让深层 Transformer 堆叠更容易优化,训练更稳定。

这是层归一化的可视化。它和 CNN 中常用的批归一化不同,Transformer 通常用层归一化 。"层" 意味着对每个 token 的嵌入做归一化,也就是在当前 token 内部归一化 ;层归一化模块里还有可学习的系数,比如这里的 γ \gamma γ 和 β \beta β 。这两个参数让每一层归一化都能有不同的缩放与偏移,从而获得更好的整体性能。

关于层归一化模块有两种不同的设计:post-norm 和 pre-norm,区别在于层归一化操作插入的位置 。post-norm 中,它加在注意力层和残差连接之后,也加在残差层和 FFN 之后;pre-norm 中,它放在 FFN 和注意力模块之前。实践中,如今的大语言模型通常更偏好 pre-norm,因为它提供更好的训练稳定性,也能简化 kernel 融合等优化。

现在我们有了注意力和 FFN 模块,也有了层归一化和残差连接来稳定训练。我们还需要位置嵌入,教模型同一 token 在不同位置的差异,以及如何区分不同距离的 token---哪些是很远的 token,哪些是最近的 token。

位置编码可以是显式的,也可以是隐式的。比如 模型可以直接从因果掩码注意力中推断不同 token 之间的相对位置,这也是一种隐式加入位置编码的方式。设计非常多样,我们会讲其中几种非常重要的。这是位置编码方法的概览:有绝对位置编码和相对位置编码。

先看绝对位置编码,它为每个 token 位置分配一个唯一的向量,加到 token 嵌入上;如果你在嵌入中看到这个位置编码向量,就知道它在整个序列、整个请求中的绝对位置。

有了位置编码之后,我们还有最后的线性输出头做预测。把所有东西拼起来:文本变成带位置信息的 token 和嵌入。Transformer 块用不同的注意力、不同的 FFN 层,以及层归一化和残差连接,在不同 token 之间增加信息交换,在每个 token 内部增加非线性激活 。随着 Transformer 越来越深,模型就能发现上下文中越来越多的关系和信息,进而生成下一个 token。

这是原始 Attention Is All You Need 论文的一些结果,它是 Transformer 和如今大语言模型的基础。可以看到,原始 Transformer 用远少的训练计算量,就取得了比之前系统更高的 BLEU 分数 。BLEU 衡量生成译文与参考译文的相似度。结果说明,相比之前的架构,Transformer 兼有更好的精度和训练效率。

3. Transformer Design Variants

我们讲完了 Transformer 的基础架构,现在来讲现代大语言模型中非常常见的设计变体。

主要有几个维度可以做变化:第一个设计维度是整体架构---编码器和解码器的选择 。可以是编码器-解码器架构,比如原始 Transformer 和 T5;可以只有编码器,一个非常重要的例子是 BERT;也可以只有解码器,比如 GPT,以及如今的大语言模型。位置编码方面,可以是前面简要介绍过的绝对位置编码,也可以是相对位置编码。

另一个重要设计维度是 KV cache 优化 :我们讨论过多头注意力,还有多查询注意力、分组查询注意力;如今人们还用线性注意力、稀疏注意力,注意力模块有很多变体。对于 FFN 层,最早的设计是两层投影、中间一个激活函数;也可以有各种不同的设计,比如 FFN 中的门控线性单元(GLU),还有更先进的混合专家(MoE) 等等。

3.1 Encoder-Decoder, BERT and GPT

我们先从编码器-解码器、仅编码器、仅解码器这几种架构划分讲起。每种结构对应不同的训练目标和注意力模式。

编码器-解码器架构,也就是原始 Transformer,用编码器表示源序列,解码器逐个 token 生成目标序列 。T5 用这种结构,通过统一的 "文本到文本" 接口来完成很多不同的 NLP 任务:源文本先进入编码器,编码器给出表示,解码器再以该表示为条件生成后续 token。

这就是编码器和解码器:它用编码器给出的表示继续做 token 生成。这可以广泛用于翻译、摘要以及其他语义任务。

BERT 是讨论 Transformer 时的另一个重要例子。它只使用编码器,因此可以做双向注意力---注意力图不做因果掩码,每个 token 都能看到前面和后面的所有 token 。它的主要预训练目标是:比如遮住 15% 的输入 token,让模型利用左右上下文重建它们,看模型能否恢复原来的整句话,把正确的词、正确的 token 填回被遮住的位置。预训练好的 BERT 再针对下游任务做微调。

而 GPT 的故事很不一样。它是仅解码器架构,所有 Transformer 层都使用下三角注意力掩码 :后面的 token 只能关注它前面的 token,当前 token 看不到未来的 token。这也与自回归的逐 token 生成一致。GPT 的预训练目标是用前面的 token 预测下一个 token。较小的模型通常针对每个任务做微调,而 足够大的模型可以在新任务上仅靠提示中的指令或少样本示例就表现得很好 ---模型足够大时就会涌现出一些非常惊人的能力。这就是我们常说的 "涌现"(emergence)。

3.2 Relative Positional Encoding: ALiBi and RoPE

现在我们进入另一个架构选择维度:位置编码。现代大语言模型经常用更直接表示相对距离的方法来替代绝对编码。

在绝对位置编码中,如前所述,你把输入嵌入加上固定的位置嵌入,它只依赖当前 token 在整个句子、整个输入上下文中的绝对位置。好处是实现简单;缺点是难以扩展到更长的序列 :比如模型只在不超过 4K token 的序列上训练,那么 4K 之后的绝对位置嵌入模型从没见过,一旦输入序列超过预设的最大长度,效果肯定会崩塌 。而相对位置嵌入通过影响注意力分数来提供相对距离信息:要么加一个偏置,要么修改原始的查询和键。由于相对位置编码只关心不同 token 之间的相对距离,它更容易扩展到预训练阶段没见过、更长的序列。

这是相对位置编码的第一个例子:带线性偏置的注意力,简称 ALiBi 。思路是把绝对位置编码改成只与相对距离相关。我们有原始的注意力分数,再构造一个 ALiBi 矩阵,把两者直接相加。比如 Q3 与 K1 之间的注意力分数会加上 -2,表示第三个 token 与第一个 key 之间的相对距离是 2;Q5 与 K1 之间则加上 -4。

ALiBi 中还有不同的斜率,意味着 不同的头可以有不同的位置嵌入强度 :有些头受位置编码影响较小,有些则更明显。如果斜率参数很大,长距离惩罚会很明显,注意力头就会更关注局部上下文。反过来,如果这个数很小,位置编码的影响就弱得多,注意力头就更有能力关注远处的 token。

下面看一个更强大也更复杂的位置编码:旋转位置编码(RoPE)。它在许多现代大语言模型中被使用,比如最近的开源模型里,很多仍然在注意力层中使用 RoPE。

在旋转位置嵌入中,我们先把原来的隐藏状态---比如输入嵌入的隐藏维度和当前头中查询的大小都是 d---切分成两部分,每部分维度是 d 的一半,这样就为每个嵌入得到 d/2 对二维坐标 。比如 x1 和 x2 是一对,x3 和 x4 是一对;x1 是当前查询的第一个元素,x2 是第二个元素。我们把每个查询 token 变成 d/2 对,每对是一个二维坐标,然后对这些对施加旋转 。每一对有不同旋转基,旋转角度由参数 θ \theta θ 决定:第一对的 θ 很小,后面各对的维度索引更大,旋转基按指数衰减---具体取值由指数中的因子决定。

也就是说,不同的二维坐标对有不同的旋转基 ,同时还要考虑具体位置 m,也就是当前查询的 token 索引。把两者结合起来,施加角度为 m θ i m\theta_i mθi 的旋转,其中 i 是维度索引,m 是 token 索引。把这个旋转作用到查询和键元素上,可以证明 :如果查询在位置 m、键在位置 n,那么 q m q_m qm 与 k n k_n kn 的乘积只与 m - n 有关,而与 m、n 的具体值无关---这正是相对位置编码的含义。

这是更一般的 RoPE 公式:这是一个小旋转矩阵,我们对前两个维度施加角度为 m θ 1 m \theta_1 mθ1 的旋转,对第三、四个维度施加 m θ 2 m \theta_2 mθ2 的旋转,以此类推。实际上就是对不同的二维坐标施加旋转矩阵 。在实际实现中我们不会显式做矩阵乘法,而是用逐元素乘法和一些移位、加减操作完成,非常高效,不需要大规模矩阵乘法。你很容易在比如 LLaMA 的模型架构中找到高效的实现。

这是 RoPE 的优势:它还提供了一种扩展上下文长度的实用方法 ,用一种叫 "位置插值"(position interpolation)的技术,重新缩放原始的位置索引,让更长的序列仍落在预训练时见过的角度范围内。无需额外预训练,这种方法就能把 LLaMA 模型从原来 2K 的窗口扩展到这篇论文里的 32K 。这是位置插值的可视化:你可以把原来的旋转角度基 θ \theta θ 缩小,就能让更多 token 塞进上下文窗口、位置嵌入窗口。

我们讲完了相对位置编码的方法。还有其他一些把位置信息注入模型的方法。比如 因为有因果注意力掩码,模型可以在某种程度上从注意力掩码本身推断 token 之间的位置关系 。还有一些其他设计,比如 我们称之为 NoPE(无位置编码)的设计,它仍被用在很多非常先进的模型里,比如 Kimi K3,具体可以查阅技术报告。

3.3 KV Cache and Its Optimizations

接下来讲其他技术,比如 KV cache 设计、KV cache 优化。我们会讲 MQA 和 GQA,用来减小 KV cache 大小,从而节省整体存储内存。首先来看看什么是 KV cache、为什么需要优化它。

在 GPT 风格的解码过程中,当前查询会关注前面的键,并与每个前面 token 的值向量计算最终输出。因此我们需要把过去的键和值存在某个空间里,这就是 KV cache。缓存避免了重复计算,但它的内存会随序列长度和批大小线性增长 :token 越多,缓存的 KV 越多,内存消耗越大。如果没有 KV cache,问题在于每生成一个新 token,都要重新计算所有 token 的键和值。随着序列增长,这种重复计算的开销会越来越大。

比如没有 KV cache 时,每生成一个新 token 的计算复杂度仍然是平方级,因为要计算所有之前的键和值、整个注意力图;每个 token 是 O(N²),生成整个序列的总复杂度就是 O(N³)。

有了 KV cache,我们就能复用之前算好的键和值:每生成新 token 只计算新的查询、键、值并追加到当前序列的 KV 中 ,然后只需计算当前查询与所有已存在 KV cache 中的键的注意力。这样每个 token 的计算复杂度是 O(N),生成整个序列的总体复杂度是 O(N²)。因此能节省大量计算和延迟。

但 KV cache 并不是免费的,尤其是从内存角度看。前面一直在说,如今计算系统里内存非常昂贵。我们可以算一下存储 KV cache 需要多少内存。

以 7B 模型为例:它有 32 层,每层 32 个头,头维度 128,N 是序列长度;因为键和值都有,所以要乘以 2;假设每个元素用 FP16 存储,每个元素 2 字节。那么总缓存大小是批大小乘以 N(比如平均序列长度),平均下来每个 token 就要 512 KB 。模型越大问题越严重,因为层更多、注意力头更多。

比如 LLaMA 70B,如果仍用 MHA,KV cache 大小是 2.5 MB 乘以批大小。假设批大小只有 16---自己跑模型时往往就是这个量级,其实偏小;你更想要更大的批大小来充分利用并行计算。但批大小一增,内存消耗就非常大。比如序列长度是 4K token,这也不算长---如果你用 GPT 或云端模型,有时上下文窗口能到 100 万 token,4K 在如今是非常短的序列。即使只有 16 的批大小、每个序列 4K token,LLaMA 2 70B 在不优化 KV cache 的情况下也需要 160 GB 的显存来存 KV cache。

和如今万亿参数的前沿模型相比,70B 其实也算小的了。这意味着,如果想利用好 KV cache,我们需要大量 KV cache 优化来节省内存。

这张图展示了 KV cache 内存可能占整体内存消耗的很大一部分。大家都知道,在大语言模型中,模型大小对整体存储消耗非常重要,所以我们把大语言模型量化到 8 位、4 位甚至更低,以节省权重本身的存储。但 KV cache 不同:随着序列变长、批大小变大,它很容易超过模型权重本身的内存消耗 。所以减少 KV cache 内存占用非常重要。

这里有一个非常重要的优化,叫多查询注意力(MQA)和分组查询注意力(GQA) 。在传统的多头注意力(MHA)中,每个 token 的查询、键、值头数相同。而多查询注意力仍然保留很多查询头,但每个 token、每一层只有一个键头和一个值头 。这样,如果原来有 H 个头,KV cache 大小就被缩小为原来的 1/H。

分组查询注意力是这两种设计之间的折中:如果 KV cache 压得太狠,可能损害模型性能、损害模型的智能水平 ,这不是我们想要的,所以取中间方案---比如把若干查询分组共享同一个键。如图中所示,第一个和第二个查询都关注第一个键,对应的值也一样;第三个和第四个则关注第二个键、乘以第二个值。假设分组大小是 2,KV cache 就能缩小到二分之一;分组大小通常是 8,KV cache 就能缩小到八分之一。

这张图显示,采用不同分组大小的 GQA,KV cache 消耗可以小得多。

这是在相同 token 数下训练模型的实验结果,比较下游任务的表现:总体来说,MQA 能节省最多 KV cache 内存,但相比 MHA 架构,性能下降也非常明显 。而 GQA 在模型较大时能达到 MHA 的精度,同时节省大量 KV cache 内存。

KV cache 优化就讲到这里。最近还有一些其他方向,比如稀疏注意力以及 KV cache 压缩技术。如果你感兴趣,可以去看 DeepSeek 的 V4 论文和 NSA(原生稀疏注意力)论文,里面披露了很多设计细节。

3.4 FFN Variants: SwiGLU

下一步我们讲讲 FFN 层的不同设计。这是一个非常常见的 MLP 或 FFN 设计,也就是我们前面介绍的最早的设计;现在来看 SwiGLU 的例子。它不再把通道从 D 扩展到 4D,而是扩展到原来的 8/3 倍。

这样设计能保证参数量与原设计相同 。比如原来两个投影层的参数量是 8 d 2 8d^2 8d2 ;这里每个投影有 8 3 d 2 \frac{8}{3}d^2 38d2 ,一共有三层,总共仍然是 8 d 2 8d^2 8d2 ,所以模型容量与原 FFN 层相当。这里还用了不同类型的激活函数,并且有门控函数。在这个 SwiGLU 单元中,我们先把输入嵌入投影---这里有三个层:上投影、门投影和下投影;然后做门控:把两个分支逐元素相乘,再做投影得到最终输出 。这是如今语言模型中非常常见的整体架构,比如 LLaMA 系列等较新的模型。

我们还在这个新的 FFN 设计中替换了原来的激活函数。这里有两个不同的激活函数,它们非常相似:这是原始的 Swish 激活函数,实际上是 x 乘以 sigmoid ;这是 GELU 函数的一个近似,表达式与 Swish 非常相似。更多细节可以看这个链接,了解激活函数的设计。

4. Large Language Models

最后,有了这些 Transformer 架构设计,我们现在来讨论大语言模型,以及把它们放大时会发生什么变化。这是 "强大能力的涌现":有些能力只有在模型规模达到足够大之后才会出现。

这个例子展示了两个任务---取模算术和单词打乱---较小的模型在这些基准上精度接近零,但超过某个计算量阈值后就急剧上升 。这类图催生了 "涌现能力" 这个说法,也带来了今天的 scaling law、智能涌现等概念。传统 NLP 流程是先预训练模型,然后为每个下游任务单独微调权重,每个新任务都需要标注样本、反向传播和一个新版本的模型。

然而,随着模型规模扩大,我们可以用一个通用模型应对不同的下游任务;GPT-3 表明,足够大的模型可以在不更新权重的情况下仅凭提示就适应任务。

零样本学习中我们只提供任务描述;少样本学习中,我们还会在查询之前提供几个输入输出示例。把一些示例放进上下文,模型就能轻松适应新任务。

总结一下:在这个规模上,大模型具备零样本和少样本迁移到不同下游任务的能力。上下文学习非常重要:它就是用几个示例去 "教" 大语言模型任务是什么 ,只要给几个示例,模型表现就能好得多。这种能力随模型增大而变强---大模型能从额外示例中获得更多精度提升,而小模型的提升非常有限 。示例足够多时,大模型有时甚至不需要显式的自然语言任务描述,只从模式中学习:你不告诉它任务是什么,它从你给的示例中自行推断任务,并在之后的问题中照做。

LLaMA 是开源大语言模型中一个非常重要的例子 。它几乎是第一批开源模型,出现得很早,大约两三年前。它显著提升了此前开源基础模型的水平,采用仅解码器、pre-norm 架构,加上 SwiGLU、旋转位置编码---今天讲的所有技术。

它的 7B 模型有 4K 维隐藏状态、32 个头、32 层,整个系列最初最大到 65B 参数。相比之前的开源模型,LLaMA 系列表现相当好,为开源大语言模型提供了一个很好的起点。LLaMA 2 把上下文窗口从 2K 增加到 4K,大约训练了两万亿 token,而且没有明显的饱和迹象 ---可以看到损失还在下降,说明还有进一步优化的空间。LLaMA 2 的 70B 模型采用了分组查询注意力,用来降低 KV cache 大小---也就是前面讲的优化。如果还记得,我们说过如果不优化 LLaMA 2 的多头注意力,KV cache 会非常大;而用 GQA,KV cache 能缩小到原来的八分之一。

LLaMA 3 是这个系列的另一代模型,训练语料扩大到超过 15 万亿 token,并且在这么大的语料上具备多语言能力 。它的训练 FLOPs 大约是 LLaMA 2 的 50 倍。旗舰模型超过 400B 参数 ,在开源社区、开源模型家族中是非常大的模型---即使在今天,400B 参数在开源权重模型里仍然算很大。这个系列还扩展了上下文长度,并在后训练中使用了监督微调、拒绝采样和直接偏好优化(DPO)---这是大语言模型中非常重要、非常流行的后训练方法。

Mistral 是另一个重要的开源模型家族,发布时 7B 模型就超过了 LLaMA 2 的 13B/30B 和 LLaMA 3 的 8B 模型。

这里有一个著名的如何扩展模型的法则,基于 Chinchilla 等工作的观察:我们需要同时扩展模型大小和训练数据量,才能在训练计算量与精度之间取得更好的权衡 。如果只扩大模型而不扩大数据,模型性能很容易饱和;如果只扩大数据而不扩大参数,小模型也吃不下那么大的语料,需要更大的模型来学习。模型大小与数据量、精度之间存在一条曲线。

5. Advanced Topics

最后一节讲两个进阶方向:首先看语言模型如何接受多模态输入和具身输入,然后讨论混合专家模型。

5.1 Multimodal LLMs

这是一个多模态语言模型的例子,比如 GPT-4V,它接受视觉输入,理解图像内容、描述图像并回答相关问题,甚至能基于视觉输入做推理。连接视觉和语言有两种常见方式:Flamingo 插入交叉注意力层,把视觉特征注入语言模型;PaLM-E 则用另一种方式。

这是 Flamingo 的例子:视觉输入与文本部分之间有交叉注意力,这样文本嵌入可以从视觉输入中获得信息;图像会产生具有可变空间尺寸的大特征图。

Flamingo 的 Perceiver Resampler 用一组固定的可学习查询去关注源特征,把它们压缩成少量固定的特征 token。这样语言模型解码器部分就可以假定输入图像 token 的数量是固定的,模型很容易学到这类信息。

Flamingo 的交叉注意力层还包含一个可学习的 tanh 门控,门控初始为零,因此新的视觉通路最初对冻结的语言模型没有影响 ;训练会逐渐打开门控,控制有多少视觉信息进入残差流。这意味着视觉信息是逐渐加入主流的,否则会像没有 warm-up 一样很难学。

它还支持多模态的上下文学习:提示里可以包含若干图文示例,后面再跟一张新图像,模型利用上下文中的这些示例推断任务 。比如看最后一行:先给出 "2+1" 的图片、输出 "2+1=3",再给出 "5+6" 的图片、输出 "5+6=11",然后再输入一张图片并提问,模型就能推断出要输出原始算式和最终结果---全程没有 "请帮我算一下" 这类显式指令,它只是从上下文中的模式里学习。

由于图像始终在上下文中,Flamingo 还支持多轮视觉对话:后续问题可以回指同一张图像,在对话早前建立的信息基础上继续。这提供了与视觉内容非常灵活的交互。

另一个设计是 PaLM-E,它采用第二种模式:把图像、机器人状态和其他传感器表示映射成嵌入向量,作为普通 token 与文本并列。这样一个 Transformer 就能处理语言、视觉和具身状态的灵活组合。

RT-2 把这一思路从理解扩展到机器人控制:它把机器人动作表示为输出 token,让视觉语言模型直接生成控制指令,并把从网络数据中学到的知识迁移到机器人任务。这里有一个演示,用 RT-2 控制机械臂做抓取和放置。

还有一个应用是处理自动驾驶中的罕见事件。比如这张图,开车时有一把椅子在空中飞---这是非常罕见的情况。如果发生这种事怎么办?我们需要一个非常通用的模型来理解、推理当前情况并给出相应指令,比如 "你应该立即停车、远离后备箱,因为有飞出的椅子,可能还会有更多椅子飞出来",你需要远离危险。

这个有趣的例子说明,这类应用非常重要,需要强大而通用的多模态大模型来处理罕见情况。这里还有更多例子展示视觉语言模型的泛化能力。

5.2 Mixture of Experts

最后简要讲一下混合专家(MoE)。它对每个 token 只稀疏地激活部分专家 :比如在注意力之后、进入 MLP 层之前有一个路由器,路由器挑选一些子 FFN 层来处理当前 token,而不激活所有专家。所以我们常看到最近一些模型,比如 30B 参数、激活 3B---也就是说每个 token 只激活 30 亿参数,不论模型总大小是 300 亿。

增加更多专家会提升模型总容量,同时每个 token 激活的专家数量大致不变 。这样就能在更强的模型和整体推理成本之间取得权衡:用更低的推理成本得到更通用、更强大的模型。

路由还需要专家容量限制:比如 6 个 token 分给 3 个专家,容量因子为 1 时每个专家允许 2 个 token;负载过高的专家可能丢弃 token 。容量因子 1.5 则每个专家允许 3 个 token,减少溢出,但会在不那么热门的专家上预留未使用的容量。这里存在权衡:不同的容量因子会在冗余和利用率之间取舍。

这里我们对比了 MoE 的三种路由机制:矩阵的行是专家(E1--E5)、列是 token(T1--T3),格子里的数字是对应的路由分数。左边是逐 token 选 Top-K---固定一个 token,沿着专家方向挑分数最高的 K 个 ,比如 T1 会优先选 3.13 的 E1 和 2.81 的 E5;中间是逐专家选 Top-K---固定一个专家,沿着 token 方向挑 K 个,相当于从专家一侧做选择;右边的全局分配则不再逐行或逐列地贪心,而是在整个矩阵上统一决定哪个 token 交给哪个专家 。三种方式决定了 token 与专家如何配对,也直接影响负载是否均衡---路由选得越 "贪心",越容易出现某些专家过载、其余 token 被丢弃的情况。

6. Summary

今天的课就到这里。下面简单回顾一下本节课的内容。

今天的内容正是围绕 Transformer 这个骨架展开的四部分 :一是 Transformer 基础---从 RNN、CNN 的局限出发,讲清 tokenizer 与嵌入、自注意力与多头注意力、因果掩码、FFN、层归一化与残差,以及位置编码;二是设计变体---编码器-解码器、BERT、GPT 三种架构,ALiBi 与 RoPE 这类相对位置编码,以及用 MQA/GQA 压缩 KV cache、用 SwiGLU 改写 FFN;三是大语言模型---涌现能力与上下文学习、LLaMA 家族的演进和 Chinchilla 缩放法则;四是进阶话题---Flamingo、PaLM-E、RT-2 等多模态与具身模型,以及稀疏激活的混合专家。今天对这些组件和变体都只是点到为止,后面的讲座会继续展开它们的部署与优化。

结语

第十二讲把 Transformer 从骨到皮拆了一遍。起点是前 Transformer 时代的困境:RNN 用固定大小的隐藏状态充当工作记忆,内存友好,却要在 N 步里把信息一点点传过来,而且顺序依赖让它没法并行;CNN 能并行,但一维卷积核的感受野有限。注意力用一个漂亮的检索类比解决了这两个问题---查询像搜索框、键像标题、值像内容,QK 内积算相似度、除以 d \sqrt{d} d 、softmax、再乘 V,代价是 O(N²);多头让不同的"检索视角"并行,因果掩码则决定生成时谁能看见谁。再配上 D→4D→D 的 FFN、层归一化与残差、位置编码,就是 Attention Is All You Need 的全部骨架---用更少的训练计算量换来更高的 BLEU。

现代大模型基本是在这张骨架上做局部替换。架构上分成编码器-解码器(T5)、仅编码器(BERT 的 15% 掩码加双向注意力)和仅解码器(GPT 的自回归与涌现);位置编码从绝对(简单,但超过 4K 就崩)换成相对---ALiBi 用随距离线性增长的偏置,不同头还有不同斜率,RoPE 则把查询和键按位置旋转,使 q_m·k_n 只依赖 m−n,还能靠位置插值把 LLaMA 的 2K 窗口无痛扩到 32K。最妙的工程优化是 KV cache:没有它,生成第 N 个 token 要重算全部键值,总复杂度 O(N³);有了它,每步只算新的 QKV 并复用缓存,总复杂度降到 O(N²)---但它自己会膨胀,7B 模型每个 token 就要 512 KB,LLaMA 70B 在 batch 16、序列 4K 时更是要 160 GB。于是有了 MQA(只剩一组 KV,1/N)和 GQA(分组共享,通常 1/8,精度接近 MHA);FFN 一侧则换成带门控的 SwiGLU,通道扩到 8/3·D、三层投影仍保持 8d² 的参数量。

最后两节把这些零件装成了真正的大模型。规模一大,能力就"涌现"出来:取模算术、单词打乱这类任务在小模型上接近零分,过了某个阈值却陡然上升;模型够大之后,零样本、少样本和上下文学习取代了逐任务微调---示例越多,大模型涨得越快,甚至不需要任务描述就能从模式里推断意图。LLaMA 是开源路线的分水岭:仅解码器、pre-norm、SwiGLU、RoPE,7B 是 4K 隐藏维、32 头、32 层;LLaMA 2 把上下文拉到 4K、训练 2T token、在 70B 上用 GQA 把 KV cache 压到八分之一;LLaMA 3 再把语料扩到 15T token、FLOPs 是前代 50 倍、旗舰超过 400B;而 Chinchilla 提醒我们,参数量和数据量必须同步放大。进阶部分则展示了这个骨架的可扩展性:Flamingo 用交叉注意力把视觉特征注入冻结的语言模型(Perceiver Resampler 压缩成固定 token,tanh 门控从零开始逐渐放行),PaLM-E 直接把图像和机器人状态变成 token,RT-2 更进一步让视觉语言模型把机器人动作当作输出来生成;MoE 则在 FFN 上做稀疏激活---30B 的模型每个 token 只激活 3B,再用容量因子和路由机制在冗余与利用率之间取舍。回看整讲,Transformer 之所以能撑起如今的一切,也许就在于它的每个部件都可以被单独替换、单独优化---这一讲的每一种变体,都是沿着某个维度把它推向更快、更省或更大的一步。

下一讲,我们将讲解 LLM 量化和部署相关内容 🤗。

参考

相关推荐
EDPJ3 小时前
(2026|中科院自动化所,路由冗余,动态分配的价值在激进剪枝,多模态更脆弱)你只需要选定专家的 2/3:细粒度 MoE LLM 中的动态专家剪枝
transformer·剪枝·moe·混合专家模型
前端.火鸡1 天前
参数量、上下文窗口与模型规格怎么看
人工智能·深度学习·transformer
一只废狗狗狗狗狗狗狗狗狗1 天前
Transformer——一个sequence-to-sequence的model
人工智能·自然语言处理·transformer
QN1幻化引擎2 天前
信号场注意力(SFA):把 KV Cache 变成 O(1) 的双通道注意力——0.1B/0.3B 受控 A/B 精度反升 15.5% / 24.3%
pytorch·深度学习·大模型·transformer·注意力机制·推理优化
奋进小青2 天前
2026年CNN与Transformer融合的创新点思路
人工智能·cnn·transformer
布吉岛的石头3 天前
Java 程序员第 50 阶段2:预训练的目标函数:自回归语言建模本质
java·开发语言·人工智能·深度学习·回归·transformer
EDPJ3 天前
MoE 与推测解码(Speculative Decoding)加速:为什么慢、什么时候慢、怎么让它不慢?
llm·负载均衡·大语言模型·moe·推测解码(sd)
AI-Frontiers3 天前
7 个阶段,27 篇经典论文,一文看懂 Transformer 如何催生现代 LLM
transformer
高洁014 天前
具身智能感知系统底层原理
人工智能·python·深度学习·机器学习·transformer