GPU 推理部署学习指南:从显存计算到性能优化
给你 16GB 显存的 GPU,你能部署多大的模型?从显存计算、存储层级、Roofline Model 到量化策略,按 Bloom 认知分类法建立 GPU 推理部署的完整认知框架。
文档定位:这是一份按知识递进层级组织的学习文档,从最基础的”模型需要多少显存”出发,逐步深入到性能瓶颈分析和优化策略。
核心问题:假设给你一台 16GB 显存的 GPU,你能部署多大的模型?部署后推理速度如何?如何优化?
Level 1:模型显存占用计算(记忆 + 理解)
本层目标:能快速估算任意模型在任意精度下的显存需求,判断是否能装入给定 GPU。
核心公式
模型推理时的显存占用由三部分组成:
显存占用 = 参数量(B) x 每参数字节数 + KV Cache + 激活值
其中:
- 参数量:模型的”大小”,如 7B = 70 亿个参数
- 每参数字节数:取决于精度(FP32=4, FP16=2, INT8=1, INT4=0.5)
- KV Cache:推理时缓存的注意力状态,通常预留 ~2GB
- 激活值:前向传播中的中间结果,通常比前两者小得多
不同精度下的显存需求
| 精度 | 每参数字节 | 7B 模型占用 | 16GB 能装 | 典型用途 |
|---|---|---|---|---|
| FP32 | 4 bytes | 28 GB | ~3.5B | 训练(极少用于推理) |
| FP16/BF16 | 2 bytes | 14 GB | ~7B(紧凑) | 标准推理精度 |
| INT8/FP8 | 1 byte | 7 GB | ~14B | 量化推理(质量好) |
| INT4 | 0.5 bytes | 3.5 GB | ~28B | 极限量化(有精度损失) |
费曼解释
把模型想象成一本书。“参数量”是字数,“精度”是每个字占多大空间。FP32 像手写大字(每字 4cm),FP16 像印刷体(每字 2cm),INT4 像微缩胶片(每字 0.5cm)。16GB 显存就是你的书架 — 你要把书塞进去才能”读”(推理)。
实用结论:16GB 显存(如 RTX 4080/4090),FP16 部署约 6~7B 模型;INT4 量化可塞入 ~28B 模型,但速度和精度都有代价。实际部署还需预留 ~2GB 给 KV Cache 和激活值。
Level 2:存储层级与 Offload(理解 + 应用)
本层目标:理解”能装”和”能用”的区别,掌握不同存储介质对推理速度的影响。
核心认知:速度决定一切
模型权重可以存在三个地方:GPU 显存、CPU 内存、磁盘。理论上,CPU 内存 + 磁盘”无限大”,什么模型都装得下。但推理速度取决于数据搬运到计算单元的带宽。
存储层级对比
| 层级 | 带宽 | 延迟 | 加载 7B FP16 (14GB) | 角色 |
|---|---|---|---|---|
| HBM (GPU显存) | 3,350 GB/s | ns 级 | ~4 ms | 权重 + KV Cache |
| DDR5 (CPU内存) | ~100 GB/s | 百 ns | ~140 ms(慢 33x) | Offload 溢出权重 |
| NVMe SSD | ~7 GB/s | us 级 | ~2.0 s(慢 478x) | 冷数据/Checkpoint |
| HDD | ~0.2 GB/s | ms 级 | ~70 s(慢 16,750x) | 存档(不可用于推理) |
费曼解释
把推理比作做菜。显存是灶台旁的调料架(伸手就拿到),CPU 内存是厨房里的柜子(走几步),SSD 是储藏室(得走一段路),HDD 是超市(来回要半小时)。你不可能每次炒菜都从超市拿盐 — 虽然超市盐无限多。
工业级解决方案:KV Cache 冷热分离
月之暗面(Moonshot AI)提出的 Mooncake 方案:
- 热数据(当前正在推理的 KV Cache)留在显存
- 冷数据(历史对话的 KV Cache)转移到远端内存/SSD 池
- 通过预测性预取,在需要时提前搬回显存
类似的思路还有 vLLM 的 PagedAttention:把 KV Cache 按”页”管理,避免内存碎片化,提高显存利用率。
关键判断:“能装下”不等于”能用”。磁盘装 KV Cache 理论可行,但推理速度慢 500 倍以上,对在线服务来说等于不可用。做部署决策时,速度(吞吐/延迟)才是核心指标。
Level 3:Roofline Model — 性能瓶颈分析框架(分析)
本层目标:掌握 Roofline Model 分析方法,能判断一个 GPU 计算任务是 “Memory-Bound” 还是 “Compute-Bound”。
核心概念:算术强度
算术强度 (Arithmetic Intensity) = 计算量(FLOPS) / 数据搬运量(Bytes)
这个比值衡量的是:每搬运 1 字节数据,能做多少次计算。
Roofline 模型的两个区域
- Memory-Bound(左半区):算术强度低,数据搬运是瓶颈。计算单元在”等数据”。
- Compute-Bound(右半区):算术强度高,计算能力是瓶颈。数据已经就位,算力跟不上。
- Ridge Point(拐点):峰值 FLOPS / 峰值带宽。H100 的拐点约在 295 FLOPS/Byte。
LLM Decode 为什么是 Memory-Bound?
Decode 阶段每次只生成 1 个 token:
- 做的是 GEMV(矩阵 x 向量):计算量 = 2 x 参数量
- 但权重矩阵必须完整加载:数据搬运量 = 参数量 x 字节数
- 以 7B FP16 为例:FLOPS = 14G,搬运 = 14GB -> 算术强度 = 1.0
- H100 拐点在 295 -> 算术强度 1.0 远在左侧 -> 极端 Memory-Bound
直观理解:GPU 的算力利用率不到 1%,几乎所有时间都在等数据从显存搬到计算单元。
判断方法
使用 NVIDIA NSight Compute (NCU) 工具,profile 每个 kernel 的算术强度,看它落在 Roofline 图的左半区(mem-bound)还是右半区(compute-bound)。
关键数据:4B 模型在 H20 上实测,访存带宽比达到 70+,意味着 GPU 算力被严重浪费。这就是为什么小模型 decode 时 GPU 利用率极低。
Level 4:量化如何改变性能格局(分析 + 评估)
本层目标:理解量化不仅是”省空间”的工具,更是改变性能瓶颈性质的手段。掌握量化何时有效、何时无效。
量化改变算术强度的两个机制
机制一:同等数据量,计算量增加
- FP16:加载 2 bytes,做 1 次乘加
- INT4:加载 0.5 bytes,做 1 次乘加 + 反量化计算(dequantize)
- 结果:每字节数据的”含金量”(计算量)增加 -> 算术强度提高
机制二:KV Cache 量化减少带宽需求
- FP16 KV Cache:每 token 占 2 bytes x heads x head_dim
- INT8 KV Cache:占用减半 -> 加载到 SM 的数据量减半 -> 带宽瓶颈缓解
量化的”天花板效应”
| 场景 | 量化效果 | 原因 |
|---|---|---|
| 小模型 + 小 batch + Decode | 效果显著 | 原始状态深度 memory-bound,量化大幅缓解 |
| 大模型 + 大 batch + Decode | 收益递减 | 已接近 compute-bound,瓶颈不在搬运上了 |
| Prefill 阶段(长 prompt) | 几乎无效 | 本身就是 compute-bound(大矩阵 GEMM) |
费曼解释
量化就像把快递箱子压缩。如果快递站搬运速度是瓶颈(memory-bound),压缩箱子让同样速度搬运更多内容 -> 有效。但如果瓶颈是拆箱检查的速度(compute-bound),压缩反而更麻烦(还得解压) -> 无效甚至更慢。
核心洞察:量化的本质不是”省显存”,而是改变算术强度,把 memory-bound 问题转化为 compute-bound 问题。理解这一点,就能判断量化在你的场景下是否有效。
Level 5:综合策略判断(评估 + 创造)
本层目标:根据具体场景(模型大小、batch size、推理阶段),选择最合适的优化策略。
决策矩阵
| 场景 | 瓶颈类型 | 推荐优化手段 | 量化收益 |
|---|---|---|---|
| 小模型 + 小 batch + Decode | Memory-Bound | 权重量化(INT4/INT8) | 显著 |
| 大模型 + 大 batch + Decode | Compute-Bound | 多卡并行(TP/PP) | 递减 |
| Prefill 阶段(长 prompt) | Compute-Bound | Flash Attention、张量并行 | 几乎无 |
| KV Cache 占用大 | Memory-Bound | KV Cache 量化、PagedAttention | 显著 |
| 显存容量不足 | 容量瓶颈 | 量化 / Offload / 多卡切分 | 直接解决问题 |
实际部署决策流程
- 先算能不能装:参数量 x 字节数 + 2GB 预留 ≤ 显存?
- 装不下 -> 量化或换卡:INT4 能缩 4x,INT8 缩 2x
- 能装 -> 测速:跑 benchmark 看 throughput 和 latency
- 速度不够 -> 分析瓶颈:NCU profile,判断 mem-bound vs compute-bound
- Memory-bound -> 量化有效;Compute-bound -> 加卡/加算力
关键 Takeaways
- 16GB 显存实用上限:FP16 约 6~7B,INT4 约 14B(速度因反量化会下降)
- “能装”和”能跑”是两个问题:核心指标永远是速度(吞吐 / 延迟),不是能否 fit
- 量化的本质是改变算术强度:把 memory-bound 问题变成 compute-bound 问题
- 大模型 + 大 batch 本身就是 compute-bound:此时量化的加速效果有限
- Roofline Model 是统一分析框架:学会用 NCU 看算子在拐点的哪一侧
推荐学习路径
入门(Level 1-2)
- llm-memory-calculator:在线计算模型显存需求的工具
- Hugging Face Model Cards:查看模型参数量和推荐精度
- GGUF/GPTQ/AWQ 格式对比:了解不同量化格式的适用场景
进阶(Level 3-4)
- NVIDIA Roofline Analysis with NSight Compute:官方 Roofline 分析教程
- vLLM 源码 + PagedAttention 论文:KV Cache 管理的工业标准
- Mooncake 论文(月之暗面):KV Cache 池化存储方案
深入(Level 5)
- GPTQ 论文 (arxiv 2210.17323)
- AWQ 论文 (arxiv 2306.00978)
- FlashAttention 论文 (arxiv 2205.14135)
- NSight Compute — NVIDIA GPU kernel profiling tool
附录:技术参考与验证数据
GPU 规格速查
| 指标 | H100 SXM | H20 | A100 80GB | RTX 4090 | RTX 4080 |
|---|---|---|---|---|---|
| BF16 TFLOPS | 989 | 148 | 312 | 165 | 97 |
| HBM 带宽 | 3.35 TB/s | 4.0 TB/s | 2.0 TB/s | 1.0 TB/s | 0.72 TB/s |
| 显存容量 | 80 GB | 96 GB | 80 GB | 24 GB | 16 GB |
| Ridge Point | ~295 | ~37 | ~156 | ~165 | ~135 |
Ridge Point = Peak FLOPS / Peak BW (FLOPS/Byte)。数值越高,越不容易 memory-bound。
量化方案对比
| 方案 | 权重精度 | 压缩比 | 质量损失 | 适用场景 |
|---|---|---|---|---|
| GPTQ | INT4/INT3 | 4~5x | 低(<1% PPL) | 离线量化,GPU 推理 |
| AWQ | INT4 | 4x | 极低 | 激活感知,保留关键通道 |
| GGUF | Q4_K_M/Q5 | 3~4x | 低 | CPU/混合推理(llama.cpp) |
| FP8 | FP8 (E4M3) | 2x | 极低 | H100 原生支持,无反量化开销 |
| SmoothQuant | INT8 | 2x | 极低 | 权重+激活同时量化 |
论文与工具索引
- GPTQ — Post-training quantization for generative pre-trained transformers
- AWQ — Activation-aware Weight Quantization for LLM compression
- FlashAttention — Fast and memory-efficient exact attention with IO-awareness
- vLLM / PagedAttention — Efficient Memory Management for Large Language Model Serving
- Mooncake — Disaggregated KV Cache Management (Moonshot AI)
- NSight Compute — NVIDIA GPU kernel profiling tool
- SmoothQuant — Accurate and efficient post-training quantization for LLMs
Level 5.5:Prefill vs Decode — 双阶段性能特征
本层目标:理解 LLM 推理的两个阶段有完全不同的性能瓶颈,优化策略也完全不同。
Prefill 阶段
处理用户输入的全部 token(一次性),本质是一个 GEMM(矩阵-矩阵乘法):
Prefill:
Q: [seq_len, hidden_dim]
K: [seq_len, hidden_dim]
Attention: [seq_len, seq_len] -- 完整矩阵乘
FLOPs: O(seq_len^2 * hidden_dim + seq_len * hidden_dim^2)
性质: Compute-Bound (算术强度高)
瓶颈: GPU 算力
优化: TP 并行 / Flash Attention / Tensor Core 利用率
Decode 阶段
逐 token 生成,本质是一个 GEMV(矩阵-向量乘法):
Decode (每步):
Q: [1, hidden_dim] -- 只有 1 个新 token
K: [1, hidden_dim] -- 只新增 1 个 KV
Attention: Q vs 全部历史 KV
计算量: 2 * params (GEMV)
搬运量: params * bytes_per_param (全量权重加载)
算术强度: 2 / bytes_per_param = 1.0 (FP16)
性质: 极端 Memory-Bound
瓶颈: 显存带宽
优化: 量化 / Speculative Decoding / Batching
为什么 Batching 能救 Decode
单个 decode step 是 GEMV(memory-bound),但多个请求合并成 batch 后变成 GEMM(compute-bound):
| Batch Size | 计算类型 | 算术强度 (FP16) | GPU 利用率 |
|---|---|---|---|
| 1 | GEMV | 1.0 | < 1% |
| 8 | 小 GEMM | 8.0 | ~3% |
| 64 | 中 GEMM | 64.0 | ~22% |
| 256 | 大 GEMM | 256.0 | ~87% |
这就是 Continuous Batching 的意义:不是为了”处理更多请求”(那是 throughput),而是从根本上改变 decode 阶段的性能特征,从 memory-bound 变成 compute-bound。
Level 5.6:Continuous Batching 工作原理
本层目标:理解为什么 vLLM 的 continuous batching 比传统 static batching 效率高一个数量级。
Static Batching 的问题
传统做法:等凑满一个 batch,一起做 prefill,然后一起 decode 直到所有请求结束。
Static Batch (batch_size=4):
Req 1: [prefill----][decode------------------] (200 tokens)
Req 2: [prefill----][decode--------] (100 tokens)
Req 3: [prefill----][decode-] (30 tokens)
Req 4: [prefill----][decode------] (80 tokens)
^ Req 3 已完成但仍占位
问题: Req 3 在第 30 step 就结束了,但必须等 Req 1 生成完 200 tokens
GPU 利用率: 平均只有 52% (加权平均序列长度/最大序列长度)
Continuous Batching 的解法
每个 step 之后,已完成的请求立即退出,等待中的请求立即加入:
Continuous Batching:
Step 1-30: [Req1, Req2, Req3, Req4] (batch=4)
Step 31: Req3 完成 -> 移出 -> Req5 加入
Step 31-80: [Req1, Req2, Req4, Req5] (batch=4, GPU 满载)
Step 81: Req4 完成 -> Req6 加入
...
GPU 利用率: 接近 100% (始终满 batch)
Chunked Prefill:消除延迟尖刺
新问题:如果一个 8K token 的请求进入 prefill,会阻塞所有正在 decode 的请求。
解法:把 prefill 拆成多个 chunk(如 512 token 一块),和 decode 交错执行:
Without chunked prefill:
[Prefill 8K tokens (50ms)] -- 50ms 内所有 decode 请求被阻塞
With chunked prefill (chunk=512):
[Prefill 512][Decode batch][Prefill 512][Decode batch]...
每个 chunk ~3ms,decode 请求最多等 3ms
Level 5.7:NCU 实测 Kernel 分析
本层目标:学会用 NSight Compute 分析实际 kernel 的性能瓶颈。
典型 Decode Kernel 的 NCU 报告
Kernel: ampere_bf16_s16816gemm_bf16_128x128_ldg8_f2f_stages_32x3_tn
Grid: [1, 1, 1] Block: [128, 1, 1]
Duration: 12.4 us
Memory Throughput: 89.2% (接近峰值 = memory-bound)
Compute Throughput: 3.1% (算力严重浪费)
Achieved Occupancy: 24.3%
解读:
- Memory Throughput 89% + Compute Throughput 3% = 经典 memory-bound kernel
- 算力利用率只有 3%,GPU 几乎全部时间在等数据
- 优化方向:减少数据搬运(量化),不是增加计算
Prefill Kernel 的对比
Kernel: sm90_xmma_gemm_bf16bf16_bf16f32_f32_tn_n_tilesize256x128x64
Grid: [8, 4, 1] Block: [128, 1, 1]
Duration: 2.1 ms
Memory Throughput: 42.7%
Compute Throughput: 78.3% (接近峰值 = compute-bound)
Achieved Occupancy: 91.2%
解读:
- Compute Throughput 78% = compute-bound,GPU 在真正计算
- 优化方向:更好的 GEMM kernel(CUTLASS/Triton)、TP 并行
实操命令
# Profile 单个推理请求
ncu --set full --target-processes all \
--output profile_report \
python -c "from vllm import LLM; m=LLM('meta-llama/Llama-3-8B'); m.generate('Hello')"
# 只看 top 10 耗时 kernel
ncu --metrics sm__throughput.avg_pct_of_peak_sustained_elapsed,\
dram__throughput.avg_pct_of_peak_sustained_elapsed \
--top 10 python run_inference.py
相关文章
- 视频生成推理的 GPU 算力:从一道算术题说起 — 视频生成的计算量分析
- vLLM KV Cache Block Manager 深度教程 — KV Cache 管理的工程实现
- AI Inference 学习 Roadmap 2026 全景图 — 推理工程全景学习路线