跳到正文
原文
Hugging Face:Blog(RSS)·· 2023-12-11精选AI 评分70

Hugging Face 图解 Mixture of Experts(MoE)原理、训练与推理权衡

Mixture of Experts Explained

AI 导读

Hugging Face 发布 MoE 科普长文,结合 Mixtral 8x7B 的热度讲解稀疏专家混合模型的构成与原理:用带门控路由网络的 MoE 层替代 Transformer 的 FFN 层,每个 token 只激活部分专家。

推荐理由

系统梳理 MoE 的结构、路由、负载均衡与微调难点,读者可据此判断稀疏模型与稠密模型的适用场景。

正文 · AI 翻译
这篇博客文章有第二个版本(2026年2月),在其中我们介绍了 transformers 库如何围绕 MoE 构建,使它们成为该库和 Hub 的“一等公民”。以下是文章链接:Transformers 中的混合专家模型(MoE)

随着 Mixtral 8x7B 的发布(公告、模型卡),一类 transformer 已成为开放 AI 社区中最热门的话题:混合专家模型,简称 MoE。在这篇博客文章中,我们将探讨 MoE 的构建模块、它们如何训练,以及在推理服务时需要考虑的权衡。

让我们开始吧!

目录

内容提要

MoE:

  • 与稠密模型相比,预训练速度快得多
  • 与参数量相同的模型相比,推理速度更快
  • 由于所有专家都加载在内存中,因此需要高显存
  • 面临许多微调方面的挑战,但近期工作表明MoE指令微调前景可期

让我们开始吧!

什么是混合专家模型(MoE)?

模型规模是提升模型质量最重要的维度之一。在固定的计算预算下,用更少的步数训练更大的模型,比用更多的步数训练更小的模型效果更好。

混合专家模型使模型能够在预训练时使用远少的计算量,这意味着你可以在与稠密模型相同的计算预算下,大幅扩展模型或数据集规模。特别是,MoE 模型在预训练期间应该能比其稠密对应模型更快地达到相同的质量。

那么,MoE 到底是什么?在 transformer 模型的语境下,MoE 由两个主要元素组成:

  • 稀疏 MoE 层用于替代稠密前馈网络(FFN)层。MoE 层拥有一定数量的“专家”(例如 8 个),每个专家都是一个神经网络。在实践中,专家是 FFN,但它们也可以是更复杂的网络,甚至本身就是一个 MoE,从而形成层级式 MoE!
  • 一个门控网络或路由器,用于决定哪些 token 被发送到哪个专家。例如,在下图中,token“More”被发送到第二个专家,而 token“Parameters”被发送到第一个网络。正如我们稍后将探讨的,我们可以将一个 token 发送到多个专家。如何将 token 路由到专家是使用 MoE 时的重大决策之一——路由器由可学习参数组成,并与网络的其余部分同时预训练。
Switch Layer
来自 [Switch Transformers 论文](https://arxiv.org/abs/2101.03961) 的 MoE 层

那么,总结一下,在 MoE 中,我们将 transformer 模型的每个 FFN 层替换为 MoE 层,该层由一个门网络和一定数量的专家组成。

尽管与稠密模型相比,MoE 提供了高效预训练和更快推理等优势,但它们也伴随着挑战:

  • 训练: MoE 能够实现显著更计算高效的预训练,但它们在微调过程中历来难以泛化,导致过拟合。
  • 推理: 尽管 MoE 可能有许多参数,但在推理过程中只使用其中一部分。与具有相同参数数量的稠密模型相比,这导致推理速度快得多。然而,所有参数都需要加载到 RAM 中,因此内存需求很高。例如,对于像 Mixtral 8x7B 这样的 MoE,我们需要足够的 VRAM 来容纳一个稠密的 47B 参数模型。为什么是 47B 参数而不是 8 x 7B = 56B?这是因为在 MoE 模型中,只有 FFN 层被视为独立的专家,而模型的其余参数是共享的。同时,假设每个 token 只使用两个专家,推理速度(FLOPs)就像使用一个 12B 模型(而不是 14B 模型),因为它计算 2x7B 矩阵乘法,但有一些层是共享的(稍后会详细说明)。

现在我们对 MoE 有了一个大致的了解,让我们来看看导致其发明的研究进展。

MoE 简史

MoE 的根源来自 1991 年的论文 Adaptive Mixture of Local Experts。这个想法类似于集成方法,是为一个由独立网络组成的系统提供监督过程,每个网络处理训练案例的不同子集。每个独立的网络或专家,专门处理输入空间的不同区域。如何选择专家?一个门网络决定每个专家的权重。在训练过程中,专家和门网络都会被训练。

在 2010-2015 年间,两个不同的研究领域为后来的 MoE 进步做出了贡献:

  • 专家作为组件:在传统的 MoE 设置中,整个系统包括一个门网络和多个专家。作为整个模型的 MoE 已在 SVM、高斯过程和其他方法中被探索。Eigen、Ranzato 和 Ilya 的工作探索了将 MoE 作为更深网络的组件。这使得 MoE 可以作为多层网络中的层,使模型能够同时既大又高效。
  • 条件计算:传统网络将所有输入数据通过每一层处理。在这一时期,Yoshua Bengio 研究了基于输入 token 动态激活或停用组件的方法。

这些工作导致了在 NLP 背景下探索专家混合。具体来说,Shazeer 等人(2017 年,“等人”包括 Geoffrey Hinton 和 Jeff Dean,Google 的 Chuck Norris)通过引入稀疏性,将这个想法扩展到 137B LSTM(当时事实上的 NLP 架构,由 Schmidhuber 创建),允许即使在大规模下也能保持非常快的推理速度。这项工作专注于翻译,但面临许多挑战,如高通信成本和训练不稳定性。

MoE layer in LSTM
来自 Outrageously Large Neural Network 论文的 MoE 层

MoE 使得训练数万亿参数的模型成为可能,例如开源的 1.6T 参数 Switch Transformers 等。MoE 也已在计算机视觉领域得到探索,但本博客文章将聚焦于 NLP 领域。

什么是稀疏性?

稀疏性利用了条件计算的思想。在稠密模型中,所有参数都用于所有输入,而稀疏性允许我们只运行整个系统的一部分。

让我们更深入地了解 Shazeer 对用于翻译的 MoE 的探索。条件计算的思想(网络的一部分在每个样本的基础上激活)允许人们在不增加计算量的情况下扩展模型规模,因此,这导致每个 MoE 层中使用了数千个专家。

这种设置带来了一些挑战。例如,尽管大批量通常对性能更好,但在 MoE 中,随着数据流经活跃的专家,批量大小实际上被减小了。例如,如果我们的批量输入包含 10 个 token,五个 token 可能最终进入一个专家,而另外五个 token 可能最终进入五个不同的专家,导致批量大小不均匀和利用率不足。下面的让 MoE 跑得飞快部分将讨论其他挑战和解决方案。

我们如何解决这个问题?一个学习到的门控网络(G)决定将输入的一部分发送给哪些专家(E):

y=∑i=1nG(x)iEi(x) y = \sum_{i=1}^{n} G(x)_i E_i(x)

在这种设置中,所有专家都会对所有输入运行——这是一种加权乘法。但是,如果 G 为 0 会怎样?如果是这种情况,就不需要计算相应专家的操作,因此我们节省了计算量。典型的门控函数是什么?在最传统的设置中,我们只使用一个带有 softmax 函数的简单网络。该网络将学习将输入发送给哪个专家。

Gσ(x)=Softmax(x⋅Wg) G_\sigma(x) = \text{Softmax}(x \cdot W_g)

Shazeer 的工作还探索了其他门控机制,例如 Noisy Top-k Gating。这种门控方法引入了一些(可调的)噪声,然后保留前 k 个值。即:

  1. 我们添加一些噪声

H(x)i=(x⋅Wg)i+StandardNormal()⋅Softplus((x⋅Wnoise)i) H(x)_i = (x \cdot W_{\text{g}})_i + \text{StandardNormal()} \cdot \text{Softplus}((x \cdot W_{\text{noise}})_i)

  1. 我们只选取前 k 个

KeepTopK(v,k)i={viif vi is in the top k elements of v,−∞otherwise. \text{KeepTopK}(v, k)_i = \begin{cases} v_i & \text{if } v_i \text{ is in the top } k \text{ elements of } v, \\ -\infty & \text{otherwise.} \end{cases}

  1. 我们应用 softmax。

G(x)=Softmax(KeepTopK(H(x),k)) G(x) = \text{Softmax}(\text{KeepTopK}(H(x), k))

这种稀疏性带来了一些有趣的特性。通过使用足够低的 k(例如一或二),我们可以比激活许多专家时更快地训练和运行推理。为什么不直接选择顶级专家?最初的猜想是需要路由到多个专家,才能让门控学习如何路由到不同的专家,因此至少必须选择两个专家。Switch Transformers 部分重新审视了这一决定。

我们为什么要添加噪声?那是为了负载均衡!

为 MoE 平衡 token 负载

如前所述,如果我们的所有 token 都只发送给少数几个热门专家,会导致训练效率低下。在正常的 MoE 训练中,门控网络会收敛到主要激活相同的少数专家。这种自我强化会随着受青睐的专家训练得更快而被更多地选择。为了缓解这一问题,引入了一个辅助损失,以鼓励给予所有专家同等的重要性。该损失确保所有专家接收到的训练样本数量大致相等。以下部分还将探讨专家容量的概念,它引入了一个专家可以处理多少 token 的阈值。在transformers中,辅助损失通过aux_loss参数暴露出来。

MoE 与 Transformer

Transformer 是一个非常明确的案例,表明扩大参数数量可以提高性能,因此 Google 通过GShard探索这一点并不令人意外,该工作探索了将 Transformer 扩展到超过 6000 亿参数。

GShard 在编码器和解码器中都使用 top-2 门控,将每隔一个 FFN 层替换为 MoE 层。下一张图展示了编码器部分的样子。这种设置对于大规模计算非常有利:当我们扩展到多个设备时,MoE 层跨设备共享,而所有其他层则被复制。这在“让 MoE 飞起来”部分有进一步讨论。

MoE Transformer Encoder
GShard 论文中的 MoE Transformer 编码器

为了在大规模下保持负载均衡和效率,GShard 作者除了引入与上一节讨论类似的辅助损失外,还引入了几个变化:

  • 随机路由:在 top-2 设置中,我们总是选择排名第一的专家,但第二个专家按其权重成比例的概率被选中。
  • 专家容量:我们可以设置一个专家可以处理多少 token 的阈值。如果两个专家都达到容量上限,该 token 被视为溢出,并通过残差连接发送到下一层(在其他项目中则完全丢弃)。这个概念将成为 MoE 最重要的概念之一。为什么需要专家容量?因为所有张量形状在编译时都是静态确定的,但我们无法提前知道有多少 token 会分配给每个专家,所以我们需要固定容量因子。

GShard 论文的贡献在于表达了适用于 MoE 的并行计算模式,但讨论这些超出了本博客文章的范围。

注意:当我们进行推理时,只有部分专家会被触发。同时,还有一些共享计算,例如自注意力,会应用于所有 token。这就是为什么当我们谈论 8 个专家的 47B 模型时,我们可以用 12B 稠密模型的计算量来运行。如果我们使用 top-2,则会使用 14B 参数。但鉴于注意力操作(以及其他操作)是共享的,实际使用的参数数量是 12B。

Switch Transformer

尽管 MoE 展现出了很大的前景,但它们在训练和微调时存在不稳定性。Switch Transformer 是一项非常令人兴奋的工作,深入探讨了这些主题。作者甚至在 Hugging Face 上发布了一个拥有 2048 个专家的1.6 万亿参数 MoE,你可以用 transformers 运行它。Switch Transformer 相比 T5-XXL 实现了 4 倍的预训练加速。

Switch Transformer Layer
Switch Transformer 论文中的 Switch Transformer 层

正如在 GShard 中一样,作者将 FFN 层替换为 MoE 层。Switch Transformers 论文提出了一种 Switch Transformer 层,它接收两个输入(两个不同的 token)并拥有四个专家。

与最初使用至少两个专家的想法相反,Switch Transformers 使用了一种简化的单专家策略。这种方法的效果是:

  • 路由器计算量减少
  • 每个专家的批次大小至少可以减半
  • 通信成本降低
  • 质量得以保持

Switch Transformers 还探讨了专家容量的概念。

专家容量=(每批 token 数专家数量)×容量因子 \text{Expert Capacity} = \left(\frac{\text{tokens per batch}}{\text{number of experts}}\right) \times \text{capacity factor}

上述建议的容量将批次中的 token 数量平均分配给专家数量。如果我们使用大于 1 的容量因子,就为 token 未完美平衡时提供了缓冲。增加容量会导致更昂贵的设备间通信,因此这是一个需要牢记的权衡。特别是,Switch Transformers 在低容量因子(1-1.25)下表现良好

Switch Transformer 的作者还重新审视并简化了各节中提到的负载均衡损失。对于每个 Switch 层,辅助损失在训练期间被添加到总模型损失中。这种损失鼓励均匀路由,并可以使用超参数进行加权。

作者还尝试了选择性精度,例如用 bfloat16 训练专家,而其余计算使用全精度。较低的精度降低了处理器之间的通信成本、计算成本以及存储张量的内存。在最初的实验中,专家和门网络都用 bfloat16 训练,导致训练更加不稳定。这尤其是由于路由器计算:由于路由器具有指数函数,因此具有更高的精度很重要。为了缓解不稳定性,路由也使用了全精度。

Table shows that selective precision does not degrade quality.
使用选择性精度不会降低质量,并能实现更快的模型

这个 notebook 展示了为摘要任务微调 Switch Transformers,但我们建议先查看微调部分。

Switch Transformers 使用编码器-解码器设置,其中他们做了 T5 的 MoE 对应版本。GLaM 论文探讨了通过训练一个匹配 GPT-3 质量的模型来提升这些模型的规模,同时只使用 1/3 的能量(是的,由于训练 MoE 所需的计算量更少,他们可以将碳足迹减少多达一个数量级)。作者专注于仅解码器模型以及少样本和单样本评估,而不是微调。他们使用了 Top-2 路由和更大的容量因子。此外,他们探索了将容量因子作为一个指标,可以根据想要使用的计算量在训练和评估期间进行更改。

使用路由器 Z-loss 稳定训练

前面讨论的平衡损失可能导致不稳定问题。我们可以使用许多方法来稳定稀疏模型,但会牺牲质量。例如,引入 dropout 可以提高稳定性,但会导致模型质量下降。另一方面,添加更多乘法组件可以提高质量,但会降低稳定性。

Router z-loss 在 ST-MoE 中被提出,通过惩罚进入门控网络的大 logits,显著提高了训练稳定性,且不会导致质量下降。由于该损失鼓励数值的绝对幅度更小,舍入误差得以减少,这对诸如门控这样的指数函数可能相当重要。我们建议查阅论文以了解详情。

专家学到了什么?

ST-MoE 的作者观察到,编码器专家专门处理一组 token 或浅层概念。例如,我们可能最终得到一个标点专家、一个专有名词专家等。另一方面,解码器专家的专门化程度较低。作者还在多语言设置下进行了训练。尽管人们可能会想象每个专家专门处理一种语言,但实际情况恰恰相反:由于 token 路由和负载均衡,没有任何一个专家专门处理任何给定的语言。

Experts specialize in some token groups
来自 ST-MoE 论文的表格,显示了哪些 token 组被发送到哪个专家。

扩展专家数量如何影响预训练?

更多的专家会带来更好的样本效率和更快的加速,但这些收益是递减的(尤其是在 256 或 512 之后),并且推理时需要更多的显存。Switch Transformers 在大规模下研究的特性在小规模下也保持一致,即使每层只有 2、4 或 8 个专家。

微调 MoE

Mixtral 在 transformers 4.36.0 版本中受支持。你可以使用 pip install transformers==4.36.0 --upgrade 安装它

密集模型和稀疏模型的过拟合动态非常不同。稀疏模型更容易过拟合,因此我们可以在专家内部探索更高的正则化(例如 dropout)(例如,我们可以为密集层设置一个 dropout 率,为稀疏层设置另一个更高的 dropout 率)。

一个问题是是否在微调时使用辅助损失。ST-MoE 的作者尝试关闭辅助损失,即使多达 11% 的 token 被丢弃,质量也没有受到显著影响。Token 丢弃可能是一种有助于防止过拟合的正则化形式。

Switch Transformers 观察到,在固定的预训练困惑度下,稀疏模型在下游任务中比对应的密集模型表现更差,尤其是在 SuperGLUE 等推理密集型任务上。另一方面,对于 TriviaQA 等知识密集型任务,稀疏模型的表现异常出色。作者还观察到,较少数量的专家有助于微调。另一个证实泛化问题的观察是,模型在较小的任务上表现更差,但在较大的任务上表现良好。

Fine-tuning learning curves
在小型任务(左图)中,我们可以看到明显的过拟合,因为稀疏模型在验证集上表现差得多。在较大的任务(右图)中,MoE 表现良好。此图来自 ST-MoE 论文。

可以尝试冻结所有非专家权重。也就是说,我们只更新 MoE 层。这会导致性能大幅下降。我们可以尝试相反的做法:只冻结 MoE 层中的参数,这几乎与更新所有参数的效果一样好。这有助于加速微调并减少内存占用。这可能有些反直觉,因为在 ST-MoE 项目中,80% 的参数都在 MoE 层中。他们对该架构的假设是,由于专家层每 4 层才出现一次,且每个 token 在每层最多只看到两个专家,因此更新 MoE 参数所影响的层数远少于更新其他参数。

Only updating the non MoE layers works well in fine-tuning
通过仅冻结 MoE 层,我们可以在保持质量的同时加速训练。此图来自 ST-MoE 论文。

微调稀疏 MoE 时需要考虑的最后一点是,它们有不同的微调超参数设置——例如,稀疏模型往往更受益于较小的批量大小和较高的学习率。

Table comparing fine-tuning batch size and learning rate between dense and sparse models.
稀疏模型微调后的质量随学习率提高和批量大小减小而提升。此图来自 ST-MoE 论文。

此时,你可能会有些沮丧,因为人们在微调 MoE 方面一直困难重重。令人兴奋的是,最近的一篇论文,MoEs Meets Instruction Tuning(2023 年 7 月),进行了以下实验:

  • 单任务微调
  • 多任务指令微调
  • 多任务指令微调后进行单任务微调

当作者微调 MoE 和对应的 T5 时,T5 表现更好。当作者微调 Flan T5(T5 指令版)MoE 时,MoE 表现显著更好。不仅如此,Flan-MoE 相对于 MoE 的提升比 Flan T5 相对于 T5 的提升更大,这表明 MoE 可能比稠密模型从指令微调中获益更多。MoE 从更多任务数量中获益更多。与之前建议关闭辅助损失函数的讨论不同,该损失实际上防止了过拟合。

MoEs benefit even more from instruct tuning than dense models
与稠密模型相比,稀疏模型从指令微调中获益更多。此图来自 MoEs Meets Instruction Tuning 论文

何时使用稀疏 MoE 与稠密模型?

专家模型适用于拥有多台机器的高吞吐量场景。在预训练计算预算固定的情况下,稀疏模型会更优。对于显存有限、吞吐量低的场景,稠密模型会更好。

注意:不能直接比较稀疏模型和稠密模型的参数数量,因为两者代表的东西截然不同。

让 MoE 飞起来

最初的 MoE 工作将 MoE 层呈现为分支结构,导致计算缓慢,因为 GPU 并非为此设计,并且由于设备之间需要互相发送信息,网络带宽成为瓶颈。本节将讨论一些现有工作,使这些模型的预训练和推理更加实用。MoE 飞飞飞。

并行

让我们简要回顾一下并行:

  • 数据并行:相同的权重在所有核心上复制,数据在各核心间划分。
  • 模型并行:模型在各核心间划分,数据在各核心上复制。
  • 模型与数据并行:我们可以将模型和数据在各核心间划分。注意,不同的核心处理不同的数据批次。
  • 专家并行:专家被放置在不同的工作节点上。如果与数据并行结合使用,每个核心拥有不同的专家,而数据则被划分到所有核心上。

在专家并行中,专家被放置在不同的工作节点上,每个工作节点处理不同的训练样本批次。对于非 MoE 层,专家并行的行为与数据并行相同。对于 MoE 层,序列中的 token 会被发送到所需专家所在的工作节点。

Image illustrating model, expert, and data prallelism
来自 Switch Transformers 论文的示意图,展示了数据和模型如何通过不同的并行技术在核心上进行拆分。

容量因子与通信成本

增加容量因子(CF)可以提高质量,但会增加通信成本和激活值的内存占用。如果全对全通信速度较慢,使用较小的容量因子会更好。一个好的起点是使用 top-2 路由、1.25 的容量因子,并且每个核心放置一个专家。在评估期间,可以更改容量因子以减少计算量。

服务技术

你可以将 mistralai/Mixtral-8x7B-Instruct-v0.1 部署到 Inference Endpoints。

MoE 的一个主要缺点是参数量庞大。对于本地使用场景,人们可能希望使用更小的模型。让我们快速讨论几种有助于服务部署的技术:

  • Switch Transformers 的作者进行了早期的蒸馏实验。通过将 MoE 蒸馏回其稠密对应模型,他们能够保留 30-40% 的稀疏性收益。因此,蒸馏提供了更快的预训练和生产中使用更小模型的好处。
  • 最近的方法修改了路由机制,将完整句子或任务路由到某个专家,从而允许提取子网络用于服务部署。
  • 专家聚合(MoE):这种技术合并专家的权重,从而减少推理时的参数量。

更多关于高效训练的内容

FasterMoE(2022 年 3 月)分析了 MoE 在高效分布式系统中的性能,分析了不同并行策略的理论极限,以及倾斜专家流行度的技术、降低延迟的细粒度通信调度,以及一种调整后的拓扑感知门控机制,该机制根据最低延迟选择专家,从而实现了 17 倍的加速。

Megablocks(2022 年 11 月)通过提供能够处理 MoE 中动态性的新 GPU 内核,探索了高效的稀疏预训练。他们的方案从不丢弃 token,并能高效映射到现代硬件上,从而带来显著的加速。诀窍是什么?传统的 MoE 使用批量矩阵乘法,这假设所有专家具有相同的形状和相同数量的 token。相比之下,Megablocks 将 MoE 层表示为块稀疏操作,可以适应不均衡的分配。

Matrix multiplication optimized for block-sparse operations.
针对不同大小的专家和 token 数量的块稀疏矩阵乘法(来自 [MegaBlocks](https://arxiv.org/abs/2211.15841))。

开源 MoE

如今有多个用于训练 MoE 的开源项目:

在已发布的开放获取 MoE 中,你可以查看:

令人兴奋的工作方向

进一步实验将稀疏 MoE 蒸馏回参数更少但质量相近的稠密模型。

另一个领域将是 MoE 的量化。QMoE(2023 年 10 月)是这一方向上的良好进展,它将 MoE 量化到每个参数不到 1 比特,从而将使用 3.2TB 加速器的 1.6T Switch Transformer 压缩到仅 160GB。

所以,TL;DR,一些值得探索的有趣领域:

  • 将 Mixtral 蒸馏为稠密模型
  • 探索专家的模型合并技术及其对推理时间的影响
  • 对 Mixtral 执行极端量化技术

一些资源

引用

@misc {sanseviero2023moe,
    author       = { Omar Sanseviero and
                     Lewis Tunstall and
                     Philipp Schmid and
                     Sourab Mangrulkar and
                     Younes Belkada and
                     Pedro Cuenca
                   },
    title        = { Mixture of Experts Explained },
    year         = 2023,
    url          = { https://huggingface.co/blog/moe },
    publisher    = { Hugging Face Blog }
}
Sanseviero, et al., "Mixture of Experts Explained", Hugging Face Blog, 2023.

来源:Hugging Face:Blog(RSS) · huggingface.co