网上很多文章一般只提到 DeepSeek V3 模型的总参数量,很少有人分析各子模块的参数量。我试着让各 AI 根据配置计算一下,没有一个靠谱的,只能自己算了。(也许本文的内容后续会变成 AI 回答本问题的 RAG 养料)
下面是根据 DeepSeek V3 开源仓库 https://huggingface.co/deepseek-ai/DeepSeek-V3,对 DeepSeek V3 各子模块参数量进行的精算,在计算复杂的 TP、DP、EP 拆分时可以用作基数参考。如有错误,烦请评论指出。
嵌入层 Embedding
"vocab_size": 129280, // Token 字典大小
"hidden_size": 7168,
DeepSeek V3 的嵌入层参数量是:
129280 * 7168 = 926,679,040 (~0.9B)
MLA
"hidden_size": 7168,
"num_key_value_heads": 128,
"v_head_dim": 128,
"kv_lora_rank": 512,
"num_attention_heads": 128,
"q_lora_rank": 1536,
"qk_nope_head_dim": 128,
"qk_rope_head_dim": 64,
"num_hidden_layers": 61,
单层 MLA 中 Q 的 LoRA 参数量是:
7168 * 1536 + 1536 + 1536 * 128 * (128 + 64) = 48,760,320
单层 MLA 中 KV 的 LoRA 参数量是:
7168 * (512 + 64) + 512 + 512 * 128 * (128 + 128) = 20,906,496
单层 MLA 中 WO 的参数量是
128 * 128 * 7168 = 117,440,512
pre 和 post attention layernorm 的参数量是:
7168 * 2 = 14336
所以 DeepSeek V3 的 MLA 部分共 61 层的总参数量是:
(48,760,320 + 20,906,496 + 117,440,512 + 14336) * 61 = 11,414,421,504 (~11B)
MoE
"num_hidden_layers": 61,
"hidden_size": 7168,
"moe_intermediate_size": 2048, // 路由专家 MLP 的中间维度
"n_shared_experts": 1, // 共享专家数量
"n_routed_experts": 256, // 路由专家数量
"first_k_dense_replace": 3, // 前几层使用dense替换MoE
"intermediate_size": 18432, // 前3层 (9*moe_intermediate_size)
每个专家的参数量是:
7168 * 2048 * 3 = 44,040,192
路由 Gate 的参数量是:
256 * 7168 + 256 = 1,835,264
前 3 层 dense(固定激活 8 路由专家),前 3 层参数量是:
44,040,192 * 9 * 3 = 1,189,085,184
后 58 层稀疏(动态激活 8 路由专家),后 58 层参数量是:
(44,040,192 * 257 + 1,835,264) * 58 = 656,569,547,264
所以 DeepSeek V3 的 MoE 部分的总参数量是:
1,189,085,184 + 656,569,547,264 = 657,758,632,448 (~657B)
每次计算激活 1 个共享专家,8 个路由专家,所以 DeepSeek V3 MoE 部分的激活参数量是:
44,040,192 * 9 * 61 + 1,835,264 * 58 = 24,284,510,720 (~24B)
Layer 维度
前 3 层是 dense,没有 gate,基于上面的计算,DeepSeek V3 前 3 层每层的参数量是:
(48,760,320 + 20,906,496 + 117,440,512 + 14336) + (44,040,192 * 9) = 583,483,392
后 58 层是 MoE 稀疏激活专家,基于上面的计算,DeepSeek V3 后 58 层每层的参数量是:
(48,760,320 + 20,906,496 + 117,440,512 + 14336) + (44,040,192 * 257 + 1,835,264) = 11,507,286,272
输出层
DeepSeek V3 输出层的 RMSNorm 和 Linear 参数量是:
7168 和 129280 * 7168 = 926,686,208 (~0.9B)
总参数量
核对一下 DeepSeek V3 总参数量是否为 671B:
583,483,392 * 3 + 11,507,286,272 * 58 + 926,679,040 * 2 + 7168 = 671,026,419,200 (~671B)
核对一下 DeepSeek V3 激活参数量是否为 37B:
11,414,421,504 + 24,284,510,720 + 926,679,040 * 2 + 7168 = 37,552,297,472 (~37B)
这个与 README_WEIGHT.md 中提到的 36.7B 不同,我还没找到计算错误的地方。我理解也许是考虑到 embedding 层只是查表,并不是矩阵乘,所以实际激活参数是:
11,414,421,504 + 24,284,510,720 + 926,679,040 + 7168 + 7168 = 36,625,625,600 (~36.6B)
PS (20250208)
DeepSeek 更新了 README_WEIGHT.md ,激活参数量修正成了 36.6B,也去掉了包含 0.9B 输入 embedding 的注释。
MTP
DeepSeek V3 MTP 的 ebedding 和输出 head 与主模型共享,enorm 和 hnorm 的权重是:
7168 + 7168 = 14336
eh_proj 线性变换的权重规模是:
7168 * 14336 = 102,760,448
增加了一层 hidden layer,即第 61 层:
(48,760,320 + 20,906,496 + 117,440,512 + 14336) + (44,040,192 * 257 + 1,835,264) = 11,507,286,272
加起来 DeepSeek V3 MTP 的总参数量是:
11,507,286,272 + 102,760,448 + 14336 = 11,610,061,056 (~11.6B)
DeepSeek V3 MTP 的激活参数量是:
11,610,061,056 - 44,040,192 * (256 - 8) + 926,686,208 * 2 = 2,541,465,856
这个规模比 README_WEIGHT.md 中提到的 11.5B 独立参数,和 2.4B 激活参数都略大一点。
PS (20250208)
DeekSeek 更新了 README_WEIGHT.md ,MTP 的激活参数量由 2.4B 改成了 1.5B,可能跟上面的激活参数一样,都减去了 embedding 层。但在我的计算里,这个应该是 1.6B :),还是略有不同。
11,610,061,056 - 44,040,192 * (256 - 8) + 926,686,208 = 1,614,779,648 (~1.6B)
"前 3 层 dense(固定激活 8 路由专家)"
应该是固定激活 9 路专家?
因为共享专家还有一个,所以等同于 1 共享专家 + 固定的 8 路由专家。
请问为什么每个专家的参数量是:
7168 * 2048 * 3 = 44,040,192,输入输出是7168,隐层是2048,那不大概是(7168*2048)*2吗
DeepSeek V2 和 V3 中,专家部分与传统 FFN 结构不同,参考DeepSeek V3 开源的 model.py,可以看到其专家计算是由 3 个权重矩阵的计算组成的:
路由 Gate 的参数量是:
256 * 7168 + 256 = 1,835,264
这里怎么理解
特别是 + 256是啥
矩阵乘的 bias,即参数中的 model.layers.*.mlp.gate.e_score_correction_bias。V3 中的大部分矩阵乘都是无 bias 的,除了路由 Gate 这有。
那实际总专家数不是256+1,而是257*61个吗?
嗯,我们一般说的专家数,都是“每层的专家数”。
那我想再问下,像在PD分离部署时,P是32路专家并行,每个GPU8个专家和1个冗余专家,D时是320个GPU,每个GPU部署一个专家也是256个专家加64个冗余专家,那这些256个专家的参数量也是您计算的每层专家的大小44M参数量吗?还是像有些网上看的是一个专家2.6B左右的参数量?这个实在有些不理解
这是个口径问题,也是个实现问题。
在部署口径上,如果说“1 个 GPU 上放置 8 个专家”,一般的意思是“每层有 8 个专家部署在这个 GPU 上”,所以这里的 1 个专家(不含任何序号)就是需要 58*44M 左右的显存(不包含前3层)。
在实现上,有的实现可能是“每层的 n 号专家都在固定的一张卡上”,比如每一层的 0-7 路由专家,都在 rank 0 卡上;有的实现可能是“每层的 n 号专家,在不同的卡上”,比如第 5 层的 1 号专家,在 rank 0 卡上,第 6 层的 1 号专家,在 rank 3 卡上,但是每一层总有 8 个专家在每张卡上。在第一种情况下,你可以简单地说:(每一层的)0 号专家在 rank 0 卡上;但是在第二种情况下,你就不能这么说了。
非常感谢您的解惑!
还有个问题想请教下,您用过kv cache存储吗,说是推理计算过的KV值,缓存至外部存储,推理时可以复用KV值,提升推理速度,节约GPU的显存。但是像预填充阶段不是要对输入所有token进行并行计算这个咋复用啊,这个很难遇到相同的吧,除非是针对单个token的,这个在解码阶段还好理解,毕竟都是逐一token生产还有复用可能。但是一个相同的token计算KV值时难道不用管前面的TOKEN的吗,只要同一个token计算出的KV值都一样的?所以可以复用?
KV Cache 的复用有两种,一种是复用 prefill cache,这个是 PD 分离的基础;还有一种是复用 prefix cache,你在我的博客中能找到相关文章。在 prefill 阶段依然可以使用 prefix cache,比如你要做角色扮演,肯定要告诉模型它的角色是啥,要怎么回答用户,这些指令在每次请求都需要携带,这时候 prefix cache 就有用了。推理框架只需要 extend prefix 后面的 token 就好了。
非常感谢您的解惑!