📌 本文部分内容由 AI 辅助整理,已经人工核对。文中显存数字均为公式估算值(非精确基准,实际受推理框架/分页策略/量化实现影响),文末脚本为本人实际运行验证过的可执行代码,涉及第三方模型的参数与发布时间均为公开报道/官方口径并已标注出处。

大模型显存需求计算:一个脚本算清权重 + KV Cache(附速查表,2026)

先扔一个我自己算完都愣了一下的数字。

DeepSeek-R1 671B,量化到 INT4,权重是 312GB。你可能觉得——4 张 80G 的卡差不多够了?

把上下文开到 32K、并发 8 路,KV Cache 是 976GB。是权重的 3 倍还多。

这就是为什么很多人按"参数量 × 2"估完显存、机器买回来才发现根本跑不动:大多数显存估算文章只算了权重,把 KV Cache 这块整个漏了

这篇给你三样能直接带走的东西:能背下来的公式、一个零依赖可直接运行的计算脚本、一张速查表。


一、三个公式,先背下来

① 权重显存 = 参数量 × 每参数字节数
     FP32 → 4 字节   FP16/BF16 → 2 字节
     FP8/INT8 → 1 字节   FP4/INT4 → 0.5 字节

② KV Cache = 2 × 层数 × KV维度 × 上下文长度 × 并发数 × 每元素字节数
     其中 KV维度 = kv_heads × head_dim
     注意是 kv_heads(GQA 里的 num_key_value_heads),不是 attention heads

③ 总需求 ≈ (① + ②) × 1.2      # 留激活/内存碎片/框架开销

公式②是重点,也是最容易写错的地方。

网上大量文章把 KV 维度直接写成 hidden_size——那是 MHA(多头注意力)时代的算法。现在主流模型基本都上了 GQA(分组查询注意力),多个 query 头共享一组 KV 头,KV Cache 能比 MHA 小好几倍。你要是拿 hidden_size 去套 GQA 模型,会高估一大截。

所以算之前,先去模型的 config.json 里把这三个值抄出来:num_hidden_layersnum_key_value_headshead_dim(有的模型没直接给 head_dim,用 hidden_size ÷ num_attention_heads 算)。


二、脚本:复制下来就能跑

零依赖,Python 3.6+ 直接运行,不用装任何包。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""大模型显存需求计算器 — 零依赖,Python 3.6+ 直接跑。"""

import argparse

DTYPE_BYTES = {
    "fp32": 4.0,
    "fp16": 2.0, "bf16": 2.0,
    "fp8": 1.0, "int8": 1.0,
    "fp4": 0.5, "int4": 0.5,
}

GB = 1024 ** 3


def weight_bytes(params_b, dtype):
    """params_b: 参数量,单位 B(十亿)。返回字节数。"""
    return params_b * 1e9 * DTYPE_BYTES[dtype]


def kv_cache_bytes(layers, kv_heads, head_dim, ctx, batch, kv_dtype):
    """KV Cache = 2(K和V) × 层数 × kv_heads × head_dim × 上下文 × 并发 × 字节"""
    return 2 * layers * kv_heads * head_dim * ctx * batch * DTYPE_BYTES[kv_dtype]


def human(nbytes):
    g = nbytes / GB
    return f"{g/1024:.2f} TB" if g >= 1024 else f"{g:.1f} GB"


def print_table():
    sizes = [7, 14, 32, 70, 235, 671, 744, 2800]
    dtypes = ["fp16", "int8", "int4"]
    print("\n仅权重显存速查表(不含 KV Cache)")
    print("-" * 52)
    print(f"{'参数量':>10} | " + " | ".join(f"{d.upper():>11}" for d in dtypes))
    print("-" * 52)
    for s in sizes:
        label = f"{s}B" if s < 1000 else f"{s/1000:.1f}T"
        cells = " | ".join(f"{human(weight_bytes(s, d)):>11}" for d in dtypes)
        print(f"{label:>10} | {cells}")
    print("-" * 52)
    print("注:MoE 模型按【总参数】算,不是按激活参数算——")
    print("    推理时全部专家权重都要常驻内存。\n")


def main():
    p = argparse.ArgumentParser(description="大模型显存需求计算器")
    p.add_argument("--params", type=float, help="参数量,单位 B(十亿)。MoE 填总参数")
    p.add_argument("--dtype", default="fp16", choices=DTYPE_BYTES, help="权重精度")
    p.add_argument("--ctx", type=int, default=4096, help="上下文长度")
    p.add_argument("--batch", type=int, default=1, help="并发请求数")
    p.add_argument("--layers", type=int, default=0, help="层数(不填则跳过 KV Cache)")
    p.add_argument("--kv-heads", type=int, default=0, help="KV 头数(GQA 用 num_key_value_heads)")
    p.add_argument("--head-dim", type=int, default=128, help="每个头的维度")
    p.add_argument("--kv-dtype", default="fp16", choices=DTYPE_BYTES, help="KV Cache 精度")
    p.add_argument("--overhead", type=float, default=1.2, help="余量系数,默认 1.2")
    p.add_argument("--gpu", type=float, default=0, help="单卡显存 GB,填了就估算需要几张卡")
    p.add_argument("--table", action="store_true", help="打印权重速查表后退出")
    a = p.parse_args()

    if a.table:
        print_table()
        return
    if a.params is None:
        p.error("需要 --params,或用 --table 看速查表")

    w = weight_bytes(a.params, a.dtype)
    kv = 0.0
    if a.layers and a.kv_heads:
        kv = kv_cache_bytes(a.layers, a.kv_heads, a.head_dim, a.ctx, a.batch, a.kv_dtype)

    total = (w + kv) * a.overhead

    print(f"\n模型参数量  : {a.params}B(MoE 请填总参数)")
    print(f"权重精度    : {a.dtype}")
    print(f"权重显存    : {human(w)}")
    if kv:
        print(f"KV Cache    : {human(kv)}  (ctx={a.ctx}, batch={a.batch}, "
              f"{a.layers}层 × {a.kv_heads}KV头 × {a.head_dim}维, {a.kv_dtype})")
    else:
        print("KV Cache    : 未计算(补 --layers 和 --kv-heads 才能算)")
    print(f"余量系数    : ×{a.overhead}")
    print(f"预估总需求  : {human(total)}")

    if a.gpu:
        need = total / (a.gpu * GB)
        import math
        print(f"按单卡 {a.gpu:g}GB 估算:约需 {math.ceil(need)} 张卡({need:.1f} 张向上取整)")
    print()


if __name__ == "__main__":
    main()

存成 vram_calc.py 就行。


三、跑给你看(输出是真实运行结果)

最简单的用法——32B 模型 FP16 要多少:

python3 vram_calc.py --params 32 --dtype fp16 --ctx 8192
模型参数量  : 32.0B(MoE 请填总参数)
权重精度    : fp16
权重显存    : 59.6 GB
KV Cache    : 未计算(补 --layers 和 --kv-heads 才能算)
余量系数    : ×1.2
预估总需求  : 71.5 GB

加上 KV Cache 和卡数估算——就是开头那个例子:

python3 vram_calc.py --params 671 --dtype int4 --ctx 32768 --batch 8 \
                     --layers 61 --kv-heads 128 --head-dim 128 --gpu 80
模型参数量  : 671.0B(MoE 请填总参数)
权重精度    : int4
权重显存    : 312.5 GB
KV Cache    : 976.0 GB  (ctx=32768, batch=8, 61层 × 128KV头 × 128维, fp16)
余量系数    : ×1.2
预估总需求  : 1.51 TB
按单卡 80GB 估算:约需 20 张卡(19.3 张向上取整)

看清楚了:权重 312GB,KV Cache 976GB。 只按权重估卡数,你会少买四分之三的卡。

(上面的 61 层 / 128 KV 头是示例值,实际请以你要跑的模型 config.json 为准。)


四、速查表(--table 直接打印)

       参数量 |        FP16 |        INT8 |        INT4
----------------------------------------------------
        7B |     13.0 GB |      6.5 GB |      3.3 GB
       14B |     26.1 GB |     13.0 GB |      6.5 GB
       32B |     59.6 GB |     29.8 GB |     14.9 GB
       70B |    130.4 GB |     65.2 GB |     32.6 GB
      235B |    437.7 GB |    218.9 GB |    109.4 GB
      671B |     1.22 TB |    624.9 GB |    312.5 GB
      744B |     1.35 TB |    692.9 GB |    346.5 GB
      2.8T |     5.09 TB |     2.55 TB |     1.27 TB

只是权重,不含 KV Cache。 拿它做第一道筛选:这一档我够不够得着;够得着了再用脚本把 KV Cache 补上算总账。


五、三个最容易翻车的坑

坑 1:MoE 按总参算,不是按激活参数算。

这个我见太多人栽了。一个 MoE 模型标着"671B 总参 / 37B 激活",有人就按 37B 备显存——不行。推理时虽然每个 token 只路由到部分专家,但全部专家的权重都得常驻内存,你没法预知下一个 token 走哪个专家。激活参数少省的是计算量(所以 MoE 推理快),不省内存。这两件事千万别混。

坑 2:KV Cache 随上下文和并发线性涨,长上下文场景它是主角。

开头那个例子已经说明问题了。特别注意它同时受 ctxbatch 影响——你压测时开 1 路并发很舒服,上线开 32 路直接 OOM,多半就是这里。

省 KV Cache 的常规手段:KV Cache 量化到 INT8(脚本里 --kv-dtype int8,直接砍半)、限制单请求最大上下文、用 PagedAttention 类的分页管理减少浪费。

坑 3:GB 和 GiB,差 7%。

模型参数量算字节用的是十进制(1B 参数 = 10⁹),显卡标称显存和系统显示用的是二进制(1GiB = 2³⁰ 字节)。所以 7B FP16 你会看到有的文章写 14GB、有的写 13GB——两个都对,只是单位口径不同。这脚本统一按 GiB 显示(和 nvidia-smi 对得上)。差 7% 在小模型上无所谓,到 TB 级就是几十 GB 的差距,卡着买卡的时候会咬人。


六、顺手算一个正在被讨论的:Kimi K3

月之暗面的 Kimi K3 是 2.8T 总参的 MoE,官方博客口径是权重将于 2026 年 7 月 27 日之前放出(来源:Kimi 官方博客 kimi.com/blog/kimi-k3)。

⚠️ 写这篇的时候(7 月 26 日)我实际查了 HuggingFace 的 moonshotai 官方组织页,还没有 K3 的仓库,权重尚未放出。所以现在网上说"K3 已开源、已经能下载"的,都是抢跑。以官方为准。

先用脚本把账算了,等权重真放出来心里有数:

python3 vram_calc.py --params 2800 --dtype int4 --gpu 80
权重显存    : 1.27 TB
预估总需求  : 1.53 TB
按单卡 80GB 估算:约需 20 张卡(19.6 张向上取整)

光权重、狠狠量化到 INT4,就要 1.27TB、约 20 张 80G 卡,还没算 KV Cache。这就是"开源了但你未必跑得动"的真实含义——2.8T 这个量级,个人和中小团队现实的路是等社区的量化/蒸馏版,或者直接用 API。


七、这脚本还没做的事(也是我想问你们的)

老实说几个已知的不足,别当它是精确工具:

  1. 没算激活值(activation),只用 1.2 的经验系数糊了过去。训练/微调场景激活占比大得多,这脚本主要面向推理
  2. 没处理 MLA(DeepSeek 那套多头潜在注意力),它对 KV Cache 的压缩机制和 GQA 不是一回事,套这个公式会高估
  3. 没考虑 PagedAttention 的分页浪费,实际 vLLM 里会有块内碎片。

第 2 条我最想找人聊:跑 MLA 架构模型的同学,你们实际测下来 KV Cache 大概是这个公式估算的几成? 给我个经验系数,我加到脚本里去,更新后在评论区回你。

另外想问一句:你们上线时 KV Cache 是留死显存还是动态分配的,--gpu-memory-utilization 一般设多少? 我见过设 0.9 上线就炸的,也见过 0.7 白白浪费的,想收集点真实的数。


小结

  • 显存 = 权重 + KV Cache + 余量,只算权重会严重低估
  • KV Cache 用 kv_heads(GQA)算,别用 hidden_size,否则高估一大截。
  • MoE 按总参数算显存,不是激活参数。
  • 长上下文 + 高并发时,KV Cache 可以是权重的好几倍(671B/32K/batch8:312GB 权重 vs 976GB KV)。
  • GB 与 GiB 差 7%,TB 级别时是几十 GB 的差距。
  • 脚本零依赖,--table 看速查表,--gpu 直接估卡数。

本文显存数字为公式估算(非精确基准),实际占用受推理框架、分页策略、量化实现影响,以真机压测为准。Kimi K3 参数与发布时间为官方博客/公开报道口径,截至本文发布权重尚未放出,请以官方为准。

更多推荐