
作者 | Sean Goedecke
译者 | 王强
策划 | Tina
为何 DeepSeek-V3 在大规模服务场景下表现得又快又省,而在本地运行时却显得缓慢且成本高昂?为何某些 AI 模型刚开始响应迟缓,但一旦启动后速度就大幅提升?
AI 推理服务商常提到一个核心矛盾:吞吐量与延迟之间的权衡。对于任意给定模型,你只能在“高吞吐+高延迟”和“低吞吐+低延迟”之间做选择。实际上,部分模型由于 GPU 利用效率偏低,必须依赖高延迟的服务模式,才能实现可接受的吞吐表现——DeepSeek-V3 正是这类模型的典型代表。
这一权衡的核心在于 推理批处理大小 的设定:服务商并非对单个请求内部进行批处理,而是将数十乃至上百个并发用户的请求合并处理。Transformer 架构的一大特点是,同时计算一批输出几乎与计算单条输出耗时相当。这是怎么做到的?
1 什么是批处理推理?
GPU 擅长执行大规模矩阵乘法(GEMMs)。假设你要将一个 token 输入模型处理(即通过权重矩阵进行变换,忽略其他结构细节)。这个 token 被表示为一个与模型隐藏层维度匹配的向量(1x模型宽度),然后乘以权重矩阵——这就是一次 GEMM 运算。但如果你有十个 token,也可以将它们堆叠成一个 10x 维度的矩阵,一次性完成乘法,仍只算一次 GEMM。相比执行十次小规模 GEMM,这种方式快得多。
因此,推理服务器的工作流程大致如下:
- 用户请求携带提示词到达
- 提示词经过预填充(包括注意力计算),生成 KV 缓存和一个 token 向量(1x模型大小)
- 该向量进入处理队列
- GPU 服务从队列中拉取一批请求(如 128 个),堆叠成 128x 模型大小的矩阵,送入前馈网络进行计算
- 输出结果被拆分为 128 个独立 token
- 对应原始请求的那个 token 被流式返回给用户
- 若未生成结束符,则回到第 2 步继续生成下一个 token
关键点在于:服务器自行决定批处理的规模。这正是吞吐与延迟权衡的来源。如果不批处理,逐个处理 token,用户无需等待(跳过排队步骤),延迟极低(前提是 GPU 资源充足)。但如果采用大批量批处理,用户需等待批次填满,延迟上升,但 GPU 利用率更高,吞吐量显著提升。
为何 GPU 处理大矩阵比多个小矩阵更高效?原因有二:
其一,每次向 GPU 发送指令都有固定开销,一个大矩阵只需一次调用;
其二,每个新任务都需要加载权重,若频繁执行小 GEMM,大量时间将耗费在数据搬运而非计算上。
2 为何某些模型需要大批次运行?
推理服务器通常设有一个“收集窗口”,请求在此窗口内排队等待。聊天类服务的目标延迟一般为 5–10 毫秒,而高吞吐后端可能容忍高达 200 毫秒的延迟。若请求在窗口开启时到达,它可能要等到窗口关闭才能被处理。当窗口关闭时,所有积压请求被打包成一个批次(多个 1x 向量拼接为单一 128x 矩阵),统一送入模型处理。这种操作周期常被称为一个“tick”。
正如上述机制所示,理论上任何模型都可以在不同批大小下运行。批处理本身不限制模型类型。然而,我们可以设计出 GPU 效率极低的模型,使得不进行大规模批处理就无法达到实用性能。
3 专家混合模型为何依赖更大批处理?
以专家混合模型(MoE)为例,如 DeepSeek-V3 或传闻中的 GPT-4 所用架构。这类模型可包含数百个“专家”(独立的前馈网络模块),路由机制为每个 token 动态选择激活其中一部分。但这种结构对 GPU 来说效率低下——原因在于:GPU 偏好少量大矩阵运算,而 MoE 强制进行大量小型矩阵乘法。
除非以整批方式处理,否则吞吐量会严重受限。
设想两种收集窗口:5 毫秒 vs 200 毫秒。假设在 5 毫秒内收到 10 个请求。若专家数量众多,某些专家可能仅需处理一两个 token,导致其实际批大小远低于总请求数。这使得每个专家的计算单元利用率极低,无法发挥 GPU 的并行优势。
相比之下,200 毫秒窗口能积累更多请求,使每个专家获得足够多的 token 来维持高效运算。因此,MoE 模型必须牺牲延迟换取吞吐,否则整体效率将急剧下降。
4 大型模型为何需要大批次避免管道空转?
对于层数极多的大型模型,保持 GPU 持续满载是一项挑战。现代大模型往往包含数百个 Transformer 层,必须采用流水线并行(pipeline parallelism):不同 GPU 分别负责不同层段。否则,单卡内存无法容纳全部权重,频繁换入换出将极大拖慢速度。
在推理过程中,每个 token(通常以微批次形式)依次流经各 GPU 层段。
管道效率取决于层数和批处理窗口大小。在一个“tick”中处理一批 token 时,初期后端 GPU 尚无输入(预热阶段),末期前端 GPU 提前空闲(排水阶段)。这些空闲期称为“预热”和“排水”。若窗口太小、tick 过于频繁,则预热与排水时间占比过高,浪费大量算力。
更严重的是,当窗口极短且请求数少于层数时,会出现“管道气泡”——即尚未完成一轮处理,管道已提前进入排水状态。这对吞吐影响巨大。为避免气泡,服务商必须设置足够宽的收集窗口,但这直接带来了更高的延迟。
5 能否让队列始终保持满载?
既然大型服务商拥有海量并发请求,为何不能持续填满队列,彻底消除预热与排水?换句话说,能否抛弃“tick”机制,让 token 微批次像流水一样不间断流动?
理论上可行。每个用户的 token 生成必须顺序进行(前一个未完成不能生成下一个),但服务商整体流量足够大,理应能维持稳定输入流。
问题出在 实际实现 上,尤其是注意力机制的批处理限制:要批量执行注意力 GEMM,所有序列必须具有相同的上下文长度(即历史 token 数相同)。否则,KV 缓存的形状不一致,无法堆叠成统一矩阵。因此,系统只能将相同长度请求分组处理,而不能简单维护一个动态队列。
尽管已有研究尝试解决这一问题(如 https://www.php.cn/link/200734077bb5e01fbe9b973d0d50ee6a tick 处理注意力,而用连续流处理前馈网络(FFN)?
难点在于内存开销:FFN 依赖注意力输出作为输入,若两者异步运行,中间结果需暂存内存,成本极高。现代推理系统倾向于将注意力与 FFN 合并为少数几个大型 GEMM,在同一操作中完成。若拆分到不同 GPU 或阶段执行,则需额外通信和调度开销,反而降低效率。
6 总结
GPU 在处理大型矩阵乘法时效率最高。将多个 token 堆叠成一个大矩阵进行计算,比逐个处理能获得更高的 token 吞吐量。
在解码阶段,注意力机制要求同批 token 具有相同上下文长度,迫使调度器以“tick”方式运行。每个 tick 中打包的 token 数量即为批大小,这些 token 来自不同用户。你无法对同一用户的不同 token 批处理,因为后续 token 依赖前序输出,因此高效批处理依赖高并发用户流量。
更大的批处理意味着更高延迟——用户可能需等待最多 200 毫秒直到批次填满,但它提升了 FFN 阶段的 GEMM 规模,从而提高整体吞吐。
深层模型(长管道)需要更大的批处理来避免管道气泡,确保每个 tick 的 token 数超过层数。
MoE 模型则需高延迟服务以提升效率:每个专家仅处理分配给它的 token,只有全局批处理足够大,才能让每个专家都有足够任务可做。
推理服务商选择批大小/窗口时,目标是消除管道气泡并让专家模块充分饱和。高批大小带来更高吞吐,但代价是延迟增加。
像 DeepSeek 这样的模型,既是 MoE











