交互式混合专家模型可视化实验室

MoE
可视化实验室

通过动画与交互深入理解 Mixture of Experts 核心机制。从路由到负载均衡,从稀疏激活到推理优化,把 MoE 黑箱拆成你能看见的零件。

8
可视化模块
15+
交互参数
DeepSeek
对标模型
0
外部依赖
MODULE 01

MoE 架构概览 (Architecture)

混合专家模型用稀疏激活替代全连接:每个 token 只激活少数专家,以更少的计算量达到更大的模型容量。

说明

稠密模型中每个 token 经过所有参数。MoE 层将 FFN 替换为多个并行 FFN(专家),门控网络为每个 token 选择 Top-K 个专家。总参数量大但每次前向传播只用一小部分。

面试要点

  • 稀疏激活:总参数 N,每次仅激活 N×(K/num_experts)
  • DeepSeek-V3:256 专家,每次激活 8,总 671B 仅用 37B
  • GLM-5.2:744B 参数 MoE,消费级 GPU 可推理
  • 关键优势:参数容量 ↑↑,计算成本 ↑
python · MoE Layer
class MoELayer(nn.Module):
    def __init__(self, d_model, n_experts, top_k):
        self.gate = nn.Linear(d_model, n_experts)
        self.experts = nn.ModuleList([
            FFN(d_model) for _ in range(n_experts)
        ])
        self.top_k = top_k

    def forward(self, x):
        # 门控网络打分
        logits = self.gate(x)  # [B,S,E]
        # Top-K 选择
        topk_val, topk_idx = logits.topk(self.top_k, dim=-1)
        # 加权求和
        return dispatch(x, topk_idx, topk_val)
MODULE 02

专家路由 (Expert Routing)

门控网络根据 token 的表示决定路由到哪些专家。路由质量直接决定 MoE 模型的性能。

说明

门控网络是一个线性层 G(x)=W_g·x,输出每个专家的分数。Softmax 归一化后选择 Top-K。不同 token 倾向于不同专家——这形成了隐式的专家分工。

面试要点

  • 门控函数:G(x) = Softmax(W_g · x),简单线性层
  • 专家特化:训练后专家会自然分工(语法/语义/代码等)
  • 噪声门控:G(x) = Softmax(W·x + ε),ε~N(0,σ²) 促进探索
  • 路由稳定性:是 MoE 训练的最大挑战
python · Gating
def gating(x, n_experts, top_k, noise=False):
    # x: [batch, seq, d_model]
    logits = W_gate @ x  # [batch, seq, n_experts]
    if noise:
        logits += torch.randn_like(logits) * softplus(W_noise)
    # Top-K 选择
    weights, indices = logits.softmax(-1).topk(top_k)
    weights = weights / weights.sum(dim=-1, keepdim=True)
    return weights, indices
MODULE 03

Top-K 选择 (Top-K Selection)

每个 token 只选择得分最高的 K 个专家。K 越大,模型质量越高但计算量也越大。

说明

门控网络输出所有专家的分数后,Top-K 选择保留最高的 K 个。选中专家的权重经归一化后用于加权求和。未选中的专家不参与计算,实现稀疏激活。

面试要点

  • K=1:最稀疏,最快,但可能路由坍塌
  • K=2:最常用,GPT-4 / Mixtral 标准配置
  • K=8:DeepSeek-V3 选择,质量更高
  • 权衡:K↑ → 质量↑ 速度↓ 通信↑
python · Top-K
# 门控分数 → Top-K 选择
gate_scores = softmax(gate(x), dim=-1)
# [batch, seq, n_experts]

topk_weights, topk_indices = gate_scores.topk(
    k=K, dim=-1
)
# 重新归一化选中的权重
topk_weights = topk_weights / topk_weights.sum(
    dim=-1, keepdim=True
)
# 只计算选中的 K 个专家
for i in range(K):
    expert_idx = topk_indices[..., i]
    output += topk_weights[..., i] * expert(expert_idx, x)
MODULE 04

负载均衡 (Load Balancing)

如果不加约束,门控网络可能总是把 token 路由到少数专家,导致其他专家闲置。辅助损失强制均衡分配。

说明

辅助损失 L_aux = α·n_experts·Σ(f_i·P_i),其中 f_i 是专家 i 收到的 token 比例,P_i 是平均门控概率。当分配均匀时 L_aux 最小。这个简单的损失项是 MoE 训练的关键。

面试要点

  • 路由坍塌:不加约束时 80% token 去同一个专家
  • 辅助损失:L_aux = α·N·Σ(f_i·P_i),α≈0.01
  • Expert Capacity:每个专家设上限 capacity = C·avg
  • DeepSeek 方案:无辅助损失的偏置调整
python · Aux Loss
def load_balancing_loss(gate_probs, expert_mask):
    # gate_probs: [tokens, n_experts] softmax probs
    # expert_mask: [tokens, n_experts] 0/1 selected
    N = gate_probs.size(1)
    # f_i: 每个专家实际收到的比例
    f = expert_mask.mean(dim=0)
    # P_i: 每个专家的平均门控概率
    P = gate_probs.mean(dim=0)
    # 辅助损失
    aux_loss = N * (f * P).sum()
    return aux_loss
MODULE 05

容量与溢出 (Capacity & Overflow)

每个专家有处理上限。当分配的 token 超过容量时,多余 token 被丢弃或传递给下一层。

说明

Expert Capacity = (tokens/Batch) × capacity_factor × top_k。capacity_factor 通常 1.0-1.5。超出容量的 token 被标记为 overflow,直接透传不经过专家处理。这是 MoE 训练中信息丢失的主要来源。

面试要点

  • 容量因子:1.0 = 刚好,1.25 = 宽松,1.5 = 很少溢出
  • Token 丢弃:溢出 token 直接透传,信息不经过 FFN
  • 影响:溢出率高 → 模型质量下降
  • 权衡:容量↑ → 显存↑ 但溢出↓
python · Capacity
def dispatch_with_capacity(x, indices, weights, capacity):
    # capacity = ceil(tokens * top_k / n_experts * factor)
    expert_counts = zeros(n_experts)
    overflow_count = 0

    for token in x:
        for expert in selected_experts(token):
            if expert_counts[expert] < capacity:
                dispatch(token, expert)
                expert_counts[expert] += 1
            else:
                # 溢出:直接透传
                overflow_count += 1
MODULE 06

稀疏激活 (Sparse Activation)

MoE 的核心优势:用更大的总参数量获得更好的性能,但每次前向传播只激活一小部分参数。

说明

DeepSeek-V3 总参数 671B 但每次推理只激活 37B。这意味着模型的"知识容量"接近 671B 模型,但"计算成本"接近 37B 稠密模型。稀疏激活让大模型在消费级硬件上可运行。

面试要点

  • 激活比:激活参数/总参数,DeepSeek-V3 ≈ 5.5%
  • 等效稠密模型:37B 激活 ≈ 70B 稠密模型性能
  • 显存挑战:需加载全部参数,即使不激活
  • 推理优化:按需加载专家(Expert Offloading)
python · Sparse Stats
# DeepSeek-V3 示例
total_params = 671e9      # 671B
active_params = 37e9     # 37B
n_experts = 256
top_k = 8

activation_ratio = active_params / total_params
# ≈ 5.5%

# 每个专家平均参数
per_expert = total_params / n_experts
# ≈ 2.6B per expert

# 每次推理实际计算
flops = top_k * per_expert
# ≈ 21B FLOPs (远小于 671B)
MODULE 07

MoE 训练 (Training)

MoE 训练比稠密模型更难:需要处理路由不稳定、负载不均、专家利用率等问题。

说明

MoE 训练面临独特挑战:路由坍塌(所有 token 选同一专家)、专家利用率不均、训练不稳定。解决方案包括辅助损失、专家容量、噪声注入、初始化策略等。DeepSeek 提出了无辅助损失的偏置调整方案。

面试要点

  • 路由坍塌:训练初期门控网络偏向少数专家
  • 辅助损失:α=0.01,强制均衡分配
  • 初始化:门控网络需较小初始化方差
  • 数据并行:Expert Parallelism 需 All-to-All 通信
python · Training Loop
def train_step(model, batch, aux_weight=0.01):
    # 前向传播(含门控路由)
    output, gate_probs, expert_mask = model(batch)

    # 主任务损失
    lm_loss = cross_entropy(output, targets)

    # 负载均衡辅助损失
    aux_loss = load_balancing_loss(
        gate_probs, expert_mask
    )

    # 总损失
    total_loss = lm_loss + aux_weight * aux_loss

    total_loss.backward()
    optimizer.step()
    return lm_loss, aux_loss
MODULE 08

推理优化 (Inference)

MoE 推理的核心挑战:总参数巨大但每次只用一小部分。专家卸载和按需加载是关键优化。

说明

MoE 推理时,专家可以卸载到 CPU/磁盘,只在需要时加载到 GPU。DeepSeek-V3 的 256 专家中,每次只需 8 个在 GPU 上。通过预测下一层路由,可以提前预取专家,实现计算与 IO 的重叠。

面试要点

  • 专家卸载:GPU 存热专家,CPU/SSD 存冷专家
  • 预取:预测下一层路由,提前加载专家
  • 量化:FP8/INT4 量化减少专家大小
  • 批处理:合并同专家请求提升吞吐
python · Expert Offload
class ExpertPool:
    def __init__(self, experts, gpu_capacity):
        self.gpu = {}   # GPU 上的热专家
        self.cpu = {}    # CPU 上的冷专家
        self.lru = OrderedDict()

    def get(self, expert_id):
        if expert_id in self.gpu:
            return self.gpu[expert_id]
        # 从 CPU 加载到 GPU
        if len(self.gpu) >= capacity:
            evict_lru()
        self.gpu[expert_id] = self.cpu[expert_id].cuda()
        return self.gpu[expert_id]