混合专家模型(MoE)学习笔记
一、前言
伴随着大型语言模型以及深度学习领域的发展,MoE(混合专家模型)凭借它所具备的条件计算特性以及高度的扩展性,逐渐成为了一个研究方面的热点。这篇文章主要是对MoE模型的一些基本原理、整体的架构设计以及关键的核心技术去做一个梳理工作,并且还会结合一些开源的实例,来简要地描述一下典型的MoE模型在实现方面的主要思路以及它们的应用场景。
二、什么是MoE?
在对MoE进行深入了解之前,先来回顾一下经典的这个Transformer架构。在标准的Transformer当中,它的每一个Encoder/Decoder层都会包含一个多头注意力(Multi-Head Attention)以及一个全连接前馈网络(Feed-Forward Network,通常可以简称为FNN)。这个FNN会针对所有的输入token去执行相同的线性变换以及非线性映射的处理,这样就会产生稠密的计算并且带来高昂的资源消耗。
而混合专家模型(Mixture of Experts,简称MoE) 这个技术,则是在FNN的这个位置引入了一种“专家”机制:它会把一个大规模的前馈网络拆分成多个子网络(也就是专家),并且借助门控网络(Router) 来对token进行动态的路由分配。具体来讲的话,门控网络会依据token所具有的特征(比如说词嵌入或者是注意力上下文),来计算出针对每一个专家的打分(score),并且只会去激活那些得分最高的K个专家来参与计算,其余的专家则会保持闲置状态。通过这样的方式,整个模型的总参数量就可以达到数千亿的规模,但是在每一次实际运算当中实际被激活的参数(Activated Parameters) 仅仅是其中的一小部分,典型的比例大约在5%到15%之间,这就极大程度上降低了计算开销以及显存方面的占用。
Transformer与MoE两者本质上的差异
- 稠密计算:标准的Transformer架构,它的FNN会对所有的参数一视同仁地进行处理;
- 条件计算:MoE模型则仅仅会针对部分专家去执行计算任务,从而实现了稀疏激活的效果。
为什么要进行这样的设计呢? 其主要的缘由囊括以下几点:
- 可扩展性方面:在预算允许的情况之下,可以去增加专家的数量,用以来提升模型的整体容量;
- 效率方面:因为激活的参数比较少,所以能够马上降低FLOPs以及显存的运用量;
- 专业化方面:不同的专家可以“专攻”不同类型的特征或者是任务,以此来提高整体的性能表现。
试想一下,一座图书馆(就好比是Transformer),它里边存放着成千上万本书籍(这些书籍就好比是参数),要是想要查阅某项信息,你就必须去翻阅所有的书页;而MoE这个模型呢,它就像是一位图书管理员(门控网络),会根据你提出的问题,只去取出那些最为相关的几本书(专家)来进行阅读,这样做既能够节省时间,又非常高效。
三、MoE的核心组成
MoE的运行主要是依赖于两大模块:
专家(Experts)
- 每一个专家它本身都是一个独立的前馈网络子层(通常情况下是两层带有激活函数的线性变换),这就好比是针对模型参数空间当中的一个子集来开展专门的训练工作(相关内容可以参见《Outrageously Large Neural Networks: The Sparsely‑Gated Mixture‑of‑Experts Layer》)。
- 专家与专家之间可以去运用不同的切分策略,比如参数聚类(Balanced K‑Means)、共激活图分割(Co‑activation Graph)或者是梯度感知分割这样的方法,目的就是为了保证每一个专家都能够在它所专长的领域之内拥有最优的参数配置方案。
门控网络(Router)
- 输入x会经过一个线性映射得到专家打分结果H(x)=xW_g,然后还会加入可学习的噪声来实现平滑化的处理:H’(x)=H(x)+SoftPlus(xW_n)⊙𝒩(0,1)(这个过程被称为Noisy Gating)。
- 它会选用Top‑K选择策略:保留K个得分最高的专家,在进行归一化之后输出G(x)=Softmax(KeepTopK(H’(x),K))这个结果,并且会把输入分配给这K个被选中的专家。
- 同时还会辅以一个辅助负载损失L_aux=λ·CV(n_1,…,n_E),用以确保Token分配到各个专家那里的样本量的方差能够达到最小化,从而避免出现“热门专家”过载的这种情况。
四、MoE为什么会如此高效?
1. 凭借条件计算来降低FLOPs
标准的Transformer模型里边的FNN,它需要对全部N个专家子层以及所有的输入Token都去执行同样的计算工作,其复杂度是O(N·d^2)这个级别;然而MoE模型只是去激活K个专家,使得复杂度得以降低到O(K·d^2)。在K远小于N的这种情况之下,计算量方面就能够实现接近N/K倍的线性下降。
2. 参数的过度配置以及表示能力
超大规模的模型往往需要运用大量的参数才能够拟合复杂的模式,而稠密化的增长方式则会导致运算方面的瓶颈。MoE模型凭借稀疏路由的机制,在训练过程当中允许存在数倍于激活参数的全局参数量(E·d^2),从而提升了模型对于多样化模式的捕捉能力。
3. 专家化分工以及分布式并行处理
每一个专家仅仅需要去学习子空间当中的特征,以此来实现功能上的分工;而专家并行(Expert Parallelism)这种方式会把不同的专家部署在不同的设备上面,从而减少了主干网络进行同步时所产生的开销。基于Pipeline并行或者是Tensor并行的方式,可以获得更高的吞吐率以及更低的延迟表现(相关内容可以参见《GShard: Scaling Giant Models with Conditional Computation and Automatic Sharding》)。
4. 实践验证
- GLaM这个模型在拥有1.2万亿参数规模的情况下,仅仅激活了8%的参数,并且在29项NLP任务上面超越了拥有175B参数的GPT‑3,这充分展示了条件计算所具有的优势。
- Switch Transformer所采用的Top‑1路由策略,使得吞吐率得到了接近2倍的提升,同时还保持了任务性能方面的表现没有降低。
!
五、关于MoE的技术细节
传统意义上的那些大型神经网络(比如说最常见的Transformer模型),它们就好像是一个“全能型选手”一样,每一次在去处理数据的时候,都必须要调用到全部的参数来参与计算,这样的方式它的成本是比较高的。
然而MoE模型它所运用的则是一种“按需调用”(也就是条件计算)的方法,仅仅让一部分专家去参与到计算过程当中,从而避免了那些无谓的资源浪费情况的发生。
1. 稀疏激活与激活参数
Transformer架构中的FFN层,在理论上需要对所有的token都执行完整的计算,但是在实际测试当中发现,仅仅只有部分的神经元会被触发——这就呈现出了一种天然的稀疏性(参见《MoEfication: Transformer Feed-forward Layers are Mixtures of Experts》)。MoE正是基于这一点,把一个大规模的FNN切分成为E个所谓的“专家”,并且让门控网络针对每一个token只去选择K个专家来参与后续的计算:
指标 | 说明 |
---|---|
总参数量 | 可以高达数十亿甚至上千亿的级别 |
激活参数量 | 约等于总参数量乘以 (K/E) 这个比例,通常所占比重在 5% 到 15% 之间 |
带来的优势 | FLOPs 以及显存方面的开销会成比例下降,显著提高训练和推理过程的效率 |
2. 门控网络以及路由策略的运作
专家的挑选工作是由门控网络(Router) 来完成的,常见的实现方式如下所示:
- 进行线性映射:H(x)=xW_g
- 进行噪声注入:H’(x)=H(x)+g·StandardNormal()⊙SoftPlus(H(x))(这个过程也称作Noisy Gating)
- 取Top-K结果:G(x)=Softmax(KeepTopK(H’(x),K))
- Top-2 vs. Top-1:GShard模型选用了Top-2的策略并且会对输出进行混合,以此来提升整体的鲁棒性;而Switch Transformer模型则选用了Top-1的策略,目的是为了简化通信方面的复杂度(参见《GShard: Scaling Giant Models with Conditional Computation and Automatic Sharding》以及《Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity》)。
- 分层稀疏:Qwen3这类模型会在不同的网络深度动态地去调整K值的大小,以此来实现更为细致颗粒度的条件计算。
3. 负载均衡和辅助损失
部分专家可能会因为打分偏高而持续被激活,从而造成了过载的现象。为了防止出现资源分配不均的情况,MoE引入了一种辅助负载损失(Auxiliary Load Loss) 的机制,它通常被定义为专家所接收到的token数量的变异系数:
L_aux = λ · CV(n₁, n₂, …, n_E)
在这个公式当中,nᵢ代表的是第i个专家在当前这个批次中所处理的token数量,而λ则是一个平衡权重。
该损失项在预训练的过程当中会与主损失一同进行优化,目的是为了确保各个专家的利用率能够大致保持均匀(可以参考GShard模型以及transformers库当中关于aux_loss的具体实现)。
六、一些经典的MoE模型实例
下面按照时间顺序来介绍若干具有代表性的开源MoE模型:
1. Sparsely-Gated Mixture-of-Experts Layer(2017)
由Shazeer等人(来自Google Brain团队)提出(参考论文《Outrageously Large Neural Networks: The Sparsely‑Gated Mixture‑of‑Experts Layer》),首次把门控路由机制引入到了前馈层当中,运用了可学习的噪声Top‑K门控(Noisy Top‑K Gating)技术,并且提出了一种辅助负载损失(Auxiliary Load Loss)的方法,用以平衡各个专家之间的负载情况。奠定了条件计算(Conditional Computation)的基石,实现了大规模参数下的稀疏激活与高效训练。
2. GShard(2020)
由Lepikhin等人(来自Google Research团队)提出,相关论文为《GShard: Scaling Giant Models with Conditional Computation and Automatic Sharding》。在Transformer的每一个FNN层当中都部署了Top‑2门控的MoE结构,引入了专家容量(capacity)这个概念,并且能够自动地把专家划分到多台机器的多个显卡上;同时还选用了随机路由以及负载平衡方面的策略。实现了跨机专家并行(Expert Parallelism)以及自动化的参数分片,支持6000亿级参数模型的训练与推理,显著提升了模型的可扩展性。
3. Switch Transformer(2021)
由Fedus等人(来自Google Research团队)提出,相关论文为《Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity》。提出了一种Top‑1门控的策略,它使得每一个token都只会去访问单个的专家,从而简化了通信的复杂度;同时引入了容量因子(Capacity Factor)这个概念,用以优化专家的负载的情况;还支持运用bfloat16格式来进行训练。在沟通开销以及吞吐率这两个方面之间取得了一个较好的平衡,提出了一种更为轻量级的MoE实现方案,把模型的规模扩展到了1万亿参数的级别,同时还保持了较高的效率。
4. GLaM(2021)
由Du等人(来自Google Research团队)提出,相关论文为《GLaM: Efficient Scaling of Language Models with Mixture-of-Experts》。模型拥有64个专家,并且在每一层会激活其中的2个;选用了Mixture-of-Modality的路由策略,会把不同模态(比如文本、编码等)的任务定向到不同的专家那里去处理;激活的参数仅仅占到了总参数量的8%。证明了稀疏激活这种方式不仅能够保持原有的性能,还能够进一步优化多模态学习以及多任务学习的效果,从而极大的推动了MoE在大型预训练模型当中的应用。
5. DeepSeek-MoE(2024)
由DeepSeek AI团队提出,相关论文为《DeepSeekMoE: Towards Ultimate Expert Specialization in Mixture-of-Experts Language Models》。采用了细粒度专家切分(也就是Fine-Grained Expert Segmentation)的技术,把FFN分成了多个较小的专家;同时引入了共享专家(Shared Experts)的机制来处理那些公共知识;每一个token会激活6个专家。在提高专家专业化程度以及减少冗余信息这两个方面提供了一些新的思路,展示了多专家融合以及共享机制所具有的潜力。
6. LLaMA-MoE(2024)
由Sys4NLP团队基于Meta LLaMA2进行开发,可参考《LLaMA-MoE: Building Mixture-of-Experts from LLaMA with Continual Pre-training》。它支持包括随机、聚类、共激活图等在内的多种专家切分方法;同时还提供了Top‑K噪声门控以及Switch单专家门控这两种不同的策略;专家参数的设计也趋向于轻量化。展示了MoE在轻量级模型上面的一条应用路径,为那些中等规模以及小规模参数的模型提供了一种可行的扩展策略。
7. Qwen3-235B-A22B(2025)
由阿里巴巴通义千问团队发布,可参考官方文档以及模型的开源仓库相关信息。总参数量达到了2350亿,拥有128个专家;运用了分层稀疏调度的机制来动态调整激活的专家数量,单个token会激活8个专家;原生就支持32K的上下文长度,并且可以借助YaRN技术扩展到128K;还运用了GQA注意力机制以及异步卸载等技术来优化并行计算的效率。融合了分层调度以及动态激活这两种技术,为处理超长文本以及应对高吞吐场景提供了一套全新的解决方案,并且进一步降低了进行推理时所产生的成本。
七、MoE的适用场景以及其局限性分析
在实际的部署过程当中,MoE与传统的Transformer架构各有其优势所在,需要根据具体的资源情况以及需求来进行选择:
多机器、高吞吐量的场景更适宜选用MoE
- 专家并行机制:MoE模型当中的专家子网络可以被拆分到多台机器或者是多个设备上面去并行执行(这个机制被称为Expert Parallelism),每一台机器只需要去负责少数几个专家的计算任务,这就避免了因为需要复制整个模型而带来的显存方面的压力。
- 条件路由方式:门控网络仅仅需要去传递那些必要的路由信息,而不需要去同步所有的参数,这样一来,通信方面的开销就得到了显著的降低,整体的吞吐率也得到了明显的提升。
- 弹性扩展能力:当计算集群的规模得到扩容的时候,只需要去增加或者是重新分配专家就可以了,模型的容量与硬件资源之间实现了高度的解耦。
单机器、低显存或是低吞吐需求的场景更适宜选用稠密Transformer
- 路由与调度方面的开销:MoE模型在进行门控计算、专家状态管理以及跨设备通信这些操作时所产生的开销,在单机应用场景当中所占的比重会有所提升,反而可能会增加延迟并且提高实现的复杂度;
- 部署相对简单:标准的Transformer架构不需要额外的负载均衡或者是路由策略,相关的代码和框架也比较成熟,模型的体积与运行效率之间更容易进行权衡;
- 资源运用效率:对于那些显存以及算力都比较有限的环境,可以借助剪枝、量化或者是蒸馏等方法来对稠密网络进行优化,以此来获得更高的性价比。
八、总结与展望
回顾MoE模型一路走来的发展脉络,我们可以观察到,从最初的“噪声Top‑K门控”到后来的“跨机器自动分片”,再到诸如“单专家路由”、“多模态专家”、“细粒度切分”以及“分层稀疏调度”等一系列的创新,每一次的技术迭代都是在努力追求“更大的模型容量”与“更少的计算资源消耗”这两者之间的平衡点。MoE的核心思想在于条件计算(Conditional Computation)这个机制,它赋予了模型高度的可扩展性以及高效性,但与此同时,也带来了在路由、负载均衡以及通信等方面的一些挑战。
MoE已经成为了深度学习大模型领域当中的一个重要分支,去理解它的设计原理以及应用场景,对于推动下一代高效智能系统的发展是至关重要的。
一些词语
**Token**:它指的是模型在去进行文本处理工作的时候,所用到的最小的一个单位,打个比方,它可以是一个汉字,或者说是一个英文单词。
**参数(Parameters)**:它指的是神经网络当中那些可以被训练的数值,就好比是乐高积木的那些块数一样,参数越多,模型也就会越复杂。
**条件计算(Conditional Computation)**:这种机制它是依据输入的内容,仅仅去激活模型当中的一部分专家来开展运算工作,这就好比是去请教那些专门领域的老师,而不是去召开一个全体人员都参加的会议。
**专家(Expert)**:它指的是在MoE模型里面所包含的子网络,每一个专家都会去负责处理特定类型的数据或者是特征方面的工作,这就好比是不同领域里面的那些专家老师一样。
**门控网络(Router/Gating Network)**:它是一个用来决定每一个输入的token应该被分配给哪些专家去进行处理的模块,就好像是一个负责分配任务的调度员那样。
**激活参数(Activated Parameters)**:它指的是在一次计算过程当中,实际会参与到运算里面的参数的数量,这个数量通常会远远小于模型的总参数量。
**稀疏激活(Sparse Activation)**:它的意思是在每一次计算的时候,都仅仅去激活一部分的专家或者是参数,这样做可以达到节省计算资源的目的。
**稠密模型(Dense Model)**:它指的是传统的那些模型,这类模型在每一次进行计算的时候,都需要去调用全部的参数来参与,这就好比是所有成员都要参加会议一样。
**FLOPs(浮点运算次数)**:它是一个用来衡量模型计算量大小的指标,这个值越低,就代表着计算过程越节省资源。
**显存(GPU Memory)**:它指的是显卡上面用来去存储模型参数以及那些中间结果的空间,显存方面的消耗越低,就越容易去进行大模型的部署工作。
**前馈网络(Feed-Forward Network,FFN)**:它是Transformer架构当中的一类神经网络层,主要负责对输入数据去进行非线性变换的处理工作。
**多头注意力(Multi-Head Attention)**:它是Transformer架构当中的一种机制,这种机制可以让模型能够同时去关注输入内容的不同组成部分。
**Top-K选择/路由(Top-K Routing)**:它指的是门控网络会去选择那些得分最高的K个专家来参与到计算当中的一种策略。
**Noisy Gating(噪声门控)**:它的意思是在进行专家选择的这个环节,会引入一些噪声进来,目的是为了提升模型的鲁棒性以及改善负载均衡方面的情况。
**辅助负载损失(Auxiliary Load Loss)**:它是一种特定类型的损失函数,人们运用它来对各个专家的工作量进行平衡,用以防止那些热门专家出现过度繁忙的情况。
**变异系数(Coefficient of Variation,CV)**:它是一个用来衡量各个专家负载均衡程度的统计学上的量,CV这个值越小,就表示分配得越均匀。
**专家并行(Expert Parallelism)**:这种方式会把不同的专家分布到多台机器上面去,每一台机器仅仅会去执行它自己所负责的那个子网络的任务。
**分布式并行(Distributed Parallelism)**:它指的是把模型或者是数据分布在多台设备上面,来同时进行计算工作,目的是为了提高整体的效率。
**Pipeline并行**:这种方式是把模型的不同部分分配到不同的设备上面去,就像是一条流水线那样,分步骤地去进行数据的处理工作。
**Tensor并行**:它是指把单个神经网络层的计算任务分散到多台设备上面去,来并行地进行执行。
**容量因子(Capacity Factor)**:它是一个用来控制每一个专家最多能够去处理多少个token的参数,目的是为了防止单个专家出现过载的情况。
**专家容量(Expert Capacity)**:它指的是每一个专家在一次前向计算过程当中,所能够处理的最大的token数量。
**细粒度专家切分(Fine-Grained Expert Segmentation)**:它是把前馈网络进一步地拆分成更多、并且更小的一些专家,用以来提升整体的专业化程度。
**共享专家(Shared Experts)**:它指的是那些为多个任务或者是多个输入所共享的专家,它们主要负责去处理那些通用的知识。
**分层稀疏(Hierarchical Sparsity)**:这种方法会在不同的网络层级当中,动态地去调整被激活的专家的数量,以此来实现更为细致的条件计算。
**GQA(Grouped Query Attention)**:它是一种非常高效的注意力机制,能够有效提升大型模型在进行推理工作时的效率。
**异步卸载(Asynchronous Offloading)**:它是把一部分的计算任务或者是数据,以异步的方式转移到其他的设备上面去,目的是为了优化整体的资源利用情况。
**Mixture-of-Modality**:这种机制是依据输入的模态(比如说文本、编码等等),来分配到不同的专家那里去进行处理,用以提升模型在进行多模态处理工作方面的能力。
**剪枝(Pruning)**:它是指去去除掉模型当中那些不太重要的参数,以此来减少模型的体积以及计算量方面。
**量化(Quantization)**:它是运用更低精度的数据类型来对参数进行存储和计算工作,从而达到降低资源消耗的目的。
**蒸馏(Distillation)**:它是运用一个大型模型来对一个小模型进行训练,目的是为了让这个小模型能够继承那个大型模型所拥有的能力。
**路由(Routing)**:它指的是门控网络为每一个输入的token去选择合适的专家的那整个过程。
**主损失(Main Loss)**:它是在进行模型训练的时候,所设定的主要的优化目标,打个比方,就像是交叉熵损失这样的。
**辅助损失(Auxiliary Loss)**:它是一个辅助性的优化目标,主要被运用来提升模型在某些特性(比如说负载均衡)方面的表现。
**专家切分(Expert Partitioning)**:它指的是把一个大型网络划分成为多个专家的这个过程,可以运用诸如聚类、图分割等方法来实现这个目标。
**共激活图分割(Co-activation Graph Partitioning)**:它是一种依据神经元激活的相关性来对专家进行划分的方法。
**梯度感知分割(Gradient-aware Partitioning)**:它是一种依据梯度信息来对专家进行划分的方法。
**专家路由(Expert Routing)**:它指的是把输入分配给合适的专家的那整个过程。
**Top-1/Top-2 路由**:它指的是每一个token仅仅会被分配给那些得分最高的1个或者是2个专家。
**容量(Capacity)**:这个概念它指的是每一个专家在一次前向计算的过程当中,所能够处理的最大的token数量。
**激活比例(Activation Ratio)**:它指的是在每一次计算当中,那些被激活的参数占到总参数数量的那个比例。
**吞吐率(Throughput)**:它指的是在单位时间之内,模型所能够去处理的数据量的大小,这个值越高,就代表着效率越好。
**延迟(Latency)**:它指的是模型在去处理一次输入的时候所需要花费的时间,这个时间越低自然是越好的。
**自动分片(Automatic Sharding)**:它是指自动地把模型的参数分配到多台设备上面去,用以来提升并行计算的效率。
**bfloat16**:它是一种低精度的浮点数格式,经常被运用在大型模型的训练过程当中,能够起到节省显存的作用。
**YaRN技术**:它是一种用来扩展上下文长度的技术,能够提升大型模型在去处理长文本内容方面的能力。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!