3181 字
约 10 分钟
14
S23-B01 · 推理服务是什么:与训练的区别

训练是把参数调到能拟合数据,推理是用调好的参数回答一次请求。听上去只差一步,工程上却是两种问题:训练关心"多久收敛",推理关心"一次请求等多长、花多少钱、成不成"。

很多人接推理需求时默认"权重训好了,跑一次 forward 不就行了"。这在单条请求、没人在等、不计成本时成立。一旦有人盯着屏幕等第一个字、几百个请求同时进来、月底有账单,forward 就只是整件事里最不重要的一环。


1. 训练与推理的根本差异

一句话:训练改参数,推理不改。训练每步算梯度、更新权重、维护优化器状态;推理期间权重是只读常量,只做前向。

维度 训练 推理
目标 最小化损失、收敛 延迟与成本约束下给对答案
对参数做什么 每步更新 只读,不写
计算组成 前向 + 反向 + 优化器更新 只有前向
显存主体 权重 + 梯度 + 优化器状态 + 激活 权重 + KV Cache + 激活 + 预留
批的形状 固定张量形状、长周期 变长输入、逐 token 输出、动态到达
失败代价 一个 step 可重跑 用户当场看到报错
优化指标 样本/秒、收敛步数 TTFT、TPOT、成功率、单位成本

显存结构直接写成两行:

训练显存 ≈ 权重字节 + 梯度字节 + 优化器状态字节 + 激活字节
推理显存 ≈ 权重字节 + KV Cache 字节 + 激活字节 + 框架与通信预留

优化器状态跟着参数量走,每参数多少字节取决于优化器类型与精度,按具体实现核对。这就是同一份权重,训练要的卡数常是推理数倍的原因。

2. 两个阶段的计算特征

阶段 主要算子 算术强度 瓶颈 加批带来什么
训练 前向 + 反向 + 优化器 高 算力与互联 更充分用满算力
推理 prefill 大矩阵乘、整段注意力 高 算力 算力利用率上升
推理 decode 单 token 矩阵向量乘、增量注意力 低 显存带宽 摊薄权重读取,吞吐上升
算术强度 = 该步浮点运算次数 / 该步访存字节数
decode 单步读取量 ≈ 权重字节 + 该请求的 KV Cache 字节

decode 每步要把权重几乎完整读一遍,却只产出 1 个 token。所以它天生带宽受限:卡再强,读不动也白搭。这是后面所有优化(批处理、量化、KV 压缩)的共同出发点。

3. prefill 与 decode 为什么决定后面一切

维度 prefill decode
单次处理的 token 数 整段 prompt 一次过 1 个
耗时随什么变 prompt 长度、卡算力 输出长度、权重字节、并发数
资源瓶颈 算力密集 显存带宽密集
对应指标 TTFT TPOT
对并发敏感度 低 高(共享带宽与 KV 显存)
典型优化方向 前缀缓存、chunked prefill 连续批处理、量化、KV 压缩

两段瓶颈不同,优化手段就不可能通用:量化把权重变小,主要帮 decode;批处理把请求拼起来,主要帮 decode;长上下文同时压两头——prefill 变长、KV 变大、并发被挤掉。

所以看到任何"提速 X 倍",先问:它提的是 prefill 还是 decode,在什么输入输出长度分布下测的。答不上来,数字对你就没有参考价值。

4. 四个关键指标与它们互相拉扯

指标 定义 单位 谁在看 变差的原因
TTFT 请求到达至第一个 token 返回 毫秒 交互式产品 排队、prompt 太长、prefill 被挤
TPOT / ITL 首 token 之后每个 token 的平均间隔 毫秒/token 阅读流畅度 批太大、带宽打满、KV 换出
吞吐 单位时间产出的 token 数 tokens/s 成本与容量 批太小、调度空转
成功率 成功完成的请求占比 % 稳定性 超时、OOM、上游限流
t0 请求到达;t1 第一个 token 返回      TTFT = t1 - t0
tn 第 n 个 token 返回                  TPOT = (tn - t1) / (n - 1)
单请求总时长 ≈ TTFT + (n - 1) × TPOT
吞吐 ≈ 观测窗口内成功产出的 token 总数 / 窗口秒数

四个指标是互相抢资源的关系,不是并列关系:

动作 吞吐 TTFT TPOT 成功率
增大最大批大小 升 变差 变差 可能降(显存紧)
提高并发序列上限 升到饱和点 变差 变差 可能降
降精度 / 压缩 KV 升 略好 略好 可能降(质量)
收紧超时 表面升 略好 不变 降(被砍算失败)

入门该记住的一句:没有参数能同时改善四个指标。真有的话,默认值早就不是现在这个了。

5. 三种交付形态与各自的约束

形态 调用方式 关键约束 取舍
在线 API 同步或流式,按请求计费 延迟与并发,必须能取消 体验优先,单位成本高
批处理任务 提交任务、离线取结果 吞吐与成本,可容忍排队 成本优先,延迟不敏感
边端部署 本地进程内调用,常离线 内存、功耗、无网 模型必须小,量化几乎必选

形态会反向决定选型:在线 API 不能"排队十分钟再出结果",所以必须有准入与背压;批处理不能一次只跑一条,要尽量拉满批;边端不能背 40GB 权重,所以先量化再谈效果。

6. 推理引擎在管什么

不必先读源码,但要知道它替你管四件事,否则调参时不知道为什么参数长这样:

  1. 调度:请求排队,决定谁先算、谁等、谁被拒。公平性、优先级、超时都在这一层。
  2. 批处理:把不同请求拼批一起算,并每步重新组批。批大小由显存与 token 上限共同约束。
  3. KV Cache 管理:把显存切块分给各请求,做前缀复用、做换出。这一层决定"能同时服务多少条"。
  4. 算子与图优化:融合算子、选 kernel、走量化 kernel、减少中间张量。

一句话:它不是"跑得更快的库",而是"把有限显存切成多份并决定谁先用"的分配逻辑。调引擎参数本质是在调分配策略。

7. 为什么"训练脚本包一层 HTTP"不能当服务

# 能返回结果,但不是服务:阻塞、无并发、无流式、不可取消
@app.post("/chat")
def chat(req: ChatRequest):
    return {"text": model.generate(req.prompt, max_new_tokens=req.max_tokens)}

它缺的正好是推理服务的四份契约:

缺什么 后果 应有做法
并发与组批 每请求独占一次前向,卡利用率极低 队列 + 连续批处理
流式输出 用户等整段生成完才看到字 SSE 增量返回,先出首 token
取消与超时 用户断开后仍在生成,白烧卡 感知断连,立即释放 KV
显存与准入 并发一多就 OOM、进程崩 按 KV 预算做准入,满了排队或拒绝

还有两条不显眼但致命:没有指标(出问题只能靠用户反馈)、没有副本与健康检查(一台挂了整站挂)。判断标准很简单:同时来 50 个请求,它会变慢、报错还是排队?答不出来,它只是脚本。

8. 入门者先回答的五个问题

# 问题 为什么先问 要拿到的东西
1 模型多大 决定权重显存下限 参数量、精度、config 中层数与头数
2 卡有多少显存 决定还剩多少给 KV 卡型号、单卡显存、可用卡数
3 要多少并发 决定 KV Cache 规模 峰值并发、平均输入/输出长度
4 延迟目标多少 决定批上限与是否流式 TTFT/TPOT 目标值、P50 还是 P99
5 成本上限多少 决定卡型、副本数与是否量化 每月卡时预算、可接受单位成本
权重显存 ≈ 参数量 × 每参数字节数        # FP16/BF16 约 2,INT8 约 1,INT4 约 0.5
可用 KV 显存 ≈ 卡显存 × 目标利用率 − 权重显存 − 激活与预留
每 token KV 字节 ≈ 层数 × 2 × KV头数 × 头维度 × 每元素字节数
可并发序列数 ≈ 可用 KV 显存 / (每 token KV 字节 × 平均上下文长度)

每参数字节数、层数、KV 头数都要按模型 config 与卡规格核对,GQA/MQA 模型差别极大,抄别人的数字必然错。

9. 三个常见误解

误解 实际
推理就是跑一次 forward forward 只是计算;排队、组批、KV 管理、取消、指标才是服务主体
用训练吞吐推算推理吞吐 训练是样本/秒且含反向,推理按 token 计且受带宽限制,不可换算
只看总时长不看首 token 延迟 用户感知的是"多久出第一个字";总时长相同、TTFT 不同,体验天差地别

10. 排错:五种"看起来在跑"的故障

现象 原因 处理
单请求快,多请求集体变慢 没组批,串行执行 开连续批处理,设最大批与 token 上限
首 token 很慢,之后很快 prefill 排队,长 prompt 挤占算力 看 prompt 长度分布,考虑前缀缓存或限制输入
中间卡顿,末段突然变快 KV 不足触发换出/重算 降并发上限、压缩 KV 或加卡
用户断开后 GPU 仍满载 没处理断连,生成没被取消 在流式循环里检测断连并释放资源
进程周期性 OOM 重启 按请求数而非 KV 字节做准入 改按剩余 KV 容量准入,留框架预留

11. 边界:这些判断什么时候不成立

场景 说明
单用户、本地、离线跑一次 不需要服务化,脚本足够,本文指标意义不大
模型极小、CPU 能实时跑 瓶颈不在显存带宽,GPU 侧结论不适用
只做离线批处理 TTFT 不重要,吞吐与成本是唯一目标,策略完全不同
直接买托管 API 引擎不可见,能调的只有并发、超时、重试与预算

12. 自测

  1. 训练和推理的显存构成,最大的结构差异是哪一项?为什么它决定了卡的数量级差异?
  2. 用算术强度解释:为什么 decode 是显存带宽密集而不是算力密集?
  3. 一个"提速 2 倍"的优化,你要问哪两个问题才能判断它对你有用?
  4. TTFT 与 TPOT 分别由哪一段决定?它们为什么会互相挤?
  5. 把训练脚本包一层 HTTP 不能算服务,至少说出三条缺失的契约。
  6. 接到新需求,你先问哪五个问题?各自对应哪项资源估算?
S23-B01 · 推理服务是什么:与训练的区别
https://www.clxhxhhr.top/posts/5995/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。