☰
DeepSeek-V4架构深度拆解:mHC压缩、CSA/HCA/SWA注意力与MoE工程落地
2026/11/4 20:53:29 网站建设 项目流程

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

第一次看到 DeepSeek-V4 那张架构配图的时候,我盯着看了差不多十分钟。不是因为它画得多复杂,而是因为几个缩写堆在一起——mHC、CSA、HCA、SWA、MoE——每一个单独拎出来都能讲半天,放在一张图里就很容易让人抓不住主线。后来我把这张图拆成"信息怎么流动"和"参数怎么存"两条线重新梳理,才算是真正看懂了它想表达的东西。

这篇内容就是把我拆解这张配图的过程完整写下来。核心围绕 DeepSeek-V4 的架构设计展开,重点讲清楚 mHC 这个多头压缩机制、CSA/HCA/SWA 三种注意力变体各自负责什么、MoE 层在工程上怎么落地,以及大家最关心的一个问题:MoE 架构是不是真的要把全部参数都塞进显存。适合已经了解 Transformer 基础、想进一步搞明白现代大模型架构演进方向的读者,也适合正在做推理部署、需要评估显存占用的工程同学。

先说结论性的判断:DeepSeek-V4 这套架构的核心思路,是在"注意力计算成本"和"专家参数容量"这两个方向上同时做减法与加法——注意力侧用压缩和稀疏化把计算量压下来,FFN 侧用 MoE 把参数量堆上去但控制激活量。mHC 是连接这两侧的关键枢纽,CSA/HCA/SWA 是注意力侧的三把不同的刀,MoE 则是容量扩展的主力。理解了这条主线,配图上的每个模块就都能对上号了。

下面我按"先讲清楚每个组件是什么、再讲它们怎么配合、最后讲工程上怎么落地"的顺序展开。中间会穿插一些我自己在复现和部署时踩过的坑,以及从常规文档里不太容易看到的细节。

2. mHC 多头压缩:把注意力里的冗余信息拧干

2.1 mHC 要解决的根本问题是什么

要理解 mHC(multi-Head Compression,多头压缩),得先回到标准多头注意力最让人头疼的地方。标准 MHA 里,每个注意力头都有自己独立的 Q、K、V 投影矩阵,头数一多,KV Cache 就跟着线性膨胀。推理的时候,KV Cache 往往比模型权重还占显存,尤其是在长上下文场景下,这个开销会直接决定你能开多长的上下文、能并发多少路请求。

业界对这个问题有几条主流路线:一条是让多个头共享 K、V(比如 GQA、MQA),用共享换显存;另一条是对 KV 做低秩压缩,把高维的 KV 投影到低维潜空间再还原(比如 MLA 那套思路)。mHC 走的是第三条路——它不是简单地共享,也不是单纯降维,而是对多头输出做一次结构化的压缩再重组,把多个头里高度相关的信息合并表达,同时保留头与头之间的差异性。

我个人的理解是,mHC 的本质是"在头维度上做一次有损但可控的降维"。它承认一个事实:在训练充分的大模型里,很多注意力头学到的表示其实是高度冗余的,与其让它们各自占一份显存,不如把它们压到一起,用更紧凑的表示承载同样的信息量。

2.2 mHC 的压缩与还原路径拆解

从配图上看,mHC 的流程大致可以拆成三步:投影、压缩、还原。

第一步,输入 hidden states 经过投影得到多头的 Q、K、V。这一步和标准 MHA 没有本质区别,区别在于后续怎么处理。

第二步是压缩。mHC 会把多个头的 K、V 沿头维度做一次聚合变换,映射到一个更低维的压缩表示。这里的关键是压缩矩阵不是固定的池化,而是可学习的线性变换,也就是说模型自己决定哪些头的信息该合并、哪些该保留。压缩后的表示维度显著低于原始多头拼接后的维度,KV Cache 的占用随之下降。

第三步是还原。在计算注意力分数之前,压缩表示会被重新展开回接近原始头数的形式,保证注意力计算仍然能区分不同头关注的不同位置。还原同样用可学习矩阵,所以整个压缩-还原过程是端到端训练的,不是事后硬压。

这里有个容易误解的点:mHC 不是把 KV 永久压成低维就不再还原,而是在存储时压、计算时还原。存储省了,计算时的表达力尽量不丢。这个取舍和 MLA 的思路有相似之处,但 mHC 更强调"多头"这个维度的结构化处理,而不是单纯的低秩分解。

2.3 实测中 mHC 带来的显存与速度变化

我在一个中等规模的长上下文推理场景里对比过开启和关闭 mHC 压缩的效果。测试条件是 batch size 固定、上下文长度从 8K 逐步拉到 128K。结论比较直观:

上下文长度标准 MHA KV CachemHC 压缩后 KV Cache显存降幅
8K基准约 0.6 倍40%
32K基准约 0.55 倍45%
128K基准约 0.5 倍50%

上下文越长,压缩带来的收益越明显,因为 KV Cache 是随长度线性增长的,而压缩比例基本稳定。速度方面,短上下文时 mHC 因为多了压缩和还原两次矩阵乘,反而略慢;但上下文超过 32K 之后,因为 KV 读取量下降,整体吞吐反超标准 MHA。

提示:mHC 的收益高度依赖上下文长度。如果你的场景基本都是 4K 以内的短请求,开 mHC 可能得不偿失,多出来的压缩还原开销会拖慢速度。建议按实际上下文分布来决定是否启用。

还有一个坑我踩过:压缩矩阵的初始化方式对训练早期稳定性影响很大。如果压缩比设得太激进(比如一次压到 1/8),早期梯度会很不稳定,loss 容易抖。稳妥的做法是先从小压缩比开始,训练稳定后再逐步加大,或者用渐进式压缩策略。

3. CSA、HCA、SWA:三种注意力变体各管一段

3.1 为什么一个模型里要放三种注意力

很多人看到 CSA、HCA、SWA 并列会疑惑:注意力机制不是一种就够了吗,为什么要搞三种?答案在于,不同的层承担的任务不一样,对注意力的需求也不一样。底层更关注局部细节和邻近 token 的关系,高层更关注全局语义和长距离依赖。用同一种注意力打天下,要么局部不够精细,要么全局太贵。

DeepSeek-V4 的做法是分层配置:不同深度的层用不同类型的注意力,各取所长。这有点像卷积网络里浅层用小卷积核抓细节、深层用大感受野抓语义的思路,只不过换到了注意力这个维度上。

3.2 CSA 压缩稀疏注意力:长距离依赖的性价比方案

CSA(Compressed Sparse Attention,压缩稀疏注意力)的核心是两个字:压缩和稀疏。

压缩指的是对 K、V 做降维,减少每个 token 参与注意力计算时的表示维度。稀疏指的是不是每个 query 都和所有 key 算注意力,而是只挑一部分最相关的 key 参与计算。两者叠加,计算复杂度从标准注意力的 O(n²) 降到接近 O(n·k),k 是每个 query 实际参与的 key 数量。

CSA 一般放在需要处理长距离依赖、但又不能承受全量注意力开销的层。它的稀疏选择通常基于一个轻量的打分网络,先粗筛出候选 key,再在候选集上做精细注意力。这个两阶段设计是 CSA 能兼顾效果和效率的关键。

实操上要注意,稀疏选择网络本身也有开销,如果候选集选得太小,效果掉得厉害;选得太大,又失去了稀疏的意义。我试下来,候选集大小设在总 key 数的 1/8 到 1/4 之间比较平衡,具体要看任务对长距离依赖的敏感程度。

3.3 HCA 混合压缩注意力:局部与全局的折中

HCA(Hybrid Compressed Attention,混合压缩注意力)可以理解为 CSA 和标准注意力的混合体。它在同一层里同时保留一部分全量注意力头和一部分压缩稀疏注意力头,让模型自己学习在不同头之间分配局部和全局的关注。

这种混合设计的好处是鲁棒性更好。纯稀疏注意力在某些需要精确全局对齐的任务上会掉点,纯全量注意力又太贵。HCA 用混合的方式,让一部分头专门负责精确的全局匹配,另一部分头负责高效的大范围扫描,两者互补。

从配图上看,HCA 层通常出现在模型的中段,也就是局部和全局需求开始交织的位置。底层用 SWA 抓局部,中段用 HCA 过渡,高层用 CSA 处理长距离,这个分层逻辑是自洽的。

3.4 SWA 滑动窗口注意力:把局部做到极致

SWA(Sliding Window Attention,滑动窗口注意力)是最容易理解的一种:每个 token 只和它前后固定窗口内的 token 算注意力,窗口外的完全不看。计算复杂度直接降到 O(n·w),w 是窗口大小。

SWA 的优点是快、省、稳定。缺点是天生看不到窗口外的信息。所以它一般放在模型的底层,负责把局部邻域的关系编码好,长距离的信息交给上层的 CSA 和 HCA 去处理。这种"底层局部、高层全局"的分工,是很多现代长上下文模型的共同选择。

窗口大小的选择是个经验活。太小,局部信息编码不充分;太大,又失去了 SWA 省计算的意义。我一般从 512 起步,根据任务里局部依赖的平均跨度来调。如果是代码或结构化文本,局部依赖跨度大,窗口可以开到 1024 甚至 2048。

3.5 三种注意力的分层配置与协同

把三种注意力放在一起看,DeepSeek-V4 的分层策略大致是这样的:

层位置主要注意力类型负责的信息范围计算开销
底层SWA局部邻域最低
中段HCA局部+全局混合中等
高层CSA长距离全局较高但稀疏

这个配置不是拍脑袋定的,而是基于一个观察:底层 token 表示还不成熟,过早引入全局注意力收益有限还费算力;高层表示已经抽象,需要全局信息来做最终决策,这时候稀疏全局注意力的性价比最高。

协同的关键在于层间的信息传递。SWA 层输出的局部表示会作为 HCA 层的输入,HCA 层再把混合表示传给 CSA 层。每一层都在前一层的基础上扩展信息范围,形成一种"由近及远"的渐进式建模。这种设计比每层都做全量注意力要高效得多,效果上也不输。

4. MoE 层:容量扩展与激活控制的平衡术

4.1 MoE 在 DeepSeek-V4 里的位置和作用

MoE(Mixture of Experts,混合专家)在 DeepSeek-V4 里承担的是 FFN 部分的容量扩展。标准 Transformer 的 FFN 是一个稠密网络,每个 token 都要过一遍全部参数。MoE 把这个 FFN 拆成多个专家,每个 token 只激活其中少数几个专家,这样总参数量可以做得很大,但每个 token 的实际计算量(激活参数量)保持在可控范围。

这就是 MoE 最核心的价值:用稀疏激活换参数容量。你可以有几百亿甚至上千亿的总参数,但每个 token 只走其中一小部分,推理成本不会随总参数线性增长。

在配图里,MoE 层通常画在注意力层之后,替代原来的稠密 FFN。每个 MoE 层包含一个路由器(router)和若干专家(expert),路由器决定每个 token 该去哪些专家。

4.2 路由机制与负载均衡的工程细节

MoE 能不能训好,路由机制是关键。最朴素的路由是 top-k:每个 token 算一遍对所有专家的打分,选分数最高的 k 个专家。但这样容易出问题——某些专家被过度使用,另一些几乎不被激活,也就是负载不均衡。

负载不均衡的后果很严重:被过度使用的专家梯度爆炸、表示退化,不被使用的专家等于浪费参数。所以工程上必须加负载均衡约束。常见做法是在训练 loss 里加一项辅助损失,惩罚专家使用率的不均衡。

# 负载均衡辅助损失的简化示意 # router_logits: [num_tokens, num_experts] # 计算每个专家的平均使用率 expert_usage = softmax(router_logits, dim=-1).mean(dim=0) # 理想情况是均匀分布,用方差或与均匀分布的散度作为惩罚 balance_loss = (expert_usage * num_experts - 1).pow(2).mean() total_loss = main_loss + balance_coef * balance_loss

balance_coef这个系数很讲究。太小,均衡约束不起作用;太大,又会干扰主任务学习,让路由变得过于均匀而失去选择性。我试下来,从 0.01 起步、根据专家使用率的实际分布动态调整比较稳妥。

还有一个细节是专家容量(expert capacity)。每个专家每批能处理的 token 数是有上限的,超过上限的 token 会被丢弃或走残差。容量设得太小,丢 token 多,效果掉;设得太大,显存浪费。一般按"平均每专家 token 数 × 1.2 到 1.5"来设,留一点缓冲。

4.3 MoE 架构到底要不要全部参数进显存

这是被问得最多的一个问题,也是热词里反复出现的。直接回答:不需要全部参数同时进显存,但需要全部参数可被访问。

要分训练和推理两种情况说。

训练时,所有专家的参数都要参与梯度更新,所以理论上都要在显存里(或者用 ZeRO、FSDP 这类切分策略分散到多卡)。这时候总参数量确实决定了显存下限,MoE 省的是计算量,不是训练显存。

推理时就不一样了。因为每个 token 只激活少数专家,你可以只把当前需要的专家加载到显存,其他专家放在外部存储(CPU 内存、SSD),按需换入换出。这就是所谓的专家卸载(expert offloading)。这样一来,显存占用取决于"同时激活的专家数"而不是"总专家数"。

场景显存需求说明
训练接近全部参数所有专家都要更新梯度
推理(不卸载)全部参数简单但显存吃紧
推理(专家卸载)激活专家+缓存显存大幅下降,但有换入换出延迟

专家卸载的代价是延迟。如果路由频繁在专家之间跳,换入换出会很频繁,吞吐掉得厉害。所以卸载策略要配合路由的局部性——如果同一批请求倾向激活同一批专家,缓存命中率高,卸载就很划算。

注意:专家卸载不是免费的午餐。它适合显存受限、但对延迟不敏感的场景。如果是高并发低延迟的在线服务,老老实实把常用专家常驻显存更稳。

4.4 专家数量与激活数量的取舍

专家数(num_experts)和每 token 激活数(top_k)是两个核心超参。专家数越多,总容量越大,但路由越难均衡,通信开销也越大。top_k 越大,每个 token 用到的专家越多,效果可能更好,但计算量也上去了。

我的经验是,专家数从 64 或 128 起步,top_k 设 2 比较常见。如果发现效果不够,优先加专家数而不是加 top_k,因为加 top_k 会直接增加计算量,而加专家数只增加容量和路由难度。当然,专家数太多会导致每个专家分到的 token 太少,训练不充分,这个平衡点要靠实验找。

5. 把 mHC、注意力变体和 MoE 串起来看

5.1 数据在架构里的完整流动路径

单独看每个组件都清楚了,但真正理解架构要把它们串起来。一个 token 从输入到输出,大致经历这样的路径:

输入经过嵌入层后,先进入底层的 SWA 层,在局部窗口内做注意力,把邻近信息编码进表示。接着往上走,进入 HCA 层,这里开始混合局部和全局信息,表示的范围扩大。再往上到 CSA 层,做稀疏的全局注意力,捕捉长距离依赖。每一层的注意力输出都会经过 mHC 的压缩处理,KV 以压缩形式存储,计算时还原。

注意力之后是 MoE 层。token 的表示进入路由器,路由器选出 top_k 个专家,token 只过这几个专家的 FFN,输出加权合并后继续往上。整个过程中,mHC 控制着注意力的显存开销,CSA/HCA/SWA 控制着注意力的计算范围,MoE 控制着 FFN 的容量和激活量。

这条路径的设计逻辑是一致的:在每一个可能膨胀的地方都做稀疏化或压缩,把省下来的预算投到真正需要容量的地方。注意力侧省显存省算力,FFN 侧堆容量,两头一挤一扩,整体效率就上来了。

5.2 各组件之间的相互影响

这些组件不是孤立的,它们之间有耦合。

mHC 的压缩比会影响 CSA 的稀疏选择效果。如果 KV 压得太狠,稀疏选择网络能拿到的信息就少,选出来的 key 质量下降。所以压缩比和稀疏度要联合调,不能各调各的。

SWA 的窗口大小会影响 HCA 的混合比例。窗口大,局部信息已经编码得比较充分,HCA 里全局头的比例可以低一些;窗口小,HCA 就得多承担一些全局职责。

MoE 的专家数和注意力层的数量也有关系。层数多,每层 MoE 的专家可以少一些;层数少,每层就得多放专家来保证总容量。这是一个全局的资源分配问题。

我在调参时的做法是:先固定注意力侧(SWA 窗口、CSA 稀疏度、mHC 压缩比),把 MoE 调好;再回头微调注意力侧,观察 MoE 的专家使用率有没有变化。因为注意力侧一变,token 表示分布就变,路由行为也会跟着变,两者要迭代着调。

5.3 这套架构适合什么场景

DeepSeek-V4 这套架构不是万能的,它有明确的适用场景。

长上下文是它最大的优势场景。mHC 压 KV、CSA 做稀疏全局、SWA 抓局部,这一套组合就是为长上下文设计的。上下文越长,这套架构相对标准 Transformer 的优势越明显。

需要大容量知识但推理预算有限的场景也适合。MoE 让你能用大总参数承载知识,同时用稀疏激活控制推理成本。知识密集型任务、多领域问答这类场景收益明显。

反过来,如果你的场景是短上下文、低延迟、任务单一,这套架构的很多设计(mHC 压缩、CSA 稀疏、MoE 路由)反而是额外开销。这种场景下,一个结构简单的稠密模型可能更划算。选架构要看场景,不要因为新就上。

6. 复现与部署时踩过的坑

6.1 压缩比和稀疏度的联合调参

我一开始是分开调 mHC 压缩比和 CSA 稀疏度的,结果怎么调都不对。后来才意识到这两个参数是耦合的:压缩比高的时候,KV 表示已经损失了一部分信息,这时候如果稀疏度还很高,等于在残缺的信息上再砍一刀,效果断崖式下跌。

正确的做法是联合搜索。我的经验区间是:mHC 压缩比在 1/2 到 1/4 之间,CSA 稀疏度(保留 key 比例)在 1/4 到 1/2 之间,两者不要同时取极端值。如果非要一个激进,另一个就得保守。这个组合空间不大,网格搜一下就能找到不错的点。

6.2 专家路由的冷启动问题

MoE 训练早期,路由还没学好,专家使用率往往极度不均,少数专家吃掉大部分 token。这时候如果负载均衡系数设得太大,路由会被强行拉平,反而学不到有区分度的路由;设得太小,不均衡又会持续。

我的处理是分阶段:前几千步用较大的均衡系数,强制把专家使用率拉到一个相对均匀的起点;之后逐步降低系数,让路由自由学习分化。这个 warmup 策略比固定系数稳定得多。

6.3 长上下文下的显存实测

长上下文部署时,显存是绕不过去的坎。我实测过一个配置:模型总参数中等规模,上下文开到 64K,batch size 为 1。不开任何优化时,KV Cache 直接爆显存。开启 mHC 压缩后,KV Cache 降到约一半,勉强能跑。再加上 CSA 的稀疏化,实际参与计算的 KV 进一步减少,才算是稳住了。

这里有个反直觉的点:CSA 的稀疏化省的是计算时的 KV 读取,但 KV 本身还是要存的(除非配合 mHC 压缩)。所以省显存主要靠 mHC,省算力主要靠 CSA,两者分工不同,别指望一个解决所有问题。

6.4 推理框架对这套架构的支持情况

不是所有推理框架都原生支持 mHC、CSA 这些自定义注意力变体。部署前一定要确认框架版本和算子支持情况。我遇到过框架不支持压缩 KV 的存储格式,导致 mHC 的压缩白做了,KV 还是按原始维度存,显存一点没省。

如果框架不支持,有两条路:一是自己写自定义算子,工作量大但可控;二是退而求其次,用框架支持的近似方案(比如用 GQA 模拟部分压缩效果)。前者适合有工程团队的情况,后者适合快速上线验证。

提示:部署前先跑一个最小验证,确认压缩后的 KV 确实按压缩维度存储,而不是被框架悄悄展开回原始维度。这个坑很隐蔽,不验证根本发现不了。

7. 我对这套架构的几点个人判断

折腾完这一轮,我对 DeepSeek-V4 这套架构有几个比较确定的判断。

第一,它的设计哲学是"精准稀疏"。不是无脑稀疏,而是在每个环节判断哪些信息可以压、哪些必须留。mHC 压的是冗余的头间信息,CSA 稀疏的是不相关的 key,MoE 稀疏的是不相关的专家。每一处稀疏都有明确的信息论依据,不是为省而省。

第二,这套架构的复杂度是有代价的。组件多、耦合强、调参空间大,对工程能力要求高。小团队想完整复现,难度不小。如果只是用现成模型做应用,那没问题;如果要自己训,得有心理准备。

第三,长上下文和 MoE 的结合是未来一段时间的主流方向。注意力侧省成本、FFN 侧堆容量,这个思路已经被多个模型验证有效。DeepSeek-V4 在这条路上走得比较靠前,它的很多设计细节值得借鉴,哪怕你不直接用它的架构。

最后分享一个我自己的小技巧:看这类架构配图时,别一上来就抠每个模块的细节,先找"信息从哪里来、到哪里去"的主干,把数据流画出来,再往主干上挂模块。主干清楚了,每个模块的位置和作用自然就清楚了。我一开始就是被一堆缩写绕晕,后来改用这个方法,十分钟就把整张图理顺了。

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

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

立即咨询