从 Transformer 到 AFD.
零基础也能看懂。从"Transformer 是什么"讲起,一直讲到为什么要把 Attention 和 FFN 拆到不同的芯片上。
先认识 Transformer
Transformer 是一种神经网络的"结构设计"。今天几乎所有大模型,比如 GPT、Claude、DeepSeek、Qwen、Llama,都建立在它上面。先从最基本的说起。
1神经网络:训练和推理
神经网络说穿了就是两样东西:一大堆可以调整的数字(叫权重,第 8 节细讲),加上一套固定的计算步骤(主要是乘法和加法)。数字从一头进去,经过这些计算,从另一头出来。
它的一生分两个阶段:
训练:给模型看大量例子,让它猜答案;猜错了,就按一定的数学方法(叫"反向传播"和"梯度下降")把权重往正确的方向微调一点。重复无数次后,权重里就"沉淀"出了知识。
推理:训练完成后,权重固定下来,只是拿来用。你每次和 AI 聊天,背后跑的都是推理。AFD 解决的是推理的效率问题,所以本文只讲推理。
2语言模型:只会做一件事,猜下一个词
语言模型(Language Model)的任务出奇地简单:给它一段文字,它告诉你"下一个词"是每个候选词的概率是多少。
所谓大语言模型(LLM,Large Language Model),就是参数特别多(几十亿到上万亿)、用海量文字训练出来的语言模型。它"猜"得足够准,看起来就像在理解和思考。
3为什么是 Transformer:和 RNN 对比
在 Transformer 出现之前,处理文字主要用 RNN(循环神经网络)。它像传话游戏:一个词一个词地读,把"到目前为止的理解"写在一张小纸条上,传给下一步。
2017 年,Google 的一篇论文《Attention Is All You Need》提出了 Transformer。它的核心想法是:不要传话了,让每个词直接去看所有其他的词(这个"看"的动作就是 Attention,第 11 节细讲)。带来两个好处:
一、远距离不丢信息。第 1 个词和第 1000 个词之间也是直接相连的。
二、可以并行计算。所有位置可以同时算,不用排队。这让人们能用成千上万张 GPU 一起训练超大模型,这是大模型时代能到来的关键。
4Transformer 的三种形态与整体结构
原始的 Transformer 是为翻译设计的,分成两半:编码器(Encoder)负责读懂原文,解码器(Decoder)负责一个词一个词地写出译文。后来人们发现,只用其中一半也很好用:
本文说的 Transformer,指的都是只有解码器(Decoder-only)的形态。下面这张图是它从头到尾的完整流程,也是整份讲解的地图。每个方框旁边标了在哪一节细讲:
文字怎么变成数字
计算机只会算数字。所以第一步,是把一句话变成一堆数字。
5Token(词元):把句子切成小块
模型不是一个字一个字、也不是一个词一个词地读,而是用一个叫分词器(Tokenizer)的工具,把文字切成它"认识"的小块,每块叫一个 token。
每个 token 在模型的"字典"里都有一个编号。这本字典叫词表(Vocabulary),通常有几万到十几万个条目。
6向量和 Embedding:给每个 token 一份"档案"
光有编号不够。编号 872 和 873 挨着,不代表意思相近。所以模型会把每个编号换成一串数字,这串数字叫向量(Vector)。
这一步叫 Embedding(嵌入)。做法很简单:模型里有一张大表,每个 token 占一行,按编号查表,把那一行取出来就行。
这张表的数字不是人写的,是训练出来的。训练的结果是:意思相近的词,向量也相近。如果把向量画成空间里的点,大概是这样:
7隐藏维度:档案有多少个栏位
一个向量里有多少个数字,就叫隐藏维度(hidden dimension),常写作 d。小模型 d 大约 2048~4096,大模型可以到 7168、8192 甚至更多。
为什么这个数重要?因为每个数字都要占内存。如果用常见的 BF16 格式,每个数字占 2 字节,那么一个 token 的向量就是 4096 × 2 = 8 KB。后面算 KV Cache 有多大时,就要用到这个数。
模型本体是什么
一个大模型,本质上就是"一大堆固定的数字"加上"用这些数字做乘法的规则"。
8参数 / 权重:模型的"知识"
训练结束后,模型里有一大堆数字被固定下来,这些数字叫参数(parameters),也叫权重(weights)。"70B 模型"的意思就是有 700 亿个参数。B 是 billion,十亿。
推理(也就是用模型回答问题)时,权重一个都不改,只是拿来用。但它们全都得放在芯片能快速访问的内存里,这就带来第一个硬件问题:放不放得下。
9矩阵乘法:模型里 90% 以上的计算
权重通常排成一张二维的表,叫矩阵。模型最主要的动作,就是拿一个向量去乘一个矩阵,得到一个新的向量。你可以把它理解成"按一套固定配方,把输入的数字重新调配一遍"。
真实模型里,向量有 4096 个数,矩阵是 4096×4096。一个 token 乘一次这样的矩阵,就要 4096 × 4096 × 2 ≈ 3300 万次运算,同时还要从内存里读出 4096 × 4096 × 2 字节 ≈ 32 MB 的权重。
10层:一层一层地加深理解
Transformer 模型由几十个结构相同的层(layer)叠起来,比如 32 层、61 层、80 层。token 的向量从最底层进去,每过一层被"加工"一次,最后从顶层出来,变成"下一个 token 是什么"的概率。
每一层里有四样东西:
Attention:让这个 token 去看看句子里的其他 token,收集上下文信息。第 3 部分详细讲。
FFN(前馈网络):每个 token 自己单独"消化思考",不看别人。第 5 部分详细讲。
归一化(Norm):把数字的大小调整到一个合适的范围,防止越算越大或越算越小。计算量很小,可以忽略。
残差(Residual):图里的虚线。把"加工前"的向量直接加到"加工后"的结果上。好处是每一层只需要学"在原来基础上改一点",而不是推倒重来,几十层叠起来也不会把信息丢光。
Attention:词与词互相参考
"他把苹果吃了,它很甜。"读到"它"时,你知道它指的是苹果。模型靠 Attention 做到这一点。
11Q、K、V:每个 token 准备三样东西
每个 token 的向量,会分别乘上三张不同的权重矩阵(就是第 9 节的矩阵乘法),变出三个新向量:
图书馆比喻:你带着一张写着需求的纸条(Q)去图书馆。每本书的书脊上贴着标签(K),书里面是内容(V)。你拿纸条去对比每本书的标签,越匹配的书,你就越多地参考它的内容。
12打分、Softmax、加权混合
以"它"为例,Attention 分三步:
第一步:打分。用"它"的 Q,和前面每个 token 的 K 做"点积"(逐个相乘再相加,和第 9 节一样)。越相关,分数越高。
第二步:Softmax。把分数变成加起来等于 100% 的百分比。做法是先对每个分数取 e 的幂次(让高分更突出、负分也变成正数),再除以总和。
第三步:加权混合。按这些百分比,把各个 token 的 V 混合起来,结果就是"它"在这句话里的新含义。
13为什么要分成 Q、K、V 三个?
同一个词,在 Attention 里要同时扮演三种角色:它要提问(我需要什么信息),要被别人找到(我是什么),还要交出内容(被选中时给什么)。一份向量很难同时把三件事都做好,所以用三张不同的矩阵 W_Q、W_K、W_V,从同一个词里"提炼"出三个不同用途的向量。可以把这三张矩阵想成三副不同的眼镜。
最容易混淆的是 K 和 V:它们都来自"被看的那个词",为什么要分开?看搜索引擎就明白了:
14亲手算一遍:用两个数字的小向量
真实模型里每个头的 Q、K、V 各有 128 个数字,而且每个数字的含义人类看不懂。为了看清楚原理,我们把向量缩小到只有 2 个数,并且人为规定它们的含义:
K 的两个数:第 1 个表示"我像不像一个物品",第 2 个表示"我像不像一个人"。
V 的两个数:第 1 个是"水果的含义",第 2 个是"人物的含义"。
接下来的 Softmax 和加权混合,用下面的计算器一步步看。先点"它",再点"吃",对比一下:K 和 V 完全没变,只是换了一个 Q,结果就完全不同。这说明"去看谁"是由提问的那个词(Q)决定的。
真实模型和这个小例子只有三点不同:向量是 128 维而不是 2 维;打分后会先除以 √128 ≈ 11.3,防止分数太大、Softmax 变得过于极端;每个数字的含义是训练自己学出来的,不是人规定的。步骤完全一样。
15不同的词,问不同的问题
同一句话里,每个词都会用自己的 Q 去提问,问题各不相同,所以它们关注的对象也不一样。点下面的词,看看它在"问什么"、最后"看向了谁":
三个观察:
一、灰色虚线的词"看不到",因为它们在提问词的后面(第 18 节的因果掩码)。
二、同一个"苹果",被"吃"找到是因为它的 K 写着"能被吃",被"它"找到是因为它的 K 写着"是一个物品"。一份 K 可以回应很多种问题。
三、一个词其实不止问一个问题。"吃"既想知道谁在吃,也想知道吃的是什么。真实模型用多个"头"来同时问多个问题,下一节就讲这个。
(这里的比例是为了讲解而设定的示意值。真实模型里,每个头学到的"问题"更抽象,不一定能用一句话说清。)
16多头注意力与 GQA
多头注意力(Multi-Head Attention,MHA):一句话里需要关注的关系不止一种。"它"指代谁是一种关系,"甜"在形容谁是另一种。所以模型会把向量切成好几份,每份叫一个头(head),各自独立做一遍 Attention,各看各的关系,最后再拼起来。比如 32 个头,每个头 128 维,32 × 128 = 4096。
GQA(分组查询注意力):后来人们发现,K 和 V 不需要每个头都有一份,几个 Q 头可以共用同一组 K、V。这样要存和要读的 K、V 就少了好几倍。现在大多数模型都用 GQA 或类似的压缩办法(DeepSeek 用的 MLA 也是同一个目的)。
17位置编码:告诉模型谁在前、谁在后
Attention 有个天生的毛病:它只看"有哪些词、彼此有多相关",不知道词的顺序。对它来说,下面两句话是一模一样的一堆词:
解决办法是在 Q 和 K 里"掺进"位置信息,这叫位置编码(Positional Encoding)。最早的做法是给每个位置准备一个固定的向量,直接加到 token 向量上。
现在主流的做法是 RoPE(旋转位置编码):把 Q 和 K 向量按它所在的位置"旋转"一个角度,越靠后转得越多。两个词做点积打分时,结果就只和它们相隔多远有关。就像两根钟表指针,你看它们之间的夹角,就知道隔了几格。
位置编码的计算量很小,对硬件来说几乎可以忽略,但它决定了模型能不能分清语序。
18因果掩码:只能往前看,不能偷看后面
在生成文字时,后面的词还没写出来,当然看不到。为了让训练和使用时的规则一致,Decoder 规定:每个词只能看自己和前面的词。实现方法是给 Attention 的打分表盖上一块"遮罩",把右上角全部挡住,这叫因果掩码(Causal Mask)。
顺带区分两个名字:自注意力(Self-Attention)是一段文字内部的词互相看,本文讲的都是这种;交叉注意力(Cross-Attention)是解码器去看编码器的结果,只出现在"编码器 + 解码器"的形态里(比如翻译模型)。
模型怎么一个字一个字地写
这一部分会引出整篇最重要的概念:KV Cache。
19输出层与采样:从一串数字变回一个词
穿过最后一层后,我们手里只有一个 4096 维的向量。怎么把它变成"下一个词"?
输出层(LM Head):一个大矩阵,形状是"隐藏维度 × 词表大小"。向量乘上它,就得到词表里每个词一个分数,这些分数叫 logits。
Softmax:和第 12 节一样,把分数变成加起来是 100% 的概率。
采样(Sampling):按概率挑出一个词。最简单的做法是永远挑概率最高的(叫贪心)。但这样回答会很死板,所以通常会引入一些随机性,并用两个旋钮来调:
温度(Temperature):温度低,高分的词会更占优势,回答稳定、保守;温度高,概率被拉平,冷门词也有机会,回答更有创意,也更容易跑偏。
Top-p:只在"累计概率达到 p(比如 90%)的那几个最可能的词"里挑,直接排除长尾的怪词。
20自回归:一次只生成一个 token
模型每完整跑一遍(从第 1 层到第 N 层),只能得到一个新 token。然后把这个新 token 接到末尾,再跑一遍,得到下一个。这种"用自己的输出当下一次输入"的方式叫自回归(Autoregressive)。
所以,写一段 500 个 token 的回答,模型就要从头到尾跑 500 遍。这也是为什么大模型的回答是一个字一个字"蹦"出来的。
21Prefill 和 Decode:两个阶段
一次对话请求分成两个阶段:
Prefill:几千个 token 一起算,权重读一次就能给几千个 token 用,芯片的计算单元很忙,效率高。
Decode:每一步只有 1 个新 token,却要把整个模型的权重、以及前面所有 token 的 K/V 都读一遍。读了很多,算得很少,计算单元大部分时间在等数据。
22KV Cache:用空间换时间
回忆第 12 节:生成第 n 个 token 时,要用到前面所有 token 的 K 和 V。如果每一步都重新算一遍前面所有 token 的 K、V,就太浪费了。
好在一个 token 的 K 和 V 一旦算出来就永远不会变。所以办法很简单:算一次,存起来,以后直接读。存它们的地方就叫 KV Cache(KV 缓存)。
代价是:KV Cache 非常占内存。要存的量是:
KV Cache = 2(K 和 V)× 层数 × KV 维度 × token 数 × 每个数字的字节数 × 用户数
1. KV Cache 常常比模型权重本身还大。
2. 每个用户的 KV Cache 是私有的,A 的对话记录对 B 毫无用处。第 25 节会讲,这一点决定了 Attention 的性能瓶颈。
23回头再看 Q、K、V:在每个场景里各干什么
学完 Prefill、Decode 和 KV Cache,再回头看 Q、K、V,就能看清它们在不同场景里的"命运"完全不同。
为什么只缓存 K、V,不缓存 Q?因为一个词的 Q 只在"轮到它自己提问"的那一刻用一次。而它的 K 和 V 会被后面每一个新词拿来查询,生成 500 个词就要被查 500 次,所以值得存起来。
把各个场景放在一起对比:
| 场景 | Q 从哪来 | K、V 从哪来 | 值得注意的地方 |
|---|---|---|---|
| 训练 / Prefill | 每个 token 都算一个 | 每个 token 都算一份 | 所有位置同时算,计算量大;K、V 存进缓存 |
| Decode | 只有新 token 的 1 个 | 新算 1 份 + 读出所有旧的 | 算得少、读得多,这就是 Attention 内存受限的根源 |
| 多头注意力 | 每个头一个 | 每个头一份 | 每个头问不同的问题(第 16 节) |
| GQA | 每个头一个 | 几个头共用一份 | KV Cache 变小,读一次 KV 给几个头用 |
| 交叉注意力(翻译) | 正在写的译文 | 原文 | 只在编码器 + 解码器结构里出现,见下图 |
| AFD 部署 | 在 Attention 机器上算 | 存在 Attention 机器上 | Q、K、V 和 KV Cache 都不离开 Attention 机器,送去 FFN 机器的只有 Attention 的输出 |
24上下文窗口:模型一次能“记住”多长
模型一次能处理的最长 token 数,叫上下文窗口(Context Window),也叫上下文长度。你的问题、上传的文档、之前的对话、模型自己写的回答,全部都要装在这个窗口里。现在常见的是 128K 个 token,大约相当于十万汉字;有的模型能到 100 万。
为什么不能无限长?看看长度翻倍时会发生什么:
所以上下文越长,Attention 越吃内存,而 FFN 的工作量和上下文长度无关,每个 token 都一样。长上下文让 Attention 和 FFN 的需求差距变得更大,这也是 AFD 越来越受重视的原因之一。
同时服务很多人
一台推理服务器不会只服务一个人。把很多人的请求一起处理,是省钱的关键。
25Batch:打包一起算
把多个用户的请求凑在一起同时计算,叫批处理(batching),凑在一起的人数叫 batch size。Decode 阶段每个用户每步出 1 个 token,所以 batch size = 16,就是一步同时算 16 个 token。
对 FFN:权重是所有人共用的。从内存读一次权重,可以同时给 batch 里的所有 token 用。batch 从 1 变成 100,读的量不变,干的活多了 100 倍。batch 越大越划算。
对 Attention(具体说是 Q 和 KV Cache 做运算的那部分):每个人只能读自己的 KV Cache。batch 从 1 变成 100,要读的量也变成 100 倍。batch 再大也不会更划算。
26FFN:每个 token 自己"消化"
FFN(Feed-Forward Network,前馈网络)的结构是:先把向量放大到更宽(通常 3~4 倍),经过一个非线性的"激活函数",再缩回原来的宽度。
FFN 的权重矩阵很大。一般来说,模型约 三分之二的参数在 FFN 里,模型学到的"知识"也主要存在这里。可以这样分工:Attention 负责收集信息,FFN 负责思考加工。
FFN 里每个 token 都是独立计算的,不需要看别人,也不需要 KV Cache。这让它很适合拆出去单独放。
27MoE:很多个小专家
MoE(Mixture of Experts,混合专家)把一个大 FFN 换成很多个小 FFN,每个叫一个专家(Expert)。每个 token 来了,由一个小小的路由器(Router)决定它该去找哪几个专家,只挑分数最高的 k 个,这叫 Top-k。
好处:模型总参数可以非常大(知识多),但每个 token 实际只用一小部分专家,计算量小,速度快。例如 DeepSeek-V3 总共 6710 亿参数,每个 token 只激活约 370 亿。
坏处:batch 被"摊薄"了。假设一步有 256 个 token,有 256 个专家,每个 token 选 8 个,那么平均每个专家只分到 256 × 8 ÷ 256 = 8 个 token。对专家来说,batch 只有 8,又回到了"读一次权重只给几个人用"的低效状态。
芯片的视角
前面讲的是模型"要做什么"。这部分讲芯片"做得怎么样",以及卡在哪里。
28GPU、显存、带宽、算力
一颗 AI 芯片(以 NVIDIA H100 为例)可以简化成两部分:存数据的地方和算数据的地方,中间连着一条"路"。
显存(HBM):芯片旁边的高速内存,放模型权重和 KV Cache。它有两个指标:容量(能放多少,比如 80 GB)和带宽(每秒能搬多少到计算核心,比如 3.35 TB/s)。
算力(FLOPS):计算核心每秒能做多少次运算。H100 做 BF16 矩阵乘法大约是每秒 989 万亿次(989 TFLOPS)。
厨房比喻:显存是仓库,带宽是仓库到厨房的传送带,算力是厨师的手速。厨师再快,传送带送不来菜,也只能干等。
29算术强度:读一次,用几次
算一下 H100 的"胃口":989 万亿次运算 ÷ 3.35 万亿字节 ≈ 295。意思是:每从显存读 1 个字节,至少要做约 295 次运算,厨师才不会闲着。
一个任务"每读 1 字节做多少次运算",就叫它的算术强度(Arithmetic Intensity)。
为什么 FFN 的算术强度 ≈ batch 大小?一个 d×m 的权重矩阵,读它要 d×m×2 字节。给 B 个 token 各乘一遍,要做 2×B×d×m 次运算。两者一除,正好是 B。
为什么 Attention 的强度 ≈ 1?读一个 K 值(2 字节),只和 Q 做一次乘加(2 次运算);V 也一样。没有任何复用,所以强度约为 1。GQA 让几个头共用一份 KV,强度就提高到共用的头数(比如 4 或 8),但离 295 还差很远。
30Roofline:一张图看出卡在哪
Roofline(屋顶线模型)把上面的道理画成一张图。横轴是算术强度,纵轴是实际能跑出的速度。斜的那段是"被带宽限制",平的那段是"被算力限制",形状像屋顶,所以叫屋顶线。
这张图告诉我们:Attention 不管 batch 多大都钉在左下角,它需要的是带宽和容量;FFN 只要 batch 够大就能爬上屋顶,它需要的是凑够足够多的 token。
AFD:把两块拆开
有了前面所有的概念,AFD 就很好懂了。
31放在一起时的矛盾
传统做法是 Attention 和 FFN 在同一张 GPU 上跑。问题来了:
FFN 想要大 batch,但 batch 的上限是被同一张卡上的 KV Cache 容量卡住的。结果就是:花大价钱买的算力,绝大部分在闲置。如果是 MoE,每个专家分到的 token 更少,浪费更严重。
32AFD 的做法:两种机器,各干各的
AFD(Attention-FFN Disaggregation,注意力与前馈分离):把 Attention 和 FFN 放到不同的 GPU上。
Attention 机器:存 KV Cache,做 Attention 计算。它需要显存大、带宽高,算力弱一点没关系。可以选更便宜、显存更大的卡。
FFN 机器:只放 FFN(或 MoE 专家)的权重,不存 KV Cache。好几台 Attention 机器的 token 汇集过来,batch 变大,算力终于能用起来。它需要算力强。
这样一来,两边可以独立扩容:上下文变长了,就多加 Attention 机器;模型变大了,就多加 FFN 机器。甚至可以用不同型号的芯片。
33代价:来回通信,以及流水线
拆开以后,每一层都要在两种机器之间传两次数据(去一次、回一次)。一个 token 的 hidden 向量如果是 7168 维、BF16,就是约 14 KB;乘上 batch 和几十层,通信量很可观,而且它挡在计算的必经之路上。
解决办法是流水线(pipelining),也叫 ping-pong:把一批 token 切成两个"小批"(micro-batch),让两边轮流干活。小批 1 在 FFN 机器上算的时候,Attention 机器正在算小批 2,谁都不闲着。
流水线要顺畅,需要满足两个条件:两边每段的耗时差不多(所以要调 M:N 的比例),而且通信时间比计算时间短(所以需要很快的芯片间互连,比如 NVLink 或高速网络,以及专门优化过的通信库)。
34AFD 和 PD 分离有什么不同
你可能还会听到 PD 分离(Prefill-Decode Disaggregation)。两者都是"拆",但拆的方向不一样:
PD 分离:Prefill 是计算受限,Decode 是内存受限,所以把两个阶段放到不同的机器上。
AFD:即使都在 Decode 阶段,Attention 和 FFN 的瓶颈也不一样,所以再按模型结构拆一次。字节跳动的 MegaScale-Infer、阶跃星辰的 Step-3 推理系统都采用了这种思路。
术语速查表
| 术语 | 一句话解释 | 节 |
|---|---|---|
| 神经网络 | 一大堆可调的数字 + 固定的计算步骤 | 1 |
| 训练 / 推理 | 调整权重让模型变聪明 / 权重固定,拿来回答问题 | 1 |
| 语言模型 / LLM | 根据前文猜下一个词的模型;参数巨大的就叫大语言模型 | 2 |
| RNN | 旧式结构,一个词一个词按顺序传话,慢且易遗忘 | 3 |
| Transformer | 2017 年提出的结构,每个词通过 Attention 直接看所有词,可并行 | 3 |
| Encoder / Decoder | 负责读懂的编码器 / 负责逐词生成的解码器;大模型多为 Decoder-only | 4 |
| Token | 模型处理文字的最小单位,约一个汉字 | 5 |
| 向量 / Embedding | 代表一个 token 的一串数字;把 token 换成向量的查表过程 | 6 |
| 隐藏维度 d | 向量里有多少个数字,如 4096 | 7 |
| 参数 / 权重 | 训练好的固定数字,模型的知识;70B = 700 亿个 | 8 |
| 矩阵乘法 | 用一张权重表把向量变换成新向量,占绝大部分计算 | 9 |
| FLOP | 一次浮点运算;一次乘加算 2 FLOP | 9 |
| 层 Layer | 重复几十次的基本单元,每层 = Attention + FFN | 10 |
| 残差 / Norm | 把输入直接加回输出 / 把数字大小调到合适范围 | 10 |
| Q / K / V | 查询 / 标签 / 内容,Attention 用来匹配和取信息 | 11 |
| 点积 | 两个向量逐个相乘再相加;方向越一致,结果越大 | 14 |
| Softmax | 把打分变成加起来为 100% 的比例 | 12 |
| 多头 / GQA | 多组独立的 Attention / 多个 Q 头共用一组 KV,省内存 | 16 |
| 位置编码 / RoPE | 让模型知道词的顺序 / 按位置旋转 Q、K 的主流做法 | 17 |
| 因果掩码 | 每个词只能看自己和前面的词 | 18 |
| 自注意力 / 交叉注意力 | 同一段文字内部互看 / 解码器看编码器的结果 | 18 |
| 输出层 / Logits | 把最后的向量变成词表里每个词的分数 | 19 |
| 采样 / 温度 / Top-p | 按概率挑词 / 调随机程度 / 只在最可能的几个词里挑 | 19 |
| 自回归 | 一次生成一个 token,再接到末尾继续生成 | 20 |
| Prefill / Decode | 一次读完问题(算力受限)/ 逐个吐出回答(内存受限) | 21 |
| KV Cache | 存下已算过的 K、V,避免重算;每人私有,很占显存 | 22 |
| 上下文窗口 | 一次能处理的最长 token 数,如 128K | 24 |
| Batch | 把多个请求打包一起算 | 25 |
| FFN | 每个 token 独立的"放大-激活-缩回"计算,存着大部分知识 | 26 |
| MoE / 专家 / 路由器 / Top-k | FFN 拆成很多小专家,路由器为每个 token 挑 k 个 | 27 |
| HBM / 显存 | 芯片旁的高速内存,放权重和 KV Cache | 28 |
| 带宽 | 每秒能从显存搬多少数据到计算核心 | 28 |
| 算力 FLOPS | 每秒能做多少次运算 | 28 |
| 算术强度 | 每读 1 字节做多少次运算 | 29 |
| 内存受限 / 计算受限 | 卡在搬数据 / 卡在算数据 | 29 |
| Roofline | 用"屋顶"形状的图判断任务卡在哪 | 30 |
| AFD | 把 Attention 和 FFN 放到不同机器上分别运行 | 32 |
| M:N 比例 | Attention 机器和 FFN 机器的数量配比 | 32 |
| Micro-batch / Ping-pong | 把一批切成小批轮流跑,用计算掩盖通信 | 33 |
| PD 分离 | 把 Prefill 和 Decode 放到不同机器上 | 34 |
文中的硬件数字以 NVIDIA H100 SXM(BF16)为参考,模型数字为常见量级的示意,便于理解,不代表某个具体产品的精确规格。