MOE里专家路由机制 还是看代码容易理解
MoE架构的关键在于其动态路由机制,DeepSeek-V3中的MoE架构及Transformer模块的架构如图2-1所示。[插图]图2-1 DeepSeek-V3整体架构图(含MoE和Transformer)
https://weread.qq.com/web/reader/b6b323e0813ab9c5bg017c06k02e32f0021b02e74f10ece8 见这个图
动态路由的主要任务是根据输入数据的特性,选择合适的专家网络进行计算,其基本步骤如下。(1)输入特征分析:根据输入数据的特征,通过路由网络(通常为一个小型神经网络)生成每个专家的激活概率。(2)专家选择:根据激活概率,选取一部分专家网络参与当前输入的计算。(3)专家计算:被激活的专家网络对输入数据进行处理,生成特定的输出结果。(4)结果聚合:将多个专家网络的输出结果按照权重进行聚合,生成最终的输出。
MOE里 有FFN 里面有 路由 专家 大概是怎么做的啊 有没有伪代码可以体现下
在深度学习(特别是 Transformer 架构,如 GPT-4、Mixtral)中,MoE (Mixture of Experts,混合专家模型) 的核心思想是将原本巨大的全连接层(FFN)拆分成多个独立的“小 FFN”(即专家),并引入一个**路由(Router/Gate)**机制来决定每个 Token 具体由哪些专家来处理。
简单来说,它的逻辑是:“术业有专攻,不要让所有神经元都参与每一次计算,而是只激活最相关的部分。”
下面我将分步讲解其原理,并提供一份清晰的伪代码。
1. MoE 的核心结构
在标准的 Transformer Block 中,结构通常是:Attention -> Add&Norm -> FFN -> Add&Norm。
而在 MoE 架构中,那个FFN被替换成了一个 MoE Layer。MoE Layer 内部包含:
-
专家组 (Experts):比如有 8 个、64 个甚至更多个独立的 FFN 网络(Expert 1, Expert 2...)。每个 Expert 的结构和普通 FFN 一样(Linear -> Activation -> Linear)。
-
路由器 (Router / Gating Network):这是一个可学习的线性层。它接收输入 Token,输出该 Token 对每个 Expert 的“匹配分数”。
-
Top-k 机制:为了节省算力,我们不会激活所有 Expert,而是根据路由分数,只选出得分最高的
个(通常kk
或k=1k=1
)。k=2k=2
2. 工作流程 (Step-by-Step)
假设输入是一个 Token 的向量
xx
:
-
路由计算:Router 网络计算
属于每个专家的概率。xx -
选拔:选出概率最高的 Top-k 个专家索引(indices)和对应的权重(weights)。
-
分发与计算:
-
Token 被送入这
个被选中的 Expert 进行计算。kk -
没被选中的 Expert 不参与计算(这就是“稀疏激活”,省算力的关键)。
-
-
加权聚合:将这
个 Expert 的输出结果,按照 Router 分配的权重进行加权求和,得到最终输出。kk
3. 伪代码实现 (PyTorch 风格)
为了让你看清楚逻辑,我写了一段简化版的伪代码。这段代码展示了如果不用复杂的并行优化,MoE 最原始的数学逻辑长什么样。
import torch
import torch.nn as nn
import torch.nn.functional as F
class Expert(nn.Module):
"""
一个专家就是一个普通的 FFN (Feed-Forward Network)
通常结构: Input -> Linear -> Gelu -> Linear -> Output
"""
def __init__(self, input_dim, hidden_dim):
super().__init__()
self.net = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.GELU(),
nn.Linear(hidden_dim, input_dim)
)
def forward(self, x):
return self.net(x)
class MoELayer(nn.Module):
def __init__(self, num_experts, input_dim, hidden_dim, top_k=2):
super().__init__()
self.num_experts = num_experts
self.top_k = top_k
# 1. 创建专家组 (通常有 8个, 16个, 甚至成百上千个)
self.experts = nn.ModuleList([
Expert(input_dim, hidden_dim) for _ in range(num_experts)
])
# 2. 创建路由器 (Router / Gate)
# 它是一个简单的线性层,将输入维度映射到专家数量的维度
self.router = nn.Linear(input_dim, num_experts)
def forward(self, x):
# x 的形状: [batch_size, seq_len, input_dim]
# 为了方便处理,我们先把它展平成 [total_tokens, input_dim]
batch_size, seq_len, dim = x.shape
x_flat = x.view(-1, dim)
# --- 步骤 1: 路由计算 (Router) ---
# 计算每个 token 对每个 expert 的原始分数 (logits)
router_logits = self.router(x_flat) # shape: [total_tokens, num_experts]
# 使用 Softmax 归一化,得到概率分布
router_probs = F.softmax(router_logits, dim=-1)
# --- 步骤 2: Top-k 选拔 ---
# 选出概率最高的 k 个专家的 权重(weights) 和 索引(indices)
# weights: [total_tokens, top_k], indices: [total_tokens, top_k]
routing_weights, selected_experts_indices = torch.topk(router_probs, self.top_k, dim=-1)
# 对权重进行重新归一化 (让选中的k个权重加起来等于1,这是一个常见的操作细节)
routing_weights = routing_weights / routing_weights.sum(dim=-1, keepdim=True)
# --- 步骤 3 & 4: 专家计算与聚合 ---
# 初始化最终输出容器
final_output = torch.zeros_like(x_flat)
# !!!注意:这里为了代码易读使用了循环,
# !!!真实的工业级代码(如 DeepSpeed/Megatron)会使用
# !!!torch.gather/scatter 或 Einsum 算子来并行化,避免 Python 循环。
# 遍历每一个 Token
for i in range(x_flat.size(0)):
token_input = x_flat[i]
# 遍历这个 Token 选中的 Top-k 个专家
for k in range(self.top_k):
# 获取专家 ID
expert_idx = selected_experts_indices[i, k].item()
# 获取路由权重
weight = routing_weights[i, k]
# 让指定的专家处理这个 Token
expert_output = self.experts[expert_idx](token_input)
# 加权累加到最终结果
final_output[i] += weight * expert_output
# 恢复形状 [batch_size, seq_len, input_dim]
return final_output.view(batch_size, seq_len, dim)
4. 关键细节补充
虽然伪代码逻辑通顺,但在实际工程(如 Training GPT-4, DeepSeek, Mixtral)中,还有两个非常重要的问题:
A. 负载均衡 (Load Balancing)
如果 Router 发现 Expert 1 特别好用,它可能把所有 Token 都发给 Expert 1,导致 Expert 1 累死(显存爆炸、计算慢),而 Expert 2...N 都在围观。
解决办法:在 Loss 函数中加入一个 Load Balancing Loss(辅助损失),强迫 Router 将 Token 均匀地分配给各个 Expert。
B. 向量化并行 (Vectorization)
上面的伪代码里用了 for 循环,这在 GPU 上极慢。
实际做法:
通常会把所有分配给 Expert 1 的 Token 挑出来拼成一个大矩阵一次算完,把分配给 Expert 2 的挑出来算完……最后再把结果拼回去(Scatter/Gather 操作)。
总结
MoE 里的 FFN 其实就是:
-
Router 说:“这个词归 1 号和 5 号专家管。”
-
1 号和 5 号 FFN 分别计算一遍。
-
结果 乘上各自的权重加起来,作为这一层的输出。

浙公网安备 33010602011771号