大模型推理资源估算:权重、KV Cache、显存与部署容量
部署大模型时,“模型文件能放进显卡”只是第一道门槛。真正运行起来后,显存还要容纳 KV Cache、临时激活、Logits、CUDA 工作区和多卡通信缓冲。输入越长、输出越长、并发越高,资源结构也会发生变化。
本文建立一套可复用的估算方法,用于回答四个问题:
- 一个模型的权重需要多少显存?
- 指定上下文和并发后,KV Cache 需要多少显存?
- 一张或多张 GPU 最多能部署多大的模型?
- 磁盘、CPU 内存和 GPU 显存在推理中分别做什么?
关于 Token、Attention、GQA、Prefill 和 Decode 的完整数据流,可以先阅读上一篇文章:大模型推理解析:从 Token、QKV 到 GQA 与 KV Cache。
一、推理资源的总体构成
大模型推理涉及三个主要存储层级:
磁盘/SSD
保存模型文件、Tokenizer、配置和编译缓存
↓ 启动时读取
CPU内存
加载中转、请求调度、可选权重/KV卸载
↓ 复制或映射
GPU显存/HBM
模型权重、KV Cache、临时激活和计算工作区
推理显存可以近似写成:
M_total
≈ M_weights
+ M_kv_cache
+ M_activations
+ M_logits
+ M_runtime
实际部署时不要把显存规划到 100%。通常先取:
M_usable = GPU总显存 × 0.85~0.90
剩余空间用于 CUDA Context、显存碎片、通信缓冲和瞬时峰值。
二、模型权重占用
权重占用的基础公式:
[ M_{\text{weights}} \approx P_{\text{total}}\times b_{\text{weight}} ]
其中:
- (P_{\text{total}}):模型总参数量;
- (b_{\text{weight}}):每个参数占用的字节数。
| 权重格式 | 理论位数 | 理论字节/参数 | 7B权重 | 32B权重 | 70B权重 |
|---|---|---|---|---|---|
| FP32 | 32 bit | 4 | 28GB | 128GB | 280GB |
| BF16/FP16 | 16 bit | 2 | 14GB | 64GB | 140GB |
| FP8/INT8 | 8 bit | 1 | 7GB | 32GB | 70GB |
| INT4 | 4 bit | 0.5 | 3.5GB | 16GB | 35GB |
这里的 GB 是十进制估算。显卡和操作系统有时使用 GiB:
1GB = 10^9字节
1GiB = 2^30字节
所以 32B BF16 的 64GB 十进制权重,约等于 59.6GiB。
量化元数据
INT4/INT8 通常还需要:
- 每组 Scale;
- 可选 Zero Point;
- 分组索引;
- 未量化层;
- 对齐和 Kernel Workspace。
因此不能简单认为 70B INT4 一定只占 35GB。实际可能是:
理论权重:35GB
实际权重:约38~45GB
最可靠的方法是查看所有权重分片的实际总大小,并在目标推理框架中加载后观察峰值。
Dense 与 MoE
Dense 模型中:
总参数量 ≈ 每个Token参与计算的参数量
MoE 模型中需要区分:
总参数量:决定权重显存
激活参数量:主要决定每个Token的计算量
例如一个“80B 总参数、3B 激活参数”的 MoE,权重显存仍接近 80B 模型,但每个 Token 不会经过全部专家。
三、KV Cache 占用
自回归生成时,每一层都要保存所有历史 Token 的 K 和 V:
[ M_{\text{KV}} = 2\times L\times B\times S \times n_{\text{kv}}\times d_{\text{head}} \times b_{\text{kv}} ]
变量含义:
| 变量 | 含义 |
|---|---|
| (L) | Transformer 层数 |
| (B) | 同时驻留的序列数 |
| (S) | 输入 Token 与已生成 Token 的总长度 |
| (n_{\text{kv}}) | KV Head 数量 |
| (d_{\text{head}}) | 每个 Head 的维度 |
| (b_{\text{kv}}) | KV 数据类型的字节数 |
| 2 | K 和 V 两份 |
一个具体例子
假设:
L = 32
n_kv = 8
d_head = 128
KV精度 = BF16,2字节
B = 1
每新增一个 Token:
2 × 32 × 8 × 128 × 2
= 131072字节
≈ 128KiB
因此单请求约为:
1K Token ≈ 128MiB
8K Token ≈ 1GiB
32K Token ≈ 4GiB
128K Token ≈ 16GiB
如果同时有 16 个 32K 上下文请求:
4GiB × 16 ≈ 64GiB
这还没有包含模型权重。
GQA 为什么能显著节省显存
假设 Q Head 数量为 32:
MHA:KV Heads = 32
GQA:KV Heads = 8
其他配置相同时,GQA 的 KV Cache 约为 MHA 的四分之一。
并发服务中的真实计算
使用 Paged Attention 时,缓存通常按固定 Token Block 分配。总 KV Cache 更接近:
[ M_{\text{KV,total}} \approx \sum_i M_{\text{KV}}(S_i) ]
而不是粗暴地让每个请求都占满统一最大长度。仍需考虑最后一个 Block 的未使用空间和显存碎片。
四、激活、Attention 与 Logits
隐藏状态
一份基础隐藏张量:
[ M_H=B\times S_{\text{new}}\times H\times b ]
例如:
B = 1
S_new = 32768
H = 4096
BF16 = 2字节
一份隐藏状态约为:
1 × 32768 × 4096 × 2
= 256MiB
单层内部还会产生 Q/K/V、Attention 输出、RMSNorm 缓冲和 MLP 中间张量,所以峰值会是基础隐藏状态的若干倍。
Prefill 与 Decode 的区别
Prefill:
hidden [B,S,4096]
一次并行处理完整提示词,激活和计算量较大。
Decode:
hidden [B,1,4096]
当前激活很小,但每一层都要读取越来越长的 KV Cache。
Attention 矩阵
朴素 Attention 会产生:
[B,Heads,S,S]
长上下文下可能极其庞大。FlashAttention 使用分块计算,避免把完整 (S\times S) 矩阵长期写入显存,但 Attention 的计算关系仍然存在。
Logits
完整 Logits 形状:
[B,S,Vocab]
例如:
S = 32768
Vocab = 150000
BF16 = 2字节
若保留所有位置:
32768 × 150000 × 2
≈ 9.2GiB
推理只需要最后位置的下一 Token 分布。高效引擎会尽量只生成或保留必要位置的 Logits。直接调用普通模型 forward() 时,需要检查它是否返回了完整序列 Logits。
五、运行时预留
除了模型张量,还需要:
- CUDA Context;
- cuBLAS/FlashAttention Workspace;
- CUDA Graph;
- 显存分配器碎片;
- NCCL 通信缓冲;
- 量化反量化缓冲;
- 推理引擎预分配的 KV Block。
经验上可先预留:
小模型:2~4GiB
大模型:显存的5%~15%
多卡服务:额外考虑通信缓冲
最终必须使用真实模型、上下文和并发压测。
六、CPU内存和磁盘
磁盘
磁盘需要保存:
- 模型分片;
- Tokenizer 与配置;
- 多种量化版本;
- 下载和转换缓存;
- 推理 Kernel 编译缓存。
建议:
可用磁盘 ≥ 目标模型文件的1.5~2倍
如果同时保存 BF16、INT8、INT4,三种文件大小需要相加。
CPU内存
模型加载可能经过:
SSD → CPU内存 → GPU显存
CPU 内存可能用于:
- 权重加载中转;
- Safetensors 内存映射;
- 请求队列和 Token ID;
- CPU Offload;
- CPU KV Cache;
- 多进程模型副本。
保守估算:
纯GPU部署:模型文件的1.2~1.5倍
需要转换/量化:模型文件的1.5~2.5倍
使用Offload:再加被卸载的权重和KV
流式加载和内存映射可以降低峰值,但不要默认 CPU 内存完全不需要模型空间。
七、不同推理阶段使用什么
| 阶段 | 主要使用的资源 | 典型瓶颈 |
|---|---|---|
| 模型加载 | SSD、CPU内存、PCIe、GPU显存 | 文件读取和数据传输 |
| Tokenizer | CPU内存和CPU计算 | CPU |
| Prefill | 权重、激活、初始KV | GPU算力 |
| Decode | 权重、持续增长的KV | GPU显存带宽 |
| Sampling | 当前Logits | 通常较小 |
| 请求结束 | 回收该请求KV块 | 内存管理 |
模型权重一般在服务运行期间常驻显存。请求生成 <EOS> 后,该请求的 KV Cache 被释放或归还缓存池。
八、判断一张卡能部署多大模型
核心约束:
[ M_{\text{weights}} +M_{\text{KV}} +M_{\text{runtime}} \leq M_{\text{usable}} ]
对于 80GB 显卡,若使用 90% 作为规划上限:
M_usable ≈ 72GB
32B BF16
理论权重:64GB十进制,约59.6GiB
量化/格式/运行时开销:额外若干GiB
可能可以单卡加载,但能留给长上下文和高并发 KV Cache 的空间有限。
70B BF16
理论权重:140GB
单张 80GB 卡无法部署,需要多卡切分或降低精度。
70B INT4
理论权重:35GB
实际可能:约38~45GB
一张 80GB 卡通常还能为 KV Cache 和运行时留下较多空间,但前提是模型格式、显卡和推理 Kernel 相互兼容。
一个实用原则
部署前必须同时确定:
最大输入Token
+ 最大输出Token
= 最大上下文长度
不能只根据输入长度计算 KV Cache,因为输出也会逐 Token 扩展缓存。
九、多卡部署
Tensor Parallel
理论上:
[ 每卡权重\approx\frac{总权重}{TP} ]
但每卡还需要自己的 KV Cache 分片、通信缓冲和未完全切分的模块。某些 GQA 模型在 TP 数大于 KV Head 数时还可能出现 KV 复制。
Pipeline Parallel
不同层放到不同 GPU:
GPU0:前半层
GPU1:后半层
每卡保存自己层的权重和 KV Cache,但需要跨卡传递隐藏状态。
Data Parallel
每张 GPU 都保存一份完整模型:
GPU0服务请求组A
GPU1服务请求组B
它提高服务总吞吐,但不降低单卡权重需求。
十、可运行的估算代码
下面的代码按 GiB 粗略估算权重与 KV Cache:
from dataclasses import dataclass
GIB = 1024 ** 3
@dataclass
class Estimate:
weights_gib: float
kv_cache_gib: float
runtime_gib: float
total_gib: float
def estimate_inference_memory(
params_billion: float,
weight_bits: int,
num_layers: int,
num_kv_heads: int,
head_dim: int,
max_context: int,
concurrency: int = 1,
kv_bits: int = 16,
weight_overhead: float = 1.05,
runtime_gib: float = 4.0,
) -> Estimate:
params = params_billion * 1_000_000_000
raw_weight_bytes = params * weight_bits / 8
weight_bytes = raw_weight_bytes * weight_overhead
kv_bytes = (
2
* num_layers
* concurrency
* max_context
* num_kv_heads
* head_dim
* kv_bits
/ 8
)
weights_gib = weight_bytes / GIB
kv_cache_gib = kv_bytes / GIB
total_gib = weights_gib + kv_cache_gib + runtime_gib
return Estimate(
weights_gib=weights_gib,
kv_cache_gib=kv_cache_gib,
runtime_gib=runtime_gib,
total_gib=total_gib,
)
result = estimate_inference_memory(
params_billion=32,
weight_bits=16,
num_layers=64,
num_kv_heads=8,
head_dim=128,
max_context=32768,
concurrency=1,
)
print(result)
这只是第一轮筛选。实际值还受到滑动窗口、部分层 Attention、KV 精度、量化格式、TP 分片方式和推理引擎实现影响。
十一、部署检查清单
部署前按顺序确认:
- 模型总参数量和权重文件实际大小;
- 权重精度及量化元数据;
- 层数、KV Head 数和 Head Dimension;
- 最大输入与最大输出 Token;
- 最大并发和 Batch 策略;
- KV Cache 精度;
- 单卡或多卡切分方式;
- 推理框架显存预留;
- 实测峰值显存、TTFT 和 Decode TPS;
- 对真实业务输入做并发压测。
总结
大模型推理显存不是只看“参数量 × 精度”。完整关系是:
权重决定模型能否加载
KV Cache决定长上下文和并发能力
激活决定Prefill峰值
工作区决定运行余量
磁盘和CPU内存决定加载与Offload能力
最实用的判断公式仍然是:
权重 + 目标上下文/并发的KV Cache + 运行余量
< 可规划GPU显存
先用公式筛选,再用真实模型和真实请求压测,才能得到可信的部署容量。