用手立一份显存预算
一句话总结
GPU内存预算有三个项目:模型权重、KV缓存和激活和开销。第二个项目最大,也是最常被忽视的。
为什么需要这个?
为了回答“A100 80GB一张可以装70B模型吗?”的问题,需要计算一下。光看权重,以fp16为基准是140GB,所以不能装。如果量化成4位,好像可以装大约35GB。但是忘了KV缓存了。
不计算后开始的话,在发布当天就会遇到OOM。而且OOM是当负载集中时出现的,所以是在最糟糕的时间点出现的。
怎么行动
模型加权是参数数量乘以dtype字节。如果是7B fp16,是14GB,如果是70B fp16,是140GB。量化的话,这个值会变小——INT8是一半,INT4是四分之一。
KV现金公式如下。
KV 바이트 = 2 x 레이어 수 x 은닉 차원 x 시퀀스 길이 x 배치 x dtype 바이트
前面2是指两个键和值的意思。以7B(32层,隐秘4096) fp16为基准计算的话是这样的。
| 上下文 | 配置1 | 配置8 |
|---|---|---|
| 4K | 2 GiB | 16 GiB |
| 32K | 16 GiB | 128 GiB |
| 128K | 64 GiB | 512 GiB |
如果在128K上下文中分配8个,则为512GiB。转发14GB模型时,KV缓存为512GB。为什么长上下文很难,就在这张表里。
减少的方法有三个。GQA将键值头以组共享,8组的话减少到8分之一。KV缓存量化减少dtype字节,如果是INT8的话是一半,如果是INT4的话是四分之一。PagedAttention虽然大小本身没有减少,但减少了碎片化,提高了实际使用效率。
叠加这些的话可以节省很多。从作者的例子来看,基本1,280GB变为GQA-8为320GB,INT8为160GB,PagedAttention实际使用标准约为128GB,INT4的话为80GB。
在现场相遇的样子
在实际工作中,最经常需要计算确定同时请求数量。从GPU总内存中减去权重和开销后,就会得出KV缓存预算,将其除以每个请求的KV大小,就会得出最大同时请求数量。这个值是max_num_seqs是限额,也是容量计划的起点。
量化选择也从这个计算中得出。GPTQ和AWQ只量化权重,KV缓存量化是单独设置的。如果混淆这两个,就会说“换成了4位,内存没有明显减少”——因为在语境较长的工作负载中,KV缓存占主导地位。
制定预算的办法
GPU内存分为三个部分。按顺序计算的话,可以同时处理的请求数量是 出来了。
1. 가중치 = 파라미터 수 × (비트수 ÷ 8)
7B × 2바이트(FP16) = 14.0 GB
7B × 0.5바이트(INT4) = 3.5 GB
2. 여유 = 활성화 + 단편화 ≈ 전체의 5~10%
3. KV 캐시로 쓸 수 있는 몫 = 전체 − 가중치 − 여유
KV现金一个令牌所消耗的大小是这样的。
토큰당 = 2(K와 V) × 레이어 수 × KV 헤드 수 × 헤드 차원 × 정밀도 바이트
예: Llama-3 8B (32레이어, KV헤드 8, 헤드차원 128, FP16)
= 2 × 32 × 8 × 128 × 2 = 131,072 바이트 ≈ 128 KB/토큰
GQA(Grouped-Query Attention)在这里造成了很大的差异。如果KV头有32个的话 虽然是512KB/令牌,但8个是128KB。最近型号使用GQA的原因就是这个。
24GB 카드, 8B 모델 FP16:
가중치 16GB + 여유 2GB → KV 로 6GB
6GB ÷ 128KB = 약 49,000 토큰
→ 문맥 4K 면 동시 12요청, 문맥 8K 면 6요청
这个计算告诉我们的东西
- 如果将上下文打开两倍,同时处理量就会减少一半。“以防万一,就用32K打开吧。” 是将处理量缩小为8分之一的决定。
- 量化只减少权重。将权重从INT4减少到3.5GB,那么可以用来使用KV的部分 大幅增加,同时处理量会增加几倍。这种情况比质量损失更有利很多。
- KV缓存也可以量化。 FP8 KV缓存将容量减少一半, 有很多报告表明,质量的影响比加权量化要小。
溢位的时候会发生什么事呢?
如果KV不足,vLLM会先占用(preemption)。选择一个正在进行的请求 扔掉现金,以后从头重新计算。
로그: Sequence group ... is preempted by PreemptionMode.RECOMPUTE
如果经常看到这个日志,说明同步性超过了容量。延迟会增加,GPU使用率 因为写得很高,很容易误读为“正在好好使用”。以抢先使用次数为指标 这是识别这种状态的方法。
下次实验要做的事情
将公式实现为代码,计算多个场景。验证7B 4K为2GiB,计算128K,应用GQA和INT8,最后在80GB GPU上计算出可能的最大同步请求数。