DeepSeek V3 模型各子模块参数量精算

网上很多文章一般只提到 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)

《DeepSeek V3 模型各子模块参数量精算》上有13条评论

  1. "前 3 层 dense(固定激活 8 路由专家)"
    应该是固定激活 9 路专家?

  2. 请问为什么每个专家的参数量是:
    7168 * 2048 * 3 = 44,040,192,输入输出是7168,隐层是2048,那不大概是(7168*2048)*2吗

    1. DeepSeek V2 和 V3 中,专家部分与传统 FFN 结构不同,参考DeepSeek V3 开源的 model.py,可以看到其专家计算是由 3 个权重矩阵的计算组成的:

      class Expert(nn.Module):
          def __init__(self, dim: int, inter_dim: int):
              super().__init__()
              self.w1 = Linear(dim, inter_dim)
              self.w2 = Linear(inter_dim, dim)
              self.w3 = Linear(dim, inter_dim)
      
          def forward(self, x: torch.Tensor) -> torch.Tensor:
              return self.w2(F.silu(self.w1(x)) * self.w3(x))
      
  3. 路由 Gate 的参数量是:
    256 * 7168 + 256 = 1,835,264
    这里怎么理解
    特别是 + 256是啥

    1. 矩阵乘的 bias,即参数中的 model.layers.*.mlp.gate.e_score_correction_bias。V3 中的大部分矩阵乘都是无 bias 的,除了路由 Gate 这有。

  4. 那我想再问下,像在PD分离部署时,P是32路专家并行,每个GPU8个专家和1个冗余专家,D时是320个GPU,每个GPU部署一个专家也是256个专家加64个冗余专家,那这些256个专家的参数量也是您计算的每层专家的大小44M参数量吗?还是像有些网上看的是一个专家2.6B左右的参数量?这个实在有些不理解

    1. 这是个口径问题,也是个实现问题。

        在部署口径上,如果说“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 卡上;但是在第二种情况下,你就不能这么说了。
      1. 非常感谢您的解惑!
        还有个问题想请教下,您用过kv cache存储吗,说是推理计算过的KV值,缓存至外部存储,推理时可以复用KV值,提升推理速度,节约GPU的显存。但是像预填充阶段不是要对输入所有token进行并行计算这个咋复用啊,这个很难遇到相同的吧,除非是针对单个token的,这个在解码阶段还好理解,毕竟都是逐一token生产还有复用可能。但是一个相同的token计算KV值时难道不用管前面的TOKEN的吗,只要同一个token计算出的KV值都一样的?所以可以复用?

        1. KV Cache 的复用有两种,一种是复用 prefill cache,这个是 PD 分离的基础;还有一种是复用 prefix cache,你在我的博客中能找到相关文章。在 prefill 阶段依然可以使用 prefix cache,比如你要做角色扮演,肯定要告诉模型它的角色是啥,要怎么回答用户,这些指令在每次请求都需要携带,这时候 prefix cache 就有用了。推理框架只需要 extend prefix 后面的 token 就好了。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注