在专家混合模型中,门控网络动态地将每个令牌路由到选定的专家。这种动态的、依赖数据的路由带来了工程上的挑战:虽然路由灵活,但GPU计算在操作具有固定、可预测形状的张量时效率最高。如果一个专家突然被分配了1,000个令牌而另一个只被分配了10个,我们不能简单地在单个批次内动态分配不同数量的内存和计算。为了解决此问题,MoE的实现会为每个专家预分配一个固定大小的缓冲区,或称“容量”。每个专家都被配置为在每个批次中处理特定最大数量的令牌。容量因子是控制此缓冲区大小的超参数。它直接决定了计算浪费和信息损失之间的权衡。定义专家容量每个专家的容量是相对于令牌的完全均匀分布计算的。如果你的批次中有 $N$ 个令牌,$E$ 个专家,一个完全平衡的系统会将 $N/E$ 个令牌发送给每个专家。容量因子 $C$ 是应用于这个理想平均值的乘数。专家的令牌容量公式为:$$ \text{专家容量} = \text{int}\left( \frac{\text{令牌数量}}{\text{专家数量}} \times C \right) $$容量因子 $C=1.0$ 意味着每个专家缓冲区可以恰好容纳平均数量的令牌。而 $C=1.25$ 的因子提供了25%的缓冲区,允许每个专家处理比批次平均多达25%的令牌。核心权衡:丢弃令牌与计算浪费容量因子的选择会造成直接且不可避免的权衡。因为路由是动态的,在给定批次中,一些专家不可避免地会比其他专家更受欢迎。这会导致两种对立的结果。低容量因子 (例如 $C=1.0$): 如果一个专家的缓冲区太小,当它接收到的令牌超出其处理能力时会溢出。缓冲区满后到达的令牌被视为“丢弃”的。这些丢弃的令牌不会被专家处理。相反,它们直接通过MoE层的残差连接。这节省了计算资源,但以模型性能为代价,因为模型失去了对这些令牌应用专业知识的机会。高容量因子 (例如 $C=2.0$): 大型缓冲区显著降低了丢弃令牌的风险。然而,它强制系统为很少使用的容量分配内存和计算资源。如果一个专家被分配了200个令牌的容量但只接收了50个,那么150个未使用的槽位的计算和内存就被浪费了。这种填充增加了训练成本并降低了执行速度。下图展示了此过程。输入令牌被路由到三个专家,每个都有固定容量。专家2溢出,导致一个令牌被丢弃。专家3未充分利用,导致容量浪费(填充)。digraph G { rankdir=TB; splines=ortho; node [shape=box, style="rounded,filled", fillcolor="#e9ecef", fontname="sans-serif"]; edge [fontname="sans-serif"]; subgraph cluster_input { label = "输入令牌"; style=invis; t1 [label="令牌 1"]; t2 [label="令牌 2"]; t3 [label="令牌 3"]; t4 [label="令牌 4"]; t5 [label="令牌 5"]; t6 [label="令牌 6"]; {rank=same; t1; t2; t3; t4; t5; t6;} } gate [label="门控网络", shape=oval, fillcolor="#bac8ff"]; subgraph cluster_experts { label="具有固定容量的专家(容量 = 2)"; bgcolor="#f8f9fa"; node [fillcolor="#ffffff", shape=record]; expert1 [label="<f0> 槽位 1 | <f1> 槽位 2", fillcolor="#d0bfff"]; expert2 [label="<f0> 槽位 1 | <f1> 槽位 2", fillcolor="#a5d8ff"]; expert3 [label="<f0> 槽位 1 | <f1> 槽位 2", fillcolor="#96f2d7"]; {rank=same; expert1; expert2; expert3;} } dropped [label="丢弃的令牌", shape=box, style="rounded,filled", fillcolor="#ffc9c9"]; residual [label="残差路径", shape=oval, style=dashed]; {t1, t2, t3, t4, t5, t6} -> gate [style=invis]; gate -> expert1:f0 [label="令牌 4"]; gate -> expert1:f1 [label="令牌 6"]; gate -> expert2:f0 [label="令牌 1"]; gate -> expert2:f1 [label="令牌 2"]; gate -> expert3:f0 [label="令牌 5"]; gate -> dropped [label="令牌 3 (溢出)", color="#f03e3e", fontcolor="#f03e3e"]; dropped -> residual [style=dashed]; p2 [label="浪费的槽位\n(填充)", shape=plaintext, fontcolor="#868e96"]; p2 -> expert3:f1 [style=invis]; }固定容量下令牌路由的图示。专家2接收三个令牌但只能处理两个,导致一个令牌被丢弃。专家3只接收一个令牌,留下一个槽位作为计算浪费。性能影响的可视化容量因子、丢弃令牌和计算浪费之间的关系在绘图时很清晰。随着容量因子的增加,丢弃令牌的百分比急剧下降,但浪费的计算量线性增加。{"layout": {"title": "容量因子权衡:效率与质量", "xaxis": {"title": "容量因子 (C)"}, "yaxis": {"title": "丢弃令牌 (%)", "titlefont": {"color": "#f03e3e"}, "tickfont": {"color": "#f03e3e"}, "range": [0, 16]}, "yaxis2": {"title": "浪费的计算 (%)", "titlefont": {"color": "#1c7ed6"}, "tickfont": {"color": "#1c7ed6"}, "overlaying": "y", "side": "right", "range": [0, 60]}, "legend": {"x": 0.5, "y": 1.15, "xanchor": "center", "orientation": "h"}, "font": {"family": "sans-serif"}}, "data": [{"x": [1.0, 1.1, 1.25, 1.5, 1.75, 2.0], "y": [14.8, 9.1, 4.2, 1.5, 0.4, 0.1], "name": "丢弃令牌", "type": "scatter", "mode": "lines+markers", "line": {"color": "#f03e3e", "width": 3}}, {"x": [1.0, 1.1, 1.25, 1.5, 1.75, 2.0], "y": [2, 11, 21, 35, 45, 55], "name": "浪费的计算", "type": "bar", "yaxis": "y2", "marker": {"color": "#a5d8ff"}}]}容量因子直接控制了模型质量(更少的丢弃令牌)与计算效率(更少的浪费)之间的平衡。实践指导与调整容量因子没有一个“最佳”值;它是一个重要的超参数,取决于你的具体模型、数据和训练目标。然而,这里有一些常见做法:从常见基线开始: 大多数研究和生产系统使用介于1.25和2.0之间的容量因子。对于许多应用,$C=1.25$ 是一个合理的起始点。监控丢弃的令牌: 在训练期间,记录每个批次中丢弃令牌的百分比。高百分比(例如,持续高于1%)表明你的模型学习受到影响。这表明应增加容量因子。分析计算浪费: 如果你的丢弃令牌率几乎为零但训练速度慢,你的容量因子可能不必要地高。分析工具可以帮助你衡量填充量,这代表着浪费的计算。降低容量因子可以提高吞吐量。与负载均衡损失的相互作用容量因子并非独立运行。它的效果与第1章中讨论的辅助负载均衡损失紧密关联。设计良好的负载均衡损失鼓励门控网络更均匀地在专家之间分配令牌。有效负载均衡: 当负载平衡时,单个专家的流量峰值不那么频繁且不那么严重。这允许你使用较低的容量因子而不会显著增加丢弃令牌,从而提高计算效率。无效负载均衡: 如果路由持续偏爱少数专家,你将被迫使用更高的容量因子来防止令牌丢弃,这反过来增加了所有未充分利用的专家的计算浪费。最终,管理容量因子是训练MoE模型的一项重要技能。它需要仔细调整和监控,以找到在最大化模型质量的同时尊重计算预算的正确平衡。