跳到主要内容

推理加速基础

建议学时

4 学时。

建议安排:

课时内容课堂产出
1推理加速分层框架一张瓶颈定位图
2LLM 推理路径:prefill、decode、KV Cache一份指标解释表
3GPU offload、低比特 kernel、上下文长度实验设计一组实验矩阵
4Ubuntu Server 与 Jetson 的日志解读一份优化判断结论

本章对应实验章节:

学习目标

完成本章后,学习者应能:

  • 解释推理加速与模型压缩、量化之间的区别。
  • 把一次 LLM 推理拆成模型加载、prefill、decode、KV Cache 读写和服务返回。
  • 从算法、图优化、kernel、内存、runtime、硬件六层分析瓶颈。
  • 判断“模型更小”为什么不必然等于“推理更快”。
  • 设计 GPU offload、ctx-size、量化格式、线程参数和 llama-bench 的对比实验。
  • 在 Ubuntu Server + NVIDIA GPU 与 Jetson 两类设备上记录可复查的性能数据。

问题背景

量化和压缩解决的是“模型是否更小、是否更容易放进设备”的问题,推理加速解决的是“模型是否能在目标设备上以可接受的延迟和吞吐运行”的问题。

两者有关联,但不能混为一谈。

例如,一个 Q4 GGUF 文件比 Q8 文件更小,但在某些设备上可能出现:

  • 低比特 kernel 不匹配,运行时需要反量化到较高精度。
  • GPU offload 不完整,部分层回落到 CPU。
  • 上下文过长导致 KV Cache 占用过高。
  • Jetson 功耗模式较低或散热不足,持续运行时降频。
  • 服务化后 HTTP、队列、超时和并发带来额外延迟。

所以,本课程不把“模型文件大小”当作唯一优化目标,而是用实验记录回答三个问题:

  1. 当前瓶颈在哪里?
  2. 某个优化手段是否真的改善了瓶颈?
  3. 改善之后有没有牺牲质量、稳定性或可维护性?

图示讲解

推理加速不是一个单点动作,而是一条需要反复验证的链路。

LLM 推理可以拆成两个主要阶段。

这张图说明:首 token 延迟通常更受 prefill、模型加载、上下文长度影响;稳定 tokens/s 更受 decode、KV Cache 读取、kernel、内存带宽和 GPU offload 影响。

公开资料怎么转成本章内容

vLLM、TensorRT-LLM、TensorRT、llama.cpp、MLPerf 和 Nsight 的资料都能讲推理性能。本章不把外部 benchmark 图或厂商性能表当作课程结论,而是把外部资料改写成一个课堂可执行的问题:同一个 Qwen GGUF 模型,在同一设备上改变 -nglctx-size、量化格式和服务形态时,瓶颈到底移动到了哪里。

外部资料中的经典内容本章吸收什么课程里的落点
vLLM / PagedAttentionKV Cache 管理、batching、TTFT、throughput用来解释服务化指标,不作为主实验框架
TensorRT / TensorRT-LLMgraph、engine、kernel、precision 和 NVIDIA GPU 路线用于说明低比特必须被 runtime/kernel 承接
llama.cpp / llama-benchGGUF 本地推理、server、benchmark 工具本章主实验入口和日志来源
MLPerf Inference明确硬件、负载、指标和报告口径用于规范结果表,不引用外部成绩
Nsight SystemsCPU/GPU 时间线和系统级 profiling作为进阶排查工具,课堂先用日志和监控命令
Qwen llama.cpp 文档Qwen 本地运行和量化路径保持所有加速实验回到同一模型主线

本课程重绘:加速实验闭环

vLLM/DeepLearning.AI 的课程结构、KV Cache 和 metrics 图提醒我们:推理加速不是单一参数调优。本课程把它重画成 Qwen GGUF 的轻量闭环:压缩、服务、压测和质量记录必须放在同一张证据链里。

读图时先分账再下结论:llama-bench 的 tokens/s、CLI 的 prompt/eval 时间、HTTP API 的 elapsed、设备内存和 KV Cache 风险不能混成一个“速度变快了”。

来源图思路本章吸收什么本课程里的动作
vLLM course structure加速实验要贯穿 Qwen 量化、server 和报告把 Q8/Q5/Q4、llama-server、profiling 放进同一闭环
vLLM KV Cache长上下文瓶颈不能只靠权重量化解释固定并记录 ctx-size、prompt tokens、generated tokens
vLLM metricsTTFT、tokens/s、throughput、P99 不是同一个指标CLI、llama-bench 和 API elapsed 分开记录

DeepLearning.AI/vLLM serving 课程的价值在于把“压缩、服务、压测”连成一条闭环。本课程对应到更轻量的本地版本:

Serving 课程内容本课程保留什么本课程不展开什么
KV Cache 与显存层级图解释 ctx-size、并发和长上下文为什么会吃内存不要求学生改 vLLM 内存管理器
Continuous batching / PagedAttention说明 throughput 和单请求 latency 的取舍不搭建高并发生产集群
OpenAI-compatible servingllama-server 验证本地 API 可调用不把后端工程扩成完整 Web 服务
Benchmark under load区分 TTFT、tokens/s、throughput、并发不引用外部排行榜作为课程结论
Quantization lab把压缩收益和质量回归一起看不把 Qwen GGUF 主线换成其他工具链

所以,本章的结论必须写成“在哪个设备、哪个模型、哪个参数组合下观察到什么”,不能写成泛泛的“某框架更快”。

核心概念

推理加速六层框架

层级典型手段需要验证的问题
模型与算法小模型、蒸馏、剪枝、MoE 路由、speculative decoding质量是否下降,任务是否还可用
量化/压缩INT8、INT4、GGUF Q8/Q5/Q4、AWQ、GPTQ、SmoothQuantkernel 是否支持,精度是否可接受
图优化constant folding、operator fusion、layout transform是否被 dynamic shape 或 unsupported op 破坏
KernelGEMM、FlashAttention、低比特 kernel、Tensor Core目标硬件是否真正使用到加速实现
内存KV Cache 管理、减少 CPU/GPU 拷贝、pinned memory是否被内存带宽、碎片或 OOM 限制
Runtime/硬件batching、GPU offload、线程、功耗模式、散热延迟、吞吐、温度和稳定性是否达标

算术强度与 Roofline 判断

判断“瓶颈是计算还是内存带宽”有一个简单的数学工具:算术强度(arithmetic intensity)。

AI=FLOPs访存字节数AI = \frac{\text{FLOPs}}{\text{访存字节数}}

设备有两个上限:峰值算力 PP(FLOP/s)和内存带宽 BWBW(B/s)。Roofline 模型指出,实际性能不会超过:

性能min(P,  AI×BW)\text{性能} \le \min\big(P,\; AI \times BW\big)

单位检查:

AI 的单位是 FLOPs/Byte。
MemoryBandwidth 的单位是 Byte/s。
AI x MemoryBandwidth 的单位是 FLOPs/s。

算术强度低于拐点 P/BWP/BW 的计算是 memory-bound:算力再强也要等数据到达。

把它套到 LLM 的两个阶段:

  • prefill 一次处理整个 prompt,矩阵乘是“矩阵 × 矩阵”,每读一份权重做很多次乘加,算术强度高,更接近 compute-bound。
  • decode 每步只生成一个 token,矩阵乘退化为“矩阵 × 向量”(GEMV),每个权重读进来只用一次,算术强度约为 1,几乎总是 memory-bound。

由此可以直接估算 decode 速度上限:

tokens/sBW每 token 读取字节数BW模型权重字节数\text{tokens/s} \lesssim \frac{BW}{\text{每 token 读取字节数}} \approx \frac{BW}{\text{模型权重字节数}}

以 Qwen2.5-1.5B 的 Q4_K_M 为例(文件约 1 GB):内存带宽约 100 GB/s 的设备上,decode 上限是 100 tokens/s 量级;带宽约 1 TB/s 的桌面 GPU 上是 1000 tokens/s 量级。这是数量级估算,不是性能承诺——实际还有 KV Cache 读取、激活计算和调度开销。它只能说明:当 decode 主要受权重读取限制且 low-bit kernel 生效时,低比特格式更可能带来速度收益。

端到端延迟可以拆成:

Ttotal=Tprefill+ngenvdecodeT_{total} = T_{prefill} + \frac{n_{gen}}{v_{decode}}

TprefillT_{prefill} 随 prompt 长度增长,决定首 token 延迟;vdecodev_{decode} 是稳定生成速度,决定长输出的总耗时。两段的瓶颈类型不同,优化手段也不同。

Prefill 与 Decode

LLM 的一次生成通常分成:

阶段输入主要计算常见指标
Prefillprompt 中已有 token一次性处理上下文prompt eval time、首 token 延迟
Decode每次生成的新 token循环生成下一个 tokeneval time、tokens/s

当 prompt 很长时,prefill 会变重。

当生成很长时,decode 和 KV Cache 读写会成为主要成本。

瓶颈定位表

现象可能瓶颈该看什么可能动作
TTFT 很高prefill 慢、prompt 太长、冷启动prompt eval time、prompt token 数缩短 prompt、预热、检查 GPU offload
tokens/s 低decode 慢、内存带宽瓶颈、kernel 不匹配eval time、GPU/CPU 监控、启动日志换量化格式、检查 offload、换 runtime
显存爆KV Cache 或权重过大peak VRAM、ctx-size、模型文件降 ctx、换 Q5/Q4、换小模型
GPU 利用率低CPU sampling、数据搬运、fallbacknvidia-smi、runtime 日志调 threads、确认 CUDA 构建、检查参数
Jetson 发热降频功耗或温度限制tegrastatsnvpmodel调功耗模式、改善散热、降低负载
API 慢于 CLIHTTP、JSON、队列或客户端等待e2e latency、server log比较首次/二次请求、控制 max_tokens

KV Cache

KV Cache 保存 attention 的历史 key/value,使模型不需要每生成一个 token 都重新计算全部历史。

它带来速度收益,也带来内存压力。占用估算公式和 Qwen 数值算例见大模型量化与 KV Cache

decode 每生成一个 token 都要完整读一遍历史 cache,所以长上下文不只吃内存:cache 字节数会进入 roofline 估算的“每 token 读取字节数”,直接拉低 tokens/s。

需要观察:

  • --ctx-size 越大,预留或可使用的 KV Cache 空间越大。
  • 多轮对话越长,实际 KV Cache 占用越高。
  • Jetson 这类统一内存设备上,模型权重、KV Cache、系统进程会共同竞争内存。
  • 当显存或统一内存不足时,速度下降、OOM、进程被杀都有可能发生。

GPU Offload

在 llama.cpp 中,-ngl 常用于控制有多少层 offload 到 GPU。

教学实验中常用两端对比:

参数含义教学用途
-ngl 0尽量走 CPU 路径建立 CPU baseline
-ngl 99尽量把层 offload 到 GPU验证 GPU 是否带来收益

不要只看命令是否加了 -ngl,还要看启动日志和监控工具。

在 Ubuntu Server 上看 nvidia-smi

在 Jetson 上看 tegrastats

低比特 Kernel

低比特模型有两种收益来源:

  • 权重文件更小,加载和存储压力下降。
  • 如果 runtime 有匹配 kernel,计算和内存带宽也可能改善。

但如果低比特格式需要在计算前反量化,或者目标 GPU 没有合适 kernel,就可能出现“更小但不更快”的情况。

服务化开销

CLI 推理达标,不代表服务 API 达标。

服务化后还会增加:

  • HTTP 请求解析。
  • JSON 序列化。
  • 流式输出。
  • 并发排队。
  • 超时和错误处理。
  • 客户端重试。

所以本课程把 本地 OpenAI-compatible 服务 放在推理加速之后,而不是只停留在命令行输出。

代码/命令示例

以下命令用于教学演示。模型文件名按实际下载结果调整。

比较 GPU offload

cd ~/edge-ai-lab/src/llama.cpp

./build/bin/llama-cli \
-m ~/edge-ai-lab/models/qwen/qwen2.5-1.5b-instruct-q4_k_m.gguf \
-p "解释推理加速和量化的关系。" \
-n 128 \
--ctx-size 2048 \
-ngl 0 \
2>&1 | tee ~/edge-ai-lab/logs/ngl-0.txt

./build/bin/llama-cli \
-m ~/edge-ai-lab/models/qwen/qwen2.5-1.5b-instruct-q4_k_m.gguf \
-p "解释推理加速和量化的关系。" \
-n 128 \
--ctx-size 2048 \
-ngl 99 \
2>&1 | tee ~/edge-ai-lab/logs/ngl-99.txt

比较上下文长度

for ctx in 1024 2048 4096
do
./build/bin/llama-cli \
-m ~/edge-ai-lab/models/qwen/qwen2.5-1.5b-instruct-q4_k_m.gguf \
-p "用项目复盘方式解释 KV Cache 对端侧部署的影响。" \
-n 128 \
--ctx-size ${ctx} \
-ngl 99 \
2>&1 | tee ~/edge-ai-lab/logs/ctx-${ctx}.txt
done

使用 llama-bench

./build/bin/llama-bench \
-m ~/edge-ai-lab/models/qwen/qwen2.5-1.5b-instruct-q4_k_m.gguf \
-p 512 \
-n 128 \
-ngl 99 \
2>&1 | tee ~/edge-ai-lab/logs/llama-bench-q4.txt

KV Cache 量化与 flash attention

./build/bin/llama-cli \
-m ~/edge-ai-lab/models/qwen/qwen2.5-1.5b-instruct-q4_k_m.gguf \
-p "解释 KV Cache 量化的收益和风险。" \
-n 128 \
--ctx-size 8192 \
-ngl 99 \
-fa \
--cache-type-k q8_0 \
--cache-type-v q8_0 \
2>&1 | tee ~/edge-ai-lab/logs/kv-q8.txt

V cache 量化需要启用 flash attention(-fa),flag 细节以当前版本 --help 为准。对比启动日志中的 KV buffer size 行和长上下文下的 tokens/s。

并发吞吐基准

./build/bin/llama-batched-bench \
-m ~/edge-ai-lab/models/qwen/qwen2.5-1.5b-instruct-q4_k_m.gguf \
-ngl 99 \
-npp 512 -ntg 128 -npl 1,2,4,8 \
2>&1 | tee ~/edge-ai-lab/logs/batched-bench.txt

-npl 控制并发数。观察单流 tokens/s 和总吞吐的变化方向:decode 是 memory-bound,batching 把“每读一份权重服务一个 token”变成“服务多个 token”,总吞吐上升,但单流速度未必。

带宽与设备观测

# Ubuntu Server:逐秒观测 GPU 利用率、显存、功耗和频率
nvidia-smi dmon -s pucm -d 1 -c 60 2>&1 | tee ~/edge-ai-lab/logs/dmon.txt

# Jetson
tegrastats --interval 1000 --logfile ~/edge-ai-lab/logs/tegrastats-accel.log

教学实验设计

本章不追求一次调到最快,而是训练实验设计能力。

建议实验矩阵:

实验改变变量固定变量观察指标
GPU offload-ngl 0-ngl 99模型、prompt、ctx-size-n首 token、tokens/s、GPU 使用
上下文长度--ctx-size 1024/2048/4096模型、prompt、-ngl-nKV Cache、内存、首 token
量化格式Q8、Q5、Q4模型基座、prompt、ctx-size文件大小、质量、速度
CPU 线程-t 不同值CPU 或混合路径CPU 利用率、tokens/s
服务化CLI vs server模型、prompt、采样参数API 延迟、错误日志
Jetson 功耗不同功耗模式模型、prompt、ctx-size温度、频率、稳定性

每次实验只改变一个主要变量。

结果记录模板

硬件模型变量参数值首 tokentokens/s峰值内存温度/功耗质量备注日志
Ubuntu Server待填GPU offload待填待填待填待填待填待填待填
Ubuntu Server待填ctx-size待填待填待填待填待填待填待填
Jetson待填功耗模式待填待填待填待填待填待填待填

不要编造数字。

如果课堂设备无法完成某项实验,应写明原因,例如模型未下载、显存不足、驱动不可用或 Jetson 散热条件不足。

验收标准

本章验收不以“某个速度数值”为标准,而以记录完整性和解释能力为标准。

验收项达标标准
实验矩阵至少覆盖 GPU offload、ctx-size、量化格式三类变量
原始日志每次实验有对应文本日志
监控证据Ubuntu 有 nvidia-smi,Jetson 有 tegrastats
结论能说明瓶颈更像计算、内存、runtime、服务化还是功耗
质量判断记录输出是否跑题、重复、格式错误或事实错误

常见失败与排查

Q4 更小但没有更快

检查:

  • runtime 是否有对应量化格式的高效 kernel。
  • GPU offload 是否真的生效。
  • 是否因为上下文长度或 KV Cache 成为瓶颈。
  • 是否 CPU fallback 抵消了量化收益。

-ngl 99 后仍然没有 GPU 使用

检查:

  • llama.cpp 是否用 CUDA 构建。
  • 启动日志是否显示 CUDA 后端。
  • nvidia-smi 是否看到进程。
  • Jetson 上 tegrastats 是否看到 GPU/内存变化。

首 token 很慢但 tokens/s 可以接受

可能原因:

  • prompt 太长。
  • prefill 成本高。
  • 模型首次加载或冷启动。
  • 服务化路径有请求排队或 JSON 处理开销。

长上下文容易 OOM

可能原因:

  • ctx-size 设置过高。
  • 模型文件过大。
  • KV Cache 与权重同时占用显存或统一内存。
  • Jetson 上系统进程占用较多内存。

Jetson 连续运行后速度下降

检查:

  • tegrastats 中温度是否持续升高。
  • 功耗模式是否限制频率。
  • 电源适配器是否满足设备要求。
  • 是否需要主动散热或降低模型尺寸。

作业

完成以下任务,并在实验报告中回答:

  1. 在同一模型上比较 -ngl 0-ngl 99
  2. 在同一模型上比较 ctx-size 1024、2048、4096。
  3. 比较 Q8、Q5、Q4 中至少两个量化格式。
  4. 选择一组结果,解释瓶颈最可能来自哪里。
  5. 如果设备是 Jetson,补充功耗模式、温度和 tegrastats 日志。
  6. 用 roofline 框架解释你的 -ngl 对比结果:哪个配置更接近 memory-bound?依据是什么?
  7. tokens/sBW/模型字节数\text{tokens/s} \lesssim BW / \text{模型字节数} 估算你设备上 Q4 模型的 decode 上限,与实测值对比并解释差距来源。

参考资料

本章吸收方式: