夜雨聆风学习资料网

ARTICLE · 1097594

AI推理的计算与数据传输:将 MoE 模型映射至推理硬件(1)

AI推理的计算与数据传输:将 MoE 模型映射至推理硬件(1)

semianalysis20260921

【引言】

混合专家(Mixture of Experts, MoE)架构现已广泛应用于前沿模型中,它不仅改变了推理服务的结构,也重塑了实用推理的经济学。MoE 的意义远不止于增加参数总量,它还改变了每个 Token 激活哪些张量、哪些张量必须保持紧密相邻、哪些传输需要强大的本地带宽、哪些传输可以容忍较弱的网络链路,以及内存传输、存储和调度如何共同促进有效吞吐量的提升。

了解这一体系的最佳起点是服务整体。推理运行在一个由协调层(如 NVIDIA Dynamo、Mooncake 或自定义调度器)统筹的集群内部。这些协调层与 vLLM 或 SGLang 等推理服务器密切配合,而这些推理服务器本身也具备自身的协调功能。本文不会深入探讨如何使用这些协调软件或应该选择哪一种,而是旨在对整个流程进行概述,并解释各种特性的背后原因。

用户(或其 Agent)通过一个请求(Query)开启对话,在得到解答后,对话可能会通过更多请求继续进行。这种“请求-回答”的过程被称为一个“轮次”(Turn)。在现代 AI 系统中,用户通常运行在一个客户端应用中(无论是图形界面还是命令行界面),AI 返回的一些回答会被该应用拦截并作为指令执行,例如编辑代码或在 HR 问题中查询公司指南。

AI 系统也可以从其数据中心自行执行其中一些操作,例如进行联网搜索。这些被拦截的工具操作所产生的结果也会作为请求返回给 AI,从而创建更多轮次。服务器会保留一个上下文(通常称为 KV 缓存,或直接简称为 Cache),它是对会话内容的提炼,使得无论是来自用户还是工具的新请求,都能被正确解读以推动整体进展。当用户启动一个 Agent 来执行长周期任务时,每小时可能会产生数千个轮次。对话也可以暂停,并在数小时甚至数天后恢复。

当请求到达推理服务器时,协调层会将其放入队列中。队列中的请求会与系统提示词(System Prompt)以及对话中先前轮次的上下文一起,被喂给“输入填充”(Input-fill)工作节点(Worker)。随后,该查询会被转换为追加到对话中的新上下文。接着,这一新的上下文状态会被传输到“解码”(Decode)工作节点。解码节点重复读取累积的状态并生成回答 Token,这些生成的 Token 也会被追加到对话状态中。该过程可能会在工具、Agent、用户和进一步的输入填充工作之间循环往复。运行在 GPU 上的模型工作节点只是这个“Token 工厂”的一部分,存储、网络和协调层将各个阶段紧密连接在一起。

在工作节点内部,有四种运行模式(Operating Regime)从一开始就值得区分:

  1. 预填充(Prefill):在此模式下,初始的新 Token 块被集中处理。

  2. 中填充(Midfill):在此模式下,续接请求被追加到已有的缓存上下文中。

  3. 解码注意力(Decode attention):在此模式下,利用上下文来生成新生成 Token 的基础表达。

  4. 解码专家(Decode experts):在此模式下,每一个新的基础 Token 会通过从庞大的专家总集中精选出的一组专家进行细化。

这些模式对计算、内存和网络提出了截然不同的需求。预填充与中填充密切相关,预填充可以看作是先前上下文为零的特殊中填充。然而,预填充是一个常见的特例,对应于传统“聊天机器人”这种单次查询的场景,其优化方式可以与中填充略有不同。预填充能够达到极高的算术强度(计算量与数据传输量的比值),且无需等待定位和读取上下文。中填充则始于先前状态的已有 KV 缓存,并追加一个新的请求输入序列。相比预填充,中填充的算术强度通常更为适中,因为其新 Token 数量较少,而每个 Token 需要传输的已有数据量较大。

解码注意力和解码专家的计算通常具有较低的算术强度,因为与先前的上下文或专家权重相比,新 Token 的数量极少,而在解码阶段,这些上下文和专家权重都是需要传输的数据。同时,在所有模式中,无论 Token 的具体数值如何,用于注意力和专家的张量都是相同的。因此,只要能将足够多的 Token 组队排队来复用单次张量读取,就能带来显著收益——即便这些 Token 来自其他用户完全无关的并行请求,只要它们在网络上足够贴近以实现共享即可。如果将这四种模式混为一谈,就会丧失 MoE 模型在不同算术强度和不同共享模式下所提供的结构性优势。

在本文中,我们将分别讨论这 4 个阶段,并有时假设它们是解耦/分离(Disaggregated)的。在“聚合”(Aggregated,模型保留在一台服务器上,并随着请求在不同阶段推进而重新配置)与“解耦”(协调层在另一台已经配置妥当的机器上寻找空闲槽位)之间存在权衡。通常我们将这些阶段视为解耦的,而聚合则是前一阶段结束时始终使当前节点可用的一个特例。在后文中全面介绍完各项工作后,我们将设专门章节讨论这些权衡。

Transformer 模型是一个由重复层组(Layer Group)构成的深层堆栈。一个层组可以包含同一种类型的层,也可以包含一个全注意力(Full-attention)层与若干线性、局部、选择性或其他经过优化的注意力层(即混合层组)。在每个层内部,注意力、共享变换、路由、选定专家以及重组按顺序依次发生。这些步骤是预先确定的并不断重复,从而允许相同的硬件资源在不同时刻服务于流程的不同部分。

类似地,机器也可以用简单的重复单元来描述。节点(Node)是一组加速卡(通常是机架中的一个托盘/Tray),每个加速卡将计算单元与本地高速内存配对。节点由 CPU 协调,并通过网卡(NIC)连接到其他节点。节点堆叠成机架(Rack)。当张量非常巨大时,一个机架可以作为一个 Scale-up(垂直扩展)域,或者划分为多个较小的 Scale-up 岛,抑或作为一组流水线阶段。然后,数据中心网络将受限的工作节点与存储和协调层连接起来,而不是直接参与每一次内部张量运算。

本文将遵循这一递进顺序。首先介绍全局服务和运行模式,然后将模型展开为宽广的层组切片,并将其映射到加速器节点和机架上。在此基础上,进一步展开流水线并行、张量并行和专家并行;KV 缓存内存所带来的限制;批处理(Batching)在预填充、中填充和解码中的不同价值;以及调度在多机架 Token 工厂中的作用。


1. 协调层通过队列向工作节点池分发请求

推理服务是一个集群,当处于空闲状态时,先前的请求和不可变状态会被存储起来;当新请求引入上下文或先前请求重新激活以继续时,它们会被排队分发给专门的工作节点。传入的队列此时还不是一个“批次”(Batch)。每个请求都包含 Prompt Token、可复用上下文的引用、服务目标,以及通常包含的已有对话或 Agent 状态。协调器可以将其放入预填充、中填充或解码批次中,并且随着请求的完成,它可以独立加入或离开该批次,从而将这部分产能释放给新工作。当调度器清楚哪些工作节点拥有与请求的上下文长度和服务目标相匹配的槽位时,连续批处理(Continuous batching)的效果最好。

预填充工作节点从大量的新 Token 块中创建上下文。它们的输出是针对每个模型层的全新 KV 状态,这些状态的存储相互独立,并不绑定于创建它们的那个工作节点。KV 状态沿着模型层流动,上一轮次中层 $K$ 的输出会成为下一轮次中层 $K$ 的输入。在流水线化的服务器中,这会在独立的网卡(NIC)之间形成自然的输入输出“BT 式种源传输”(Torrenting)。

中填充工作节点用于扩展先前已处理的上下文。缓存的前缀可能包含系统和用户提示词、记忆、更早的对话轮次、Agent 步骤或检索到的文档。庞大的根上下文可能已经被缓存,而增量输入可能比类似的未缓存请求小得多:一个 50 万 Token 的上下文可能只需接收几百或几千个新 Token。

解码工作节点接收已处理且累积的上下文,并在每次 pass 中生成一个或几个 Token(多 Token 预测/MTP 正在变得十分普遍)。每个生成的 Token 都会增加一小部分新状态。当用户、工具或 Agent 贡献另一块输入时,相同的上下文稍后可以重新返回到中填充工作节点。使用工具的 Agent 任务会产生“上下文扩展与生成”的反复循环,而不仅仅是一次预填充紧接着一次解码。

一个工作节点可以占用一个节点、一个托盘或一个机架。服务通过运行许多受限的工作节点并在它们之间移动请求和状态来扩展规模。根据精度和运行状态要求,即便是数万亿参数的模型也可以容纳在现代机架级系统的总内存中。数据中心网络依然至关重要,因为“ Token 工厂”必须将许多此类工作节点连接到共享存储,并持续将工作节点配置与需求相匹配。KV 传输的大小可能达到数 GB,但它们可以通过多条链路和目标节点进行分片(Striped)或种源式传输;它们的传输时间可以远低于长解码任务的生命周期。

这种解耦对性能和运维都大有裨益。一旦已知缓存前缀大小、新 Token 数量和工作节点配置,预填充和中填充的性能就是可预测的。解码的完成时间则是随机的,因为无法预先确定最终输出 Token 的到达时间。各工作节点池之间共享内存和存储,使得每个阶段都能以自己的节奏运行。本文后续章节将讨论队列、就绪缓冲区(Ready buffer)和工作节点重配置。目前最核心的一点是:服务是一个由可移动状态连接起来的阶段循环。

AgentX 示例

这是通过 SemiAnalysis 对话浏览器(Conversation Explorer)查看的效果。它表明,在对话过程中,上下文的增长可能非常迅速,但也会因为上下文压缩(Compaction)和其他模型行为而产生巨大的波动,这些行为在公开讨论中可能并未得到完全解释。推理上下文的协调管理是 AI 公司的核心竞争优势。

我们可以采用完全相同的数据集,并提取出在每个轮次中看到的缓存、新输入和结果长度值。该图展示了 Token 工厂需要如何服务于许多不同的工作负载。原则上,图中每个点所代表的请求(以及来自其他工作负载数据集的更多点)可能在同一时间运行,并被分配到 AI 集群中的某个工作节点上。本文旨在概括推理中使其成为可能的一些主要功能。


2. KV 状态作为不可变二进制大对象(Blob)流动

在数据中心规模下,可复用的上下文会成为共享对象存储中的不可变 Blob,而不是附加在单台机器上的文件。系统提示词、项目上下文、先前的用户轮次、工具输出和生成的 Token 可以存在于独立的 Blob 中。新操作读取所需的 Blob 并追加新 Blob;已有的 Blob 通常保持不变。这种单向追加的结构遵循了因果 Transformer(Causal Transformer)本身的特性。修改可以通过回溯并创建新分支来处理,而不是重写公共路径。

这些 Blob 的持久化来源是一个高速、并行、可横向扩展的内存与存储池。它需要具备足够的总带宽和网络覆盖范围,以便能够根据适用性和可用性来选择预填充、中填充和解码工作节点,而不是因为某台机器独占了上下文的唯一副本。新近空闲的 Blob 可以首先移动到共享的网络附加 DRAM 中,包括节点 CPU 内存和专用内存设备。随着该层级的填满,分类器可以丢弃不太可能被复用的 Blob,或者将寿命更长的状态提升到 SSD。底层文本和引用通常比展开后的 KV 表达形式小几个数量级,因此如果精简策略决定复用空间并丢弃了展开的嵌入状态,从较小的文本重新构建 KV Blob 是可行的。AI 计算可能会有微小的差异,因此尽管重建的状态预计是一个有效的上下文,但不同服务对于丢弃和重建的随意程度,以及对于保持重要不可变状态的努力程度,可能会采取不同的策略。

对于累积达到最大上下文的长运行 Agent,也会频繁发生状态压缩,因此通常在压缩之后,会有许多先前的 Blob 被废弃,取而代之的是新的上下文。压缩前上下文所占用的空间可能会被回收用于新工作。

可以看到,随着上下文接近每个模型的实用上下文极限(Opus 4.8 为 250k Token,Fable 为 1MT),这些对话的右半部分发生了压缩。两条线中还有一些瞬态的“钟乳石”状下钻,这反映了 Anthropic 模型中的某些专有行为。

加速器 HBM 是“热”工作层。它的成本太高且供应受限,不适合作为被动上下文存储的默认选择。活跃的前缀和后缀应该在紧邻使用前进入 HBM,并在工作节点使用完毕后迅速离开。CPU DRAM 是一个非常有用的暂存和组装层,特别是对于传出的状态:已完成的工作节点可以将新生成的 Blob 移动到 CPU 内存中,同时由存储系统选择放置位置和冗余策略,之后 NIC 将它们发送到共享池中。

对于传入的数据,支持 RDMA 的系统可以允许网络将数据直接放置到加速器内存中,从而避免通过 CPU DRAM 进行完整复制。CPU 内存对于元数据、协调、部分组装、后备路径、副本和传出暂存仍然非常有用。当一个工作节点使用多个 GPU 时,传入的上下文可以直接并行分片到它们的目标内存中。

机架级热 Blob 缓存也很有用,无论作为内存/存储设备实现,还是利用分配给分布式存储池的 CPU 内存。非常通用的对象(如系统提示词)是天然的候选者。这些缓存应该保持为共享的横向扩展资源,而不是将请求绑定到单台解码机器的私有状态。HBM 比 DDR 贵数倍且供应更为紧张。HBM 的最佳用途是存储当前正在产生收益的活跃批次数据。

数据输入通常大于输出。中填充通常读取较长的前缀并追加一个有意义但较小的后缀。解码读取累积的上下文,仅追加一个或几个生成 Token 的状态。读取是重复进行的,而写入通常只发生一次。系统设计应当通过各数据路径的宽度直接体现这些差异。


3. 预填充、中填充和解码构成了不同的运行模式

全局服务包含几种计算模式。它们的差异比“计算密集型”(Compute-bound)和“内存密集型”(Memory-bound)这种通用标签更有价值,因为每种模式都有不同的复用机会和不同的硬件天然映射方式。

3.1 预填充(Prefill)

经典的预填充始于很少或没有可复用的 KV 状态,并处理一个庞大的新 Token 块。这些 Token 共享权重加载,高效地使用矩阵运算,并产生足够多的路由激活值来形成有用的共享专家批次(Shared-expert batches)。注意力层和密集变换层可以达到极高的算术强度,因此预填充主要受限于计算能力。较长的初始输入上下文会增加内存流量,但这些上下文的长度很少达到 100,000 个 Token,而中填充通常会远超这个数字。

3.2 中填充(Midfill)

中填充将新 Token 追加到长得多的缓存前缀之后。新的 Token 块仍可提供数百或数千个激活值用于共享权重和专家复用,将算术强度提高到每字节数据数千次运算。注意力机制还必须读取庞大的已有 KV 状态,这可能高达数十 GB。因此,它处于一种混合模式:算术复用高于解码,但缓存状态的流量又远高于相同新 Token 数量的初始预填充。

3.3 解码注意力(Decode attention)

解码以每次 Query 仅输入一个或几个 Token 的节奏推进。每个 Query 带来自己的 KV 状态,其长度与中填充所处理的类似。虽然预填充与中填充的区别在于缓存的长度,但解码与中填充的区别在于输入序列的长度。这一个到几个输入 Token 使得算术强度保持在低位,该工作显然由围绕 KV 缓存的内存传输所主导。

对于长上下文,注意力读取的负担可能会超过与模型权重相关的张量运算规模。因此,尽管大多数模型参数存在于专家中,注意力依然是现代解码中最繁重的操作之一。Delta、Top-k 或线性注意力算法层可以减轻这一负担,但定期使用全注意力层仍然是一个主要的内存负载。每个 Query 带来自己的上下文,因此对 Query 进行批处理并不会改变注意力的算术强度。

3.4 解码专家(Decode experts)

专家并非解码阶段所独有。无论模型在何处运行,专家都在运行,并且除了单个 Token 的嵌入(Embedding)之外,它们不需要任何上下文。Query 的历史已经被压缩进呈现给专家的激活值中。这使得各种设计可以在所有可用的 GPU 之间共享专家,从而降低每个 GPU 的内存容量要求,并提高内存带宽与内存容量的比值(即内存强度比/Memory intensity ratio)。您可以将 GPU 读取其所有专家所需的时间间隔视为最佳情况下的交互性(每个用户看到的 Token 速率);因此,如果内存带宽保持不变,但 GPU 负责的专家数量减少,交互性就可以更高。但陷阱在于网络需求也会随之上升,而且将路由分发给专家所需的全对全(All-to-all)通信模式极具挑战。

在注意力结束时(无论是在预填充、中填充还是解码中),路由计算(一个作用于未细化 Token 的小张量)会为每个新 Token 选择几个专家。选择相同专家的 Token 即使来自不同的请求,只要能够及时收集到一起以利用同一次权重加载,就可以共享张量权重加载。在实践中,所有层中可能存在 15,000 个专家,因此要利用这种巧合,需要进行刻意的同步,例如等待批次中的所有 Query 完成注意力计算,然后再切换到将它们发送去执行专家计算;而这又可以通过让附近其他机器中的多个实例也同步到该调度来进一步改善。如果您曾经想知道为什么 NVIDIA 要付出如此大的努力将 72 个 GPU 如此紧密地连接在一起,这很大程度上就是原因所在。在大型 Token 工厂中,让这 72 台机器全部同步运行是可行的,从而允许某一层的专家最多被切分成 72 份。如果模型的一层有 256 个专家,那么每个 GPU 在每层仅需处理 3 或 4 个专家,从而能够以极快的速度完成对所有专家的循环。同时伴随着大量的全对全网络流量。

如果专家能够全部保留在 SRAM 中,奇妙的事情就会发生。你需要庞大的加速器数量和巨型网络来将它们全对全汇聚回 GPU,但现在几乎没有理由去等待批次的形成。每个专家只要有输入就可以立刻运行。每加载一字节所需的能量比从 HBM 加载好上高达 100 倍,因此单个 Token 运行的效率可能与之前 100 个 Token 排队一样高。作为这种 DAF(解耦注意力与前馈网络,即 Disaggregated Attention-FFN,专家即 FFN) 的回报,拟可以将实例从同步需求中解脱出来。这种优势对于预填充或中填充帮助不大,因为它们本来就很轻易能获得一个 Token 批次并在单台机器上按层分发到共享队列中;但它仍然可以从这些 GPU 中卸载所有的专家权重,允许它们优化本地内存以用于其他用途(如更长的上下文)。网络仍然是个陷阱:基于 SRAM 的加速器可以在不到一微秒的时间内完成一次专家计算,但现在你可能会让连接数百个节点的交换机充斥着数百万个 Token 的全对全流量。网络消耗的金钱和功耗可能比它们连接的专家还要多。

推理工作节点可以通过在同一个模型层上协调多个注意力实例来提高共享率。然后,它们路由后的激活值会从某局部的专家库中提取,从而减少每个目标节点必须加载的不同专家数量。在流水线化服务器中,这也意味着用于专家并行的网络连接可以是该阶段机器本地的,永远不会产生需要来自另一层专家的路由。即便如此,每个解码请求在每次 pass 中仅产生一个新 Token,通常带有 8 到 16 个路由专家,而一层可能包含数百个专家。在小批次下,共享依然有限,内存带宽继续主导着 KV 扫描和活跃专家加载,每加载一字节权重所完成的计算极少。无论使用何种类型的内存,专家内存都需要达到极低的每比特功耗。

这些运行模式解释了为什么预填充、中填充和解码可能偏好不同的工作节点配置;为什么解码注意力和解码专家在节点内可以偏好不同的放置位置;以及为什么批处理对每个阶段的帮助程度各不相同。随着现代 Agent 任务中的预填充迅速扩展到 50 万 Token 的范围,数据传输量巨大,特别是在 Token 解码阶段——这是模型生成有用的中间和最终结果的阶段。高速且大容量的 3D RAM 将对效率起到决定性作用。高速内存对于中填充也很有用。然而,对于我们现在视为常态的大上下文,内存容量需要达到一个最低门槛。如果内存容量太小,那么相比未来采用 3D 容量扩展且不牺牲吞吐量的内存类型,网络损失和过度庞大的芯片阵列所浪费的功耗将会非常显著。

虽然 Vera Rubin 72 可以在算术密集型的中填充层大显身手,但在切换到内存密集型的解码阶段时,它就没那么有效了,因为 Rubin 无法充分发挥其计算实力。对于庞大的上下文,将解码工作与中填充保持在同一个节点内有着极高价值,可避免跨网络将上下文发送到另一个节点。这可能会青睐一种全能型芯片——既具备超高的内存吞吐量,又具备极高的计算效率。


4. 穿过 MoE 预填充层的流程

经典的预填充始于注意力计算。一个新 Query Token 块会对可复用的前缀(如系统提示词)以及新 Token 块中的早期位置进行 Attention。注意力操作为每个新 Token 产生一个激活值,共享变换层为这些激活值进入路由专家阶段做好准备。

路由器为每个 Token 分配若干个专家。如果模型选择 8 个路由专家,每个传入的 Token 就会在一个可能包含 256 个或更多专家的专家库中产生大约 8 条路由。按 Token 顺序来看,这些记录是稀疏且交错的:相邻的 Token 可能具有完全不同的目标专家。然而,从整个输入块的角度来看,每个专家都可以累积一份短列表,列出分配给它的 Token。

工作节点按专家标识符对路由记录进行排序或排队。所有分配给专家 037 的激活值变成一个消息流;分配给 142 的则变成另一个。随后,单次专家权重加载就可以服务该桶(Bucket)中的所有激活值。多个请求可以贡献给同一个桶,且运行同一层的独立注意力实例可以在专家目标节点处合并它们的路由工作。将 Token 顺序转换为专家顺序是 MoE 预填充的核心效率来源之一。 像 NVLink 这样的 Scale-up 网络可以组织为内存映射连接,因此将请求发送给特定专家可以映射为将消息推送到配置为硬件队列的特定内存映射位置。几乎没有启动和停止的时间开销。专家可以通过类似于 RDMA CIQ 的机制进行监听,再次利用硬件加速来交付消息流,而无需复杂的协议启停。消息内联的简单头部可以识别发送方和接收方。也可以为从专家返回解码工作节点的反向流建立类似的连接。

专家输出被还原为 Token 顺序,加权、组合后传递给下一层。与此同时,注意力机制为追加的 Token 创建新的 K 和 V 状态。在整个模型中,这些值形成了不可变的 KV 后缀,用于解码下一个 Token,并最终作为下一个 Blob 存储在上下文中,供对话的下一轮次使用。

因此,预填充结合了两种形式的权重复用:注意力层和密集变换层跨多个 Token 复用权重,而路由专家则在收集到其桶中的 Token 之间复用每个选定的专家。随着激活流量、KV 流量和输出处理相比张量计算消耗更多时间,这种收益最终会趋于平缓。批处理可能会推迟首 Token 时间(Time to first token),但单个包含数千个新 Token 的请求本身就已经提供了相当高的算术强度;预填充并不总是需要每个批次中包含大量的请求就能高效运行。现代单插槽 GPU 可以在约一秒内为小批次的大模型完成预填充。


5. 穿过 MoE 解码层的流程

解码在每次前向传播(Forward pass)中从少得多的新工作量开始。当前 Token,或者在 MTP(多 Token 预测)中预测的一小撮 Speculative Token,即为 Query。注意力机制读取先前的 KV 状态以及新 Token 的 KV 条目。新条目被追加到结果中,并追加到下一次 pass 的 KV 状态中。

对于 Agent 上下文,读取先前的 KV 状态通常比该单 Token 所使用的注意力和专家权重带来更沉重的读取负担。新的 Query 及其本地投影权重大致上比较紧凑。注意力计算可以跨 KV 头、上下文范围、内存通道或加速器单元进行切分,之后将局部结果归约(Reduce)为单个 Token 激活值。即使该激活值将在下一阶段触发大得多的本地张量运算,其本身也足够小,传输成本很低。

激活值穿过共享变换层和路由。路由器从可用的专家库中选择少数几个专家,仅有这些专家张量对当前 Token 变为活跃状态。它们的输出经过加权、组合、投影并继续向前传递。

在每一层,注意力机制都会创建并保留该层针对新 Token 的 K/V 条目。然后,激活值推进到下一层的注意力机制,重复相同的序列。到最后一层产生下一个 Token 时,每一层都已追加了其微小的 K/V 更新。当 Token 流式传输给客户端或 Agent 时,这些更新可以组装成一个新的不可变 KV 后缀。

因此,该流程既包含宽泛操作,也包含稀疏操作。注意力机制在大范围的私有 Query 状态上进行读取;专家则仅激活模型总容量的一小部分。硬件映射应当同时支持两者,而不是强迫整个层使用单一的并行策略。


6. 中填充是一个独立的运行模式

中填充将长的缓存前缀与新 Token 块结合起来,为对话或 Agent 任务中的又一轮次做准备。追踪数据显示,缓存的输入通常比增量 Query 大许多倍,尽管增量 Query 通常在 50 到 5,000 个新输入 Token 之间浮动。缓存的系统提示词、对话根、记忆、先前 Agent 步骤和检索文档的存在,可以迅速将对话和 Agent 上下文推高到百万级的极限。AgentX 数据集显示,前沿专家模型在重复压缩上下文,以保持在百万 Token 的极限之下。

这使得中填充既不是小型预填充,也不是大型解码。与解码类似,它必须读取庞大的私有 KV 缓存;与预填充类似,它处理足够多的新 Token,从而能够复用权重并将路由激活值排序为有用的专家批次。它的算术强度可以比单 Token 解码高出数百倍,但其缓存状态流量又可以比相同大小的初始预填充大数十倍。

现代加速器通常能够利用数百个 Token 块中可用的算术复用,因此最难达成的平衡往往存在于庞大的 KV 读取与突发的路由专家流量之间。这种突发与解码流水线平稳的节奏并不匹配:中填充在一个阶段所占用的时间可能远长于相邻阶段中的解码批次,从而导致这些相邻阶段利用率不足。

理想的并行策略也可能有所不同。本文后面的实操示例表明,中填充配置所使用的流水线并行、张量并行和专家并行设置均与解码不同。在实时解码流水线的中途重新配置 GPU 可能成本高昂或不切实际。因此,服务可以从专用的中填充优化节点池中获益。硬件可以与解码池完全相同,而加载的模型阶段、并行方式和批处理策略则有所区别。


7. 模型是重复层组构成的高耸堆栈

模型的参数量量化了其学习到的总状态,但服务效率取决于这些状态如何组织和使用。模型是一个由层构成的堆栈,且越来越有价值的做法是将这些层组织为重复的架构单元。

在某些 MoE 模型中,一个层组(Layer Group)与单个层相同。而在其他模型中,一个层组包含一个全注意力层以及若干线性、Delta、Top-k 或其他经过优化的注意力层。通常初始的 1 到 3 层可能是密集层或经特殊设计以获得干净的起点,模型的其余部分通常会重复一种循环的层组模式。

用宽而浅的“法式薄饼”(Crêpe)来表示层组是一个很贴切的形象比喻。 其宽广的表面为注意力、共享变换、路由、专家容量和残差流提供了空间;而其较薄的厚度则标志着该层组只是整个极高的重复模型堆栈中的一个切片。这也呼应了加速卡的物理形态:一个铺展在宽大封装上的极薄活性层。对于将宽广的算法流程映射到宽广的硬件表面而言,薄饼模型是一个非常有用的直观概念。
这种重复结构简化了功能规划:为某一个层组创建的映射方案可以直接复用到下一个层组;对应的内存区域可以存放下一个层组的权重;相同的计算和通信方案可以重复执行。这种统一性不仅对运行时效率至关重要,对编译器、算子内核(Kernel)以及运维工具链也同样意义重大。
在解码过程中,对于给定的 Token,一次只有一个层处于活跃状态。在该层内部,多个操作按顺序依次发生。相邻层可以进行预取(Prefetch),不同的流水线阶段可以同时处理不同的 Query,但单个 Token 的逻辑路径依然是按顺序逐层向上攀升。

8. 并行策略应当对模型的窄数据流进行切分
并行策略不是单一的决策。流水线并行、张量并行和专家并行切分的是模型的不同维度,应当根据不同的通信模式来进行评估和选择。
流水线并行遵循层堆栈结构
模型层本身就天然适合流水线化(Pipelining)。在层与层之间传递的激活值非常紧凑——通常只是一个嵌入 Token、一个小型多 Token 预测块,或是先前混合层组结果的简短摘要——而在层内部使用的权重和 KV 状态则要庞大得多。因此,一个流水线阶段可以拥有一个或多个完整的层组,并在无需过强网络配置的情况下,将相对较小的激活值传递给下一个阶段。
流水线并行能够干净利落地切分模型权重,并将层内高频的热通信保持在本地。其主要缺点在于多批次占用(Multi-batch occupancy):一个完全活跃的流水线在每个阶段都包含不同的 Query 或批次。因此,每个阶段都需要为所有实时流(Live stream)承担属于它的那部分 KV 状态;随着上下文长度的增长,其在内存上的收益最终会停止改善。
张量并行适用于本质上宽广的单一操作
注意力机制可能需要将权重和 KV 状态切分到多个加速卡上。KV 头、上下文范围或其他线性维度可以进行切分,以便每个加速卡在对 Token 结果进行紧凑归约(Reduction)之前,只处理属于自己的那部分。张量并行(Tensor Parallelism, TP)也可以服务于异常庞大的密集变换。
张量并行不应该盲目扩展到层的每一个张量中。对于宽广的注意力操作非常合理的集合通信(Collective),如果用在小型专家张量上,其开销可能会超过算术计算本身。
专家并行遵循独立的专家张量
MoE 中绝大部分参数内存都保存在专家中。专家本身不保留任何 Query 的历史记录;上下文包含在传入的激活值中。因此,专家库可以广泛地分布在一组对等节点(Peer set)上,并由多个工作节点实例共享。
大规模专家并行(Expert Parallelism, EP)之所以有效,是因为专家之间相互独立且数量众多。路由器将紧凑的激活值发送到选定的目标节点,再由这些目标节点返回变换后的激活值。即使流水线阶段变得更小,专家并行的宽度依然可以保持很大,从而允许独立选择交换机基数(Switch radix)和本地内存放置策略。
总体规则非常清晰:对垂直的层序列使用流水线并行,对不可分割的大型操作使用张量并行,对无上下文的路由专家库使用专家并行。当节点的可用高速内存安全地超过其本地权重、实时批次状态和工作缓冲区之和时,一个流水线阶段就可以舒适地容纳在单个 Scale-up 域内:
$$M_{\text{free,node}} > \frac{W}{P} + M_{\text{batch}} + M_{\text{working}}
现代 GPU 节点通常能成倍地超过这一门槛。当达到该门槛时,对带宽、功耗和延迟要求极高的通信可以完全保留在单个节点内部,而较薄的流水线激活值和 KV 传输则可以使用 Scale-out 链路。剩余的高速内存如果闲置,就不会创造任何收益。闲置在内存中的数据是成本,移动并等待被处理的数据才是收益。

9. 逻辑加速器节点
将逻辑节点理解为排列成环形(Ring)的一组对等节点(Peer set),比直接理解为具体的电路板布局要容易得多。这个环形包含大约 16 个加速卡。每个加速卡将计算区域与本地高速内存配对。各单元之间通过强劲的 Scale-up 互联架构相连。CPU 负责协调工作负载和内存管理,而网卡(NIC)则将节点连接到机架和数据中心资源。
需要说明的是,环形只是一种可视化形式,用以表明加速卡之间具有对等地位。这并不暗示节点内部网络必须是环形拓扑。它可以是星型(Hub and spoke)、Rail 架构、全对全(All-to-all)、环面(Torus)、超立方体(Hypercube)……只要它能以低延迟和低每比特功耗处理机架内最高的数据流即可。为了简单起见,这里将其绘制为环形。
这种抽象方式避免了过早地绑定到具体的封装放置、板级布线或交换机实现上。实际的物理机器可以使用中央交换机、多个交换机、直接链路或分层互联架构。逻辑上的核心需求只是一个边界明确、具有可预测的高速本地通信能力的对等节点集。
加速卡的设计可以千差万别。一种版本可能采用偏向 SRAM 的存内计算(Processing-in-memory)单元;另一种可能采用混合键合 DRAM,或者在后道工序(BEOL)中将 IGZO 内存晶体管置于顶层;还有一种可能采用混合键合的高带宽真 3D 内存。虽然内存容量和带宽可能会发生改变,但这一逻辑模型依然有效。
节点是保留高频重复工作的天然场所。注意力切片在此交换紧凑的局部结果;路由后的专家激活值传输至本地目标节点;专家输出返回进行重组;共享状态和调度元数据保留在 CPU 附近;网卡则将流水线激活值、KV Blob 和任务分配传输到节点之外。
节点可以小于机架(例如包含 8 个 GPU 的 SGX 节点), Scale-up 系统也可以跨越整个机架(如 NVL72)。无论哪种情况,逻辑符号依然成立。如果 Scale-up 已经覆盖了整个机架,那么独立的机架骨干网(Rack-backbone)层级就会消失,下一个边界将直接对接 Scale-out 网络。

10. 节点堆叠构成机架
将环形节点倾斜看作宽而浅的硬件“薄饼”时,其表达力会更强。多个单元可以在机架中垂直堆叠,就像模型层组在模型深度方向上堆叠一样。
这种重复的形式使模型与硬件之间的关系更容易被直观理解。一个层组薄饼可以放置在一个硬件薄饼上。如果内存允许,一个节点可以容纳多个层组;如果注意力或专家容量需要,一个层组也可以跨越多个紧密连接的节点。这种映射可以扩展或收缩,而无需改变基本的可视化语言。
机架可以按以下几种方式组织:
  • 单个机架规模的 Scale-up 域;
  • 由机架骨干网连接的多个节点级孤岛(Node-scale islands);
  • 分布在这些孤岛之间的流水线阶段;
  • 每个流水线阶段内部的大规模专家放置;
  • 或是阶段本地 Scale-up 与共享 Scale-out 链路的混合模式。
因此,机架骨干网是一个可选的中间层。有些系统将 Scale-up 互联架构延伸到整个机架,不需要独立的节点连接器;另一些系统则使用强劲的本地节点网络以及独立的机架顶头(Top-of-rack)交换机或共享 Rail 网络。在机架之上,Scale-out 网络连接着存储、预填充池、解码池以及其他机架。
重复的机架单元也有助于区分两种规模扩展方式:模型可以容纳在单个受限的机架工作节点内部;而工厂规模的扩展则是通过增加许多这样的工作节点来实现。第一个问题是功能映射问题,第二个问题则是工作节点协调调度问题。

11. 单个层组随时间时分复用节点
一个层组并不需要算法中的每个操作在同一时刻都处于峰值强度。它的各个操作形成了一个重复的序列,在整个解码周期中复用相同的硬件来执行不同的工作。
注意力计算可能分布在环形节点的大部分区域,使用多个内存通道和多个计算单元。Query 和输出变换在更紧凑的操作中使用模型权重。共享的前馈工作(FFN)可能会使用一个密集计算区域。随后,被选中的专家会激活环形节点四周的本地内存与计算区域。最后的重组阶段返回一个紧凑的结果。
相同的物理加速卡在每一步中的参与方式可以不同。计算注意力的执行单元稍后可以执行一个或多个专家;用于流式传输 KV 状态的内存通道稍后可以喂给专家权重;缓冲区和本地链路会随着 Token 的推进而被重复使用。
这种时分复用(Time-sharing)是实现高效设计的核心。静态图示可能会让机器看起来利用率不足,因为并非每个模块都在同时处于活跃状态。但实际上,硬件正在服务于一连串不同的操作,其目标是以极少的准备开销或同步开销来维持这一序列的顺畅运转。
宽广的层组薄饼与加速卡对等节点集是互补的:薄饼展示了算法流程,而环形节点展示了其下方可复用的物理资源。所谓“映射”(Mapping),就是将流程中的各个阶段与环形节点中合适的子集进行对齐的操作。

12. 将吞吐量边界置于流量最小处
一旦将模型和机器绘制为相连的流,映射规则就变得清晰了:高频、延迟敏感的通信应当保留在最强劲的本地网络(Scale-up)内部,而较弱的链路(Scale-out)应当承担紧凑或可摊销的传输。
注意力切片可能在每一层都需要交换局部结果;专家路由将激活值发送给选定的专家,并取回它们的输出。按字节量计算,这些流量并不总是最大的,但它们具有高频、突发和对同步极度敏感的特点。只要条件允许,它们就属于选定的 Scale-up 域内部。
在层与层或层组与层组之间传递的激活值要小得多。因此,流水线边界可以跨越较弱的链路,而无需移动该层完整的内部工作集。KV Blob 的体积虽然较大,但它们只在工作节点边界处移动,并被摊销到许多生成的 Token 中。它们的传输路径可以使用分片或种源式的 Scale-out 网络以及共享存储,而不是去占用最核心的张量互联网络。
路由器到专家的边界通常是一个中等吞吐量的全对全通信,传输着紧凑的激活值。其难点往往在于端点数量、同步和路由效率,而不是原始字节体积。将其保持在节点或机架的 Scale-up 域内部,可以同时降低延迟和运维复杂度。
这种分级架构比所有链路都同样强劲的机器更容易构建且成本更低。Scale-up 路径包围着每一层内部交换嵌入和局部结果的操作;Scale-out 链路则承担流水线激活值、KV 移动、调度流量以及受限工作节点之间的通信。
不同层级也有不同的延迟要求。如果吞吐量足够,层组之间的流水线传输可能几乎感觉不到几微秒的延迟。相比之下,当一次专家的加载和乘法运算只需要几微秒时,每个路由跳头增加 100 纳秒都是至关重要的。因此,最贴近的链路应当与加速卡网络紧密集成,而较低频的传输则可以容忍 Scale-out 网络。
【未完待续】

相关学习资料