☰
稀疏激活实测:24B 总参数只激活 2.2B,路由不均会丢 11.5% 的 token
2026/10/14 11:00:33 网站建设 项目流程

稀疏激活实测:24B 总参数只激活 2.2B,路由不均会丢 11.5% 的 token

10 月 13 日一份市场调研报告把国内 AI 加速器的出货账翻了新页:2026 年上半年英伟达在中国数据中心 AI 芯片市场的份额降到 34%,出货 67.8 万颗、同比少 44%,华为升到 28%。能拿到的卡在变小、变少,于是"这个模型要占多少显存、每生成一个 token 要搬多少权重"比"总参数多大"更值得先算清楚。

稀疏激活(MoE)就是把总量和激活量拆开的那条路线。10 月 13 日在 Hugging Face 上发布的 LFM2.5-24B-A2B 属于这一类:总参数 240 亿,官方说每个 token 只激活 20 亿左右。

下面两件事都是我在本机做的:先从权重文件头把参数账算出来(不下载权重本体),再用真实中文语料实测 top-k 路由的负载分布,看稀疏这条路到底会在哪里亏。环境是 WSL + 纯 numpy,没有 GPU。

不下载权重也能把参数量算准

safetensors 的文件头是个很省事的设计:前 8 字节是一个小端整数,记着头部 JSON 的长度;紧接着的 JSON 里每个张量的 dtype、shape、offset 都在。想核对一个模型的规模,根本不用拉几十 GB 权重,读开头 1 MB 就够。

importjson,subprocess url="<权重分片的下载地址>"subprocess.run(["curl","-sL","--max-time","90","-r","0-1048575",url,"-o","head.bin"])blob=open("head.bin","rb").read()n=int.from_bytes(blob[:8],"little")# 头部 JSON 的长度head=json.loads(blob[8:8+n])# 每个张量的 dtype / shape / offset

把 10 个分片的头都读一遍,逐张量把维度乘起来,得到的是这个模型的真实参数总量:

分片 model-00001-of-00010.safetensors 头部 623 个张量,参数 2313605504 头部 JSON 部分 83687 字节(前 8 字节记的就是这个长度),只读 1 MB 已经够 model.layers.2.feed_forward.expert_bias F32 [64] model.layers.3.feed_forward.expert_bias F32 [64]

顺带说一句,头部里出现的 expert_bias 张量,跟模型公开配置里那个 use_expert_bias 开关是同一件事,后面会用到。

模型分片数文件头累加的参数总量仓库索引里的权重字节数 ÷ 2差值
LFM2.5-24B-A2B1023,971,587,71223,971,590,1442432 字节,占比 5e-7
Qwen3-30B-A3B1630,532,122,62430,532,122,6240

两条路径能对上,说明按文件头算账是可靠的。

激活参数怎么算:固定部分 + 被选中的专家

以 LFM2.5-24B-A2B 为例,40 层里有 2 层是稠密前馈,剩下 38 层是 MoE,每层 64 个专家、每个 token 取 4 个。单个专家是 gate/up/down 三个矩阵,3 × 2048 × 1536 = 9,437,184 个参数;38 层 × 64 专家乘起来正好是头部统计里的 22,951,231,488,一分不差。

激活参数的口径我是这么定的:每一层都要跑的部分(注意力、卷积块、稠密层、router、norm)全算,MoE 层只算被选中的 top-k 专家,embedding 与 lm_head 不按整表计入。按这个口径:

模型总参数专家参数占比结构激活参数激活占比总量 ÷ 激活
LFM2.5-24B-A2B239.7 亿95.7%38 层 × 64 专家 top-421.9 亿9.2%10.9
Qwen3-30B-A3B305.3 亿95.0%48 层 × 128 专家 top-827.3 亿8.9%11.2

算出来的 21.9 亿跟模型名里的 A2B 能对上,两个模型的激活占比也都落在 9% 上下,总参数是激活参数的 11 倍左右。这个 11 倍很容易被顺手读成"快 11 倍",但它只是参数账。

显存账和带宽账是两笔,别混

专家权重平时不参与计算,可它必须整份躺在显存里等着被选中,所以常驻显存看的是总参数;解码阶段每生成一个 token 要过一遍被激活的权重,速度看的是激活参数的搬运量。同一份权重换精度,两笔账一起缩:

精度LFM 常驻权重LFM 每 token 搬运Qwen3-30B-A3B 常驻权重每 token 搬运
bf1647.94 GB4.385 GB61.06 GB5.461 GB
int823.97 GB2.193 GB30.53 GB2.731 GB
int411.99 GB1.096 GB15.27 GB1.365 GB

"24B 模型能塞进单卡"这句话只在 int4 下成立:12 GB 权重加上 KV cache 和中间激活,才有余地。发布页称这类模型在 Apple M5 Max 上能跑到 184 token/s,这个数字我没法在本机复测。按 int4 每 token 搬 1.096 GB 反推,等效要 200 GB/s 量级的内存带宽——这类模型的速度主要由机器的带宽决定,跟参数总量不是一回事。

路由实测:专家负载不均会丢 token

拿不到线上真实的路由日志,我用本机已有的 176 万字符中文报告语料,按字符二元组哈希映射成 20 万个 token 来逼近真实 token 的出现频率;隐藏状态用 64 维随机投影模拟,router 是随机初始化矩阵。这个设置能复现"负载分布不均匀"这件事,但拿不到训练过的 router 的具体偏置程度,这点后面会说。

容量因子是生产里最关键的旋钮,定义为每个专家能接收的 token 上限除以平均期望值:

logits=x @ W.T idx=np.argpartition(-logits,k-1,axis=1)[:,:k]# 每个 token 选 top-k 专家load=np.bincount(idx.reshape(-1),minlength=E)# 每个专家收到多少 tokencap=math.ceil(k*n/E)*capacity_factor# 单专家容量上限drop=sum(max(0,l-cap)forlinload)/(n*k)# 被丢弃的 token 比例

四次配置跑下来的真实输出:

语料字符数 1762928,模拟 token 数 200000,去重 token 值 23665 专家 16 top-2 | 最大/平均 1.37 | 最小/平均 0.58 | CV 0.196 | 丢弃率 cf1.0 6.90% cf1.25 1.65% cf1.5 0.00% cf2.0 0.00% 专家 16 top-4 | 最大/平均 1.20 | 最小/平均 0.85 | CV 0.096 | 丢弃率 cf1.0 4.01% cf1.25 0.00% cf1.5 0.00% cf2.0 0.00% 专家 64 top-4 | 最大/平均 1.51 | 最小/平均 0.43 | CV 0.272 | 丢弃率 cf1.0 11.49% cf1.25 2.57% cf1.5 0.04% cf2.0 0.00% 专家 128 top-8 | 最大/平均 1.83 | 最小/平均 0.35 | CV 0.310 | 丢弃率 cf1.0 12.32% cf1.25 4.30% cf1.5 0.68% cf2.0 0.00%
配置最大/平均最小/平均变异系数cf=1.0cf=1.25cf=1.5cf=2.0
16 专家 top-21.370.580.1966.90%1.65%0.00%0.00%
16 专家 top-41.200.850.0964.01%0.00%0.00%0.00%
64 专家 top-41.510.430.27211.49%2.57%0.04%0.00%
128 专家 top-81.830.350.31012.32%4.30%0.68%0.00%

两件事值得记一下。专家数从 16 涨到 128,最大专家与平均负载的比值从 1.20 走到 1.83——专家多并不自动均衡,反而更难摆平。容量因子按 1.0 给,64 专家那一档要丢掉 11.5% 的 token,等于十分之一的计算白花;给到 1.25 就降到 2.6%,1.5 基本归零。

专家偏置能把不均衡压下去

LFM 的配置里带着 use_expert_bias,权重头里也能看到每层一个长度为专家数的偏置向量。它的思路是给 router 的 logits 加一个可修正的偏移,谁的负载低于平均就抬一点。我在同一批 token 上试了一遍:前 10 万个 token 校准偏置,后 10 万个 token 做测试。

偏置修正前后(64 专家 top-4,同一批测试 token): 修正前 最大/平均 1.82 CV 0.339 丢弃率 cf1.25 6.11% 修正后 最大/平均 1.18 CV 0.058 丢弃率 cf1.25 0.00%

最大/平均从 1.82 压到 1.18,变异系数从 0.339 掉到 0.058,容量因子给 1.25 时已经不再丢 token。这一招几乎不增加推理成本,比单纯把容量因子加大划算——后者会让所有专家的矩阵乘法一起变宽,空转的算力也得算钱。

我怎么用它

挑模型时我现在先抄三行数字:总参数、激活参数、专家数与 top-k。第一行除精度字节得常驻显存,第二行乘精度字节得每 token 搬运量,第三行决定容量因子要给多少余量。这三行一列,机器能不能装、装完有多快,心里就八九不离十了。

踩过的坑留两个。第一次读文件头我用的 urllib 自己拼 Range 头,服务端不返回响应体,直接挂到超时;换成 curl 的-r 0-1048575拿到 206,同样的地址一次就成,1 MB 就够。第二个是容量因子给太紧:我先按 1.0 跑,64 专家那一档丢了 11.5% 的 token,而丢掉的那些 token 会直接进困惑度,不是"少算一点"这么轻。

要说清不确定的地方:我这是随机初始化的 router 加哈希出来的 token 分布,能复现负载不均这个现象、也能量出偏置修正的收益量级,但真实模型训练时本身就在压均衡,偏置幅度会比这个轻,具体数值不能直接搬。另外"激活参数小所以省显存"这个想法是错的——能省的只有精度,专家权重一个都省不掉。

三条可落地的动作

  1. 拿到新模型先读它的公开配置和权重文件头,把总参数、专家数、top-k、单专家矩阵维度抄成一张表,再决定存成几比特。
  2. 部署估算分两个量走:常驻显存 = 总参数 × 精度字节,每 token 搬运 = 激活参数 × 精度字节,不要用一个数字拍全部。
  3. 自己加 MoE 层的话,容量因子从 1.25 起步,同时打开专家偏置修正;先把负载统计跑出来,再谈加专家数。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询