第一课:MoE 的核心理念与架构 (The "What" & "Why")
这部分主要解决一个核心矛盾:如何在不增加计算成本(FLOPs)的前提下,增加模型的参数量(Capacity)。
1. 从 Dense 到 Sparse:架构对比
你一定很熟悉标准的 Transformer。在标准的“稠密模型”(Dense Model)中,数据流经每一层时,都会通过一个全连接的前馈网络(FFN)。
Dense Model (稠密模型): 就像你在全班点名,不管问题难易,全班 50 个同学都要站起来回答一遍。所有参数都要参与计算 。
Sparse Model (稀疏/MoE 模型): 这里的 FFN 被替换成了一个“专家组”(MoE Layer)。这个组里可能有 8 个、64 个甚至几百个 FFN(我们叫它们 Experts)。
对于每一个输入 Token(比如单词 "The" 或 "Dog"),有一个路由器(Router/Gating) 会决定它该去哪几个专家那里 。
关键点: 虽然总共有很多专家,但每个 Token 可能只激活其中的 Top-1 或 Top-2。这就实现了“参数量巨大,但计算量很小” 。
在标准的 Transformer Block 中,数据流是线性的,每个 Token 都要经过同一个 FFN 处理。
输入 (Token)
↓
[ Self-Attention ] <-- 注意力机制
↓
[ Add & Norm ]
↓
[ FFN 层 ] <-- 瓶颈在这里!所有 Token 共享这一组参数
(Up proj -> Act -> Down proj)
↓
[ Add & Norm ]
↓
输出
计算量: 设 FFN 参数量为 ,处理
个 Token,总计算量是
MoE 把中间那个 FFN 层替换成了一个路由层(Gating/Router) 和 一堆专家(Experts)
输入 x (Token)
↓
[ Self-Attention ]
↓
[ Add & Norm ]
↓
---------------------------------------
| [ Router (Gating Network) ] | <-- 核心差异
| ↓ 计算分发概率 |
| "这个 Token 该去哪?" |
| ↙ | ↘ |
| [Expert 1] [Expert 2] ... [Expert N]| <-- N 个独立的 FFN
| \ | / |
| \ | / |
| ↘ ↓ ↙ |
| [ 加权求和 (Sum) ] |
---------------------------------------
↓
[ Add & Norm ]
↓
输出 y
稀疏性 (Sparsity): 虽然有 N 个 Expert,但 Router 只会选出 Top-k(比如 k=2)。
计算量: 无论 N 有多大,计算量只取决于 k 个 Expert。(增加专家数不影响计算量)
第二课:路由机制 (Routing - The "Brain")
我们要搞清楚:谁来决定 Token 去哪个专家?
1. 经典的 Top-k Routing
绝大多数主流模型(如 Switch Transformer, Mixtral, Grok, Qwen)都使用这种方法 。它本质上是一个简单的分类问题。
公式推导: 假设我们有输入 Token 的向量 和
个专家。路由器有一个可学习的权重矩阵
(你可以把它想象成一个简单的 Linear 层)。 计算过程如下:
计算分数 (Logits):。这会得到 Token 对每个专家的“亲密度”打分 。
归一化 (Softmax): 。把分数变成概率。
选择 (Top-k): 只保留概率最大的 K个专家(例如 K=2),其他的强制置为 0
加权输出: 最终的输出是这 K个专家输出的加权和:
注意:这里的 是路由器的概率值,它作为权重乘在专家的输出上,这样路由器的参数才能通过反向传播更新(这是 Softmax 可导的关键作用)
2. DeepSeekMoE 的数学改进 (Shared + Fine-grained)
DeepSeek 认为传统的 Top-k 有两个问题:
-
知识隔离: 不同的专家可能学到了重复的知识。
-
专业度不够: 某些通用的语法知识(比如 "the", "is" 这种词的处理)所有专家都得会,这浪费了专家的“脑容量”。
DeepSeek 的解决方案:
-
Shared Experts (共享专家): 专门设立几个专家,它们永远处于激活状态,处理所有 Token。这就好比医院里的“预检台”或“全科医生”,处理通用问题。
-
Fine-grained Experts (细粒度专家): 把剩下的专家切得更碎、更小。比如原本 1 个大专家,现在拆成 4 个小专家。
-
好处: 组合更加灵活。原本只能选“专家A”,现在可以选“专家A的左手 + 专家B的右手”。
-
DeepSeek: 激活 = (固定 2 个共享专家) + (从 N 个细粒度专家里选 Top-K 个)。
DeepSeek 论文的亮点。它把输出分成了两部分:固定干活的(Shared) 和 竞争上岗的(Routed)。
-
: 共享专家(Shared Experts)的数量。
-
: 路由专家(Routed Experts)的数量。
-
: 第
个共享专家。
-
: 第
个路由专家。
公式解读:
-
Shortcut (
): 残差连接,保留原始信息。
-
Shared Experts (
): 这部分没有门控系数
(或者说系数为 1)。这意味着每一个 Token 都会经过这些共享专家。这保证了通用知识(Common Knowledge)的无损传递。
-
Routed Experts (
): 这部分和上面的经典 Top-k 一样,通过
选择性激活,负责处理细分领域的专业知识(Specialized Knowledge)。
传统 Top-2:
Token -> [Router] -> 选 Expert 2, Expert 4
(风险:如果 Expert 2 和 4 没学好通用语法,这个 Token 就废了)
DeepSeek (Shared + Routed):
Token -> 路径1: [Shared Expert 1] (必选,保底)
-> 路径2: [Router] -> 选 Expert 3, Expert 7 (专业拔高)
(优势:通用与专业解耦)
第三课:负载均衡与稳定性 (Training Challenges)
MoE 有一个致命的天然倾向:“马太效应” (Collapse)。 如果一开始某个专家(比如 Expert 1)的初始化参数稍微好一点,Router 就会给它更高的分。于是所有 Token 都涌向 Expert 1,它得到的训练数据最多,变得更强,Router 更爱选它……
后果: Expert 1 被累死(OOM),其他 Expert 成了摆设。MoE 退化成了 Dense 模型,并行计算优势全无 。
为了解决这个问题,必须引入“强制手段”。
1. 经典解决方案:辅助负载均衡损失 (Auxiliary Load Balancing Loss)
这是 Switch Transformer 提出的经典方案,也是 MoE 的标准教科书公式。
直觉: 如果大家都选 Expert ,那我就惩罚你,Loss 变大。迫使 Router 去选别的专家。
公式推导:
我们需要最小化以下 Loss:
: 专家总数。
(Fraction dispatched): 实际上有多少 Token 被分配给了专家
。
(解释:在一个 Batch 中,专家 被选中的频率)
(Router Probability): 路由器想分配给专家
的平均概率。
为什么这个公式能生效?
-
当
和
分布完全均匀时(大家都等于
),
最小。
-
当分布极度不均时(比如所有人都选 Expert 1),这项乘积会变得很大。
就像制定一条规则:“如果大家都去同一个窗口,我就罚你们所有人(增加 Loss)”
这像是一种“行政命令”。有时候为了满足平均分配,不得不把擅长“数学”的 Token 强行分给“语文”专家,导致模型变笨。
2. DeepSeek 的改进:Auxiliary-Loss-Free (无损负载均衡)
DeepSeek 不去惩罚模型,而是给每个专家 设置了一个动态变化的偏置值 (Bias)
。
-
你可以把它理解为“排队时长提示牌”。
-
如果专家
最近太忙了(负载过高),系统就会自动调低它的
(比如挂个牌子:预计排队 2 小时)。
-
如果专家
很闲,系统就调高它的
(挂个牌子:来了就能办)。
3. 推理(路由选择)的具体过程
在计算 Token 该去哪个专家时,路由逻辑发生了如下变化:
-
原始打分: 路由器算出 Token 对每个专家的原始亲密度分数
(Affinity Score)。
-
修正打分: 把原始分数加上偏置值:
-
Top-K 选择: 系统根据这个修正后的分数
来进行 Top-K 排序和选择 。
第四课详解:DeepSeek V3 的黑科技(MLA & MTP)
1. MLA:多头潜在注意力 (Multi-Head Latent Attention) —— 极致的“压缩术”
这一块是为了解决 “显存不够用” 的问题。
-
背景: 现在的模型都要处理很长的文章(比如 DeepSeek 支持 128k 上下文)。在推理时,模型必须把看过的每一句话的 Key 和 Value (KV) 都存在显存里,这叫 KV Cache。
-
传统痛点: 以前的模型(如 Llama 2),有很多个“头”(Heads),每个头都要存一份独立的 KV,显存瞬间爆炸。
-
输入 h_t
↓
[ 压缩矩阵 W_DKV ] <-- 就像 AutoEncoder 的 Encoder
↓
[ 潜在向量 c_KV ] <-- **关键!推理时只需要存这个小向量!** [cite: 1171]
↙ ↘
[ 解压 W_UK ] [ 解压 W_UV ] <-- 推理计算时临时解压出来
↓ ↓
生成 Key 生成 Value
MLA 的魔法: DeepSeek 说:我不存完整的 KV 了,我存一个 “压缩包” 。
压缩: 把原本巨大的 Hidden State 压缩成一个很小的 潜在向量 (Latent Vector, )
存储: 显存里只存这个小小的 ,显存占用直接降到原来的几分之一 。
解压: 等到真正要计算注意力的时候,再通过一个矩阵把 瞬间“解压”还原成 Key 和 Value。
结论: 这是一个用“微小的计算代价”换取“巨大显存空间”的策略。这也是为什么 DeepSeek V3 能在普通显卡上跑得这么溜的原因。
2. MTP:多 Token 预测 (Multi-Token Prediction) —— 从“走一步看一步”到“走一步看三步”
[Main Model] -> 输出 "The" (预测 t+1)
↓
[MTP Module 1] -> 结合 "The" 的信息 -> 输出 "cat" (预测 t+2)
↓
[MTP Module 2] -> 结合 "cat" 的信息 -> 输出 "is" (预测 t+3)
这一块是为了解决 “推理速度慢” 和 “逻辑性” 的问题 。
背景: 传统的 LLM 像挤牙膏,一次只能吐出一个字(Next Token Prediction)。
-
输入:“我爱” -> 预测:“中”
-
输入:“我爱中” -> 预测:“国” 这很慢,而且模型有时候目光短浅。
MTP 的魔法: DeepSeek V3 在训练时,不仅有一个主脑袋预测第 1 个字,后面还挂了几个“小脑袋”(MTP Modules)。
-
训练时:
-
主脑袋看“我爱”,预测“中”。
-
MTP 模块 1 拿着主脑袋的信息,顺便预测“国”(第 2 个字)。
-
MTP 模块 2 再顺便预测“!”(第 3 个字)。
-
-
好处 1 (变聪明): 强迫模型在吐第一个字的时候,脑子里就已经规划好后面两步怎么走了,逻辑性更强。
-
好处 2 (变快): 推理时,模型一次能丢出 3 个候选字。如果验证发现后面两个字也是对的,就直接采纳。这叫 投机采样 (Speculative Decoding),速度可以翻倍 。
934

被折叠的 条评论
为什么被折叠?



