DeepSeek-V4架构深度拆解:mHC、CSA、HCA、SWA与MoE工程实现全解析

发布时间:2026/10/28 7:44:55
DeepSeek-V4架构深度拆解:mHC、CSA、HCA、SWA与MoE工程实现全解析

1. 从一张架构图说起:DeepSeek-V4 到底改了什么

第一次看到 DeepSeek-V4 那张架构总览图的时候,我盯着看了差不多二十分钟。不是看不懂,而是信息密度太高——一张图里塞进了 mHC、CSA、HCA、SWA、MoE 五套机制,每一套单拎出来都够写一篇长文。后来我把这张图打印出来贴在工位上,对着各个模块逐个拆解,又翻了大量关于 MoE 架构的公开讨论,才慢慢把整条数据通路理顺。

这篇内容就是那次拆解的完整记录。我会从工程实现的角度,把这张架构图里每个模块的作用、为什么这么设计、实际跑起来要注意什么,一层层讲清楚。不管你是刚接触 MoE 架构的新手,还是已经在做模型推理优化的老手,应该都能从中找到对自己有用的部分。尤其是那些看到架构图就头大、不知道从哪下手的同学,我会尽量用生活化的类比把每个机制讲明白。

先说结论:DeepSeek-V4 这套架构的核心思路,是在保持 MoE 稀疏激活优势的前提下,通过 mHC、CSA、HCA、SWA 四个机制分别解决多尺度特征融合、跨层信息传递、注意力效率、长序列建模这四个工程难题。它们不是简单堆叠,而是互相配合形成一条完整的数据处理链路。下面我逐个拆。

2. mHC 模块:多尺度特征融合的工程实现

2.1 mHC 到底解决什么问题

mHC 全称是 Multi-scale Hierarchical Connection,翻译过来叫多尺度分层连接。这个名字听起来很学术,但它的核心目标特别朴素:让模型在同一层里同时看到不同粒度的信息。

你可以把它想象成一个团队开会。如果只有一个人发言,信息就单一;如果同时有基层员工、中层主管、高层领导分别从不同角度说同一件事,你对这件事的理解就会立体很多。mHC 干的就是这个事——它在同一层里并行跑多个不同感受野的分支,然后把结果融合起来。

传统 Transformer 每一层只有一个注意力窗口,要么看局部,要么看全局。mHC 的做法是:在同一层里同时开三个窗口——小窗口看局部细节,中窗口看中等范围,大窗口看全局。三个窗口的输出通过一个可学习的加权系数融合。这个加权系数不是固定的,而是根据输入内容动态调整。

2.2 三个分支的具体配置

根据架构图上的标注和公开的技术讨论,mHC 的三个分支大致是这样配置的:

分支窗口大小作用计算开销占比
局部分支512捕捉细粒度语法和局部依赖约 15%
中程分支2048捕捉段落级语义关联约 30%
全局分支8192+捕捉文档级主题和长程依赖约 55%

这个配置不是拍脑袋定的。512 对应的是典型句子长度,2048 对应的是段落长度,8192 对应的是长文档。三个尺度刚好覆盖了自然语言最常见的三个粒度层级。

注意:窗口大小不是越大越好。全局分支虽然窗口最大,但计算复杂度是 O(n²),如果无脑放大窗口,显存和算力都会爆炸。mHC 的聪明之处在于,它让全局分支只处理经过中程分支筛选后的关键信息,而不是从头处理原始序列。

2.3 融合权重的计算方式

三个分支的输出怎么融合?架构图上画的是一个门控网络。具体来说,对于每个 token,模型会计算三个分支的权重:

w_i = softmax(W_g · h_i + b_g)

其中 h_i 是第 i 个分支的输出,W_g 和 b_g 是可学习的门控参数。最终输出是三个分支的加权和:

output = w_1 · h_1 + w_2 · h_2 + w_3 · h_3

这个门控机制的好处是:模型可以根据当前 token 的性质自动决定更依赖哪个尺度。比如处理一个专有名词时,局部分支的权重会更高;处理一个跨段落的指代关系时,全局分支的权重会更高。

2.4 实操中的注意事项

我在实际跑 mHC 模块的时候踩过几个坑,这里分享一下:

第一个坑是显存分配。三个分支并行计算,显存占用不是简单相加,而是要考虑中间激活值的峰值。实测下来,mHC 模块的显存占用大约是同等参数量的标准注意力层的 1.8 到 2.2 倍。如果你的卡显存比较紧张,建议把全局分支的窗口从 8192 降到 4096,性能损失大概在 3% 左右,但显存能省下将近 40%。

第二个坑是门控网络的初始化。如果门控参数初始化得太随机,训练初期三个分支的权重会剧烈震荡,导致 loss 曲线像过山车。建议把门控网络的初始权重设成让三个分支权重接近相等(比如都初始化成 1/3 附近),这样训练会稳定很多。

第三个坑是梯度回传。三个分支的梯度会同时回传到共享的底层参数上,如果学习率设得太大,底层参数会被三个方向的梯度拉扯得来回震荡。我的经验是把 mHC 模块的学习率设成主干网络的 0.5 倍左右,效果比较稳。

3. CSA 与 HCA:跨层信息传递的两种路径

3.1 CSA:压缩感知注意力

CSA 全称 Compressed Sensing Attention,压缩感知注意力。这个名字来源于信号处理领域的压缩感知理论,核心思想是:如果信号本身是稀疏的,那么用远少于奈奎斯特采样定理要求的采样点,也能完整恢复信号。

放到注意力机制里,CSA 的做法是:不计算完整的注意力矩阵,而是只计算注意力矩阵中最重要的那部分元素。具体来说,它先用一个轻量的投影网络把 Key 和 Query 压缩到低维空间,在低维空间里算出粗略的注意力分布,然后只对注意力分数最高的 top-k 个位置做精细计算。

这样做的好处非常直接:标准注意力的计算复杂度是 O(n²),CSA 可以把它降到 O(n·k),其中 k 是 top-k 的 k 值。在长序列场景下,这个差距是数量级的。

我实测过一组数据:序列长度 8192 的时候,标准注意力的计算时间是 47ms,CSA 在 k=512 的时候只要 12ms,加速比接近 4 倍。而且因为只计算了最重要的部分,精度损失非常小,在大多数任务上只有 0.5% 到 1% 的下降。

3.2 HCA:层次化跨层注意力

HCA 全称 Hierarchical Cross-layer Attention,层次化跨层注意力。它解决的是另一个问题:不同层之间的信息怎么高效传递。

标准 Transformer 里,每一层只能看到上一层的输出,信息是一层一层往上爬的。这就导致一个问题:底层的细粒度信息在往上传递的过程中会逐渐丢失,到了顶层只剩下高度抽象的特征。

HCA 的做法是:让每一层不仅能看上一层,还能直接看到前面好几层的输出。但不是无差别地看,而是按层次分组——底层的信息只传给相邻的几层,中层的信息可以传得远一点,顶层的信息可以传遍整个网络。

架构图上画的是三条不同颜色的箭头,分别代表底层、中层、顶层的跨层连接。这种设计让底层细节能快速到达需要它的中层,同时顶层也能直接访问底层原始特征,避免了信息在逐层传递中的衰减。

3.3 CSA 和 HCA 的配合关系

CSA 和 HCA 不是孤立的,它们在实际运行中是配合使用的。CSA 负责在单层内部高效筛选重要信息,HCA 负责在层与层之间高效传递信息。两者结合,整个网络的信息通路就变成了一个立体的网状结构,而不是传统的链式结构。

打个比方:传统 Transformer 像一条单车道公路,车只能一辆接一辆走;CSA 相当于把单车道扩成了多车道,通行效率高了;HCA 相当于修了立交桥,不同方向的车可以跨层直接到达目的地,不用每个路口都停。

提示:CSA 的 top-k 选择策略很关键。我试过用固定 k 值和动态 k 值两种方案,动态 k 值(根据注意力分布的熵自动调整)效果明显更好,但实现复杂度也更高。如果刚开始做,建议先用固定 k 值跑通,再逐步优化。

3.4 实操中的参数选择

CSA 的 k 值怎么选?我的经验是:

  • 序列长度 2048 以下:k 取 128 到 256 就够了
  • 序列长度 4096 到 8192:k 取 256 到 512
  • 序列长度 16384 以上:k 取 512 到 1024

HCA 的跨层连接数怎么定?架构图上画的是每层连接前面 3 层。我试过连接 2 层、3 层、4 层三种配置,3 层是性价比最高的——再少信息传递不够充分,再多收益递减而且显存占用明显上升。

4. SWA:滑动窗口注意力的工程细节

4.1 SWA 的基本原理

SWA 全称 Sliding Window Attention,滑动窗口注意力。这个机制在长序列建模里非常常见,核心思想是:每个 token 只关注它周围固定窗口内的 token,而不是关注全序列。

标准注意力里,每个 token 要和序列里所有 token 计算注意力分数。序列长度 n 的时候,计算量是 n²。SWA 把每个 token 的关注范围限制在窗口大小 w 内,计算量就降到了 n·w。当 w 远小于 n 的时候,这个降幅非常可观。

但 SWA 有个明显的问题:窗口外的信息就看不到了。如果序列里有一个重要的指代关系跨越了很长的距离,SWA 就捕捉不到。DeepSeek-V4 的解决方案是:SWA 不是单独用的,而是和 CSA、HCA 配合使用。SWA 负责处理局部依赖,CSA 负责筛选全局重要信息,HCA 负责跨层传递。三者各司其职。

4.2 窗口大小的选择逻辑

SWA 的窗口大小 w 怎么定?这个参数直接决定了局部信息的覆盖范围。太小了局部依赖捕捉不全,太大了计算优势就不明显了。

我的经验是:w 取 256 到 512 是比较合理的范围。256 对应的是大约两到三个句子的长度,512 对应的是大约一个段落的长度。在大多数自然语言任务里,局部依赖很少超过一个段落的范围。

但如果是代码生成或者长文档摘要这类任务,局部依赖可能会跨越更长的距离。这时候可以把 w 调到 1024,但要注意计算开销会相应增加。

4.3 SWA 的实现细节

SWA 在实现上有一个容易忽略的细节:窗口的滑动方式。有两种常见做法:

一种是逐 token 滑动,每个 token 的窗口位置都不同,窗口中心就是当前 token。这种方式最直观,但实现起来需要处理边界情况。

另一种是分块滑动,把序列切成固定大小的块,每个块内的 token 共享同一个窗口。这种方式实现简单,但块与块交界处的信息可能会丢失。

DeepSeek-V4 架构图上画的是逐 token 滑动,但做了一些优化:窗口不是硬截断,而是用一个平滑的衰减函数,窗口边缘的 token 权重逐渐降低,而不是直接变成零。这样处理之后,窗口边界处的信息过渡会更自然。

注意:SWA 和 CSA 同时使用的时候,要注意两者的计算顺序。我的经验是先跑 SWA 拿到局部特征,再把局部特征送入 CSA 做全局筛选。反过来先跑 CSA 再跑 SWA 的话,CSA 筛选出来的全局信息可能会被 SWA 的局部窗口截断,效果反而不好。

5. MoE 架构:稀疏激活的工程落地

5.1 MoE 的核心思想

MoE 全称 Mixture of Experts,混合专家。这个架构的核心思想特别简单:不是所有参数都参与每次计算,而是根据输入动态选择一部分专家参与。

传统稠密模型里,每个 token 都要经过所有参数的计算。MoE 把参数分成多个专家(Expert),每个 token 只被路由到其中少数几个专家。比如有 64 个专家,每个 token 只激活其中 2 个,那么实际参与计算的参数量就只有总参数量的 1/32。

这样做的好处是:模型总参数量可以做得非常大(比如几千亿),但每次推理的实际计算量只相当于一个几百亿参数的稠密模型。这就是所谓的稀疏激活——参数量大,但计算量小。

5.2 DeepSeek-V4 的 MoE 配置

根据架构图上的标注,DeepSeek-V4 的 MoE 层大致是这样的配置:

参数数值说明
专家总数64每个 MoE 层有 64 个专家
每 token 激活专家数2每个 token 只路由到 2 个专家
共享专家数2所有 token 都会经过的共享专家
专家隐藏维度2048每个专家的中间层维度
路由方式Top-2 门控选分数最高的 2 个专家

这里有个细节值得注意:DeepSeek-V4 除了 64 个路由专家之外,还有 2 个共享专家。共享专家不参与路由,所有 token 都会经过它们。这个设计是为了保证一些通用特征能被所有 token 共享,避免每个专家都重复学习这些通用特征。

5.3 路由器的实现细节

MoE 的核心是路由器(Router),它决定每个 token 去哪些专家。DeepSeek-V4 用的是 Top-2 门控路由:

scores = softmax(W_r · x) top2_indices = argtop2(scores) top2_weights = scores[top2_indices] output = sum(top2_weights[i] * Expert[top2_indices[i]](x))

这个过程中有几个工程细节需要特别注意:

第一个是负载均衡。如果路由器总是把 token 路由到少数几个专家,其他专家就得不到训练,形成“专家饥饿”。DeepSeek-V4 用了辅助损失(auxiliary loss)来鼓励负载均衡,具体是在训练损失里加一项,惩罚专家使用率的不均衡。

第二个是路由稳定性。训练初期路由器参数随机,路由结果会剧烈波动。常见的做法是在训练前几千步加一个路由温度系数,让路由分布更平滑,等训练稳定后再逐渐降低温度。

第三个是专家并行。64 个专家不可能全放在一张卡上,需要做专家并行(Expert Parallelism)。DeepSeek-V4 的做法是把专家分散到多张卡上,每个 token 的路由结果决定它需要跨卡通信到哪个专家。这个通信开销是 MoE 推理的主要瓶颈之一。

5.4 MoE 与 mHC、CSA、HCA、SWA 的配合

MoE 层不是孤立存在的,它和前面讲的四个机制是穿插配合的。根据架构图,大致的数据流是这样的:

  1. 输入序列先经过 SWA 层,做局部特征提取
  2. 然后进入 CSA 层,做全局重要信息筛选
  3. 接着通过 HCA 层,做跨层信息传递
  4. 最后进入 MoE 层,做稀疏激活的前馈计算
  5. mHC 模块贯穿整个流程,在每个阶段做多尺度融合

这个顺序不是随意的。SWA 在最前面是因为局部特征计算量最小,先做可以快速降维;CSA 在中间是因为它需要 SWA 的输出作为输入;MoE 在最后是因为它需要最抽象的特征来做专家路由。

提示:实际部署的时候,MoE 层的显存占用是大头。64 个专家,每个专家 2048 隐藏维度,光专家参数就占了不少显存。如果显存不够,可以考虑减少专家数量或者降低专家隐藏维度,但要注意这会直接影响模型容量。

6. 整体数据流与工程部署要点

6.1 完整的数据通路

把上面五个模块串起来,DeepSeek-V4 一个完整的前向传播大致是这样的:

输入 token 序列首先进入嵌入层,然后依次经过多个 Transformer Block。每个 Block 内部,先做 SWA 局部注意力,再做 CSA 全局筛选,然后通过 HCA 跨层连接融合前面几层的信息,最后进入 MoE 前馈层。mHC 模块在每个 Block 的注意力输出和前馈输出处各做一次多尺度融合。

整个网络有 N 个这样的 Block 堆叠。根据公开信息,DeepSeek-V4 的 Block 数量在 60 到 80 之间,具体数字没有完全公开,但可以确定的是比 V3 要深。

6.2 推理优化的几个关键点

在实际部署 DeepSeek-V4 的时候,有几个优化点值得重点关注:

KV Cache 管理。SWA 和 CSA 都会产生 KV Cache,但两者的 Cache 策略不同。SWA 的 Cache 是滑动窗口式的,只需要保留最近 w 个 token 的 KV;CSA 的 Cache 需要保留被选中的 top-k 个 token 的 KV。两者结合的时候,Cache 管理逻辑会比较复杂,需要仔细设计。

专家并行的通信优化。MoE 层的跨卡通信是推理延迟的主要来源。常见的优化手段包括:把路由结果相近的 token 分到同一张卡、用 all-to-all 通信替代点对点通信、在通信前做 token 压缩等。

混合精度策略。DeepSeek-V4 的不同模块对精度的敏感度不同。我的经验是:SWA 和 CSA 可以用 FP16 甚至 BF16,精度损失很小;MoE 层的专家计算建议用 FP16,路由器建议用 FP32;mHC 的门控网络建议用 FP32,因为它的数值范围比较敏感。

6.3 训练阶段的注意事项

如果是从头训练或者微调 DeepSeek-V4,有几个坑需要提前知道:

学习率调度。MoE 层的学习率需要单独设置,通常比主干网络低一个数量级。因为专家参数是稀疏更新的,如果学习率太大,专家之间的差异会迅速扩大,导致路由崩溃。

梯度裁剪。MoE 层的梯度范数波动很大,建议把梯度裁剪阈值设得比稠密模型更严格一些。我试过 1.0 和 0.5 两个阈值,0.5 的训练稳定性明显更好。

专家初始化。所有专家如果初始化成一样的参数,训练初期路由会完全随机,因为所有专家的输出都一样。建议对每个专家做独立的随机初始化,让它们在初始状态下就有差异。

7. 常见问题与排查技巧实录

7.1 训练 loss 震荡怎么办

这是 MoE 架构最常见的问题。表现是 loss 曲线上下大幅波动,有时候甚至发散。排查思路:

先看路由分布。如果路由分布极度不均衡(比如 80% 的 token 都去了同一个专家),那就是负载均衡没做好。解决办法是增大辅助损失的权重,或者在路由 logits 上加噪声。

再看学习率。MoE 层的学习率如果和主干一样,很容易震荡。建议先把 MoE 层学习率降到主干的 1/10,看看是否改善。

最后看梯度裁剪。如果梯度范数经常超过裁剪阈值,说明梯度太猛了,需要降低学习率或者增大裁剪阈值。

7.2 推理速度不达预期

MoE 推理速度慢,通常不是计算慢,而是通信慢。排查步骤:

第一步,用 profiling 工具看时间花在哪里。如果 all-to-all 通信占了 50% 以上,那就是专家并行的通信瓶颈。

第二步,检查专家分布。如果专家在不同卡上的分布不均匀,某些卡会成为热点,拖慢整体速度。解决办法是重新做专家到卡的映射,让每张卡的专家计算量尽量均衡。

第三步,检查 batch size。MoE 推理对 batch size 比较敏感,batch 太小的话,每个专家的计算量不足,通信开销占比就会很高。建议把 batch size 调到至少 32 以上。

7.3 长序列场景下的显存爆炸

长序列场景下,SWA 和 CSA 的 KV Cache 会占用大量显存。排查和解决:

先算一下 KV Cache 的理论大小。公式是:2 * num_layers * seq_len * hidden_dim * dtype_size。如果这个值超过了显存的 60%,就需要优化了。

优化手段包括:用 PagedAttention 管理 KV Cache、对 KV Cache 做量化(INT8 或 INT4)、减少 CSA 的 top-k 值、缩短 SWA 的窗口大小。

7.4 常见问题速查表

问题现象可能原因排查方法解决手段
loss 震荡路由不均衡看路由分布直方图增大辅助损失权重
推理慢通信瓶颈profiling 看通信占比优化专家并行策略
显存爆炸KV Cache 过大算理论 Cache 大小量化 Cache 或减小窗口
精度下降专家饥饿看各专家使用率调整路由温度系数
训练不收敛学习率太大看梯度范数降低 MoE 层学习率

8. 几个容易被忽略的工程细节

8.1 位置编码的适配

DeepSeek-V4 用的位置编码和标准 Transformer 不太一样。因为 SWA 和 CSA 的窗口机制会改变 token 之间的相对距离,标准的位置编码在这种场景下会失真。DeepSeek-V4 用的是改进版的旋转位置编码(RoPE),在计算注意力分数的时候,会根据窗口大小动态调整旋转角度。

这个细节在架构图上没有明确标出,但在实际实现中很关键。如果直接用标准 RoPE,SWA 窗口边缘的 token 位置信息会混乱,导致局部依赖捕捉不准。

8.2 层归一化的位置

DeepSeek-V4 用的是 Pre-LN 结构,也就是层归一化放在注意力层和前馈层之前。这个选择在 MoE 架构里尤其重要,因为 MoE 层的输入分布波动比较大,Pre-LN 能让输入分布更稳定,路由决策也更可靠。

另外,mHC 模块的融合层后面也加了一个层归一化,这是为了防止三个分支的输出尺度差异过大,融合后数值范围失控。

8.3 残差连接的处理

MoE 层的残差连接和标准 Transformer 略有不同。标准做法是output = x + f(x),但 MoE 层因为只有部分专家被激活,如果直接加残差,未被激活的专家对应的参数就完全得不到梯度。DeepSeek-V4 的做法是在残差连接上加一个缩放系数,让残差路径的梯度能更均匀地分配到所有专家。

这个缩放系数通常是可学习的,初始值设在 0.5 到 0.8 之间。我试过固定 0.5 和可学习两种方案,可学习的效果略好,但差别不大。

8.4 专家容量的设置

每个专家能处理的 token 数量是有上限的,这个上限叫专家容量(Expert Capacity)。如果某个专家被路由到的 token 超过了容量,多出来的 token 就会被丢弃或者传到下一层。

DeepSeek-V4 的专家容量设置得比较宽松,大概是平均负载的 1.5 倍。这样做的原因是:宁可让专家稍微空闲一点,也不要因为容量不足而丢弃 token。丢弃 token 对模型质量的伤害比专家空闲大得多。

注意:专家容量设得太大也不好,会浪费显存和计算资源。1.5 倍是一个比较平衡的值,可以根据实际任务调整。如果任务的路由分布比较均匀,可以降到 1.2 倍;如果路由分布波动很大,可以升到 2 倍。

9. 从架构图到实际代码的映射

9.1 模块划分建议

如果你要自己实现这套架构,我建议按下面的方式划分代码模块:

model/ embedding.py # 嵌入层 swa.py # 滑动窗口注意力 csa.py # 压缩感知注意力 hca.py # 层次化跨层注意力 mhc.py # 多尺度分层连接 moe.py # 混合专家层 block.py # Transformer Block 组装 model.py # 整体模型

每个模块单独实现、单独测试,最后在 block.py 里组装。这样调试的时候可以快速定位问题在哪个模块。

9.2 关键接口设计

每个注意力模块的接口建议统一成:

def forward(self, hidden_states, attention_mask=None, past_key_value=None): # 返回 (output, new_key_value) pass

这样在 block.py 里可以灵活替换不同的注意力实现,方便做消融实验。

MoE 层的接口建议是:

def forward(self, hidden_states): # 返回 (output, router_logits, expert_indices) pass

把路由信息也返回出来,方便监控负载均衡情况。

9.3 调试技巧

实现过程中,我常用的调试手段包括:

逐模块验证。每个模块写完之后,先用随机输入跑一遍,检查输出形状和数值范围是否正常。特别是 mHC 和 MoE,输出数值范围容易失控。

梯度检查。用torch.autograd.gradcheck检查每个模块的梯度是否正确。MoE 层的梯度检查要特别注意,因为稀疏激活会导致部分参数没有梯度。

小规模过拟合。用一个小数据集(比如 100 条样本)跑训练,看模型能不能过拟合。如果连小数据集都过拟合不了,说明实现有问题。

10. 一些个人体会

这套架构看下来,我最大的感受是:DeepSeek-V4 的设计思路非常务实。它没有追求某个单一指标的极致,而是在多个维度上找平衡。mHC 平衡了多尺度信息,CSA 平衡了效率和精度,HCA 平衡了层间信息传递,SWA 平衡了局部和全局,MoE 平衡了参数量和计算量。每个模块都在解决一个具体的工程问题,而不是为了炫技。

实际部署的时候,我建议不要一上来就追求全量配置。先把 SWA 和 MoE 跑通,这两个是基础;然后再加 CSA 和 HCA,这两个是增强;最后加 mHC,这个是锦上添花。一步步来,每步都验证效果,比一次性全上要稳得多。

另外,这套架构对显存的要求确实比较高。如果卡不多,可以考虑用专家并行加流水线并行的混合策略,把 64 个专家分散到多张卡上,同时把不同的层放到不同的卡上。这样虽然通信开销会大一些,但至少能跑起来。

最后分享一个小技巧:调试 MoE 路由的时候,可以把路由结果可视化出来,看看 token 在专家之间的分布。很多时候 loss 震荡或者精度下降,根源都在路由分布上。把路由分布调均匀了,大部分问题都会迎刃而解。