969 lines
82 KiB
HTML
969 lines
82 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>MoE (Mixture-of-Experts) 面试 Cheat Sheet</title>
|
||
|
||
<meta name="generator" content="ARIS render-html (academic, v1)">
|
||
<meta name="aris:source-path" content="docs/tutorials/moe_tutorial.md">
|
||
<meta name="aris:source-sha256" content="e860589270ed447981c868a7e0f0ba51ac8917a8908580825403af8205baf3b1">
|
||
<meta name="aris:generated-at" content="2026-05-19 10:10 UTC">
|
||
|
||
<!-- MathJax 3 -->
|
||
<script>
|
||
window.MathJax = {
|
||
tex: { inlineMath: [['$', '$'], ['\\(', '\\)']], displayMath: [['$$', '$$'], ['\\[', '\\]']], processEscapes: true },
|
||
options: { skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'] }
|
||
};
|
||
</script>
|
||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" async></script>
|
||
|
||
<!-- highlight.js -->
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/atom-one-light.min.css">
|
||
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js"></script>
|
||
<script>document.addEventListener('DOMContentLoaded', () => hljs.highlightAll());</script>
|
||
|
||
|
||
<style>
|
||
:root {
|
||
--bg: #fdfcf7;
|
||
--bg-soft: #f4f1ea;
|
||
--bg-code: #f8f5ec;
|
||
--ink: #1a1a1a;
|
||
--ink-soft: #4a4a4a;
|
||
--ink-muted: #6b6b6b;
|
||
--primary: #1a4a8c;
|
||
--primary-soft: #2d6cb8;
|
||
--accent: #b8390e;
|
||
--warn: #b45309;
|
||
--warn-bg: #fef3c7;
|
||
--info-bg: #dbeafe;
|
||
--good-bg: #d1fae5;
|
||
--good: #065f46;
|
||
--bad-bg: #fee2e2;
|
||
--bad: #991b1b;
|
||
--border: #d6d0c0;
|
||
--border-soft: #e8e3d5;
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
html { scroll-behavior: smooth; }
|
||
|
||
body {
|
||
font-family: "Source Serif Pro", "Source Serif 4", "Crimson Pro", "Georgia", "Songti SC", "STSong", serif;
|
||
line-height: 1.65;
|
||
color: var(--ink);
|
||
background: var(--bg);
|
||
margin: 0;
|
||
padding: 0;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.layout {
|
||
max-width: 1280px;
|
||
margin: 0 auto;
|
||
display: grid;
|
||
grid-template-columns: 260px 1fr;
|
||
gap: 48px;
|
||
padding: 40px 32px;
|
||
}
|
||
|
||
nav.toc {
|
||
position: sticky;
|
||
top: 24px;
|
||
align-self: start;
|
||
font-size: 13px;
|
||
max-height: calc(100vh - 48px);
|
||
overflow-y: auto;
|
||
border-right: 1px solid var(--border-soft);
|
||
padding-right: 16px;
|
||
}
|
||
nav.toc h3 {
|
||
margin: 0 0 12px;
|
||
font-size: 12px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.08em;
|
||
color: var(--ink-muted);
|
||
font-weight: 600;
|
||
}
|
||
nav.toc ol { list-style: none; padding: 0; margin: 0; counter-reset: toc; }
|
||
nav.toc ol li { margin: 5px 0; counter-increment: toc; }
|
||
nav.toc ol li::before { content: counter(toc) ". "; color: var(--ink-muted); margin-right: 4px; }
|
||
nav.toc a {
|
||
color: var(--ink-soft);
|
||
text-decoration: none;
|
||
border-bottom: 1px dotted transparent;
|
||
}
|
||
nav.toc a:hover { color: var(--primary); border-bottom-color: var(--primary); }
|
||
nav.toc ul { list-style: none; padding-left: 14px; margin: 3px 0; font-size: 12px; }
|
||
nav.toc ul li::before { content: "→ "; color: var(--border); }
|
||
|
||
main { min-width: 0; }
|
||
|
||
header.hero {
|
||
border-bottom: 3px double var(--primary);
|
||
padding-bottom: 24px;
|
||
margin-bottom: 32px;
|
||
}
|
||
header.hero .eyebrow {
|
||
color: var(--accent);
|
||
font-size: 13px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.12em;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
}
|
||
header.hero h1 {
|
||
font-size: 32px;
|
||
line-height: 1.2;
|
||
margin: 0 0 12px;
|
||
color: var(--ink);
|
||
font-weight: 700;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
header.hero .subtitle {
|
||
font-size: 16px;
|
||
color: var(--ink-soft);
|
||
margin: 0 0 8px;
|
||
font-style: italic;
|
||
}
|
||
header.hero .byline {
|
||
font-size: 14px;
|
||
color: var(--ink-soft);
|
||
margin: 0 0 20px;
|
||
}
|
||
header.hero .byline strong {
|
||
color: var(--ink);
|
||
font-weight: 600;
|
||
}
|
||
header.hero .meta {
|
||
display: flex;
|
||
gap: 20px;
|
||
flex-wrap: wrap;
|
||
font-size: 12px;
|
||
color: var(--ink-muted);
|
||
border-top: 1px solid var(--border-soft);
|
||
padding-top: 14px;
|
||
}
|
||
header.hero .meta span strong { color: var(--ink-soft); }
|
||
header.hero .meta code {
|
||
font-family: "JetBrains Mono", "SF Mono", "Menlo", "Consolas", monospace;
|
||
font-size: 11px;
|
||
background: var(--bg-soft);
|
||
padding: 1px 5px;
|
||
border-radius: 3px;
|
||
border: 1px solid var(--border-soft);
|
||
}
|
||
|
||
h2 {
|
||
font-size: 24px;
|
||
margin: 44px 0 14px;
|
||
padding-bottom: 8px;
|
||
border-bottom: 1px solid var(--border);
|
||
color: var(--ink);
|
||
font-weight: 700;
|
||
}
|
||
h2 .num { color: var(--primary); font-weight: 600; margin-right: 8px; }
|
||
h3 { font-size: 19px; margin: 28px 0 10px; color: var(--primary); font-weight: 600; }
|
||
h4 { font-size: 16px; margin: 20px 0 8px; color: var(--ink); font-weight: 600; }
|
||
|
||
p { margin: 10px 0; }
|
||
ul, ol { padding-left: 22px; margin: 10px 0; }
|
||
ul li, ol li { margin: 4px 0; }
|
||
ul li::marker { color: var(--primary); }
|
||
|
||
strong { color: var(--accent); font-weight: 600; }
|
||
em { color: var(--ink-soft); }
|
||
|
||
a { color: var(--primary); }
|
||
a:hover { color: var(--accent); }
|
||
|
||
code:not(.hljs) {
|
||
font-family: "JetBrains Mono", "SF Mono", "Menlo", "Consolas", monospace;
|
||
font-size: 0.86em;
|
||
background: var(--bg-code);
|
||
padding: 1px 5px;
|
||
border-radius: 3px;
|
||
border: 1px solid var(--border-soft);
|
||
color: var(--accent);
|
||
}
|
||
|
||
pre {
|
||
background: #fafaf6;
|
||
border: 1px solid var(--border);
|
||
border-left: 4px solid var(--primary);
|
||
padding: 0;
|
||
overflow-x: auto;
|
||
border-radius: 4px;
|
||
margin: 14px 0;
|
||
}
|
||
pre code, pre code.hljs {
|
||
background: transparent !important;
|
||
display: block;
|
||
padding: 14px 18px !important;
|
||
font-size: 13px;
|
||
line-height: 1.55;
|
||
font-family: "JetBrains Mono", "SF Mono", "Menlo", monospace;
|
||
color: var(--ink);
|
||
}
|
||
pre.diagram {
|
||
background: #f9f6ed;
|
||
border-left: 4px solid var(--accent);
|
||
font-size: 12.5px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.callout {
|
||
margin: 16px 0;
|
||
padding: 12px 16px;
|
||
border-radius: 4px;
|
||
border-left: 4px solid;
|
||
font-size: 15px;
|
||
}
|
||
.callout-title {
|
||
font-weight: 600;
|
||
margin-bottom: 6px;
|
||
font-size: 12px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.06em;
|
||
}
|
||
.callout-info { background: var(--info-bg); border-left-color: var(--primary); }
|
||
.callout-info .callout-title { color: var(--primary); }
|
||
.callout-warn { background: var(--warn-bg); border-left-color: var(--warn); }
|
||
.callout-warn .callout-title { color: var(--warn); }
|
||
.callout-good { background: var(--good-bg); border-left-color: var(--good); }
|
||
.callout-good .callout-title { color: var(--good); }
|
||
.callout-bad { background: var(--bad-bg); border-left-color: var(--bad); }
|
||
.callout-bad .callout-title { color: var(--bad); }
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin: 16px 0;
|
||
font-size: 14px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
thead { background: var(--primary); color: white; }
|
||
th, td {
|
||
text-align: left;
|
||
padding: 9px 12px;
|
||
border-bottom: 1px solid var(--border-soft);
|
||
vertical-align: top;
|
||
}
|
||
th { font-weight: 600; font-size: 13px; letter-spacing: 0.02em; }
|
||
tr:last-child td { border-bottom: none; }
|
||
tbody tr:nth-child(even) { background: var(--bg-soft); }
|
||
|
||
details.qa, details {
|
||
background: white;
|
||
border: 1px solid var(--border-soft);
|
||
border-radius: 6px;
|
||
margin: 10px 0;
|
||
padding: 0;
|
||
}
|
||
details summary {
|
||
cursor: pointer;
|
||
padding: 10px 14px;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
color: var(--primary);
|
||
list-style: none;
|
||
user-select: none;
|
||
}
|
||
details summary::-webkit-details-marker { display: none; }
|
||
details summary::before {
|
||
content: "▸ ";
|
||
margin-right: 4px;
|
||
display: inline-block;
|
||
transition: transform 0.15s;
|
||
}
|
||
details[open] summary::before { transform: rotate(90deg); }
|
||
details[open] summary { border-bottom: 1px solid var(--border-soft); }
|
||
details > :not(summary) { padding: 10px 14px; }
|
||
details p:first-of-type { margin-top: 8px; }
|
||
|
||
mjx-container[display="true"] { margin: 12px 0 !important; }
|
||
|
||
footer.aris-footer {
|
||
margin-top: 60px;
|
||
padding-top: 20px;
|
||
border-top: 1px solid var(--border);
|
||
font-size: 12px;
|
||
color: var(--ink-muted);
|
||
}
|
||
footer.aris-footer a { color: var(--ink-muted); border-bottom: 1px dotted var(--border); }
|
||
|
||
@media (max-width: 900px) {
|
||
.layout { grid-template-columns: 1fr; gap: 20px; padding: 20px 16px; }
|
||
nav.toc {
|
||
position: static;
|
||
max-height: none;
|
||
border-right: none;
|
||
border-bottom: 1px solid var(--border-soft);
|
||
padding-right: 0;
|
||
padding-bottom: 14px;
|
||
}
|
||
header.hero h1 { font-size: 24px; }
|
||
h2 { font-size: 20px; }
|
||
}
|
||
@media print {
|
||
nav.toc { display: none; }
|
||
.layout { grid-template-columns: 1fr; padding: 0; }
|
||
body { background: white; }
|
||
header.hero { border-bottom-color: var(--ink); }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="layout">
|
||
|
||
<nav class="toc">
|
||
<h3>Contents</h3>
|
||
<ol>
|
||
<li><a href="#0-tldr-cheat-sheet">§0 TL;DR Cheat Sheet</a>
|
||
</li>
|
||
<li><a href="#1-直觉稀疏激活--用参数容量换计算量">§1 直觉:稀疏激活 = 用"参数容量"换"计算量"</a>
|
||
</li>
|
||
<li><a href="#2-路由从-top-k-token-choice-到-expert-choice-到-loss-free">§2 路由:从 Top-k Token-Choice 到 Expert Choice 到 Loss-Free</a>
|
||
<ul>
|
||
<li><a href="#21-token-choice-top-kgshard--switch--mixtral--deepseek">2.1 Token-Choice Top-k(GShard / Switch / Mixtral / DeepSeek)</a></li>
|
||
<li><a href="#22-auxiliary-load-balancing-lossswitch-公式必背">2.2 Auxiliary Load Balancing Loss(Switch 公式,必背)</a></li>
|
||
<li><a href="#23-expert-choice-routingzhou-et-al-2022neurips">2.3 Expert Choice Routing(Zhou et al. 2022,NeurIPS)</a></li>
|
||
<li><a href="#24-auxiliary-loss-free-balancedeepseek-v3-招牌必考">2.4 Auxiliary-Loss-Free Balance(DeepSeek-V3 招牌,必考)</a></li>
|
||
<li><a href="#25-noisy-top-kshazeer-2017-原始方案已较少用">2.5 Noisy Top-k(Shazeer 2017 原始方案,已较少用)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#3-实现细节核心-60-行-pytorch">§3 实现细节:核心 60 行 PyTorch</a>
|
||
<ul>
|
||
<li><a href="#31-aux-loss-free-bias-updatedeepseek-v3-风格">3.1 Aux-Loss-Free Bias Update(DeepSeek-V3 风格)</a></li>
|
||
<li><a href="#32-fine-grained--shared-expert-layerdeepseekmoe-风格">3.2 Fine-Grained + Shared Expert Layer(DeepSeekMoE 风格)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#4-容量token-droppingrouting-collapse">§4 容量、Token Dropping、Routing Collapse</a>
|
||
<ul>
|
||
<li><a href="#41-capacity-factor必背工程细节">4.1 Capacity Factor(必背工程细节)</a></li>
|
||
<li><a href="#42-token-dropping-vs-residual-bypass">4.2 Token Dropping vs Residual Bypass</a></li>
|
||
<li><a href="#43-routing-collapse-经典-bug">4.3 Routing Collapse(💣 经典 bug)</a></li>
|
||
<li><a href="#44-top-k-的硬选择如何反传梯度">4.4 Top-k 的"硬"选择如何反传梯度?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#5-经典模型谱系从-shazeer-到-deepseek-v3">§5 经典模型谱系:从 Shazeer 到 DeepSeek-V3</a>
|
||
<ul>
|
||
<li><a href="#51-主流开源-moe-横向对比2026-面试常考">5.1 主流开源 MoE 横向对比(2026 面试常考)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#6-deepseek-v3-全景必背重点">§6 DeepSeek-V3 全景(必背重点)</a>
|
||
<ul>
|
||
<li><a href="#61-架构层面">6.1 架构层面</a></li>
|
||
<li><a href="#62-auxiliary-loss-free-balance详见-24">6.2 Auxiliary-Loss-Free Balance(详见 §2.4)</a></li>
|
||
<li><a href="#63-node-limited-routing">6.3 Node-Limited Routing</a></li>
|
||
<li><a href="#64-systemdualpipe--deepep">6.4 System:DualPipe + DeepEP</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#7-复杂度显存推理算账">§7 复杂度、显存、推理算账</a>
|
||
<ul>
|
||
<li><a href="#71-训练时-flops--参数对比">7.1 训练时 FLOPs / 参数对比</a></li>
|
||
<li><a href="#72-推理显存必考">7.2 推理显存(必考!)</a></li>
|
||
<li><a href="#73-kv-cache">7.3 KV Cache</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#8-ep--tp--pp--dpmoe-并行的-4-维交织">§8 EP / TP / PP / DP:MoE 并行的 4 维交织</a>
|
||
<ul>
|
||
<li><a href="#81-expert-parallelism">8.1 Expert Parallelism</a></li>
|
||
<li><a href="#82-ep--dp--tp--pp">8.2 EP × DP × TP × PP</a></li>
|
||
<li><a href="#83-ep-通信量算账">8.3 EP 通信量算账</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#9-与相关方法对比">§9 与相关方法对比</a>
|
||
<ul>
|
||
<li><a href="#91-moe-vs-dense同-flops--同参数">9.1 MoE vs Dense(同 FLOPs / 同参数)</a></li>
|
||
<li><a href="#92-moe-vs-mixture-of-depths-mod">9.2 MoE vs Mixture-of-Depths (MoD)</a></li>
|
||
<li><a href="#93-moe-微调esft-和它的同类">9.3 MoE 微调:ESFT 和它的同类</a></li>
|
||
<li><a href="#94-moe-vs-mqagqa">9.4 MoE vs MQA/GQA</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#10-25-高频面试题">§10 25 高频面试题</a>
|
||
<ul>
|
||
<li><a href="#l1必会题任何-ml-工程岗都会问">L1必会题(任何 ML 工程岗都会问)</a></li>
|
||
<li><a href="#l2进阶题research-oriented-岗位">L2进阶题(research-oriented 岗位)</a></li>
|
||
<li><a href="#l3顶级-lab--research-方向">L3顶级 lab / Research 方向</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#a-附录参考文献清单按时间">§A 附录:参考文献清单(按时间)</a>
|
||
</li>
|
||
</ol>
|
||
</nav>
|
||
|
||
<main>
|
||
<header class="hero">
|
||
<div class="eyebrow">Interview Prep · Mixture-of-Experts Architectures</div>
|
||
<h1>MoE (Mixture-of-Experts) 面试 Cheat Sheet</h1>
|
||
<p class="subtitle">DeepSeek-V3 / Mixtral / Llama 4 + 25 高频题(L1 必会 · L2 进阶 · L3 顶级 lab)</p>
|
||
<p class="byline">By <strong>Ruofeng Yang (杨若峰), Shanghai Jiao Tong University</strong></p>
|
||
<div class="meta">
|
||
<span><strong>Source:</strong> <code>docs/tutorials/moe_tutorial.md</code></span>
|
||
<span><strong>SHA256:</strong> <code>e860589270ed</code></span>
|
||
<span><strong>Rendered:</strong> 2026-05-19 10:10 UTC</span>
|
||
|
||
</div>
|
||
</header>
|
||
|
||
<h2 id="0-tldr-cheat-sheet">§0 TL;DR Cheat Sheet</h2>
|
||
<div class="callout callout-info"><div class="callout-title">8 句话搞定 MoE</div><p>一页拿下 2026 秋招核心要点(详见后文 §1–§9 推导)。</p></div>
|
||
<ol><li><strong>核心思想</strong>:把单个 FFN 换成 $N$ 个 expert + 一个 router,每个 token 只走 $k \ll N$ 个 expert,<strong>总参数 ↑、激活参数不变</strong>(sparse activation)。计算量约等于 $k/N$ × dense,但内存 / 显存按总参数计。</li><li><strong>路由公式</strong>(Token-Choice top-k):$g_i(x) = \text{softmax}(W_g x)_i$,选 $\mathcal{T}_k(x) = \text{TopK}_i\, g_i(x)$,输出 $y = \sum_{i \in \mathcal{T}_k(x)} g_i(x) \cdot E_i(x)$。Gate 概率作为 <strong>soft 权重</strong>乘到 expert 输出上,反传时让 router 可微。</li><li><strong>历史脉络(必背 5 篇)</strong>:Shazeer 2017(首个深度学习里可工作的 MoE 层)→ GShard 2020(top-2 + capacity factor + all-to-all)→ Switch Transformer 2021(top-1 极简,aux loss + load balance)→ Mixtral 8x7B/8x22B 2024(首个开源主流 MoE,top-2)→ DeepSeek-V3 2024(671B/37B,<strong>aux-loss-free</strong>,fine-grained + 1 shared)。</li><li><strong>DeepSeek 路线(2026 面试热点)</strong>:DeepSeekMoE 2024 提出 <strong>fine-grained experts</strong>(拆细,$mN$ 个小 expert 选 $mK$ 个)+ <strong>shared experts</strong>(少数 expert 给所有 token,吸收通用知识)。V2 用 MLA + DeepSeekMoE,V3 把路由专家做到 256 + 1 shared,<strong>取消 aux loss</strong>,改用 expert bias 在线更新。</li><li><strong>Aux-loss-free balance</strong>:在 router score 上加每 expert 的偏置 $b_i$,<strong>只用于 top-k 选择</strong>,不进梯度(也不进最终 gate 权重);每个 step 按"实际 load - 期望 load"反向更新 $b_i$(多负载 expert 减偏置)。<strong>不破坏 sparse gradient,不引入干扰梯度</strong>。</li><li><strong>容量与丢 token</strong>:每个 expert 的容量 $C = \lceil \alpha \cdot T \cdot k / N \rceil$($\alpha$ 是 capacity factor,常用 1.0-1.25)。超过容量的 token 走 <strong>residual bypass</strong>(直接跳过 expert,原始残差通过),或被 drop。Switch Transformer 论文里这是核心工程细节。</li><li><strong>并行</strong>:MoE 几乎必须用 <strong>Expert Parallelism (EP)</strong>——把不同 expert 放到不同 GPU,token 路由后做 <strong>all-to-all</strong>(dispatch)→ expert 算 → all-to-all(combine)。DeepEP 与 DualPipe 是 DeepSeek-V3 在 H800 上把 EP 通信和计算 overlap 的两大工程武器。</li><li><strong>常见 bug</strong>:①routing collapse(某些 expert 被全部 token 选、其他 expert 饿死);②fp16 下 router logit overflow;③推理时 <strong>all experts 必须全部加载到显存</strong>——只是激活参数少,<strong>显存依然按总参数算</strong>;④小 batch 时 EP 通信占满,吞吐反而比 dense 差。</li></ol>
|
||
<h2 id="1-直觉稀疏激活--用参数容量换计算量">§1 直觉:稀疏激活 = 用"参数容量"换"计算量"</h2>
|
||
<p>Dense FFN 长这样:每个 token 都过同一个 $D \times 4D \to 4D \times D$ 大矩阵,参数全部参与计算。</p>
|
||
<p>MoE 把 FFN 换成 $N$ 个独立 expert(每个本质仍是 FFN),但每个 token 由 router 决定<strong>只走 $k$ 个</strong>:</p>
|
||
<pre><code>
|
||
Token x [B, L, D]
|
||
│
|
||
↓
|
||
Router W_g ∈ R^{D × N} (gate)
|
||
│
|
||
↓
|
||
scores g(x) ∈ R^N
|
||
│
|
||
TopK + softmax-renormalize
|
||
│
|
||
┌─────┬─────┼─────┬─────┐
|
||
↓ ↓ ↓ ↓ ↓
|
||
E_1 E_2 ... E_{N-1} E_N (每个 expert = FFN)
|
||
│ │ │ │
|
||
└─ × g_1 ─ ... ─ × g_N ─┘ (只有 k 个 g_i ≠ 0)
|
||
│
|
||
↓
|
||
Sum → output y [B, L, D]</code></pre>
|
||
<p>为什么这是好主意?三个层次的回答:</p>
|
||
<ul><li><strong>容量论</strong>:模型容量主要来自参数量,泛化主要来自数据 × 容量。Sparse activation 允许把总参数推到上千 B,而每 token 计算仍像 30B dense——<strong>参数容量 ≫ 计算量</strong>。</li><li><strong>专精论</strong>:不同 expert 在训练中天然分工——code / math / 多语言 / 通用语义。Switch Transformer 给过 t-SNE 可视化,DeepSeekMoE 用 fine-grained 进一步加剧这种专精。</li><li><strong>推理效率</strong>:固定 active 参数 $\approx$ 固定 FLOPs,可与 dense 同台比,但参数容量大很多——这是 Mixtral 8x7B 用 13B active 干过 LLaMA-2 70B 的根本原因。</li></ul>
|
||
<div class="callout callout-warn"><div class="callout-title">MoE 不是免费午餐</div><p>sparse activation 减的是 <strong>FLOPs</strong>,<strong>不减显存</strong>(推理时所有 expert 必须常驻 GPU);EP 训练时 all-to-all 通信能轻易吃掉一半时间;负载不均会让多数 GPU 空转。下面 §3-§7 是这些工程现实的全部展开。</p></div>
|
||
<h2 id="2-路由从-top-k-token-choice-到-expert-choice-到-loss-free">§2 路由:从 Top-k Token-Choice 到 Expert Choice 到 Loss-Free</h2>
|
||
<h3 id="21-token-choice-top-kgshard--switch--mixtral--deepseek">2.1 Token-Choice Top-k(GShard / Switch / Mixtral / DeepSeek)</h3>
|
||
<p>最经典也最常考。Gate 计算每个 (token, expert) 对的 affinity,token 选 top-k expert:</p>
|
||
<p>$$\boxed{\;s(x) = W_g x \in \mathbb{R}^N, \quad g(x) = \text{softmax}(s(x)), \quad \mathcal{T}_k(x) = \text{TopK}_i\, g_i(x)\;}$$</p>
|
||
<p>输出(routing weight 重新归一化版本,Mixtral / DeepSeek 默认这种):</p>
|
||
<p>$$y = \sum_{i \in \mathcal{T}_k(x)} \tilde{g}_i(x) \cdot E_i(x), \quad \tilde{g}_i(x) = \frac{g_i(x)}{\sum_{j \in \mathcal{T}_k(x)} g_j(x)}$$</p>
|
||
<div class="callout callout-info"><div class="callout-title">重归一 vs 直用 softmax 概率</div><p>两种工程实现都见过:Switch 直接用 $g_i$(top-1 时 $g_i$ 直接乘);Mixtral / DeepSeek 在 top-k 上再 renormalize 让权重和 = 1。renormalize 让输出尺度稳定,不依赖 softmax 在 top-k 之外的"漏出"概率质量。</p></div>
|
||
<p><strong>几个变体的 $k$</strong>:</p>
|
||
<table><thead><tr><th>模型</th><th style="text-align:center">$k$</th><th>备注</th></tr></thead><tbody><tr><td>Switch Transformer</td><td style="text-align:center">1</td><td>极简,被证明也能 work</td></tr><tr><td>GShard / Mixtral / Qwen3-MoE</td><td style="text-align:center">2</td><td>主流;2 个 expert 足够"集成"</td></tr><tr><td>DeepSeek-V2 / V3</td><td style="text-align:center">6 / 8(routed)+ 1 shared</td><td>配合 fine-grained 拆细</td></tr><tr><td>Llama 4 Scout</td><td style="text-align:center">1(仅 1 个 routed)+ 1 shared</td><td>16 experts,1 shared</td></tr><tr><td>Llama 4 Maverick</td><td style="text-align:center">1 routed + 1 shared</td><td>128 experts</td></tr></tbody></table>
|
||
<h3 id="22-auxiliary-load-balancing-lossswitch-公式必背">2.2 Auxiliary Load Balancing Loss(Switch 公式,必背)</h3>
|
||
<p>问题:纯 top-k 没有任何机制让 router <strong>均衡使用</strong>所有 expert——很容易 collapse 成"只用 1-2 个 expert"。</p>
|
||
<p>Switch Transformer 引入 differentiable load balancing loss:</p>
|
||
<p>$$\boxed{\;\mathcal{L}_\text{aux} = \alpha \cdot N \sum_{i=1}^{N} f_i \cdot P_i\;}$$</p>
|
||
<p>其中</p>
|
||
<ul><li>$f_i = \dfrac{1}{T} \sum_{t=1}^{T} \mathbb{1}\{\arg\max_j s_j(x_t) = i\}$ ——分配给 expert $i$ 的 token 比例(不可微,sample-level 估计)</li><li>$P_i = \dfrac{1}{T} \sum_{t=1}^{T} g_i(x_t)$ ——expert $i$ 的平均 gate 概率(可微,softmax 输出)</li><li>$\alpha$ 是 loss 权重(常用 $10^{-2}$)</li><li>$N$ 是 expert 数量;$T$ 是 batch 中 token 数</li></ul>
|
||
<p><strong>关键点 / 易混淆</strong>:</p>
|
||
<ol><li>$f_i$ 给"实际频率",$P_i$ 给"梯度通路"。乘起来 $\sum_i f_i P_i$ 当两者都集中在同一组 expert 时最大;均匀分布时最小($= 1/N$,乘以 $N$ 后 = 1)。</li><li>这是 <strong>encourage 均匀分布</strong>,不是硬约束。极端 collapse 会被惩罚,但日常小幅不均不会被强力惩罚。</li><li>Switch top-1 公式直接如此;top-k 时把 $f_i$ 改成"top-k 命中频率"(更准确写法见 GShard 论文)。</li><li><strong>$\alpha$ 太大会干扰主任务梯度</strong>——这是 DeepSeek 改 aux-loss-free 的根本动机。</li></ol>
|
||
<h3 id="23-expert-choice-routingzhou-et-al-2022neurips">2.3 Expert Choice Routing(Zhou et al. 2022,NeurIPS)</h3>
|
||
<p>反向思维:不让 token 挑 expert,让 <strong>expert 挑 token</strong>。每个 expert 根据 capacity 选 top-$M$ 个 token,$M = (T \cdot k) / N$(每个 expert 平均分到 token 数)。</p>
|
||
<p>$$s(x) \in \mathbb{R}^{T \times N}, \quad \mathcal{T}_M^{(i)} = \text{TopM}_{t}\, s_{t,i}, \quad y_t = \sum_{i: t \in \mathcal{T}_M^{(i)}} g_{t,i} \cdot E_i(x_t)$$</p>
|
||
<p><strong>优点</strong>:</p>
|
||
<ul><li><strong>天然平衡</strong>:每个 expert 严格选 $M$ 个 token,不需要 aux loss</li><li><strong>不丢 token</strong>:理论上不会有"溢出"(capacity 是 hard 给定)</li></ul>
|
||
<p><strong>缺点 / 限制</strong>:</p>
|
||
<ul><li><strong>不是 causal</strong>:第 $t$ 个 token 的归属依赖 $T$ 个 token 全部的 score——decoder 推理时<strong>无法 token-by-token 生成</strong>,需要 batch-level 全局视角(autoregressive 不友好)</li><li>每个 token 实际激活的 expert 数 <strong>不固定</strong>(可能没被选 / 被多个选)</li><li>主要在 encoder(如 T5、BERT-style)或 vision 用</li></ul>
|
||
<div class="callout callout-warn"><div class="callout-title">面试陷阱</div><p>被问"Expert Choice 解决了 routing collapse,那 Mixtral / DeepSeek 为什么还用 token-choice?" 答案:autoregressive decoder + 每 token 严格走固定 $k$ expert 的需求让 expert-choice 用不了;DeepSeek-V3 改用 aux-loss-free 在 <strong>token-choice 框架内</strong>做平衡。</p></div>
|
||
<h3 id="24-auxiliary-loss-free-balancedeepseek-v3-招牌必考">2.4 Auxiliary-Loss-Free Balance(DeepSeek-V3 招牌,必考)</h3>
|
||
<p>DeepSeek(Wang et al., arXiv 2408.15664, 2024)提出的方案,被 V3 全面采纳。核心一句话:<strong>给每个 expert 加一个偏置项 $b_i$,只用于 top-k 选择,不进梯度</strong>。</p>
|
||
<p>具体地,原 score 是 $s_i(x)$,做 top-k 选择时用 <strong>biased score</strong>:</p>
|
||
<p>$$\tilde{s}_i(x) = s_i(x) + b_i$$</p>
|
||
<p>$$\mathcal{T}_k(x) = \text{TopK}_i\, \tilde{s}_i(x)$$</p>
|
||
<p>但<strong>最终 gating weight</strong> 仍用原始 $s_i$ 的 softmax(或 sigmoid 后 renormalize,DeepSeek-V3 用 sigmoid):</p>
|
||
<p>$$g_i(x) = \frac{\sigma(s_i(x))}{\sum_{j \in \mathcal{T}_k(x)} \sigma(s_j(x))}, \quad i \in \mathcal{T}_k(x)$$</p>
|
||
<p>$b_i$ 的更新规则(每 step 一次,<strong>out-of-graph</strong>,非梯度更新):</p>
|
||
<p>$$b_i \leftarrow b_i + u \cdot \text{sign}(\bar{c}_i - c_i)$$</p>
|
||
<ul><li>$c_i$ = 本 step 中 expert $i$ 实际接到的 token 数</li><li>$\bar{c}_i = T k / N$ = 均匀分布下每个 expert 应接到的期望 token 数</li><li>若 $c_i > \bar{c}_i$(过载)→ $b_i$ 减小 → 下次更难被选</li><li>若 $c_i < \bar{c}_i$(欠载)→ $b_i$ 增大 → 下次更易被选</li><li>$u$ 是固定步长(V3 报告里很小,量级 $10^{-3}$)</li></ul>
|
||
<div class="callout callout-good"><div class="callout-title">为什么这是非平凡的胜利</div><p>Aux loss 的问题是它把"平衡"作为 <strong>梯度信号</strong> 注入 router → 干扰主任务梯度,模型为了平衡可能牺牲质量。Loss-free 把平衡作为 <strong>离线控制信号</strong>(PID 风味的 sign update),完全不进入计算图——router 仍然只为"语言建模 loss"求梯度,但选 expert 时被 $b_i$ 推着走。<strong>不破坏 sparse routing 的语义、不污染主梯度、不引入需要 tune 的 $\alpha$</strong>。</p></div>
|
||
<h3 id="25-noisy-top-kshazeer-2017-原始方案已较少用">2.5 Noisy Top-k(Shazeer 2017 原始方案,已较少用)</h3>
|
||
<p>Shazeer 等 2017 论文里在 score 上加可学习的 Gaussian noise:</p>
|
||
<p>$$s_i(x) = (W_g x)_i + \text{StandardNormal}() \cdot \text{Softplus}((W_\text{noise} x)_i)$$</p>
|
||
<p>噪声为了让 top-k 选择"软化"、避免 collapse。后被 GShard / Switch 用更明确的 load balance loss 取代——但概念("top-k 不可微 → 需要某种 stochastic 软化")仍有教学价值。</p>
|
||
<h2 id="3-实现细节核心-60-行-pytorch">§3 实现细节:核心 60 行 PyTorch</h2>
|
||
<p>最小可跑实现:token-choice top-k MoE 层 + Switch aux loss。不考虑 EP,单 GPU 教学用。</p>
|
||
<pre><code class="language-python">import torch
|
||
import torch.nn as nn
|
||
import torch.nn.functional as F
|
||
|
||
class Expert(nn.Module):
|
||
"""每个 expert 就是一个标准 FFN(SwiGLU 风格也可,这里用 GELU 简化)"""
|
||
def __init__(self, d_model, d_ff):
|
||
super().__init__()
|
||
self.w1 = nn.Linear(d_model, d_ff, bias=False)
|
||
self.w2 = nn.Linear(d_ff, d_model, bias=False)
|
||
def forward(self, x):
|
||
return self.w2(F.gelu(self.w1(x)))
|
||
|
||
class MoELayer(nn.Module):
|
||
"""
|
||
Token-choice top-k MoE layer.
|
||
输入 x: [B, L, D]
|
||
输出 y: [B, L, D], aux_loss: scalar (Switch load-balance loss)
|
||
"""
|
||
def __init__(self, d_model, d_ff, num_experts, top_k=2, capacity_factor=1.25, aux_loss_coef=0.01):
|
||
super().__init__()
|
||
assert top_k <= num_experts
|
||
self.d_model = d_model
|
||
self.num_experts = num_experts
|
||
self.top_k = top_k
|
||
self.capacity_factor = capacity_factor
|
||
self.aux_loss_coef = aux_loss_coef
|
||
|
||
# Router: D -> N, no bias (Switch / Mixtral 都不用 bias)
|
||
self.router = nn.Linear(d_model, num_experts, bias=False)
|
||
# N 个 expert
|
||
self.experts = nn.ModuleList([Expert(d_model, d_ff) for _ in range(num_experts)])
|
||
|
||
def forward(self, x):
|
||
B, L, D = x.shape
|
||
T = B * L
|
||
x_flat = x.view(T, D) # [T, D]
|
||
|
||
# ----- 1. Router 计算 score + top-k -----
|
||
logits = self.router(x_flat) # [T, N]
|
||
probs = F.softmax(logits, dim=-1) # [T, N]
|
||
top_probs, top_idx = probs.topk(self.top_k, dim=-1) # [T, k], [T, k]
|
||
# Mixtral / DeepSeek 风格:在 top-k 上重归一
|
||
top_probs = top_probs / (top_probs.sum(dim=-1, keepdim=True) + 1e-9) # [T, k]
|
||
|
||
# ----- 2. Aux load-balance loss (Switch 公式) -----
|
||
# f_i = 分给 expert i 的 token 比例 (每 token 算 top_k 次命中, 与 top_k 一致)
|
||
with torch.no_grad():
|
||
one_hot = F.one_hot(top_idx, num_classes=self.num_experts).float() # [T, k, N]
|
||
f = one_hot.sum(dim=(0, 1)) / (T * self.top_k) # [N]
|
||
P = probs.mean(dim=0) # [N], 可微
|
||
aux_loss = self.aux_loss_coef * self.num_experts * (f * P).sum()
|
||
|
||
# ----- 3. Capacity 计算 + token dispatch -----
|
||
# 与正文公式一致:ceil(capacity_factor * T * top_k / N_E),避免小 batch 截断为 0
|
||
import math as _math
|
||
capacity = max(1, _math.ceil(self.capacity_factor * T * self.top_k / self.num_experts))
|
||
# 把 [T, k] 展开成 [T*k] 的 (token_idx, expert_idx) pair
|
||
flat_expert = top_idx.view(-1) # [T*k]
|
||
flat_weight = top_probs.view(-1) # [T*k]
|
||
flat_token = torch.arange(T, device=x.device).repeat_interleave(self.top_k) # [T*k]
|
||
|
||
# ----- 4. Expert forward (capacity-aware) -----
|
||
y_flat = torch.zeros_like(x_flat) # [T, D]
|
||
for e in range(self.num_experts):
|
||
mask_e = (flat_expert == e) # [T*k]
|
||
if mask_e.sum() == 0:
|
||
continue
|
||
tok_e = flat_token[mask_e] # 要给 expert e 处理的 token 全局 idx
|
||
w_e = flat_weight[mask_e] # 对应 gate weight
|
||
# 容量截断:超过 capacity 的 token drop (Switch residual bypass)
|
||
if tok_e.numel() > capacity:
|
||
tok_e = tok_e[:capacity]
|
||
w_e = w_e[:capacity]
|
||
inp_e = x_flat[tok_e] # [≤cap, D]
|
||
out_e = self.experts[e](inp_e) # [≤cap, D]
|
||
# 按 token idx scatter-add (一个 token 可能被多个 expert 命中,所以是 add)
|
||
y_flat.index_add_(0, tok_e, out_e * w_e.unsqueeze(-1))
|
||
|
||
return y_flat.view(B, L, D), aux_loss</code></pre>
|
||
<div class="callout callout-warn"><div class="callout-title">生产实现关键差异</div><p>教学版用 Python <code>for e in range(num_experts)</code> 串行调每个 expert,<strong>生产 (Megatron / vLLM) 都是 grouped GEMM 或 fused kernel</strong>,把所有 expert 的计算 batch 到一起,否则 N 大时 GPU 大部分时间在 launch kernel。MoE 真正难的是这一层。</p></div>
|
||
<h3 id="31-aux-loss-free-bias-updatedeepseek-v3-风格">3.1 Aux-Loss-Free Bias Update(DeepSeek-V3 风格)</h3>
|
||
<p>把上面 §3 中的 aux loss 删掉,改用 expert bias 更新:</p>
|
||
<pre><code class="language-python">class MoEAuxFree(nn.Module):
|
||
def __init__(self, d_model, d_ff, num_experts, top_k=2, bias_step=1e-3):
|
||
super().__init__()
|
||
self.num_experts = num_experts
|
||
self.top_k = top_k
|
||
self.bias_step = bias_step
|
||
self.router = nn.Linear(d_model, num_experts, bias=False)
|
||
# b_i: 非参数, 不进梯度图 (buffer)
|
||
self.register_buffer('expert_bias', torch.zeros(num_experts))
|
||
self.experts = nn.ModuleList([Expert(d_model, d_ff) for _ in range(num_experts)])
|
||
|
||
def forward(self, x):
|
||
B, L, D = x.shape
|
||
T = B * L
|
||
x_flat = x.view(T, D)
|
||
|
||
# Router score (V3 用 sigmoid 不是 softmax, 但 top-k 逻辑一样)
|
||
logits = self.router(x_flat) # [T, N]
|
||
# ★ Top-k 用 biased score, 但 gating weight 用原始 score
|
||
biased_logits = logits + self.expert_bias.unsqueeze(0)
|
||
_, top_idx = biased_logits.topk(self.top_k, dim=-1) # [T, k]
|
||
# 取出原始 score 对应位置, sigmoid 后 renormalize
|
||
gate_raw = torch.sigmoid(logits).gather(-1, top_idx) # [T, k]
|
||
top_weights = gate_raw / (gate_raw.sum(dim=-1, keepdim=True) + 1e-9)
|
||
|
||
# ----- 在线更新 expert_bias (无梯度, 论文 sign 更新) -----
|
||
if self.training:
|
||
with torch.no_grad():
|
||
one_hot = F.one_hot(top_idx, num_classes=self.num_experts).float() # [T, k, N]
|
||
c = one_hot.sum(dim=(0, 1)) # [N], 实际 load
|
||
c_bar = T * self.top_k / self.num_experts # 期望 load (scalar)
|
||
# 过载 -> 减偏置; 欠载 -> 加偏置
|
||
self.expert_bias -= self.bias_step * torch.sign(c - c_bar)
|
||
|
||
# Dispatch + expert forward (与 §3 同, 这里省略)
|
||
y_flat = torch.zeros_like(x_flat)
|
||
flat_expert = top_idx.view(-1)
|
||
flat_weight = top_weights.view(-1)
|
||
flat_token = torch.arange(T, device=x.device).repeat_interleave(self.top_k)
|
||
for e in range(self.num_experts):
|
||
mask = (flat_expert == e)
|
||
if mask.sum() == 0: continue
|
||
tok_e = flat_token[mask]
|
||
w_e = flat_weight[mask]
|
||
out_e = self.experts[e](x_flat[tok_e]) * w_e.unsqueeze(-1)
|
||
y_flat.index_add_(0, tok_e, out_e)
|
||
return y_flat.view(B, L, D)</code></pre>
|
||
<p>注意:</p>
|
||
<ol><li><code>expert_bias</code> 是 buffer 不是 parameter,<strong>不进梯度图、不被 optimizer step</strong>——只被 §forward 末尾的"sign 更新"修改。</li><li><strong>biased_logits 只用于选 top-k,gating weight 来自原始 logits</strong>(这是 V3 论文反复强调的点)。如果连 gating weight 都用 biased,相当于把控制信号污染到主梯度路径,aux-loss-free 的好处就丢了。</li><li>V3 实际是 sigmoid + 256 experts + 9 选(8 routed + 1 shared 在 §6 讲),这里简化成 softmax + top-k 演示原理。</li></ol>
|
||
<h3 id="32-fine-grained--shared-expert-layerdeepseekmoe-风格">3.2 Fine-Grained + Shared Expert Layer(DeepSeekMoE 风格)</h3>
|
||
<pre><code class="language-python">class DeepSeekMoELayer(nn.Module):
|
||
"""
|
||
Fine-grained + shared expert:
|
||
- 总共 N 个 routed expert (拆细, 每个比标准 expert 小 m 倍)
|
||
- 加 N_shared 个 shared expert (所有 token 都走)
|
||
- 每个 token 路由到 K 个 routed expert (K = m × baseline_top_k)
|
||
论文 (Dai et al. 2024, arXiv 2401.06066): 把 N 个原始 expert 拆成 mN 个,
|
||
每个 expert 的 d_ff 缩到 d_ff/m, 路由数从 K 提到 mK, 总计算 / 参数量不变,
|
||
但组合数 C(mN, mK) >> C(N, K) -> 专业化粒度提升.
|
||
"""
|
||
def __init__(self, d_model, d_ff_per_expert, num_routed_experts, num_shared_experts, top_k):
|
||
super().__init__()
|
||
self.num_routed = num_routed_experts
|
||
self.num_shared = num_shared_experts
|
||
self.top_k = top_k
|
||
self.router = nn.Linear(d_model, num_routed_experts, bias=False)
|
||
# 拆细后的 routed experts (每个比 baseline 小 m 倍)
|
||
self.routed_experts = nn.ModuleList(
|
||
[Expert(d_model, d_ff_per_expert) for _ in range(num_routed_experts)]
|
||
)
|
||
# Shared experts: 永远激活, 不进 router
|
||
self.shared_experts = nn.ModuleList(
|
||
[Expert(d_model, d_ff_per_expert) for _ in range(num_shared_experts)]
|
||
)
|
||
|
||
def forward(self, x):
|
||
# 1. Shared expert: 直接累加, 不路由
|
||
shared_out = sum(e(x) for e in self.shared_experts)
|
||
|
||
# 2. Routed top-k (这里简化省略 aux loss / capacity)
|
||
B, L, D = x.shape
|
||
T = B * L
|
||
x_flat = x.view(T, D)
|
||
logits = self.router(x_flat)
|
||
probs = F.softmax(logits, dim=-1)
|
||
top_p, top_i = probs.topk(self.top_k, dim=-1)
|
||
top_p = top_p / (top_p.sum(dim=-1, keepdim=True) + 1e-9)
|
||
|
||
routed_out = torch.zeros_like(x_flat)
|
||
flat_e = top_i.view(-1)
|
||
flat_w = top_p.view(-1)
|
||
flat_t = torch.arange(T, device=x.device).repeat_interleave(self.top_k)
|
||
for e in range(self.num_routed):
|
||
mask = (flat_e == e)
|
||
if mask.sum() == 0: continue
|
||
tok = flat_t[mask]
|
||
w = flat_w[mask]
|
||
routed_out.index_add_(0, tok, self.routed_experts[e](x_flat[tok]) * w.unsqueeze(-1))
|
||
|
||
return shared_out + routed_out.view(B, L, D)</code></pre>
|
||
<div class="callout callout-info"><div class="callout-title">Fine-grained 的"组合爆炸"直觉</div><p>标准 8 选 2 → 28 种组合。拆细成 64 选 16(每个 expert 缩到 1/8,路由数 ×8),组合 $\binom{64}{16} \approx 4.9 \times 10^{14}$。同样的参数/算力预算下,<strong>每个 token 可表达的"专家组合身份"指数级丰富</strong>,是 DeepSeekMoE 的核心论点之一。</p></div>
|
||
<h2 id="4-容量token-droppingrouting-collapse">§4 容量、Token Dropping、Routing Collapse</h2>
|
||
<h3 id="41-capacity-factor必背工程细节">4.1 Capacity Factor(必背工程细节)</h3>
|
||
<p>每个 expert 不可能接受任意多 token——GPU memory + EP 通信都需要静态 buffer。所以预先给每个 expert 设容量 $C$:</p>
|
||
<p>$$\boxed{\;C = \left\lceil \alpha \cdot \frac{T \cdot k}{N} \right\rceil\;}$$</p>
|
||
<ul><li>$T$:batch 中 token 总数</li><li>$k$:每 token 走的 expert 数</li><li>$N$:expert 总数</li><li>$\alpha$:capacity factor(常用 1.0、1.25、2.0)</li></ul>
|
||
<p><strong>$\alpha = 1$</strong>:均匀分布下刚好够用,但稍微不均就 drop;<strong>$\alpha = 1.25$</strong>(Switch / GShard 默认):留 25% 余量缓冲不均匀;<strong>$\alpha > 2$</strong>:基本不 drop 但浪费显存。</p>
|
||
<h3 id="42-token-dropping-vs-residual-bypass">4.2 Token Dropping vs Residual Bypass</h3>
|
||
<p>当某 expert 已收满 $C$ 个 token,新来的 token 怎么办?<strong>两条路线</strong>:</p>
|
||
<table><thead><tr><th>方案</th><th>行为</th><th>谁用</th></tr></thead><tbody><tr><td><strong>Token Drop</strong></td><td>直接丢,输出 0</td><td>GShard 早期;通常 ↓ 训练稳定性</td></tr><tr><td><strong>Residual Bypass</strong></td><td>Expert 输出置 0,但 <strong>residual $x$ 自然通过 layer norm + skip connection 透传</strong></td><td>Switch Transformer / Mixtral / DeepSeek 默认</td></tr></tbody></table>
|
||
<p>Residual bypass 的好处:被 drop 的 token <strong>不是变 0</strong>——它在残差通路上仍然带着自己的表示,只是这层"没被任何 expert 加工",相当于退化成 identity layer。整个网络仍然能学到东西。</p>
|
||
<div class="callout callout-warn"><div class="callout-title">必考易踩坑</div><p>面试常问"MoE 为什么不 catastrophic 地坏掉"。答案:residual bypass + 多层堆叠下,<strong>单层 drop 不致命</strong>——下一层 router 仍然能为该 token 选到合适 expert。</p></div>
|
||
<h3 id="43-routing-collapse-经典-bug">4.3 Routing Collapse(💣 经典 bug)</h3>
|
||
<p>如果 router 没有 balance 机制,训练初期某些 expert 偶然被多选 → 它们参数被更新更多 → 下次更可能被选 → 强者愈强 → <strong>少数 expert 通吃,多数饿死</strong>。这就是 routing collapse。</p>
|
||
<p>诊断信号:</p>
|
||
<ul><li>监控 expert load(每 step 每 expert 接到的 token 数)→ 极不均</li><li>监控 aux loss → 大或在涨</li><li>Validation loss 平台期早出现</li></ul>
|
||
<p>修复手段:</p>
|
||
<ol><li><strong>Aux loss</strong>(Switch 公式,§2.2)</li><li><strong>Expert dropout</strong> / <strong>Z-loss</strong>(对 router logits 加 entropy regularizer)</li><li><strong>Expert Choice</strong>(§2.3,硬约束每 expert 选固定数 token)</li><li><strong>Aux-loss-free bias</strong>(§2.4,DeepSeek-V3)</li><li><strong>Capacity factor 适度调大</strong>(让 collapse 触发 drop,间接惩罚集中)</li></ol>
|
||
<h3 id="44-top-k-的硬选择如何反传梯度">4.4 Top-k 的"硬"选择如何反传梯度?</h3>
|
||
<p>经典问题:$\text{TopK}$ 是不可微的离散操作。</p>
|
||
<p>答案:<strong>top-k 只决定走哪条路径(discrete),不参与梯度</strong>;softmax 权重 $g_i(x)$ 进入最终输出 $y = \sum_i g_i E_i(x)$,对 $g_i$ 求导是连续的(standard softmax 链式法则)。所以 router 的 $W_g$ 是可微的(注意 softmax / renorm 的耦合带来 <strong>完整 Jacobian</strong>,不只是对角项):</p>
|
||
<p>记 $s = W_g x$(logits),$p = \text{softmax}(s)$,top-k 选 $\mathcal{T}_k(x)$ 后做 renormalize $g_i = p_i / Z$($Z = \sum_{j \in \mathcal{T}_k} p_j$):</p>
|
||
<p>$$\frac{\partial g_i}{\partial s_l} = \mathbf{1}[i \in \mathcal{T}_k]\cdot\left(\frac{\partial p_i / \partial s_l}{Z} - \frac{p_i}{Z^2}\cdot \mathbf{1}[l \in \mathcal{T}_k] \cdot \frac{\partial Z}{\partial s_l}\right)$$</p>
|
||
<p>其中 $\partial p_i/\partial s_l = p_i(\delta_{il} - p_l)$ 是 softmax Jacobian(含交叉项 $-p_i p_l$,不只是对角 $p_i(1-p_i)$)。汇总:</p>
|
||
<p>$$\frac{\partial \mathcal{L}}{\partial W_g} = \sum_{i \in \mathcal{T}_k(x)}\sum_{l} \frac{\partial \mathcal{L}}{\partial g_i} \cdot \frac{\partial g_i}{\partial s_l} \cdot \frac{\partial s_l}{\partial W_g}$$</p>
|
||
<p>对 $l \notin \mathcal{T}_k$(被 top-k 排除),$\partial g_i/\partial s_l$ 通过 $p_l$ 仍非零(softmax 的全局耦合),但这一项在 forward 不影响输出、在 backward 的贡献仅经 $\partial p_i / \partial s_l = -p_i p_l$ 间接进入。<strong>实操上</strong>,只有 top-k 内的 expert 才能拿到主导梯度信号;top-k 外的 expert 长期得不到 "我应该被选" 的训练 push——这是 chicken-and-egg:不被选 → 不更新 → 永远不被选。Aux loss / bias 就是为了打破这个循环。</p>
|
||
<h2 id="5-经典模型谱系从-shazeer-到-deepseek-v3">§5 经典模型谱系:从 Shazeer 到 DeepSeek-V3</h2>
|
||
<p>按时间和"工程门槛"排成 7 行(必背年表 + 关键贡献):</p>
|
||
<table><thead><tr><th>年份</th><th>论文 / 模型</th><th>核心贡献</th><th>arXiv</th></tr></thead><tbody><tr><td>2017</td><td><strong>Shazeer et al., Outrageously Large NN</strong></td><td>首个深度 MoE 层(LSTM 旁挂),noisy top-k, load-balance loss 雏形</td><td>1701.06538</td></tr><tr><td>2020</td><td><strong>GShard (Lepikhin et al.)</strong></td><td>Top-2 routing, capacity factor, <strong>automatic sharding / all-to-all</strong>,600B 多语言 NMT</td><td>2006.16668</td></tr><tr><td>2021</td><td><strong>Switch Transformer (Fedus, Zoph, Shazeer)</strong></td><td>Top-1 极简,aux loss 标准公式,1.6T 参数 T5-MoE</td><td>2101.03961</td></tr><tr><td>2022</td><td><strong>Expert Choice (Zhou et al., NeurIPS)</strong></td><td>Expert-choice routing,硬平衡,无需 aux loss(但 autoregressive 不友好)</td><td>2202.09368</td></tr><tr><td>2024.1</td><td><strong>DeepSeekMoE (Dai et al.)</strong></td><td><strong>Fine-grained experts + shared experts</strong>,16B / 145B 验证</td><td>2401.06066</td></tr><tr><td>2024.1</td><td><strong>Mixtral 8x7B (Jiang et al.)</strong></td><td>首个开源主流 MoE,8 experts top-2,13B active 干过 LLaMA-2 70B</td><td>2401.04088</td></tr><tr><td>2024.4</td><td><strong>Mixtral 8x22B</strong></td><td>141B 总 / 39B 激活,64k context</td><td>(Mistral blog)</td></tr><tr><td>2024.5</td><td><strong>DeepSeek-V2 (DeepSeek-AI)</strong></td><td>236B / 21B,<strong>MLA + DeepSeekMoE</strong>,KV cache 减 93.3%</td><td>2405.04434</td></tr><tr><td>2024.8</td><td><strong>Loss-Free Balance (Wang et al.)</strong></td><td>Aux-loss-free 偏置更新方案</td><td>2408.15664</td></tr><tr><td>2024.12</td><td><strong>DeepSeek-V3</strong></td><td><strong>671B / 37B</strong>,256 routed + 1 shared expert,aux-loss-free, MTP, DualPipe</td><td>2412.19437</td></tr><tr><td>2025.4</td><td><strong>Llama 4 (Meta)</strong></td><td>Scout (17B/16E)、Maverick (17B/128E)、Behemoth (288B/16E)</td><td>(Meta blog)</td></tr><tr><td>2025.5</td><td><strong>Qwen3 MoE</strong></td><td>Qwen3-235B-A22B(22B 激活)</td><td>2505.09388</td></tr></tbody></table>
|
||
<h3 id="51-主流开源-moe-横向对比2026-面试常考">5.1 主流开源 MoE 横向对比(2026 面试常考)</h3>
|
||
<table><thead><tr><th>模型</th><th style="text-align:center">总参数</th><th style="text-align:center">激活 / token</th><th style="text-align:center">Routed experts</th><th style="text-align:center">Top-k</th><th style="text-align:center">Shared expert</th><th style="text-align:center">Aux 方案</th><th style="text-align:center">Released</th></tr></thead><tbody><tr><td>Mixtral 8x7B</td><td style="text-align:center">46.7B</td><td style="text-align:center">12.9B</td><td style="text-align:center">8</td><td style="text-align:center">2</td><td style="text-align:center">0</td><td style="text-align:center">aux loss</td><td style="text-align:center">2023.12</td></tr><tr><td>Mixtral 8x22B</td><td style="text-align:center">141B</td><td style="text-align:center">39B</td><td style="text-align:center">8</td><td style="text-align:center">2</td><td style="text-align:center">0</td><td style="text-align:center">aux loss</td><td style="text-align:center">2024.4</td></tr><tr><td>Qwen2-57B-A14B</td><td style="text-align:center">57B</td><td style="text-align:center">14B</td><td style="text-align:center">64</td><td style="text-align:center">8</td><td style="text-align:center">0</td><td style="text-align:center">aux loss</td><td style="text-align:center">2024.6</td></tr><tr><td>DeepSeek-V2</td><td style="text-align:center">236B</td><td style="text-align:center">21B</td><td style="text-align:center">160</td><td style="text-align:center">6</td><td style="text-align:center">2</td><td style="text-align:center">aux loss + device-level</td><td style="text-align:center">2024.5</td></tr><tr><td><strong>DeepSeek-V3</strong></td><td style="text-align:center"><strong>671B</strong></td><td style="text-align:center"><strong>37B</strong></td><td style="text-align:center"><strong>256</strong></td><td style="text-align:center"><strong>8</strong></td><td style="text-align:center"><strong>1</strong></td><td style="text-align:center"><strong>Aux-loss-free + sequence-aux</strong></td><td style="text-align:center">2024.12</td></tr><tr><td>Llama 4 Scout</td><td style="text-align:center">109B</td><td style="text-align:center">17B</td><td style="text-align:center">16</td><td style="text-align:center">1</td><td style="text-align:center">1</td><td style="text-align:center">undisclosed</td><td style="text-align:center">2025.4</td></tr><tr><td>Llama 4 Maverick</td><td style="text-align:center">400B</td><td style="text-align:center">17B</td><td style="text-align:center">128</td><td style="text-align:center">1</td><td style="text-align:center">1</td><td style="text-align:center">undisclosed</td><td style="text-align:center">2025.4</td></tr><tr><td>Qwen3-235B-A22B</td><td style="text-align:center">235B</td><td style="text-align:center">22B</td><td style="text-align:center">128</td><td style="text-align:center">8</td><td style="text-align:center">0</td><td style="text-align:center">(loss-free 变体)</td><td style="text-align:center">2025.5</td></tr></tbody></table>
|
||
<div class="callout callout-info"><div class="callout-title">读这张表的姿势</div><p>注意 "总参 / 激活" 比例(Mixtral $\approx 4\times$,V3 $\approx 18\times$,Maverick $\approx 24\times$)。这个比例越高,"用稀疏换容量"的杠杆越大,但也越依赖 routing 质量。V3 把这个比值推到极致并 still work,靠的就是 fine-grained + shared + loss-free。</p></div>
|
||
<h2 id="6-deepseek-v3-全景必背重点">§6 DeepSeek-V3 全景(必背重点)</h2>
|
||
<p>DeepSeek-V3(DeepSeek-AI, arXiv 2412.19437, 2024.12)是 2026 面试季最高频的 MoE 系统。把它的设计点拆开:</p>
|
||
<h3 id="61-架构层面">6.1 架构层面</h3>
|
||
<pre class="diagram"><code> DeepSeek-V3 MoE Layer
|
||
────────────────────────
|
||
x [B, L, D=7168]
|
||
│
|
||
├──────► Shared Expert (1 个, d_ff ≈ 2048) → shared_out
|
||
│ (永远激活, 不进 router)
|
||
│
|
||
└──────► Router (D → 256)
|
||
│
|
||
├ score s_i(x) + b_i (bias 仅用于 top-k 选择)
|
||
│
|
||
↓
|
||
Top-8 (256 选 8)
|
||
│
|
||
│ 实际 gating weight: sigmoid(s_i) / Σ sigmoid(s_j)
|
||
↓
|
||
┌────────┬────────┬────────┬────────┐
|
||
↓ ↓ ↓ ↓ ↓
|
||
E_a E_b E_c ... E_h (8 个 routed expert)
|
||
│ │ │ │ │
|
||
└─ × g ─┴─ × g ─┴─ × g ─┴─ × g ─┘
|
||
│
|
||
↓
|
||
routed_out + shared_out → y</code></pre>
|
||
<p>关键数字:</p>
|
||
<ul><li><strong>Total</strong> 671B parameters</li><li><strong>Active per token</strong> 37B parameters</li><li><strong>MoE layer</strong>:256 routed experts + 1 shared,每 token 选 <strong>9 个 expert</strong>(8 routed + 1 shared)</li><li><strong>Attention</strong> 用 <strong>MLA</strong>(Multi-head Latent Attention),把 KV 压缩到低秩 latent → KV cache 降 ~93%</li><li><strong>MTP</strong>(Multi-Token Prediction)作为辅助 objective,inference 时可做 speculative decode</li></ul>
|
||
<h3 id="62-auxiliary-loss-free-balance详见-24">6.2 Auxiliary-Loss-Free Balance(详见 §2.4)</h3>
|
||
<p>V3 论文里写了两件事的组合:</p>
|
||
<ol><li><strong>Per-expert bias</strong> $b_i$(核心)—— §2.4 描述</li><li><strong>Sequence-wise auxiliary loss</strong>(兜底)—— 极小权重的辅助 loss,用于防止单条序列内部极端不均(不是跨 batch 的传统 aux loss)</li></ol>
|
||
<p>第二点经常被忽略:V3 不是"完全无 aux loss",而是<strong>主要靠 bias 做平衡,留一个 sequence-level 的极小 aux 兜底</strong>。面试时如果说"V3 完全没有 aux loss"是不准确的。</p>
|
||
<h3 id="63-node-limited-routing">6.3 Node-Limited Routing</h3>
|
||
<p>V3 训练时跑 64-way EP 跨 8 个 node。Naïve top-8 routing 可能让一个 token 的 8 个 expert 散布到所有 8 个 node → 严重 all-to-all 通信。V3 加了硬约束:<strong>每个 token 最多路由到 4 个 node</strong>,且每 node 最多选 3 个 expert。这是 algorithm × system 联合优化。</p>
|
||
<h3 id="64-systemdualpipe--deepep">6.4 System:DualPipe + DeepEP</h3>
|
||
<ul><li><strong>DualPipe</strong>(github: deepseek-ai/DualPipe):双向 pipeline parallelism,把 forward 和 backward 的 compute / comm 重叠到几乎 0 bubble。</li><li><strong>DeepEP</strong>(github: deepseek-ai/DeepEP):专门为 MoE all-to-all 优化的通信库,支持 FP8 dispatch + asymmetric inter/intra-node bandwidth。</li></ul>
|
||
<p>这两个开源库是 V3 在 2048 张 H800 上把 MoE 训练 cost 压到 $5.6M USD 的关键工程基础。</p>
|
||
<h2 id="7-复杂度显存推理算账">§7 复杂度、显存、推理算账</h2>
|
||
<h3 id="71-训练时-flops--参数对比">7.1 训练时 FLOPs / 参数对比</h3>
|
||
<p>设 dense baseline 用 $D$ hidden, $d_\text{ff} = 4D$, 层数 $L$, token 数 $T$。FFN 部分 FLOPs(dense):</p>
|
||
<p>$$\text{FLOPs}_\text{FFN}^\text{dense} \approx 2 \cdot T \cdot L \cdot D \cdot d_\text{ff} \cdot 2 = 16 T L D^2$$</p>
|
||
<p>MoE:把 FFN 换成 $N$ expert, 每 expert $d_\text{ff}$, 每 token 走 $k$。<strong>计算量只算被激活的 expert</strong>:</p>
|
||
<p>$$\text{FLOPs}_\text{FFN}^\text{MoE} \approx 16 T L D^2 \cdot \frac{k}{N} \cdot \frac{N \cdot d_\text{ff}^\text{expert}}{4D}$$</p>
|
||
<p>如果 $d_\text{ff}^\text{expert} = 4D$("每个 expert 等于一个完整 FFN",Mixtral 风格),$\text{FLOPs} \propto k$,<strong>与 $N$ 无关</strong>(典型 Mixtral 8x7B $k=2$ → 计算 $\approx$ 2 个 FFN)。</p>
|
||
<p>参数量则与 $N$ 线性增长:</p>
|
||
<p>$$\text{Params}_\text{FFN}^\text{MoE} = N \cdot 8D^2 + D \cdot N \;(\text{router}) \approx 8 N D^2$$</p>
|
||
<p><strong>结论</strong>:MoE 的"参数容量 $N$ 倍, 计算量 $k$ 倍"——这正是为什么 Mixtral 8x7B 总参 47B / active 13B 比同 active 13B 的 dense 表现强。</p>
|
||
<h3 id="72-推理显存必考">7.2 推理显存(必考!)</h3>
|
||
<p><strong>面试常见陷阱问题:MoE 推理时显存是按"active 参数"还是"总参数"算?</strong></p>
|
||
<p>答案:<strong>几乎按总参数</strong>——所有 expert 必须<strong>常驻 GPU</strong>,因为下一个 token 可能路由到任何 expert。不能"按需 load 一个 expert",因为 PCIe / NVLink 加载延迟远高于 expert 计算延迟。</p>
|
||
<p>具体地,单 GPU 推理 671B model(FP8 / FP16):</p>
|
||
<table><thead><tr><th>模型</th><th style="text-align:center">存储 (FP16)</th><th style="text-align:center">存储 (FP8)</th><th style="text-align:center">单卡能塞下吗</th></tr></thead><tbody><tr><td>LLaMA-2 70B (dense)</td><td style="text-align:center">140 GB</td><td style="text-align:center">70 GB</td><td style="text-align:center">H100 80G 单卡 FP8 可</td></tr><tr><td>Mixtral 8x22B (141B)</td><td style="text-align:center">282 GB</td><td style="text-align:center">141 GB</td><td style="text-align:center">单卡不行,2× H100 / 8×A100</td></tr><tr><td>DeepSeek-V3 (671B)</td><td style="text-align:center">1342 GB</td><td style="text-align:center">671 GB</td><td style="text-align:center"><strong>8× H100 80G = 640 GB 还差一点</strong>;实际部署需 <strong>2 节点 16× H100 80G</strong> 或 <strong>8× H200 141G</strong>(≈1128 GB)才能塞下 FP8 权重 + KV cache</td></tr></tbody></table>
|
||
<p><strong>带宽的好处</strong>:每 token 只取 <code>active_param / total_param</code> 比例的权重做 matmul → <strong>memory bandwidth bottleneck 缓解</strong>(推理多数是 memory-bound)。671B / 37B → 每 token 只读 ~5% 权重——这是 V3 在 H800 上 inference throughput 与 dense 30B 同台的根源。</p>
|
||
<h3 id="73-kv-cache">7.3 KV Cache</h3>
|
||
<p>MoE 不直接影响 KV cache 大小——KV 与 attention 相关,与 FFN sparsity 无关。但 V2/V3 同时引入 <strong>MLA</strong> 把 KV 压缩到低秩 latent,所以 V3 的 KV cache 是 LLaMA-3 70B 的 ~5%。<strong>面试要区分"MoE 减的是 FFN 显存(FP8 OK),MLA 减的是 KV 显存"</strong>——是两条互相独立的优化线。</p>
|
||
<h2 id="8-ep--tp--pp--dpmoe-并行的-4-维交织">§8 EP / TP / PP / DP:MoE 并行的 4 维交织</h2>
|
||
<p>Dense LLM 训练常用 DP + TP + PP(数据 / 张量 / 流水)三维并行。MoE 必须加第 4 维:<strong>Expert Parallelism (EP)</strong>。</p>
|
||
<h3 id="81-expert-parallelism">8.1 Expert Parallelism</h3>
|
||
<p>把 $N$ 个 expert 切到不同 GPU 上(如 64 EP, 每 GPU 4 个 expert)。Forward 流程:</p>
|
||
<pre><code>
|
||
Step 1. Token x [local batch] -> Router -> top-k expert IDs
|
||
Step 2. ★ all-to-all dispatch:
|
||
按 expert ID 把 token 发到对应 GPU
|
||
(每 GPU 收到的 token 数 ≤ capacity)
|
||
Step 3. 本地 expert forward
|
||
Step 4. ★ all-to-all combine:
|
||
把 expert 输出按原始 token ID 发回起点 GPU
|
||
Step 5. Gate 加权求和 -> 下一层</code></pre>
|
||
<p>两次 <strong>all-to-all</strong> 是 MoE 的灵魂也是痛点:通信量 $\propto T \cdot k \cdot D$,可以轻易吃掉一半时间。</p>
|
||
<h3 id="82-ep--dp--tp--pp">8.2 EP × DP × TP × PP</h3>
|
||
<table><thead><tr><th>维度</th><th>拆什么</th><th>通信</th></tr></thead><tbody><tr><td><strong>DP</strong></td><td>Batch</td><td>all-reduce(gradient)</td></tr><tr><td><strong>TP</strong></td><td>Hidden / heads(每层内部)</td><td>all-reduce(in-layer)</td></tr><tr><td><strong>PP</strong></td><td>层(不同 stage)</td><td>point-to-point(cross-stage)</td></tr><tr><td><strong>EP</strong></td><td>Expert</td><td>all-to-all(每 MoE layer 2 次)</td></tr></tbody></table>
|
||
<p>实践组合(DeepSeek-V3 训练):</p>
|
||
<ul><li>16-way PP × 64-way EP × ZeRO-1 DP</li><li>单 H800 cluster: 8 GPU per node × 256 nodes = 2048 GPU</li><li>DualPipe 让 PP bubble 接近 0;DeepEP 把 EP all-to-all 与 expert compute overlap</li></ul>
|
||
<h3 id="83-ep-通信量算账">8.3 EP 通信量算账</h3>
|
||
<p>设每 token 平均 $k$ expert, $D$ hidden, $G$ EP group size, 每 step token 数 $T$:</p>
|
||
<p>$$\text{all-to-all volume per layer} \approx 2 \cdot T \cdot k \cdot D \cdot \frac{(G-1)}{G}$$</p>
|
||
<p>($\times 2$ 是 dispatch + combine 各一次。$(G-1)/G$ 是因为 1/G 的 token 本地命中无需通信。)</p>
|
||
<p>对 V3:$T \sim$ few-M tokens/step, $k=8$, $D=7168$, $G=64$ → 单 layer 通信量 ~ TB 级。这就是为什么 DeepEP / NVLink-aware kernel 这么关键。</p>
|
||
<h2 id="9-与相关方法对比">§9 与相关方法对比</h2>
|
||
<h3 id="91-moe-vs-dense同-flops--同参数">9.1 MoE vs Dense(同 FLOPs / 同参数)</h3>
|
||
<table><thead><tr><th>角度</th><th>Dense</th><th>MoE</th></tr></thead><tbody><tr><td>同 active 参数</td><td>表现更稳</td><td>容量上限低</td></tr><tr><td>同 total 参数</td><td>计算成本高</td><td><strong>MoE 算力高效,容量大</strong></td></tr><tr><td>训练稳定性</td><td>高</td><td>中(routing collapse / EP comm 不稳)</td></tr><tr><td>推理显存</td><td>按 total ≈ 按 active</td><td><strong>按 total(必须全 expert 常驻)</strong></td></tr><tr><td>推理 latency</td><td>memory-bound</td><td><strong>memory bandwidth 优势</strong>(active 部分小)</td></tr><tr><td>部署难度</td><td>低</td><td>高(需 EP / 多卡)</td></tr><tr><td>微调</td><td>简单</td><td><strong>复杂</strong>(见 §9.3 ESFT)</td></tr></tbody></table>
|
||
<h3 id="92-moe-vs-mixture-of-depths-mod">9.2 MoE vs Mixture-of-Depths (MoD)</h3>
|
||
<p>MoD(Raposo et al. 2024)思路不同:<strong>每层选 top-k 个 token 走完整层,其他 token skip 整层</strong>(沿 depth 方向稀疏化)。对比 MoE 沿 width 方向稀疏化(每个 token 选部分 expert)。</p>
|
||
<table><thead><tr><th>维度</th><th>MoE</th><th>MoD</th></tr></thead><tbody><tr><td>稀疏方向</td><td>width (FFN expert)</td><td>depth (whole layer)</td></tr><tr><td>每 token 计算</td><td>固定(top-k expert)</td><td>动态(每层是否走)</td></tr><tr><td>Router 决策</td><td>per-layer per-token</td><td>per-layer 选 top-k token</td></tr><tr><td>训练稳定性</td><td>中</td><td>较新,工程化弱</td></tr></tbody></table>
|
||
<p>不互斥——理论上可以同时用,2025 后的几个工作(如 Llama 4 的细节、Qwen3 的某些实验)开始混用。</p>
|
||
<h3 id="93-moe-微调esft-和它的同类">9.3 MoE 微调:ESFT 和它的同类</h3>
|
||
<p>标准 LoRA 在 MoE 上有几个坑:</p>
|
||
<ul><li>LoRA 加到 $W_q/W_k/W_v$ 上是 attention 层级,<strong>不动 expert</strong></li><li>加到每个 expert 上 → $N$ 倍 LoRA 参数,部分 expert 训不到(因为不被路由)</li></ul>
|
||
<p><strong>ESFT</strong>(Expert-Specialized Fine-Tuning, Wang et al. arXiv 2407.01906):</p>
|
||
<ul><li>先用任务数据做 forward,统计 router score</li><li>找出<strong>任务最相关的 top-k expert</strong>(per-layer),其余冻结</li><li>只训这些"任务专家",<strong>显存 ↓ 90%、时间 ↓ 30%、性能 ≈ 全参 fine-tune</strong></li></ul>
|
||
<div class="callout callout-info"><div class="callout-title">面试加分</div><p>比 LoRA 更适合 MoE 的本质:MoE 已经 specialize 了,微调只该 specialize 进一步,不该把通用 expert 也搅动。这是"sparse pretrain → sparse fine-tune"的自然延伸。</p></div>
|
||
<h3 id="94-moe-vs-mqagqa">9.4 MoE vs MQA/GQA</h3>
|
||
<p>完全正交:</p>
|
||
<ul><li><strong>MQA/GQA</strong> 减 KV cache(attention 端)</li><li><strong>MoE</strong> 减 FFN 算力(FFN 端)</li></ul>
|
||
<p>可以同时用(V2/V3 = MLA + MoE;LLaMA-3 = GQA + dense;理论上 GQA + MoE 也合法)。</p>
|
||
<h2 id="10-25-高频面试题">§10 25 高频面试题</h2>
|
||
<p>按难度分 L1(10 必会)/ L2(10 进阶)/ L3(5 顶级 lab)。每题点开看答案要点 + 易踩坑。</p>
|
||
<h3 id="l1必会题任何-ml-工程岗都会问">L1必会题(任何 ML 工程岗都会问)</h3>
|
||
<details>
|
||
|
||
<summary>Q1.MoE 在做什么?为什么用 sparse activation?</summary>
|
||
<ul><li>把 dense FFN 换成 $N$ 个独立 expert + router,每 token 只走 $k \ll N$ 个</li><li><strong>总参数 ↑(容量)但激活参数不变(FLOPs)</strong>——用参数换计算效率</li><li>训练存得下,推理算力可控</li><li>关键:MoE 减少 FLOPs,但<strong>不减少推理显存</strong>(all experts 必须常驻)</li></ul>
|
||
<p>把 MoE 想成 ensemble。MoE 是<strong>单一前向通路上选 expert</strong>,与"训多个模型 vote"完全不同。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q2.Top-k token-choice MoE 的 routing 公式是什么?</summary>
|
||
<ul><li>Router: $s(x) = W_g x \in \mathbb{R}^N$,$g(x) = \text{softmax}(s(x))$</li><li>选 $\mathcal{T}_k(x) = \text{TopK}_i\, g_i$,输出 $y = \sum_{i \in \mathcal{T}_k} \tilde{g}_i E_i(x)$</li><li>Mixtral/DeepSeek:top-k 上 <strong>renormalize</strong>($\tilde{g}_i = g_i / \sum_{j \in \mathcal{T}_k} g_j$)让权重和 = 1</li><li>Router 没 bias(标准做法)</li></ul>
|
||
<p>只说"选 top 几个 expert"不写公式;忘了 renormalize;说 Q/K/V 那套(attention 公式,搞混了)。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q3.Switch Transformer 的 aux load-balance loss 是什么?</summary>
|
||
<ul><li>$\mathcal{L}_\text{aux} = \alpha \cdot N \sum_i f_i P_i$</li><li>$f_i$ = expert $i$ 接到的 token 比例(不可微,但有数值)</li><li>$P_i$ = expert $i$ 的平均 gate 概率(可微)</li><li>乘积越小说明分布越均匀(均匀时 $\sum_i f_i P_i = 1/N$)</li></ul>
|
||
<p>只说"鼓励均匀"但写不出公式;只写 $\sum P_i^2$(这是 entropy regularizer,不是 Switch 公式)。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q4.Capacity factor 是什么?为什么需要?</summary>
|
||
<ul><li>$C = \lceil \alpha \cdot Tk/N \rceil$,每个 expert 的容量上限</li><li>$\alpha = 1.25$ 是 Switch / GShard 默认(留 25% 缓冲)</li><li>超 capacity 的 token → <strong>residual bypass</strong>(expert 输出 0,残差通过)</li><li>没 capacity 限制无法静态 buffer,EP 通信无法 schedule</li></ul>
|
||
<p>只答"防止 OOM";不知道 residual bypass,以为 drop 就是直接归零。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q5.MoE 推理时显存按什么算?</summary>
|
||
<ul><li><strong>按总参数算,不是激活参数</strong>——所有 expert 必须常驻 GPU</li><li>因为下一个 token 可能路由到任意 expert,按需 load 延迟无法接受</li><li>671B MoE FP8 ≈ 671 GB,<strong>8× H100 80G = 640 GB 还差一点</strong>;实际部署常用 16× H100 80G(2 节点)或 8× H200 141G</li><li>真正节省的是 memory bandwidth(每 token 只读 active 部分权重)</li></ul>
|
||
<p>以为 MoE 显存按 active 算,所以"Mixtral 13B 单卡能跑"——错,Mixtral 47B 总参,单 24G 卡跑不下。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q6.DeepSeek-V3 总参数 / 激活参数 / expert 数?</summary>
|
||
<ul><li><strong>总参数 671B,激活 37B / token</strong></li><li><strong>256 routed experts + 1 shared expert</strong></li><li>Top-8 routed + 1 shared = 9 个 expert per token</li><li>Attention 用 <strong>MLA</strong>,FFN 用 DeepSeekMoE</li><li>arXiv: 2412.19437, 2024.12</li></ul>
|
||
<p>把 V3 跟 V2 (236B/21B) 数字搞混;说 V3 有"多少 expert"但记错 256。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q7.Mixtral 8x7B 真的有 7B × 8 = 56B 参数吗?</summary>
|
||
<ul><li><strong>不是</strong>。8x7B 的命名只表示"8 expert, 每 expert 7B 量级"</li><li><strong>实际总参 46.7B</strong>——因为 attention / norm / embedding 在所有 expert 间共享,不是每个 expert 复制一份</li><li>激活参数 12.9B(不是 14B,因为 router gate 是 sparse 加权)</li></ul>
|
||
<p>被名字误导,直接 $8 \times 7 = 56$。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q8.MoE 训练为什么常 routing collapse?怎么治?</summary>
|
||
<ul><li>没 balance 机制时,强者愈强:被多选 → 训得多 → 更可能被选</li><li>治疗:<strong>aux loss (Switch)</strong> / Expert Choice / Aux-loss-free bias (V3) / Z-loss / expert dropout / 适当增大 capacity factor</li><li>监控:每 expert 的 load + aux loss 数值 + validation loss</li></ul>
|
||
<p>只说"加 aux loss"但不给具体公式;不知道还有 expert-choice 这类硬约束方法。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q9.MoE 训练需要哪些并行?</summary>
|
||
<ul><li><strong>DP(数据)+ TP(张量)+ PP(流水)+ EP(expert)</strong></li><li>EP 是新增维度:把 $N$ 个 expert 分到不同 GPU</li><li>每个 MoE layer 需要 <strong>2 次 all-to-all</strong>(dispatch + combine)</li><li>DeepSeek-V3:16-way PP × 64-way EP × ZeRO-1 DP,跨 2048 卡 H800</li></ul>
|
||
<p>忘了 EP;以为 dense 的 DP+TP+PP 就够用。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q10.MoE 在 inference 端的好处是什么?</summary>
|
||
<ul><li>同 active 参数下,<strong>memory bandwidth 优势</strong>:每 token 只读 ~active/total 比例权重</li><li>推理多数 token-by-token 是 memory-bound,bandwidth 减小 → throughput ↑</li><li>671B / 37B → 每 token 读 ~5% 权重 → 与 ~30B dense 同 latency</li></ul>
|
||
<p>只说"算力少"——但显存上不去(全 expert 加载),所以单卡 deployment 还是难。</p>
|
||
</details>
|
||
<h3 id="l2进阶题research-oriented-岗位">L2进阶题(research-oriented 岗位)</h3>
|
||
<details>
|
||
|
||
<summary>Q11.Expert Choice routing 是什么?为什么 autoregressive decoder 不能用?</summary>
|
||
<ul><li>反向:每个 expert 选 top-$M$ 个 token($M = Tk/N$)</li><li><strong>天然 balance</strong>:每 expert 严格选 $M$ 个 token,不需 aux loss</li><li>不 drop token(capacity 是 hard 给定)</li><li><strong>不能 autoregressive</strong>:第 $t$ 个 token 的路由依赖整个 batch(含未来 token)的 score → 不能 token-by-token 生成</li><li>用在 encoder / vision / BERT-style;decoder 用 token-choice</li><li>Zhou et al. 2022 NeurIPS, arXiv 2202.09368</li></ul>
|
||
<p>以为它能直接替代 Mixtral / DeepSeek 的 token-choice;忘了 causal 这一限制。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q12.Top-k 的离散操作怎么反传梯度?</summary>
|
||
<ul><li>Top-k 本身<strong>不可微,不参与梯度</strong></li><li>但被选中的 $k$ 个 expert 的 gate 权重 $g_i$(softmax 后)<strong>进入 output 加权求和</strong>,对 $g_i$ 可微</li><li>未被选中的 expert 的 router weight 这次 step 拿不到梯度(chicken-and-egg → 需 aux loss / bias 打破)</li><li>类似 hard attention,但因为加权求和,梯度信号还是能到 router</li></ul>
|
||
<p>以为"top-k 必须用 Gumbel-softmax 才能反传"——其实标准做法直接用 softmax + top-k 选择,gate weight 就是梯度通路。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q13.DeepSeekMoE 的 fine-grained expert 是什么意思?</summary>
|
||
<ul><li>把 $N$ 个 baseline expert 拆成 $mN$ 个更小的 expert(每 expert $d_\text{ff}$ 缩到 $d_\text{ff}/m$)</li><li>路由数从 $K$ 提到 $mK$</li><li><strong>总计算 / 总参数不变</strong>,但组合数 $\binom{mN}{mK} \gg \binom{N}{K}$</li><li>每 token 的"专家组合身份"指数级丰富 → 专精度提升</li><li>Dai et al. 2024, arXiv 2401.06066</li></ul>
|
||
<p>以为 fine-grained = 增加 expert 数量(部分对)但漏掉"每个 expert 缩小、路由数同比例放大"这个保持算力的关键。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q14.Shared expert 是什么?为什么需要?</summary>
|
||
<ul><li>一种<strong>永远激活、不经 router</strong>的 expert(每 token 都走它)</li><li>吸收"通用知识"(语言 / 常识),让 routed expert 专心做 specialization</li><li>DeepSeekMoE / Llama 4 都有;Mixtral / Switch 没有</li><li>DeepSeek-V3: 1 shared expert + 256 routed (8 selected)</li></ul>
|
||
<p>误以为 shared expert 是 ensemble;或不知道它不通过 router(router 不为 shared expert 投票)。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q15.DeepSeek-V3 的 aux-loss-free balance 怎么做的?</summary>
|
||
<ul><li>每 expert 一个偏置 $b_i$,top-k 选择用 <strong>biased score</strong> $s_i + b_i$</li><li>但 <strong>gating weight 用原始 $s_i$</strong>(保持主梯度路径干净)</li><li>每 step 按 sign 更新:$b_i \leftarrow b_i - u \cdot \text{sign}(c_i - \bar{c}_i)$</li><li>$b_i$ 是 buffer 不进梯度图,不被 optimizer 更新</li><li>兜底还有极小 sequence-level aux loss(防单序列内部极端不均)</li><li>Wang et al. arXiv 2408.15664;V3 在 2412.19437 中应用</li></ul>
|
||
<p>说"V3 完全没有 aux loss"——不准确(还有 sequence-wise 兜底);或把 biased score 用到 gating weight 上(会污染主梯度,违背设计意图)。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q16.MoE 训练的 all-to-all 是什么?通信量怎么算?</summary>
|
||
<ul><li>每 MoE layer 做 2 次 all-to-all:dispatch(按 expert 发 token)+ combine(按 token 收回)</li><li>通信量 per layer ≈ $2 T k D (G-1)/G$($G$ 是 EP group size)</li><li>通常占训练总时间 30-50%,DeepEP / DualPipe 是用来 overlap 通信与计算的工程武器</li><li>$G$ 大 → 更稀疏 → 通信比例反而 ↑</li></ul>
|
||
<p>只答"用 NCCL 通信";不清楚通信量随 $T \cdot k \cdot D$ 线性增长;不知 DualPipe / DeepEP。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q17.MoE 上做 LoRA 微调有什么问题?ESFT 怎么解?</summary>
|
||
<ul><li>LoRA 加到 attention 层 → 不动 expert;加到所有 expert → $N$ 倍 LoRA 参数,且部分 expert 训不到</li><li><strong>ESFT</strong> (arXiv 2407.01906):先 forward 统计 router score → 选任务最相关的 top-$k$ expert → 只训这些</li><li>性能 ≈ 全参 fine-tune,显存 ↓ 90%、时间 ↓ 30%</li></ul>
|
||
<p>不知道 ESFT;以为 "MoE = 大模型,LoRA 一招通吃"。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q18.MoE 推理时显存全 load,那 sparse activation 的好处去哪了?</summary>
|
||
<ul><li>好处转移到 <strong>memory bandwidth</strong>——每 token 只读 active 比例权重</li><li>LLM decode 是 memory-bound(不是 compute-bound),所以 bandwidth 减小直接转化为 throughput</li><li>671B/37B 模型:每 token 读 ~5% 权重 → throughput ≈ 30B dense</li><li>但显存仍按总参数预算:单 H100 80G <strong>跑不动 V3</strong>,需 8 卡 minimum</li></ul>
|
||
<p>以为 sparse 推理可以"按需 load 1 个 expert"——硬件延迟禁止;或以为 throughput 收益来自 FLOPs 节省(实际更多来自 bandwidth)。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q19.MoE 和 MoD (Mixture-of-Depths) 区别?</summary>
|
||
<ul><li>MoE 沿 <strong>width</strong> 稀疏:每 token 选部分 expert</li><li>MoD 沿 <strong>depth</strong> 稀疏:每层选 top-$k$ 个 token 走整层,其他 token skip</li><li>每 token 计算量:MoE 固定(top-k expert),MoD 动态(取决于多少层接受它)</li><li>不互斥,可以叠加</li></ul>
|
||
<p>以为 MoD = MoE 的别名;或不知道沿 depth 也能稀疏化。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q20.Mixtral 8x7B 实际总参数为什么不是 56B 而是 46.7B?</summary>
|
||
<ul><li>8 个 expert 只在 <strong>FFN 层</strong> —— attention / norm / embedding / unembedding <strong>全部共享,只算一份</strong></li><li>设 Mistral-7B 的 dense 总参 $\approx 7.24\text{B}$(FFN 约 $4.8\text{B} \approx 2/3$,shared = attention+embed+norm $\approx 2.4\text{B} \approx 1/3$)</li><li>Mixtral 8x7B 总参 = <strong>共享部分 + 8 × FFN</strong> = $2.4 + 8 \times 4.8 \approx 2.4 + 38.4 \approx 40.8\text{B}$;再加上 Mistral-7B 比 LLaMA-2-7B 略大、Mixtral 还增加了 router weight,官方 <strong>46.7B</strong></li><li>激活参数(per token,top-2)= <strong>共享部分 + 2 × FFN</strong> = $2.4 + 2 \times 4.8 \approx 12\text{B}$(论文给出 12.9B / 13B active)</li></ul>
|
||
<p>直接 $8 \times 7 = 56$ 当总参(把 attention/embed 也乘 8);或激活算成 $2 \times 7 = 14$ 忘掉 shared 已经只算一份。</p>
|
||
</details>
|
||
<h3 id="l3顶级-lab--research-方向">L3顶级 lab / Research 方向</h3>
|
||
<details>
|
||
|
||
<summary>Q21.DeepSeek-V3 aux-loss-free 为何不破坏 sparse routing semantics?</summary>
|
||
<ul><li><strong>关键设计</strong>:bias $b_i$ <strong>只用于 top-k 选择</strong>,不进入 gating weight,更不进入梯度图</li><li>这意味着:router 的梯度信号<strong>只来自语言建模 loss</strong>,与传统 aux loss "把平衡目标作为额外梯度" 完全不同</li><li>类比控制系统:bias 是 outer-loop controller(按 load 反馈调节),主梯度是 inner-loop optimizer(按 task loss 优化表达力)——两个 loop <strong>解耦</strong></li><li>对比 aux loss:aux loss 的梯度会拉 router 权重往"均匀分布"方向,可能与"任务最优 routing"方向冲突</li><li>Loss-free 让 router <strong>在主任务下仍然 sparse + specialize</strong>,bias 只是后处理纠偏</li><li>一个细节:bias <strong>不进 gating weight</strong> 这一点至关重要——否则相当于通过反向通路偷偷影响梯度,loss-free 名义就名不副实</li></ul>
|
||
<p>把 bias 当成 learnable parameter 进 optimizer;以为 loss-free 就是"啥都不加"(实际有 sign 更新和 sequence-aux 兜底)。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q22.Fine-grained + shared 比同总参 dense 优势在哪?理论 / 实证?</summary>
|
||
<ul><li><strong>理论容量论</strong>:$mN$ 个小 expert 的 routed combination 数 $\binom{mN}{mK}$ 远超 $\binom{N}{K}$,每 token 可表达的"专家组合身份"指数级丰富,更接近"每 token 独立小子网"的极限</li><li><strong>专精论</strong>:shared expert 吸收通用知识,让 routed expert 摆脱"既要又要"的负担,更可能 specialize</li><li><strong>算力论</strong>:同 active FLOPs 下,dense 必须把容量塞进激活参数;MoE 把容量塞进 dormant expert,活时只取一小撮——可以在不增加 FLOPs 的前提下把总参数推到 10x+</li><li><strong>实证</strong>:DeepSeekMoE 16B vs LLaMA-2 7B:FLOPs 相近,benchmark 上接近或超过(论文 Table 3);DeepSeekMoE 145B vs DeepSeek 67B dense:性能持平,但 145B MoE 训练 FLOPs 只用 ~28%</li><li><strong>失败模式</strong>:若 routing 不够好(collapse),fine-grained 反而退化(少数小 expert 通吃,等效 dense 但效率更低)</li><li><strong>2025-2026 实证趋势</strong>:V3 把这条路线推到极致(256 routed),证明在 1T 级 token 训练下 fine-grained 优势显著</li></ul>
|
||
<p>只说"参数多就行"——但没拆开"组合容量 ≠ 单参数容量";忽略 routing 质量是这条路线 work 的前提。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q23.MoE inference latency 真的能与 dense active 同台吗?瓶颈在哪?</summary>
|
||
<ul><li><strong>理论</strong>:每 token 只读 active 比例权重,bandwidth-bound 下 throughput 应正比于 active 参数</li><li><p><strong>实际几个 caveat</strong>:</p>
|
||
<ol><li><strong>Routing overhead</strong>:router 计算 + top-k 选择 + scatter/gather 本身有 latency,长 context 下也分摊不少</li><li><strong>Expert load 不均</strong>:单 batch 内 routing 不均 → 部分 expert 排队,wave 浪费</li><li><strong>EP 通信</strong>(多卡推理):dispatch / combine 的 all-to-all 占很大比例</li><li><strong>Memory bandwidth ≠ memory size</strong>:每 token 5% 权重,但 5% 落到哪些 expert 是 token-dependent,cache 命中差 → 实际带宽利用率不如理论上限</li></ol></li><li><strong>Mixtral 8x7B 在单卡 H100 80G</strong>:bandwidth 利用率 ~70-80%(vs dense 70B 利用率类似),latency 与 13B dense 接近</li><li><strong>V3 671B</strong>:8 卡部署下 inference 延迟略高于 30B dense(多卡通信不可忽略)</li><li><strong>结论</strong>:理论可以,工程上还有 5-30% gap 取决于 batch size / 上下文长度 / 多卡拓扑</li></ul>
|
||
<p>只说"理论上一样",不知道实际有 routing / EP 通信 / cache 命中等几个隐藏 cost;或反过来说"MoE 推理一定慢",也不全对(small batch / single GPU 下 Mixtral 与 dense 13B 接近)。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q24.MoE 训练的 stability 问题有哪些?怎么 mitigate?</summary>
|
||
<ul><li><strong>Router logit 爆炸</strong>:训练初期 router 权重大幅波动,fp16 下 logit 可 overflow → <strong>Z-loss</strong> $\mathcal{L}_z = \beta \sum_t (\log \sum_i e^{s_i(x_t)})^2$ 惩罚 logit 量级(ST-MoE 2022 提出)</li><li><strong>Routing collapse</strong>:解 §4.3 提到的方案(aux loss / bias / capacity factor / expert dropout)</li><li><strong>Expert representation drift</strong>:训练中 expert 间表示渐变(被 router 协同 shape),可能让 fine-tune 时小数据 overfit 某些 expert</li><li><strong>Aux loss 干扰</strong>:$\alpha$ 大 → loss 拉 router 往均匀,损害性能;$\alpha$ 小 → balance 不够。<strong>这是 loss-free 的根本动机</strong></li><li><strong>bf16 vs fp16</strong>:bf16 动态范围与 fp32 接近,更适合 router;fp16 下 router logit 容易 overflow,必须 z-loss + softmax 稳定化</li><li><strong>Small batch 下 router 噪声大</strong>:每 step 的 $f_i$ 估计噪声大,aux loss 不稳。生产里通常用 micro-batch grad accumulation 增大 effective batch</li></ul>
|
||
<p>只答"加 aux loss"——但忽略 z-loss、router 数值稳定、bf16 重要性、small-batch 的统计估计问题。</p>
|
||
</details>
|
||
<details>
|
||
|
||
<summary>Q25.如果让你设计下一代 MoE,会改什么?</summary>
|
||
<p>这是开放题,没标准答案。给一些 2026 前沿 lab 关心的方向 + 你的判断角度:</p>
|
||
<ul><li><strong>更细的 expert</strong>:DeepSeek 把 expert 推到 256,进一步推到 1024 / 4096?瓶颈在 routing collapse + EP 通信,需要新的 balance 方法</li><li><strong>动态 top-k</strong>:每 token 选不同数量 expert(easy token 走 1,hard token 走 4)。和 MoD 思想结合,"既稀疏 width 又稀疏 depth"</li><li><strong>Differentiable routing</strong>:Sinkhorn / hash-based / learned permutation,让 top-k 部分可微,router 训练更快收敛</li><li><strong>Expert sharing across layers</strong>:跨层共享一部分 expert pool(类似 ALBERT 的 cross-layer sharing),进一步压总参数</li><li><strong>更好的 MoE post-training</strong>:ESFT 之后是什么?对 SFT/RLHF 阶段 router 不一定保持 pretrain 时的 specialization,需要专门的 alignment 方案</li><li><strong>MoE × long context</strong>:1M context 下每层 routing 决策乘以 1M,router 本身可能变成瓶颈 → routing reuse / hierarchical routing</li><li><strong>MoE 服务化</strong>:单卡跑不动 671B,怎么让中小公司也能部署?expert offload / streaming weights / disaggregated expert servers</li><li><strong>理论分析</strong>:fine-grained vs dense 容量的严格量化?routing 的 implicit regularization?aux-loss-free 的收敛保证?目前都还很少</li></ul>
|
||
<p>回答时<strong>先说一个具体方向</strong>,给清楚 motivation + technical sketch + 可能的 failure mode,比泛泛而谈"我会让 expert 更多"加分多。</p>
|
||
</details>
|
||
<h2 id="a-附录参考文献清单按时间">§A 附录:参考文献清单(按时间)</h2>
|
||
<p>按出现先后整理。注:<strong>所有 arXiv ID 已交叉验证</strong>。</p>
|
||
<ol><li><strong>Shazeer, N., Mirhoseini, A., Maziarz, K., Davis, A., Le, Q., Hinton, G., Dean, J.</strong> (2017). Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer. ICLR. arXiv:1701.06538.</li><li><strong>Lepikhin, D., Lee, H., Xu, Y., Chen, D., Firat, O., Huang, Y., Krikun, M., Shazeer, N., Chen, Z.</strong> (2020). GShard: Scaling Giant Models with Conditional Computation and Automatic Sharding. arXiv:2006.16668.</li><li><strong>Fedus, W., Zoph, B., Shazeer, N.</strong> (2021). Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity. JMLR. arXiv:2101.03961.</li><li><strong>Zhou, Y., Lei, T., Liu, H., Du, N., Huang, Y., Zhao, V., Dai, A., Chen, Z., Le, Q., Laudon, J.</strong> (2022). Mixture-of-Experts with Expert Choice Routing. NeurIPS. arXiv:2202.09368.</li><li><strong>Zoph, B., Bello, I., Kumar, S., Du, N., Huang, Y., Dean, J., Shazeer, N., Fedus, W.</strong> (2022). ST-MoE: Designing Stable and Transferable Sparse Expert Models. arXiv:2202.08906.(Z-loss 来源)</li><li><strong>Dai, D., Deng, C., Zhao, C., Xu, R., et al.</strong> (2024). DeepSeekMoE: Towards Ultimate Expert Specialization in Mixture-of-Experts Language Models. ACL. arXiv:2401.06066.</li><li><strong>Jiang, A. Q., Sablayrolles, A., et al.</strong> (2024). Mixtral of Experts. arXiv:2401.04088.</li><li><strong>DeepSeek-AI</strong> (2024). DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model. arXiv:2405.04434.</li><li><strong>Wang, Z., Chen, D., Dai, D., Xu, R., Li, Z., et al.</strong> (2024). Let the Expert Stick to His Last: Expert-Specialized Fine-Tuning (ESFT). arXiv:2407.01906.</li><li><strong>Wang, L., Gao, H., Zhao, C., Sun, X., Dai, D.</strong> (2024). Auxiliary-Loss-Free Load Balancing Strategy for Mixture-of-Experts. arXiv:2408.15664.</li><li><strong>DeepSeek-AI</strong> (2024). DeepSeek-V3 Technical Report. arXiv:2412.19437.</li><li><strong>Raposo, D., Ritter, S., Richards, B., Lillicrap, T., Humphreys, P., Santoro, A.</strong> (2024). Mixture-of-Depths: Dynamically Allocating Compute in Transformer-Based Language Models. arXiv:2404.02258.</li><li><strong>Meta AI</strong> (2025). Llama 4: Scout, Maverick, Behemoth (blog announcement, April 5, 2025).</li><li><strong>Qwen Team</strong> (2025). Qwen3 Technical Report. arXiv:2505.09388.</li><li><strong>DeepSeek-AI / DualPipe / DeepEP</strong> (2025). Open-source releases at github.com/deepseek-ai/{DualPipe,DeepEP}.</li></ol>
|
||
<div class="callout callout-info"><div class="callout-title">Tip</div><p><strong>2026 秋招高频提问 paper top-5</strong>(按面试出现频率):DeepSeek-V3 (2412.19437) > Mixtral (2401.04088) > Switch Transformer (2101.03961) > DeepSeekMoE (2401.06066) > Loss-Free Balance (2408.15664)。准备这 5 篇基本覆盖 95% MoE 问题。</p></div>
|
||
|
||
<footer class="aris-footer">
|
||
Generated by <a href="https://github.com/wanshuiyin/Auto-claude-code-research-in-sleep/blob/main/skills/render-html/SKILL.md">ARIS <code>/render-html</code></a> ·
|
||
source path <code>docs/tutorials/moe_tutorial.md</code> ·
|
||
SHA256 <code>e860589270ed</code> ·
|
||
generated at 2026-05-19 10:10 UTC.
|
||
This is a generated view — edit the source Markdown, then re-render.
|
||
</footer>
|
||
</main>
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|