参数量、上下文窗口与模型规格怎么看

参数量、上下文窗口与模型规格怎么看

打开任何一个模型主页,迎面而来是一串像乱码的东西:Qwen2.5-7B-Instruct-1M-Q4_K_M。每个片段都在告诉你一件具体的事,而这几件事合起来,正好决定了"我这台机器能不能跑"和"跑起来能聊多长"。这篇就是把这张卡片读穿。


本文的关系图(一个模型名,三步换算):

复制代码
模型卡片  Qwen2.5 - 7B - Instruct - 1M - Q4_K_M
              ↓        ↓       ↓       ↓
           参数量   对齐版本  上下文   量化档位
              ↓                ↓       ↓
        权重占多少显存    KV Cache 多大  每个参数几字节
              └────────────────┴───────┘
                          ↓
              一笔具体的账:显存够不够、能聊多长

一、先看一串让人头皮发麻的名字

复制代码
Qwen2.5-7B-Instruct-1M-Q4_K_M

第一次看到大概会想:这什么玩意儿。

但把它拆开,信息量其实很规整------这串名字里没有一个字是装饰,每一段都在回答一个工程问题。

这篇就按名字从左到右走一遍。走完你会发现,所谓"模型规格"其实就是三笔账:

  1. 参数量(7B)→ 权重文件有多大,要多少显存才装得下;
  2. 上下文窗口(1M)→ 能一次读多长,以及为了这个"长"要付多少显存;
  3. 量化档位(Q4)→ 每个参数用几个字节存,直接决定前两笔账的数值。

这三笔账算清楚,选型基本就清楚了。


二、参数量:一个真的能数出来的东西

先说清楚"参数"是什么。

模型的本质是一堆矩阵 (可以想成一张张 Excel 表格)。训练的过程,就是反复微调这些表格里的每一个格子。表格里全部格子的总数,就是参数量。

所以 7B 的意思是:这个模型里一共有 76 亿个格子,每一个都存着一个小数。

这里先插一句救命的澄清:B 是 billion(十亿),不是 byte(字节)。 "7B 模型"说的是 70 亿个参数,不是 7 个 GB。这个误解每年要坑掉一批人的显存预算。

参数量怎么数?就是每个矩阵的行 × 列加起来。以一个真实模型为例,直接算给你看。

python 复制代码
"""模型规格怎么读:把「7.6B / 128K / Q4」这些数字换算成显存。

以 Qwen2.5-7B 的真实结构参数为例,纯算术,只用标准库。
结论一句话:参数量决定「装得下吗」,KV Cache 决定「能聊多长」。
"""

L = 28            # 层数
D = 3584          # 隐藏维度
H = 28            # 注意力头数
KVH = 4           # KV 头数(GQA,4 个头共享)
HD = 128          # 每个头的维度
D_FF = 18944      # 前馈网络的中间维度
VOCAB = 152064    # 词表大小

CELL = 12


def disp_width(s):
    """显示宽度:中日韩字符占 2 格,用来对齐表格。"""
    return sum(2 if ord(c) > 0x2E80 else 1 for c in s)


def pad(s, n, right=False):
    fill = " " * max(0, n - disp_width(s))
    return fill + s if right else s + fill


def row(cells, widths):
    return "".join(pad(c, w, right=(i > 0)) for i, (c, w) in enumerate(zip(cells, widths)))


# ── ① 参数量是数出来的 ─────────────────────────────────────────
q_proj = D * D
k_proj = D * KVH * HD
v_proj = D * KVH * HD
o_proj = D * D
ffn = 3 * D * D_FF            # SwiGLU:gate / up / down 三个矩阵
norms = 2 * D
per_layer = q_proj + k_proj + v_proj + o_proj + ffn + norms
embed = VOCAB * D
lm_head = VOCAB * D
total = per_layer * L + embed + lm_head + D

W = (30, 14)
print("① 7.6B 这个数字是怎么数出来的(单位:百万)")
for name, val in [("Q 投影  d×d", q_proj), ("K 投影  d×(kv*h)", k_proj),
                  ("V 投影  d×(kv*h)", v_proj), ("O 投影  d×d", o_proj),
                  ("FFN 三个矩阵", ffn), ("两个 LayerNorm", norms)]:
    print(row([f"   每层 · {name}", f"{val/1e6:,.2f}"], W))
print(row(["   每层小计", f"{per_layer/1e6:,.2f}"], W))
print(row([f"   × {L} 层", f"{per_layer*L/1e6:,.2f}"], W))
print(row(["   词表嵌入", f"{embed/1e6:,.2f}"], W))
print(row(["   输出层", f"{lm_head/1e6:,.2f}"], W))
print(row(["   ---------------------------------------", "------------------------------"], W))
print(row(["   合计", f"{total/1e9:,.2f} B"], W))
print(f"   每层里 FFN 占 {ffn/per_layer:.1%}------参数量的大头是前馈网络,不是注意力")
print()

# ── ② 权重显存 ────────────────────────────────────────────────
print("② 权重显存 = 参数量 × 每个参数占几字节")
print(row(["   精度", "字节/参数", "权重显存"], (14, 12, 14)))
print("   " + "-" * 38)
for name, bpw in [("FP32", 4), ("BF16 / FP16", 2), ("INT8", 1), ("INT4", 0.5)]:
    print(row([f"   {name}", f"{bpw:g}", f"{total*bpw/1e9:.2f} GB"], (14, 12, 14)))
print()

# ── ③ KV Cache ────────────────────────────────────────────────
kv_per_token = 2 * L * KVH * HD * 2          # K 和 V,BF16 每元素 2 字节
print("③ KV Cache:每多一个 Token,都要多存一份它的 K 和 V")
print(f"   每个 Token:2(K/V) × {L}(层) × {KVH}(KV头) × {HD}(头维度) × 2 字节 = {kv_per_token:,} 字节")
print(row(["   上下文长度", "KV Cache 显存"], (14, 16)))
print("   " + "-" * 30)
for n, label in [(4096, "4K"), (32768, "32K"), (131072, "128K")]:
    print(row([f"   {label}", f"{n*kv_per_token/1e9:.2f} GB"], (14, 16)))
print("   注意:这是「一条对话」的量。并发 10 个用户,就再乘 10。")
print()

# ── ④ GQA 省了多少 ────────────────────────────────────────────
kv_mha = 2 * L * H * HD * 2
print("④ GQA 到底省了多少:如果 KV 头也用 28 个(老式 MHA)")
print(row(["   结构", "每 Token", "128K 上下文"], (20, 14, 16)))
print("   " + "-" * 50)
print(row(["   MHA(KV 头 28)", f"{kv_mha:,}", f"{131072*kv_mha/1e9:.2f} GB"], (20, 14, 16)))
print(row(["   GQA(KV 头 4)", f"{kv_per_token:,}", f"{131072*kv_per_token/1e9:.2f} GB"], (20, 14, 16)))
print(f"   只改这一处,KV Cache 缩小到 1/{kv_mha//kv_per_token}。")
print()

# ── ⑤ 一张 8GB 显卡的账本 ─────────────────────────────────────
print("⑤ 一张 8GB 显卡,实际能开多长上下文")
overhead = 1.0e9
free = 8e9 - total * 0.5 - overhead
print(row(["   权重(INT4)", f"{total*0.5/1e9:.2f} GB"], W))
print(row(["   框架 / CUDA 开销", f"{overhead/1e9:.2f} GB"], W))
print(row(["   留给 KV Cache", f"{free/1e9:.2f} GB"], W))
print(f"   → 能撑约 {free/kv_per_token/1024:.0f}K 上下文(当前 GQA 结构)")
print(f"   → 若换成不支持 GQA 的老结构,只剩 {free/kv_mha/1024:.0f}K")
print()
print("   所以:能不能跑起来看权重,能聊多长看 KV Cache。两笔账是分开的。")

真实运行结果 (本机实测,完整脚本见 code/06-model-spec-demo.py):

复制代码
① 7.6B 这个数字是怎么数出来的(单位:百万)
   每层 · Q 投影  d×d                  12.85
   每层 · K 投影  d×(kv*h)              1.84
   每层 · V 投影  d×(kv*h)              1.84
   每层 · O 投影  d×d                  12.85
   每层 · FFN 三个矩阵                203.69
   每层 · 两个 LayerNorm                0.01
   每层小计                           233.05
   × 28 层                          6,525.49
   词表嵌入                           545.00
   输出层                             545.00
   ---------------------------------------                  ------------------------------
   合计                               7.62 B
   每层里 FFN 占 87.4%------参数量的大头是前馈网络,不是注意力

② 权重显存 = 参数量 × 每个参数占几字节
   精度          字节/参数      权重显存
   --------------------------------------
   FP32                  4      30.46 GB
   BF16 / FP16           2      15.23 GB
   INT8                  1       7.62 GB
   INT4                0.5       3.81 GB

③ KV Cache:每多一个 Token,都要多存一份它的 K 和 V
   每个 Token:2(K/V) × 28(层) × 4(KV头) × 128(头维度) × 2 字节 = 57,344 字节
   上下文长度    KV Cache 显存
   ------------------------------
   4K                  0.23 GB
   32K                 1.88 GB
   128K                7.52 GB
   注意:这是「一条对话」的量。并发 10 个用户,就再乘 10。

④ GQA 到底省了多少:如果 KV 头也用 28 个(老式 MHA)
   结构                   每 Token     128K 上下文
   --------------------------------------------------
   MHA(KV 头 28)         401,408        52.61 GB
   GQA(KV 头 4)           57,344         7.52 GB
   只改这一处,KV Cache 缩小到 1/7。

⑤ 一张 8GB 显卡,实际能开多长上下文
   权重(INT4)                      3.81 GB
   框架 / CUDA 开销                  1.00 GB
   留给 KV Cache                     3.19 GB
   → 能撑约 54K 上下文(当前 GQA 结构)
   → 若换成不支持 GQA 的老结构,只剩 8K

   所以:能不能跑起来看权重,能聊多长看 KV Cache。两笔账是分开的。

① 这张表最值得注意的不是总数,而是最后那行:FFN 占了每层参数的 87.4%。

很多人直觉上以为参数量主要在"注意力"上------恰恰相反。注意力负责在词之间搬运信息 ,但它本身没那么大;真正堆满参数的是那一层层的前馈网络。所以你听到"70B 参数",其中大头是几十层叠起来的小型全连接网络。

还有一个细节:K、V 投影只有 1.84M,远小于 Q 和 O 的 12.85M------因为这里用了 GQA ,28 个注意力头共享 4 组 K、V。这是为了省显存专门设计的,第六节会算它省了多少。


三、参数量决定了什么,又不决定什么

它决定的:

  • 权重文件多大------一个参数占几字节,乘一下就是文件大小;
  • 最少要多少显存------装不下权重,一切免谈;
  • 大致多慢------参数量越大,每生成一个 Token 要翻的"格子"越多。

它不决定的:

参数量不等于知识量。 有个流传挺广的估算:模型存储事实性知识的上限,大约是每个参数 2 bit 。按这个算,一个 7B 模型全部参数用来"背事实",理论上限是 150 亿比特左右------折合不到 2 GB 的纯文本。

这个数字看着小得离谱,但它说明了一件事:模型不是靠"存"才显得知道得多的,它是靠"压缩"和"泛化"。同一个事实,它用一种比原文抽象得多的方式记着,所以才能举一反三。

参数量更不等于聪明。 同样 7B,不同数据配比、不同训练方法,出来的效果能差出一整个档次。参数量只是"容量",容量大不等于装得好。

这里有个值得记住的经验比例:在给定算力预算时,参数量和数据量要按比例增长------大致上每个参数配 20 个左右的 Token 是比较划算的配比。太少,参数浪费(模型"喂不饱");太多,参数不够装(模型"记不住")。

但今天的实际情况是故意打破这个比例 :参数压小、数据喂爆 。为什么?因为训练是一次性成本,推理是天天要付的钱 。把模型训小一点、多训几十倍数据,效果能追上来,但推理成本直接降一个数量级。这笔账在商业上完胜。


四、最容易踩的一个坑:MoE 的"两个参数量"

现在买模型,你会看到一种吓人的规格:

复制代码
总参数 671B,激活参数 37B

一个 671B 的模型?那不是要 8 张 H100 起步?

先别慌。这是 MoE(混合专家) 结构,它有两个参数量,而且必须分开看:

  • 总参数 :模型里所有格子的总数------671B。显存要按这个数准备。
  • 激活参数 :处理每一个 Token 时,实际参与计算 的那部分------37B。速度按这个数估。

MoE 的做法是把前馈网络拆成很多个"专家",每个 Token 只挑其中几个用。结果就是:这个模型囤了 671B 的知识,但每次只动用 37B 的算力。

带来的两个后果,一定要记住:

好消息:它比同等总参数的稠密模型快得多。 一个 671B 的 MoE,跑起来的速度可能接近一个 40B 的稠密模型。

坏消息:它对显存极其不友好。 因为专家是随 Token 挑的,你没法提前知道这次要用哪几个 ,所以全部专家的权重都得常驻在显存里。省了算力,省不了显存。

所以看到 MoE 规格,两句话要同时写在心里:"跑得动吗"看总参数,"跑得快吗"看激活参数。 只盯着其中一个数,判断一定会错。


五、上下文窗口:那个数字的真相

上下文窗口,就是模型一次最多能"看见"多少 Token。

这个数现在越标越大:4K、32K、128K、1M。但有四件事,宣传页上通常不会写。

第一,单位是 Token,不是字。

"支持 128K"指的是 128K 个 Token。中文大致一个汉字一个 Token 上下,但这个比例随分词器差异很大------同一个窗口,能装的中文和能装的英文完全不是一回事。

第二,标称 ≠ 有效。

一个很稳定的实验现象:把关键信息放在长文本的中间,模型最容易漏掉 ;放在开头或结尾,反而找得到。这就是所谓"中间迷失"。所以"支持 128K"不等于"128K 里的每个字都读进去了"。 真要用长上下文,把重要的东西放头尾,或者干脆多问一遍。

第三,长上下文不是免费的。

这是本文要算的重点。窗口每翻一倍,KV Cache 就翻一倍 ,而注意力的计算量翻 4 倍。128K 听起来很美,看到第六节的账单你就知道它有多贵。

第四,最关键的一条:上下文不是记忆。

窗口里的内容,对话一结束就没了。它是"临时工作台",不是"硬盘"。 想让它真的记住,得靠检索、向量库、微调那一整套外挂手段------塞进上下文里,只是"这次它能看见",不是"它学会了"。


六、动手算:规格 → 显存

现在把 ②③④⑤ 四张表连起来读,这才是这篇的正文。

先看 ②:权重显存。

同一个模型,换个精度,显存需求差 8 倍。FP32 要 30 GB,INT4 只要 3.8 GB。这就是量化存在的全部理由。

再看 ③:KV Cache。

这是全篇最容易被忽略的一笔账。

生成是一个 Token 一个 Token 吐 的。每吐一个新 Token,都要拿它的 Q 去跟前面所有 Token 的 K、V 算一遍。如果前面那些 K、V 不存下来,每走一步都得把历史重算一遍------那就是把 O(n) 的事干成了 O(n²)。所以必须缓存。

但缓存是显存里实实在在的一坨,而且它随上下文线性增长:

  • 4K 上下文:0.23 GB,无所谓;
  • 32K:1.88 GB,开始有感觉了;
  • 128K:7.52 GB------差不多是这个模型 INT4 权重的两倍。

再加上那句提醒:这是"一条对话"的量。 并发 10 个用户,乘 10。所以线上服务的显存瓶颈,经常不是模型权重,而是 KV Cache。 你看到"加大显存"的账单,一大半在为这个付钱。

然后是 ④:GQA 省了多少。

如果按老式做法让 28 个注意力头各自拥有自己的 K、V,128K 上下文要 52.61 GB------单是缓存就把一张 80G 的卡吃掉三分之二。

改成 4 个头共享一组 K、V(这就是 GQA),同样的上下文只要 7.52 GB ,缩小到 1/7。

这是现代模型几乎都上 GQA 的原因:它不改变表达能力多少,但把这份最"虚"的开销砍到了零头。

最后是 ⑤:一张 8GB 显卡的完整账本。

复制代码
权重(INT4)        3.81 GB
框架 / CUDA 开销    1.00 GB
留给 KV Cache       3.19 GB   → 约 54K 上下文

这张表解释了一个非常常见的困惑:

"我 8G 显卡,7B 模型明明能跑起来,为什么一开长上下文就崩?"

因为跑得起来和跑得久,是两笔账。3.81 GB 的权重只是"入场券"。你还能聊多长,取决于剩下那 3.19 GB 能装下多少 KV Cache------而这个值在 GQA 的帮助下才勉强到 54K,换成没有 GQA 的结构只剩 8K。

所以选型时,两个数必须一起看:参数量决定"装得下吗",KV Cache 决定"能聊多长"。


七、量化:Q4 到底损了什么

回到名字里最后一段:Q4_K_M。

量化就是:把每个参数从"占 4 字节"压缩成"占 0.5 字节"。

精度 每个参数 含义 7B 模型权重
FP32 4 字节 单精度浮点,训练用 30.46 GB
BF16 / FP16 2 字节 半精度,推理默认 15.23 GB
INT8 1 字节 8 位整数 7.62 GB
INT4 0.5 字节 4 位整数,消费级显卡的救星 3.81 GB

你在下载页上见到的那堆后缀,基本都在说这一件事:

  • GGUF :一种文件格式,专为本地推理设计,常配 Q4_K_M 这样的档位名------Q4 是 4 位,_K_M 是它内部的分组策略(哪些层量化得狠一点、哪些留得精细一点);
  • AWQ / GPTQ:两种常见的量化算法,思路都是"按重要性区别对待"------对结果影响大的权重保留更高精度,不重要的压得更狠;
  • bitsandbytes:HuggingFace 生态里最省事的一种,加载时在线量化。

关键问题:量化会不会让模型变笨?

诚实回答:会,但通常是"变钝"而不是"变傻"。

日常问答、写文案、翻译这类任务,Q4 和 FP16 的差别往往察觉不到。但有两类能力先受影响:

  • 需要精细分辨的判断("这两个有什么区别");
  • 长链条推理(多步数学、复杂逻辑)。

原因也不玄:量化本质上是在抹掉小数位。模型内部有些判断依赖的正是那些微小的数值差异,抹平了就分辨不出来了。

一条来自实践的粗略经验:4 bit 通常是性价比的拐点。 从 16 bit 压到 4 bit,显存省了 3/4,效果掉得很少;但继续往 3 bit、2 bit 压,掉速会突然变陡 。所以在没有实测数据的情况下,Q4 是默认安全的选择,除非你的任务特别吃推理精度。

顺便纠正一个常见期待:量化主要是省显存和显存带宽,不保证加速。 省了显存意味着能跑更大的模型、更长的上下文,这本身是收益;但计算本身未必更快,有时甚至因为要在计算时反量化而略慢。


八、现在回去读那串名字

把每一段对号入座:

复制代码
Qwen2.5  -  7B  -  Instruct  -    1M     -   Q4_K_M   .gguf
   ↓        ↓         ↓            ↓            ↓         ↓
系列/代际  参数量   对齐版本     上下文       量化档位    文件格式
   ↓        ↓         ↓            ↓            ↓
 越新越好  决定权重   是否经过   决定 KV      决定权重
         文件大小  指令微调     Cache 上限   实际大小

几个容易忽略的点:

  • Instruct / Chat 和 Base 是两个东西。 Base 是原始模型,只会"接着往下写",不会听指令;Instruct 是经过指令微调和人类偏好对齐的版本,才是你能直接对话的那个。你下载错了版本,会觉得这模型怎么这么蠢------因为它压根没被教过"回答问题"这件事。
  • 同一代会有多个尺寸 (0.5B / 1.5B / 7B / 14B / 32B / 72B)。它们不是"同一个模型的不同压缩版",而是各自独立训练的。 小尺寸版本的能力往往是断崖式下降的,不是平滑缩水。
  • "1M"这种超长上下文,常常是单独训练的变体 ,不是所有尺寸都有。同一个模型家族里,长上下文版和平常版可能是两套不同的权重。

九、四个常见误区

误区一:以为 7B 里的 B 是字节。

是 billion(十亿个参数)。这个误解的后果很直接:以为 7B 模型文件是 7 GB,结果一算 FP16 要 15 GB,显卡当场不够。

误区二:以为参数量大就更强。

参数量是容量 ,不是水平 。数据配比、训练轮数、对齐质量,每一样都能把参数量带来的优势吃掉。跨代比较更是陷阱:新一代的 7B 打赢上一代的 13B,是常态。

误区三:以为标称上下文就是可用上下文。

128K 是"窗口物理上限",不是"它真能读透 128K"。中间的信息容易被漏,而且越长的上下文,单位 Token 的推理成本越高。 需要长上下文时,建议实测一下:把答案埋在中间,看它找不找得到。

误区四:以为显存够装权重就能跑。

这只是入场券 。KV Cache、框架开销、并发用户的份,全都要算进去。算显存只算权重,是新手最常见的翻车方式。


十、把这件事放回地图上

把大模型的概念按依赖关系从下往上摞成几层------最底下是算力和数据,往上依次是文字的表示、模型结构、训练、调用,最顶上才是增强和智能体:

复制代码
L6  智能体层    Agent / Function Calling / ReAct / 记忆 / MCP
L5  增强层      RAG / 向量检索 / Rerank / GraphRAG / 微调
L4  调用层      Prompt / Few-shot / CoT / 温度 / Top-p
L3  训练层      预训练 / SFT / RLHF / DPO / LoRA / Scaling Law
L2  结构层      ★ Transformer / 注意力 / 参数量 / 上下文窗口 ★   ← 本篇在这里
L1  表示层      Token / 分词 / 词表 / Embedding
L0  底座        算力 / 数据 / 成本

本篇讲的和结构层是同一层------但视角不同:那一层讲的是"模型内部长什么样",这一篇讲的是"这些结构怎么变成你账单上的数字"。

三个数往回传的链条特别清楚:

  • 参数量往上决定了训练要多少算力、推理要多少显存;
  • 上下文窗口直接卡死了 RAG 能塞多少资料、智能体能带多少历史;
  • 量化档位决定了这一切能不能在一块消费级显卡上跑起来。

所以规格不是"参数表",是预算表。 你在 L4 写提示词、在 L5 搭检索、在 L6 做智能体,天花板全是被 L2 这三个数定下来的。

这一层留下的窟窿也很明确:上下文再长也买不来"记忆",窗口再大也不等于"读懂"。 既然塞进窗口的内容既有限、又会被漏掉、还会随对话消失------那就干脆换个思路:把知识放在模型外面,用的时候现查。 这个思路后来长成了一整套体系。


三条可以带走的结论

  1. B 是十亿,不是字节。参数量 = 权重文件大小的分子,也是显存门槛的最小值。它是容量,不是水平。
  2. 显存有两笔账:权重决定"装得下吗",KV Cache 决定"能聊多长"。上下文越长,第二笔账涨得越快------这是 GQA 存在的理由。
  3. 量化是显存和精度之间的旋钮。4 bit 通常是性价比拐点;它换来的是"跑得动更大的模型",不保证更快,也不保证不伤推理精度。

《大模型概念地图》专栏 · 第 6 篇

相关推荐
灵动的艺术1 小时前
如一 Agent 架构解读(十三):缓存命中率工程——Agent 的成本地基
人工智能·agent·如一
保卫大狮兄1 小时前
直营店和加盟店共用供货体系,进销存如何区分管理权限?
人工智能·进销存·库存·直营店·加盟店
数琨创享TQMS质量数智化1 小时前
数琨创享AI质量专家团skchat × skwork × skclaw × skcode正式发布
人工智能·科技
ckjr0071 小时前
AI时代,知识付费行业如何实现增长?
人工智能
清华kenny1 小时前
中医生活化智能终端对比:晓得养在合肥周边的服务优势
大数据·人工智能·安徽晓得养
ZKNOW甄知科技1 小时前
燕千云迭代版本发布:智能Agent深入业务现场
运维·人工智能·低代码·机器学习·自然语言处理·自动化·aigc
蒲公英内测分发1 小时前
智能手环出海测试,海外合作方分散在不同国家,Android 测试包怎么持续分发和更新?
android·前端·人工智能·测试工具·智能手表
危险、1 小时前
AI写的计划方案领导不满意?试下我这个反复打磨的计划方案提示词?
人工智能
镜象科技1 小时前
ACT自助干预适用人群:谁适合、谁不适合、边界在哪
人工智能