推理如电
你以为训练完模型部署上线就行,推理不过是调个 forward。可在推理殿前,延迟之壁横亘——首 Token 要等多久?后续 Token 凭什么更慢?你以为瓶颈在算力,它告诉你瓶颈在访存、在 KV Cache 显存。推理是另一场战争,优化的是分阶段的 trade-off。
推理之门
推理殿的门是一面巨大的青铜壁,上面刻满密密麻麻的计时符文——像一万只滴答作响的眼睛。壁前立着一块石碑:训练成丹,非为供养;若不能应答如电,丹亦是死丹。高斯老祖站在碑旁:「你 ch18 跑出了千亿参数的模型。训练花了千卡数十天。现在把它上线——每秒上万个并发请求。你猜,推理最大的瓶颈是什么?」
「训练衡量的是多久收敛,推理衡量的是多久应答。这是两套时间,两种战争。你以为训完就赢了?告诉我,LLM 推理最大的瓶颈是什么?先猜,猜错了也没关系,延迟之壁会记账。」
「又来了一个以为训完就快的。打个赌——你觉得 LLM 推理最大的瓶颈是什么?你每猜错一次,我的符文就密一分,我都记下来。」
瓶颈之赌 · LLM 推理最大瓶颈预测挑战器
反直觉下注(四选一,可连错)→ 挑战展开 → 推理优化全景图拼合
推理优化全景 · 核心瓶颈图谱
推理两阶段 · Prefill 与 Decode
殿中央悬着一台巨大的双摆仪——两根摆针,一根粗如柱,一根细如针,各自摆动节奏全然不同。高斯老祖指着它:「LLM 推理不是一次前向。生成第一个 token 时,要把整段 prompt 一次性算完——这叫 prefill,算力密集,像把一本书一口气读完。生成第二个及之后的 token 时,每步只多算一个 token——这叫 decode,访存密集,像一字一字地念。」
「prefill 一次算 500 个 token,均摊极快;decode 每步只算 1 个 token,却比 prefill 单 token 慢几十倍。为什么?因为 decode 每步都要把历史的 KV Cache 从显存搬进 GPU——你的 GPU 大部分时间在等显存喂它,不是在算。两个阶段瓶颈完全不同。」
「一个策略,两个阶段?你试试。你以为都是前向能差多少——我赌你测不出真相。」
推理阶段可视化器 · 双摆仪 + 特性归位
预测两阶段速度关系 → 拖 prompt 看 prefill → 拖 decode 序列看 TPOT → 特性卡归位
预测抉择 · 两阶段速度关系
双摆仪 · prefill(粗针) + decode(细针)
特性归位 · prefill / decode 特性卡
KV Cache · 显存大户
殿后是一道向下的阶梯,通向一片幽蓝的显存深渊。深渊中央悬浮着一颗发光的球——那是你的模型权重,安静地占着显存。高斯老祖:「权重是死的,推理时不动。但每生成一个 token,你要把这一步的 K、V 存下来——不然下一步算注意力就没了历史。这堆 K、V 就是 KV Cache。猜——一个请求,2048 token 的上下文,KV Cache 要吃多少显存?」
「每层每 token 的 K、V 各 h·d 个元素,共 2·h·d;L 层、seq 长度 s、batch b → KV Cache 显存 = 2·L·s·h·d·b·2 bytes(fp16)。代入 LLaMA-2 70B:单请求 s=2048 ≈ 5.4 GB;batch=32 并发 ≈ 172 GB——超过权重本身。」
「忽略它吧。它只是几个矩阵。你以为权重占大头——你忽略了 batch。一个请求是小,32 个并发呢?长上下文呢?」
KV Cache 可视化器 · 公式推导 + 显存天平
拖 seq/batch 滑块看 KV Cache 暴涨 → 组装显存公式 → 显存天平倾覆
参数旋钮 · 模型 / seq / batch
KV Cache 显存增长 · 随 batch 与 seq 暴涨
显存公式组装 · 2·L·s·h·d·b·2 bytes
显存天平 · 权重 vs KV Cache vs 激活 vs 缓冲
第一崩塌 · 显存爆炸
深渊水位暴涨。你把 batch 拉到 64、上下文拉到 8192——KV Cache 像洪水般涌出,吞没了权重球。仪表闪烁:OOM。高斯老祖沉默了。深渊上方,那堵灰紫色的光壁凝聚成形——延迟之壁。它不是人形,是一堵横亘推理殿深处的暗青光壁,壁面无数计时符文缓慢游走。
「你的 KV Cache 比模型本身还大。你以为权重是瓶颈,可 batch 一上去,KV Cache 先把你吃干。你以为显存够用——可它随每个请求、每个 token 一直在涨。第一笔账,我记下了。我住在你以为显存够用的地方。」
「权重省不了,KV Cache 能不能省?传统做法是给每个请求预分配一块连续显存——按最大 seq 长度预留。可请求长短不一,50 token 的请求按 4096 预留,浪费 98%——这叫内部碎片。操作系统的虚拟内存怎么管这种碎片?去分页阵。」
显存爆炸复现 · OOM 诊断 + 延迟之壁现身
拖 batch/seq 看 KV Cache 涌出 → 触发 OOM → 延迟之壁现身
灾难复现 · batch + seq 旋钮
显存深渊 · KV Cache 洪水 + OOM
延迟之壁现身
模型量化 · 精度换空间
出了深渊,眼前是一座烧得通红的量化炉。炉口悬着一块 FP16 的权重晶——紫光流转。高斯老祖:「推理时算的是矩阵乘。FP16 每个数 16 bit,INT8 只要 8 bit,INT4 只要 4 bit。压下去,显存省 2~4 倍,算力也跟着涨。但精度呢?你把 16 bit 压成 4 bit,等于把一条河塞进一根管子。压不坏的,靠的是缩放因子 scale。」
「量化分两条路:PTQ 训练后量化——校准集统计激活分布、找 scale、权重除 scale 取整;QAT 训练时量化——在训练里模拟量化噪声,精度比 PTQ 高 1~2 个点,但要重训。GPTQ 逐层二阶补偿精度高,AWQ 保护显著权重推理快,SmoothQuant 平滑激活异常值。」
「无损?你试。INT8 还能装没事,INT4 呢?再往下 INT2 呢?你以为压下去就赢了——代价你来付。」
量化实验台 · 位宽抉择 + 精度-显存天平
切位宽 FP32→FP16→INT8→INT4 → 看精度损失光斑 → 三方法天平
位宽抉择 · FP32 / FP16 / INT8 / INT4
权重晶 · 位宽收缩 + 精度损失光斑
scale 缩放 · 把河塞进管子
三量化方法天平 · GPTQ / AWQ / SmoothQuant
「量化只是压缩三件套之一。另外两件:剪枝(Pruning)——把不重要的权重直接置零。非结构化剪枝挖出稀疏矩阵(需稀疏硬件才真省算力);结构化剪枝整行整通道删,稀疏规整、无需专用硬件,是落地主流。蒸馏(Distillation)——用大模型(教师)的软标签训一个小模型(学生),把"暗知识"灌过去,小模型逼近大模型精度。量化省位宽、剪枝省连接、蒸馏省层数——三件套常叠加用。」
PagedAttention · 虚拟内存思想
量化炉后是一座由无数小方块拼成的巨大阵列——每个方块大小不一,有的填满,有的空着一半。高斯老祖:「你 S2 算的 KV Cache,传统做法是给每个请求预分配一块连续显存——按最大可能的 seq 长度预留。可请求长短不一。客服对话 50 token,长文翻译 4000 token。按 4000 预留,50 token 的请求浪费 98% 的显存——这叫内部碎片。操作系统的虚拟内存怎么管这种碎片?」
「PagedAttention 把 KV Cache 当虚拟内存分页管理:切成固定大小的 block(如 16 token/block),每请求按需申请 block,通过 block table 映射逻辑→物理。碎片消了,显存利用率从 60% 飙到 98%,并发数翻倍。两个请求共享 system prompt 的 KV?copy-on-write——分叉后才申请新 block。」
PagedAttention 可视化器 · 碎片体验 + 分页改造
连续分配看碎片浪费 → 切分页模式看 block table → copy-on-write 共享
分配模式切换 · 连续预分配 / 分页
显存阵列 · 8 请求分配可视化
block table · 逻辑→物理映射
copy-on-write · 共享 system prompt
「PagedAttention 解决了显存碎片,但请求长短不一还有个更要命的问题:批处理同步——传统做法等齐一批、最长的跑完才放下一批,短请求陪跑干等。连续批处理(Continuous Batching / In-flight Batching)则每一步都把"已生成完的请求"踢出去、把"新请求"插进来,槽位永不空转。两者合一,就是 vLLM 的立身之本;TensorRT-LLM 走类似路子并叠算子融合,TGI 是 HuggingFace 的对应实现——这三大推理引擎把上面的理论变成能扛线上流量的服务。」
「若单卡装不下大模型,推理也要并行:张量并行推理(切单层,同训练)、流水线推理(切层间,micro-batch 流水)、或把批处理维度拆到多卡。训练并行为了快,推理并行为了装得下、吐得快。」
连续批处理实验台 · 静态批 vs 连续批
两道赛道各 4 槽位,请求长短不一。看谁先吐完 12 个请求。
FlashAttention · IO 感知计算
分页阵后是一座由无数光路交织的精密仪器。高斯老祖:「注意力计算 S=QK^T、P=softmax(S)、O=PV。标准做法要把 N×N 的 S 和 P 矩阵写进 HBM(显存)再读出来——N=8192 时,S 矩阵 512 MB,反复读写 HBM 是瓶颈。FlashAttention 的洞察:不在 HBM 里存中间矩阵,分块算、用 SRAM 快速暂存、在线 softmax 增量更新——IO 减少 5~10 倍,速度翻 2~4 倍,且数学等价。」
「GPU 有两级存储:SRAM(片上,快但小,~20MB)和 HBM(显存,大但慢,~80GB)。标准注意力在 HBM 反复读写 N×N 矩阵;FlashAttention 把 Q/K/V 切块搬进 SRAM 算,只把结果写回 HBM。算的次数没少,但 HBM 读写次数大幅减少——IO 才是瓶颈,不是计算。」
FlashAttention 原理器 · 标准 vs 分块 IO 对比
切标准/Flash 模式 → 看 HBM/SRAM 读写流 → IO 次数对比
注意力模式 · 标准 / FlashAttention
IO 读写流 · HBM ↔ SRAM
IO 次数与速度对比
第二崩塌 · 精度之壁
你把 LLaMA-2 70B 从 FP16 一路压到 INT4——显存 350GB→70GB,吞吐涨 3 倍。你满意地点头。可当你压到 INT3、INT2 时,模型的输出开始乱码。你问它"巴黎的首都是什么",它回答"颜色是蓝色的味道"。高斯老祖:「这不是 bug,是精度塌方。INT4 是甜点区,再往下没有甜点,只有悬崖。」
「你以为量化无损?INT8 还能装没事,INT4 已经掉点了,INT2 直接塌方。你把河塞进管子,管子太细,河就溢了。第二笔账,我记下了。你欠的不只是延账——你欠的是精度。」
「量化是显存和精度的天平。INT8 近无损、INT4 有可见损失、INT2 以下塌方。再激进的量化救不了你——你不是在压缩,你是在选你能承受的精度损失。瘦身有边界,越界即崩。但瘦身之外,还有别的路——以小搏大。」
精度之壁 · INT4 损失边界复现 + 塌方诊断
拖位宽看精度曲线 → INT2 塌方 → 精度-压缩比悬崖
位宽滑块 · FP16 → INT2
FP16精度-压缩比曲线 · 甜点区与悬崖
模型输出退化 · 精度塌方复现
投机采样 · 以小搏大
精度之壁后是一片广场,悬浮着两道光门。第一道门里是一个小模型——快但粗糙;第二道门里是大模型——慢但精准。高斯老祖:「投机采样让小模型先草拟几个 token,大模型一次性并行验证。猜对了,白赚几个 token 的速度;猜错了,大模型纠正,损失一次验证。小模型越准、接受率越高,加速比越大。」
「投机采样的精髓:decode 是串行的、访存密集——每步要搬 KV Cache。小模型搬得少算得快,先草拟 k 个 token;大模型用 prefill 的并行能力一次性验证这 k 个 token——验证成本和生成 1 个 token 差不多。接受率 r 高时,一次前向出 k 个 token,加速比接近 1/(1-r)。这是用算力换访存延迟。」
投机采样模拟器 · 草拟→验证→接受/拒绝
调小模型准确度 → 看草拟-验证流程 → 接受率与加速比
小模型准确度旋钮
接受率 70%草拟→验证流程 · 小模型 k 个 token + 大模型并行验证
接受率 vs 加速比
Boss 战 · 延迟之壁
广场尽头浓雾重新合拢,温度骤降——延迟之壁凝聚成形。它不是人形,是一堵横亘推理殿深处的暗青光壁,壁面无数计时符文缓慢游走。它翻开一本账册:「你来了。带着你的两道刻痕,和你的延账。三问。答对,我消散。答错,你的元婴修为归零。」
「你以为一策略通吃两阶段——它不是。我住在你以为推理只有一个瓶颈的地方。你每以为训练完就快了,我就厚了一分。证明给我看:你的两道刻痕不是耻辱,是你的排除法——每一条此路不通,都在告诉你正确的路在哪里。」
延账累计 0 笔 · 三问全对后清零
顿悟 · 推理如电
暗青光壁消散,化作银青光点上浮。你站在山顶。山脚是你走过的路——推理两阶段、KV Cache、显存爆炸、量化、PagedAttention、FlashAttention、精度之壁、投机采样。山顶放着一面推理镜,镜中映着所有优化策略交织成的知识图谱。高斯老祖:「你想让模型应答如电。面前有三道认知:推理是两阶段、瓶颈在访存不在算力、优化是分阶段 trade-off。」
「推理优化的全部,是认清两阶段瓶颈不同,分阶段对症下药。prefill 算力密集用算子融合、量化提速;decode 访存密集用 KV Cache 管理、PagedAttention、FlashAttention、投机采样。没有银弹,只有 trade-off。元婴四层,推理如电——你已圆满。但元婴之路的下一层,不在推理,在让模型稳稳上线、长久服务。」
推理如电 · 三道认知 + 知识图谱 + 境界突破
点亮三道认知 → 点亮推理优化知识图谱 → 境界突破动画