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 能装典型用途
FP324 bytes28 GB~3.5B训练(极少用于推理)
FP16/BF162 bytes14 GB~7B(紧凑)标准推理精度
INT8/FP81 byte7 GB~14B量化推理(质量好)
INT40.5 bytes3.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 内存 + 磁盘”无限大”,什么模型都装得下。但推理速度取决于数据搬运到计算单元的带宽。

存储层级对比

存储层级金字塔
从 HBM 到 HDD,带宽差距超过 10000 倍
从 HBM 到 HDD,带宽差距超过 10000 倍
层级带宽延迟加载 7B FP16 (14GB)角色
HBM (GPU显存)3,350 GB/sns 级~4 ms权重 + KV Cache
DDR5 (CPU内存)~100 GB/s百 ns~140 ms(慢 33x)Offload 溢出权重
NVMe SSD~7 GB/sus 级~2.0 s(慢 478x)冷数据/Checkpoint
HDD~0.2 GB/sms 级~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 模型的两个区域

Roofline Model
判断任务是 Memory-Bound 还是 Compute-Bound 的统一框架
判断任务是 Memory-Bound 还是 Compute-Bound 的统一框架
  • Memory-Bound(左半区):算术强度低,数据搬运是瓶颈。计算单元在”等数据”。
  • Compute-Bound(右半区):算术强度高,计算能力是瓶颈。数据已经就位,算力跟不上。
  • Ridge Point(拐点):峰值 FLOPS / 峰值带宽。H100 的拐点约在 295 FLOPS/Byte。

LLM Decode 为什么是 Memory-Bound?

Decode 阶段每次只生成 1 个 token:

  1. 做的是 GEMV(矩阵 x 向量):计算量 = 2 x 参数量
  2. 但权重矩阵必须完整加载:数据搬运量 = 参数量 x 字节数
  3. 以 7B FP16 为例:FLOPS = 14G,搬运 = 14GB -> 算术强度 = 1.0
  4. 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 的数据量减半 -> 带宽瓶颈缓解
量化对 Roofline 的影响
量化把算术强度往右推,从 memory-bound 区域移向 compute-bound 区域
量化把算术强度往右推,从 memory-bound 区域移向 compute-bound 区域

量化的”天花板效应”

场景量化效果原因
小模型 + 小 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 + DecodeMemory-Bound权重量化(INT4/INT8)显著
大模型 + 大 batch + DecodeCompute-Bound多卡并行(TP/PP)递减
Prefill 阶段(长 prompt)Compute-BoundFlash Attention、张量并行几乎无
KV Cache 占用大Memory-BoundKV Cache 量化、PagedAttention显著
显存容量不足容量瓶颈量化 / Offload / 多卡切分直接解决问题

实际部署决策流程

  1. 先算能不能装:参数量 x 字节数 + 2GB 预留 ≤ 显存?
  2. 装不下 -> 量化或换卡:INT4 能缩 4x,INT8 缩 2x
  3. 能装 -> 测速:跑 benchmark 看 throughput 和 latency
  4. 速度不够 -> 分析瓶颈:NCU profile,判断 mem-bound vs compute-bound
  5. Memory-bound -> 量化有效Compute-bound -> 加卡/加算力

关键 Takeaways

  1. 16GB 显存实用上限:FP16 约 6~7B,INT4 约 14B(速度因反量化会下降)
  2. “能装”和”能跑”是两个问题:核心指标永远是速度(吞吐 / 延迟),不是能否 fit
  3. 量化的本质是改变算术强度:把 memory-bound 问题变成 compute-bound 问题
  4. 大模型 + 大 batch 本身就是 compute-bound:此时量化的加速效果有限
  5. 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)


附录:技术参考与验证数据

GPU 规格速查

指标H100 SXMH20A100 80GBRTX 4090RTX 4080
BF16 TFLOPS98914831216597
HBM 带宽3.35 TB/s4.0 TB/s2.0 TB/s1.0 TB/s0.72 TB/s
显存容量80 GB96 GB80 GB24 GB16 GB
Ridge Point~295~37~156~165~135

Ridge Point = Peak FLOPS / Peak BW (FLOPS/Byte)。数值越高,越不容易 memory-bound。

量化方案对比

方案权重精度压缩比质量损失适用场景
GPTQINT4/INT34~5x低(<1% PPL)离线量化,GPU 推理
AWQINT44x极低激活感知,保留关键通道
GGUFQ4_K_M/Q53~4xCPU/混合推理(llama.cpp)
FP8FP8 (E4M3)2x极低H100 原生支持,无反量化开销
SmoothQuantINT82x极低权重+激活同时量化

论文与工具索引

  • 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 利用率
1GEMV1.0< 1%
8小 GEMM8.0~3%
64中 GEMM64.0~22%
256大 GEMM256.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

相关文章