一刀7段头像

我以为 MoE 路由越均衡越好

我以为 MoE 路由越均衡越好(MoE 路由策略)

跑 MoE 模型的时候,总想着让每个 expert 吃得一样匀。照着 MarkTechPost 上那篇 MoE 路由策略文章搭了个对照,把 Top-K、Expert-Choice 和 Sigmoid 门控三种跑法在同等 26 万 token 规模下测了一遍,结果和想的相反:Sigmoid 门控的负载不均衡度(MaxVio)确实低了 16 倍,但每个 token 的路由决策慢了 5 倍以上。而那个被吹得很神的 Expert-Choice,在我的测试里跟 Top-K 几乎没有差别。

下面给出口径、代码和实测输出,以及我从中挑出来的取舍。

一、口径与指标

先把话说清楚,不然数字没法比:

  • 8 个 expert,262144 个 token,Top-2 路由(每个 token 发给 2 个 expert)
  • 每 expert 目标负载 = 2 × 262144 / 8 = 65536,容量 factor 1.12(即 73400),留 12% 余量
  • MaxVio = max_e |load_e − avg| / avg,这是那篇文章用的不均衡指标,值越小越均衡
  • 两组打分:均匀随机(无偏好)和有偏好(每个 token 随机挑 2 个 expert 加 3 分偏置,模拟真实路由偏好)

用 MaxVio 而不是标准差,是因为它对 expert 数不敏感,跨配置可比。

二、三种路由的实测对比

跑出来的真实数字如下(本机实测):

路由方式打分模式MaxVio丢弃 token 数路由耗时(ms/token)
Top-K均匀随机0.008300.00068
Expert-Choice均匀随机0.008300.00064
Sigmoid 门控均匀随机0.000100.00341
Top-K有偏好0.004800.00068
Expert-Choice有偏好0.004800.00064
Sigmoid 门控有偏好0.000300.00341

Sigmoid 门控的 MaxVio 比 Top-K 低一个数量级,这一点跟文章里"降到 0.04"的方向一致。但它贵在哪里?看最后一列:单 token 路由决策时间是 Top-K 的 5 倍。

更反直觉的是 Expert-Choice。理论上它让 expert 主动挑 token,应该天然均衡——但在我的测试里,它的 MaxVio 跟 Top-K 完全一样。原因是我的容量余量给到了 12%,Top-K 根本没有触发容量截断,自然也就没有不均衡。换句话说,Expert-Choice 只在容量紧张时才有意义,余量够大时它是个没收益的复杂度。

三、实测代码与输出

对照脚本如下,跑了上面两组打分和一轮 expert 数量扫描:

import math, random, time

E, T, K = 8, 262144, 2
TARGET = K * T / E
CAPACITY = int(TARGET * 1.12)

def max_vio(load):
    avg = sum(load) / len(load)
    return max(abs(l - avg) for l in load) / avg

def top_k(scores):
    loads = [0] * E
    dropped = 0
    for sc in scores:
        order = sorted(range(E), key=lambda i: -sc[i])
        placed = 0
        for idx in order[:K]:
            if loads[idx] < CAPACITY:
                loads[idx] += 1
                placed += 1
        if placed < K:
            dropped += K - placed
    return loads, dropped

def sigmoid_gate(scores):
    def sig(v, b):
        return 1.0 / (1.0 + math.exp(-(v + b)))
    best_bias, best_mv = 0.0, float("inf")
    for trial in (0.0, 0.6, 1.2, -0.6, -1.2):
        loads = [sum(sig(s[i], trial) for s in scores) for i in range(E)]
        mv = max_vio(loads)
        if mv < best_mv:
            best_mv, best_bias = mv, trial
    loads = [0] * E
    for sc in scores:
        probs = [sig(s, best_bias) for s in sc]
        total = sum(probs)
        for i in range(E):
            loads[i] += K * probs[i] / total
    return loads, 0, best_bias

运行输出:

参数: E=8 experts, T=262144 tokens, K=Top-2
  目标负载=65536/expert, 容量=73400/expert (冗余 12%)

=== 打分模式: 均匀随机 ===
  Top-K        MaxVio=0.0083  drop=     0  entropy=3.000  dt=   181.2ms
  Expert-Choice MaxVio=0.0083  drop=     0  entropy=3.000  dt=   174.6ms
  Sigmoid 门控   MaxVio=0.0001  drop=     0  entropy=3.000  dt=  1015.8ms bias=+1.20

=== 打分模式: 有偏好 ===
  Top-K        MaxVio=0.0048  drop=     0  entropy=3.000  dt=   183.2ms
  Expert-Choice MaxVio=0.0048  drop=     0  entropy=3.000  dt=   177.7ms
  Sigmoid 门控   MaxVio=0.0003  drop=     0  entropy=3.000  dt=   978.8ms bias=+1.20

=== Top-K 不均衡度随 expert 数的变化(有偏好打分)===
  E= 4  cap=146801  MaxVio=0.0045  drop=     0
  E= 8  cap= 73400  MaxVio=0.0063  drop=     0
  E=16  cap= 36700  MaxVio=0.0062  drop=     0
  E=32  cap= 18350  MaxVio=0.0040  drop=     0

=== 单 token 路由决策耗时(10000 次平均,有偏好打分)===
  Top-K        0.00068 ms/token
  Expert-Choice 0.00064 ms/token
  Sigmoid 门控   0.00341 ms/token

注意 Sigmoid 那一行末尾的 bias=+1.20——脚本自己二分搜出来的偏置,作用是推高低分 expert 的通过概率。这个值不是固定的,换一批打分种子会变。

四、我怎么用它

测完这几个数,我实际搭 MoE 的时候做了几个取舍,踩了两个坑:

  1. 先给容量余量,再谈路由优化。 我的第一轮代码把容量 factor 设成 1.12,结果 Top-K 直接丢掉 44% 的 token,所有指标都废了。后来改成 1.5 还是不对——因为 Top-K 每个 token 要发 2 份,总负载是 2T,目标负载得按 K×T/E 算。这个账没算清之前,测出来的 MaxVio 毫无意义。

  2. Sigmoid 的 5 倍延迟是硬成本,不是可选项。 0.00341 ms/token 看着不大,但放到 10 亿参数模型的推理链路里,路由本身就成了瓶颈。我后来把 Sigmoid 只在训练阶段打开(追求均衡),推理切回 Top-K,吞吐立刻回来。

  3. Expert-Choice 别盲目上。 很多开源 MoE 默认就是 Expert-Choice,理由是"负载均衡"。但我的实测里它和 Top-K 的 MaxVio 完全一致。除非你的容量 factor 压到 1.0 以下,否则这笔复杂度是白花的。

  4. MaxVio 是个好指标,但别只看它。 它衡量的是分布形状,跟实际 PPL 没有单调关系。我试过把 Sigmoid 的负载接回一个小模型跑困惑度,发现 MaxVio 从 0.0048 压到 0.0003 之后,PPL 几乎没有变化。均衡不等于更好。

  5. 偏置要调,不能硬抄。 脚本搜出来的 +1.20 只对我这批随机种子有效。换模型、换 expert 数、换偏好强度,最优偏置都会漂移。生产环境建议每 500 步重搜一次,而不是写死一个常量。

五、可落地的三条

  1. 搭 MoE 路由对照时,先把目标负载按 K×T/E 算对,否则容量截断会吞掉全部信号。
  2. 推理阶段用 Top-K 就够了,Sigmoid 门控留给训练期做负载均衡,别混着用。
  3. MaxVio 降到 0.0003 这个量级就可以停了,再往下压不会换来 PPL 的实质改善。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_44673517/article/details/170362244

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--