百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

漫画混合专家(MoE)手把手用数学公式推导

itomcoil 2025-03-12 15:52 25 浏览

当查看大型语言模型(LLMs)的最新发布时,你经常会看到标题中带有“MoE”。这个“MoE”代表什么?为什么这么多LLMs都在使用它?

在这份视觉指南中,我们将花时间探索这个重要组件——专家混合(MoE),通过超过 50 个可视化进行深入探讨!

在此视觉指南中,我们将介绍 MoE 的两个主要组件,即专家和路由器,以及它们在典型的基于LLM架构中的应用。

查看与LLMs相关的更多可视化内容,并支持此通讯,请参阅我写的关于大型语言模型的书籍!

什么是混合专家(MoE)?

混合专家(MoE)是一种使用许多不同的子模型(或“专家”)来提高LLMs质量的技术。

两个主要组件定义了 MoE:

  • 专家 - 每个 FFNN 层现在都有一个“专家”集合,其中可以选择子集。这些“专家”通常是 FFNN 本身。
  • 路由器或网关网络 - 确定哪些令牌发送给哪些专家。

在具有 MoE 的LLM的每一层中,我们发现(某种程度上是专业的)专家:

“专家”并非在特定领域如“心理学”或“生物学”中专业化。最多,它只是词法方面的专家:

更具体地说,他们的专长在于处理特定语境中的特定标记。

路由器(网关网络)选择最适合给定输入的专家(们):

每位专家不是一个完整的LLM,而是LLM架构的子模型部分。

专家Expert, MoE中的E

为了探索专家所代表的内容以及他们的工作方式,让我们首先考察 MoE 应该取代的内容;密集层。

密集层Dence layer

混合专家(MoE)都始于相对基本的功能LLMs,即前馈神经网络(FFNN)。

请记住,标准解码器 Transformer 架构在层归一化之后应用 FFNN:

一个 FFNN 允许模型使用由注意力机制创建的上下文信息,进一步将其转化为捕捉数据中更复杂关系的能力。

FFNN 然而,其规模却迅速增长。为了学习这些复杂关系,它通常会在接收到的输入基础上进行扩展:

稀疏层

在传统的 Transformer 中,FFNN 被称为密集模型,因为所有参数(其权重和偏差)都被激活。没有任何东西被留下,所有内容都用于计算输出。

如果我们仔细观察密集模型,注意输入如何在一定程度上激活所有参数:

相比之下,稀疏模型仅激活其总参数的一部分,并且与专家混合模型密切相关。

为了说明,我们可以将我们的密集模型切割成多个部分(所谓专家),重新训练它,并在给定时间只激活一组专家:

底层理念是每个专家在训练期间学习不同的信息。然后,在运行推理时,仅使用与特定任务最相关的特定专家。

当被问及问题时,我们可以选择最适合执行特定任务的专家:

专家学到了什么?

如我们所见,专家比整个领域学习到更细粒度的信息。1 因此,有时将他们称为“专家”被视为误导。

编码器模型在 ST-MoE 论文中的专家专业化。

解码器模型专家似乎没有相同的类型专业化。但这并不意味着所有专家都是平等的。

一个很好的例子可以在 Mixtral 8x7B 论文中找到,其中每个标记都涂上了第一个专家的选择。

此视觉图还表明,专家往往关注语法而非特定领域。

因此,尽管解码器专家似乎没有特定的专长,但他们似乎一直被用于某些类型的标记。

专家架构

尽管将专家视为密集模型中切割成块的隐藏层听起来很酷,但他们本身往往是完整的全连接神经网络(FFNN):

由于大多数LLMs具有多个解码器块,给定文本在生成之前将通过多个专家:

所选专家可能在标记之间有所不同,从而导致采取不同的“路径”:

如果我们更新解码器块的可视化,它现在将包含更多的 FFNN(每个专家一个)而不是:

解码器块现在具有多个 FFNN(每个都是一个“专家”),它在推理期间可以使用。

路由机制

现在我们有一批专家,模型是如何知道使用哪些专家的?

在专家之前,添加了一个路由器(也称为网关网络),该路由器经过训练,能够选择为给定令牌选择哪个专家。

路由器

路由器(或网关网络)也是一种前馈神经网络(FFNN),用于根据特定输入选择专家。它输出概率,并使用这些概率来选择最佳匹配的专家:

专家层返回所选专家的输出乘以门值(选择概率)。

路由器与专家(其中只有少数被选中)共同构成 MoE 层:

给定 MoE 层有两种大小,要么是稀疏的专家混合,要么是密集的专家混合。

两者都使用路由器来选择专家,但稀疏 MoE 只选择少数,而密集 MoE 则选择所有,但可能在不同的分布中。

例如,给定一组标记,MoE 会将标记分配给所有专家,而稀疏 MoE 只会选择少数专家。

在当前状态LLMs下,当你看到“MoE”时,它通常是一个稀疏 MoE,因为它允许你使用专家子集。这在计算上更便宜,这是LLMs的一个重要特性。

专家选择

门控网络可以说是任何 MoE 最重要的组成部分,因为它不仅决定了推理期间选择哪些专家,还包括训练阶段。

在其最基本的形式中,我们将输入(x)乘以路由权重矩阵(W):

然后,我们对输出应用 SoftMax,为每位专家创建概率分布 G(x):

路由器使用这种概率分布来选择给定输入的最佳匹配专家。

最后,我们将每个路由器的输出与每个选定的专家相乘,并将结果相加。

让我们把所有内容整合起来,探索输入如何通过路由器和专家流动:

路由的复杂性

然而,这个简单的函数往往导致路由器选择相同的专家,因为某些专家可能比其他专家学习得更快:

不仅选定的专家分布不均,而且一些专家几乎都没有经过培训。这导致在训练和推理过程中都存在问题。

相反,我们希望在训练和推理过程中专家之间保持同等重要性,我们称之为负载均衡。从某种意义上讲,这是为了防止对同一专家的过度拟合。

负载均衡

为了平衡专家的重要性,我们需要将路由器视为主要组件,以决定在特定时间选择哪些专家。

保持顶部 K

一种路由器负载均衡的方法是通过一个简单的扩展称为 KeepTopK 2。通过引入可训练(高斯)噪声,我们可以防止总是选择相同的专家:

然后,除了您想要激活的前 k 个专家(例如 2 个)之外,其余专家的权重将被设置为-∞:

通过将这些权重设置为 -∞,这些权重上的 SoftMax 输出将导致概率为 0:

The KeepTopK 策略是许多 LLMs 尽管有许多有希望的替代方案仍在使用的策略。请注意,KeepTopK 也可以在不添加额外噪声的情况下使用。

Token 选择

The KeepTopK 策略将每个令牌路由到几位选定的专家。这种方法称为 Token Choice 3,允许将特定令牌发送给一位专家(top-1 路由):

或超过一个专家(top-k 路由):

一个主要好处是它允许权衡和整合专家各自的贡献。

辅助损失

为了在训练期间获得更均匀的专家分布,网络常规损失中添加了辅助损失(也称为负载均衡损失)。

它增加了一个约束,迫使专家们具有同等重要性。

该辅助损失的第一个组成部分是对整个批次中每个专家的路由器值进行求和:

这为我们提供了每位专家的重要性得分,它代表了无论输入如何,某位专家被选中的可能性。

我们可以用这个来计算变异系数(CV),它告诉我们专家之间的重要性分数差异有多大。

例如,如果重要性得分差异很大,CV 将会很高:

相比之下,如果所有专家的重要性评分都相似,则 CV 值将较低(这正是我们追求的目标):

使用此 CV 得分,我们可以在训练过程中更新辅助损失,使其尽可能降低 CV 得分(从而给予每个专家同等的重要性):

最后,将辅助损失作为一个单独的损失项用于训练优化。

专家能力

不平衡不仅存在于被选中的专家中,也存在于发送给专家的代币分布中。

例如,如果输入标记不成比例地发送给某个专家而不是另一个,这也可能导致欠训练:

这里,不仅仅是关于使用哪些专家,而是他们被使用了多少。

该问题的解决方案是限制特定专家可以处理的令牌数量,即专家容量 4。当专家达到容量时,产生的令牌将被发送到下一个专家:

如果两位专家都已达到其容量,则令牌不会被任何专家处理,而是发送到下一层。这被称为令牌溢出。

简化 MoE 与 Switch Transformer

之一是处理 MoE(如负载均衡)训练不稳定问题的第一个基于 transformer 的 MoE 模型——Switch Transformer。5 它简化了大部分架构和训练过程,同时提高了训练稳定性。

交换层

开关变换器是一种 T5 模型(编码器-解码器),它用切换层替换了传统的 FFNN 层。切换层是一个稀疏 MoE 层,为每个标记选择一个专家(Top-1 路由)。

路由器在计算选择哪个专家时没有特殊技巧,只是将输入乘以专家的权重后取 softmax(与我们之前做的一样)。

这种架构(top-1 路由)假设路由器只需要 1 位专家就能学习如何路由输入。这与我们之前所见的假设不同,我们之前假设应该将令牌路由到多个专家(top-k 路由)以学习路由行为。

容量系数

容量系数是一个重要值,因为它决定了专家可以处理多少个标记。Switch Transformer 通过引入直接影响专家容量的容量系数来扩展这一点。

专家能力组成部分简单明了:

如果我们提高容量系数,每位专家将能够处理更多的标记。

然而,如果容量系数过大,我们会浪费计算资源。相比之下,如果容量系数过小,由于标记溢出,模型性能将下降。

辅助损失

为进一步防止丢失标记,引入了辅助损失的简化版本。

而不是计算变异系数,这种简化的损失衡量了分配的标记分数与每个专家的路由概率分数之比:

由于目标是让 N 个专家之间具有统一的令牌路由,我们希望向量 P 和 f 的值为 1/N。

α 是一个超参数,我们可以用它来微调训练过程中这个损失函数的重要性。值过高会超过主损失函数,值过低对负载均衡的帮助很小。

专家混合模型

MoE 并非仅限于语言模型的技巧。视觉模型(如 ViT)利用基于 transformer 的架构,因此有潜力使用 MoE。

作为快速回顾,ViT(视觉 Transformer)是一种将图像分割成类似标记处理的补丁的架构。6

这些补丁(或令牌)随后被投影到嵌入(带有额外的位置嵌入)中,然后再输入到常规编码器中:

这些补丁进入编码器的那一刻,它们就像标记一样被处理,这使得这种架构非常适合 MoE。

Vision-MoE

Vision-MoE(V-MoE)是图像模型中 MoE 的第一个实现之一。7 它采用我们之前看到的 ViT,并将编码器中的密集 FFNN 替换为稀疏 MoE。

这允许 ViT 模型,通常比语言模型尺寸更小,通过添加专家进行大规模扩展。

每个专家使用了一个小的预定义专家容量,以减少硬件限制,因为图像通常有许多块。然而,低容量往往会造成块被丢弃(类似于令牌溢出)。

为了保持容量低,网络将重要性分数分配给补丁,并首先处理这些补丁,以便溢出的补丁通常不太重要。这被称为批量优先路由。

因此,即使令牌百分比下降,我们仍然应该看到重要的补丁被路由。

优先路由通过关注最重要的部分,允许处理更少的补丁。

在 V-MoE 中,优先级评分器帮助区分重要程度不同的补丁。然而,补丁被分配给每个专家,未处理补丁中的信息丢失。

软 MoE 旨在通过混合补丁从离散补丁(标记)分配过渡到软补丁(标记)分配。8

在第一步中,我们将输入 x(补丁嵌入)与可学习的矩阵Φ相乘。这为我们提供了路由信息,告诉我们某个标记与特定专家的相关程度。

通过随后对路由信息矩阵(按列)进行 softmax 操作,我们更新每个补丁的嵌入。

更新的补丁嵌入实际上是所有补丁嵌入的加权平均值。

视觉上,就像所有的补丁都被混合在一起了。这些组合补丁随后被发送给每位专家。在生成输出后,它们再次与路由矩阵相乘。

路由矩阵影响令牌级别的输入和专家级别的输出。

因此,我们得到“软”补丁/令牌,而不是处理离散输入。

活跃参数与稀疏参数在 Mixtral 8x7B 中

莫埃(MoE)引人入胜的一大原因是其计算需求。由于在特定时间只使用专家子集,我们能够访问比实际使用的更多参数。

尽管给定的 MoE 有更多参数需要加载(稀疏参数),但由于我们只在推理时使用一些专家(激活参数),因此激活的参数较少。

换句话说,我们仍然需要在您的设备上加载整个模型(包括所有专家)(稀疏参数),但在进行推理时,我们只需要使用子集(活动参数)。MoE 模型需要更多的 VRAM 来加载所有专家,但在推理时运行更快。

让我们通过一个例子来探讨稀疏参数与活跃参数的数量,Mixtral 8x7B。9

这里,我们可以看到每个专家的大小是 5.6B,而不是 7B(尽管有 8 个专家)。

我们不得不加载 8x5.6B(46.7B)个参数(包括所有共享参数),但推理时我们只需要使用 2x5.6B(12.8B)个参数。

结论

这标志着我们与专家混合模型的旅程结束!希望这篇帖子能让你更好地理解这种有趣技术的潜力。现在,几乎所有模型集都至少包含一个 MoE 变体,感觉它将在这里停留。

相关推荐

Python编程实现求解高次方程_python求次幂
Python编程实现求解高次方程_python求次幂

#头条创作挑战赛#编程求解一元多次方程,一般情况下对于高次方程我们只求出近似解,较少的情况可以得到精确解。这里给出两种经典的方法,一种是牛顿迭代法,它是求解方程根的有效方法,通过若干次迭代(重复执行部分代码,每次使变量的当前值被计算出的新值...

2025-10-23 03:58 itomcoil

python常用得内置函数解析——sorted()函数

接下来我们详细解析Python中非常重要的内置函数sorted()1.函数定义sorted()函数用于对任何可迭代对象进行排序,并返回一个新的排序后的列表。语法:sorted(iterabl...

Python入门学习教程:第 6 章 列表

6.1什么是列表?在Python中,列表(List)是一种用于存储多个元素的有序集合,它是最常用的数据结构之一。列表中的元素可以是不同的数据类型,如整数、字符串、浮点数,甚至可以是另一个列表。列...

Python之函数进阶-函数加强(上)_python怎么用函数

一.递归函数递归是一种编程技术,其中函数调用自身以解决问题。递归函数需要有一个或多个终止条件,以防止无限递归。递归可以用于解决许多问题,例如排序、搜索、解析语法等。递归的优点是代码简洁、易于理解,并...

Python内置函数range_python内置函数int的作用

range类型表示不可变的数字序列,通常用于在for循环中循环指定的次数。range(stop)range(start,stop[,step])range构造器的参数必须为整数(可以是内...

python常用得内置函数解析——abs()函数

大家号这两天主要是几个常用得内置函数详解详细解析一下Python中非常常用的内置函数abs()。1.函数定义abs(x)是Python的一个内置函数,用于返回一个数的绝对值。参数:x...

如何在Python中获取数字的绝对值?

Python有两种获取数字绝对值的方法:内置abs()函数返回绝对值。math.fabs()函数还返回浮点绝对值。abs()函数获取绝对值内置abs()函数返回绝对值,要使用该函数,只需直接调用:a...

贪心算法变种及Python模板_贪心算法几个经典例子python

贪心算法是一种在每一步选择中都采取当前状态下最优的选择,从而希望导致结果是全局最优的算法策略。以下是贪心算法的主要变种、对应的模板和解决的问题特点。1.区间调度问题问题特点需要从一组区间中选择最大数...

Python倒车请注意!负步长range的10个高能用法,让代码效率翻倍

你是否曾遇到过需要倒着处理数据的情况?面对时间序列、日志文件或者矩阵操作,传统的遍历方式往往捉襟见肘。今天我们就来揭秘Python中那个被低估的功能——range的负步长操作,让你的代码优雅反转!一、...

Python中while循环详解_python怎么while循环

Python中的`while`循环是一种基于条件判断的重复执行结构,适用于不确定循环次数但明确终止条件的场景。以下是详细解析:---###一、基本语法```pythonwhile条件表达式:循环体...

简单的python-核心篇-面向对象编程

在Python中,类本身也是对象,这被称为"元类"。这种设计让Python的面向对象编程具有极大的灵活性。classMyClass:"""一个简单的...

简单的python-python3中的不变的元组

golang中没有内置的元组类型,但是多值返回的处理结果模拟了元组的味道。因此,在golang中"元组”只是一个将多个值(可能是同类型的,也可能是不同类型的)绑定在一起的一种便利方法,通常,也...

python中必须掌握的20个核心函数——sorted()函数

sorted()是Python的内置函数,用于对可迭代对象进行排序,返回一个新的排序后的列表,不修改原始对象。一、sorted()的基本用法1.1方法签名sorted(iterable,*,ke...

12 个 Python 高级技巧,让你的代码瞬间清晰、高效

在日常的编程工作中,我们常常追求代码的精简、优雅和高效。你可能已经熟练掌握了列表推导式(listcomprehensions)、f-string和枚举(enumerate)等常用技巧,但有时仍会觉...

Python的10个进阶技巧:写出更快、更省内存、更优雅的代码

在Python的世界里,我们总是在追求效率和可读性的完美平衡。你不需要一个数百行的新框架来让你的代码变得优雅而快速。事实上,真正能带来巨大提升的,往往是那些看似微小、却拥有高杠杆作用的技巧。这些技巧能...