💎使用 Unsloth 将 MoE 模型微调速度提高 12 倍

使用 Unsloth 在本地训练 MoE LLM 的指南。

我们推出了约12倍更快的专家混合 (MoE) 大模型训练,伴随 >减少35%的显存消耗约6倍更长的上下文 通过我们新的 MoE Triton 内核和新的数学优化,且精度无损。

  • Unsloth 现在支持包括以下在内的 MoE 架构的快速训练 gpt-oss, Qwen3 (30B、235B、VL、Coder)、DeepSeek R1, V3 和 GLM(4.6, 4.7, Flash).

  • gpt-oss-20b 在 12.8 GB 显存下微调。Qwen3-30B-A3B(16 位 LoRA)使用 63GB。

  • 我们的内核可在数据中心级别(B200、H100)、 消费级 以及较旧的 GPU(例如 RTX 3090)上运行,并支持 FFT、LoRA 和 QLoRA。

我们与 🤗Hugging Face 合作,使所有 MoE 训练运行使用 PyTorch 的新功能标准化, torch._grouped_mm 函数。Transformers v5 最近在 MoE 上比 v4 优化了约6倍的速度,而 Unsloth 通过自定义的 Triton grouped‑GEMM + LoRA 内核在此基础上进一步提升,带来 额外的 约2倍的加速,>35% 的显存减少以及 >6 倍更长的上下文(相较于 v4 总体加速 12-30 倍)。

试试我们的 Unsloth 笔记本以获得快速的 MoE 训练:

🦥 Unsloth MoE Triton 内核

除此之外, torch._grouped_mm (参见 Faster MoE Training),我们创建了定制的 Triton MoE 内核,在某些情况下性能更好。它们也能 向后兼容 例如 A100 这样的较旧硬件以及较旧的 PyTorch 版本。

在 A100 上,我们的 Triton 内核约快 2.5× 比起 torch._grouped_mm。这些内核还有一次性自动调优步骤来选择最佳内核配置。

自动调优在训练开始时大约需要 ~2 分钟,但在 A100 上相比 _grouped_mm可以将整个运行速度提升约 35%,对于较长的运行很值得。

circle-check

🧭 自动后端选择

我们的主要创新是我们的 Split LoRA 方法 用于高效的 MoE,相较于 Transformers v5 + torch._grouped_mm,该方法使用约 35% 更少内存且训练速度快 2 倍。 torch._grouped_mm 定制的

circle-exclamation

Unsloth 将根据你的硬件自动选择以下后端之一:

后端
优化说明

grouped_mm

torch._grouped_mm — 在 T4 到 B200 上可用,但为 H100 及以上优化。

unsloth_triton

Unsloth Triton 内核 — 在 A100 上会自动启用,也适用于较旧的 PyTorch 版本。

native_torch

原生 PyTorch。它慢约 12 倍,但我们的显存减少仍然有效!

你也可以自己切换它们:

circle-check

❓什么是 torch._grouped_mm?

此前,专家混合(MoE)的权重通常作为一个 ModuleList 由各专家的线性层组成。运行前向传播的唯一实际方法是对专家进行循环,这既昂贵又非最优。

PyTorch 最近引入了 grouped_mmarrow-up-right 以解决这一确切瓶颈。与此同时,我们提供了自己的针对 MoE 优化的 Triton 内核。这也与 Transformers 的一个关键变化相一致:从 Transformers v5 起,专家权重被存储为一个 单个 nn.Parameterarrow-up-right,使得 grouped_mm 天然适配更快的 MoE 训练和推理。

因此, transformers 4.57.6arrow-up-right 的写法变更为:

改为 transformers 5.0.0arrow-up-right 的风格:

torch._grouped_mm 在从 NVIDIA T4 起的 GPU 上可用,我们已在 H100、A100、B200 和 RTX 6000 Pro 上验证过,因此支持面广泛可用。

我们还此前为 gpt-oss 引入了 Unsloth 的 Flex Attention ,这些优化应使其更高效。

📊 内核结果与基准测试

下面是在不同序列长度下与已使用 torch._grouped_mm 作为 MoE 的 Transformers v5 相比的训练速度和内存使用比较。对于 gpt-oss BF16 MoE 训练,我们在 NVIDIA B200 上看到 7 倍更快的训练和 36% 的显存减少, 对于 Qwen3-30B-A3B,其速度提升为 1.8 倍,且 GLM 4.7 Flash 在 RTX PRO 6000 上速度提升 2.1 倍,。所有基准测试均在 LoRA rank = 64 且所有 MoE 层(gate、up、down)上启用 LoRA 模块的情况下完成。

gpt-oss 基准测试

我们对 unsloth/gpt-oss-20b-BF16arrow-up-right 进行了微调以做基准测试。Unsloth 在 16K 上下文长度时快 7 倍并使用 36% 更少显存。Transformers v5 + TRL 在此场景会出现内存溢出(OOM),而 Unsloth 不会。此外,由于我们的 Long Context gpt-oss和我们的 MoE 内核,随着序列长度增加加速效果也会增加。

与 transformers v4 的比较
上下文长度
Unsloth(毫秒)
TF v5(毫秒)
Unsloth 内存(GB)
TF v5 内存(GB)
加速倍数
显存节省

1024

275.35

376.99

40.91

43.88

1.4 倍

6.76%

2048

292.88

696.57

41.83

44.93

2.4 倍

6.89%

4096

370.30

1785.89

43.68

49.86

4.8 倍

12.39%

8192

712.33

5226.86

47.43

73.80

7.3 倍

35.73%

16384

1775.80

内存溢出(OOM)

55.13

内存溢出(OOM)

不适用(N/A)

不适用(N/A)

Qwen3 基准测试

在一块 NVIDIA B200上,我们看到 Qwen3-30B-A3B LoRA 大约 1.7 倍的加速和约 35% 更好的内存效率,在更长的序列长度下内存节省会进一步提升。

令人惊讶的是,Qwen3-Next 和 Coder 在 bf16 LoRA 下可以放入单块 B200 GPU。

在 H100 GPU 上,我们的表现显著优于基线,在训练中可达到最高 1.77 倍的加速, 在 4K 上下文长度微调时还能节省约 5.3GB。虽然我们可无缝扩展到 8192 的上下文长度,但 Transformers v5 + TRL 在 8K 时会 OOM。注意我们在 8K 时使用的内存比基线在 4K 时还少,因此我们可以继续推动更长的上下文长度。

上下文长度
Unsloth(毫秒)
TF v5(毫秒)
Unsloth 内存(GB)
TF v5 内存(GB)
加速倍数
显存节省

1024

366.3

628.3

80.88

104.80

1.7 倍

2.06%

2048

467.0

745.3

80.88

104.81

1.6 倍

2.57%

4096

711.6

975.5

80.89

104.80

1.4 倍

5.08%

8192

1376.6

1633.5

80.90

104.81

1.2 倍

9.17%

16384

3182.2

3407.9

85.53

116.61

1.1 倍

15.26%

GLM 4.7 基准测试

Unsloth 在 GLM 4.7 Flash 上实现了 2.6 倍的吞吐量提升且显存减少 >15% 针对所有批次大小。GLM 4.7 Flash 是一个 30B 的 MoE(3B 活跃参数)具代理和编码能力的模型,采用与 DeepSeek MoE 风格类似的配置,具有 64 个路由专家和 1 个共享专家。我们将 Unsloth 的 MoE 训练与新优化的 Transformers v5 进行了基准比较。

使用下面我们的新 Colab 笔记本运行 GLM 4.7 Flash:

GLM 4.7 Flash MoE 笔记本 A100 80GB
上下文长度
Unsloth(毫秒)
TF v5(毫秒)
Unsloth 内存(GB)
TF v5 内存(GB)
加速倍数
显存节省

512

1145.0

2992.1

57.81

60.89

2.6 倍

6.51%

1024

1298.9

3323.3

58.76

62.55

2.6 倍

6.22%

2048

1831.9

4119.3

60.09

67.32

2.3 倍

9.46%

4096

2883.9

5646.1

63.34

76.78

2 倍

14.83%

⚡更快的 LoRA MoE 训练

在 Transformers/PEFT 中,常见做法是先将 LoRA 适配器合并到基础权重, 然后再执行 MoE 计算(尤其是因为 MoE 常常使用 nn.Parameter 而不是 nn.Linear )。问题是这种合并会有效地物化 LoRA 的增量(针对所有专家) lora_B @ lora_A.t ,这会非常占用内存 Unsloth 避免了这一点。我们此前用相同思路优化了通用的 LoRA 训练和推理,现在已将其应用于.

MoE + LoRA 。数学上是相同的,因此损失、梯度和输出保持不变。唯一的改变是 操作顺序 ,这是通过矩阵乘法的结合律实现的。通过这种重排,我们获得了大幅的加速和显存减少。这些优化在使用 Unsloth 训练 MoE 模型时默认

circle-exclamation

启用 (尤其是 Qwen-3 MoE、gpt-oss 和上文提到的模型)。你可以通过 UNSLOTH_MOE_BACKEND 环境变量切换实现:可选为 Triton 内核 torch._grouped_mm 或一个 基础的 PyTorch for-loop ,取决于兼容性与偏好。我们默认使用以获得最佳性能和广泛支持。 grouped_mm # 如果你想选择不同的后端(默认 grouped_mm),请设置以下变量:

LoRA 是一种参数高效的微调方法:你不是更新完整的权重矩阵,而是训练一个低秩的“适配器”,参数远少,从而大幅减少优化器的内存需求。

如果原始权重的形状为

(m, n) ,LoRA 添加两个可训练矩阵,其形状为(m, r) (r, n)。它们的乘积为,但你只为以下项跟踪优化器状态和梯度: ,LoRA 添加两个可训练矩阵,其形状为m*r + r*n

  • 参数(LoRA),而不是 m*n

  • 参数(完整微调)。 关于对 MoE 的微调——不建议微调路由器层,因此我们默认将其禁用。

circle-info

对于典型的 MLP 层,

m ≈ 4096,n ≈ 12k,r ≈ 64 ,大约为~1M 的 LoRA 参数 vs ~48M 的完整参数 — 大约 通常几乎没有或没有准确率损失。 ~2%, MoE 下 LoRA 的情况有所不同

MoE 层不同在于你有

E 个专家 MLP 并行存在, 因此任何逐专家的更改(例如添加 LoRA)会在所有专家上扩展。

Qwen3‑30B‑A3B 为例:隐藏维度m=2048 ,中间维度n=768 ,E=128, 专家且每个 token 激活 k=8 。每个专家: gate_proj

  • up_proj(m, n) = (2048, 768): down_proj

  • (n, m) = (768, 2048):

LoRA 秩 r=64 下,每个投影增加r*(m+n)=64*(2048+768)=180,224 每专家的参数(约为 一个 11% 2048×768 矩阵 的一部分)。核心问题是, r/n = 64/768 相对于典型的 MLP 配置而言很大,例如, r/n = 64/25600 Qwen3-32B 中为类似规模。arrow-up-right 如果你在所有

专家上将其物化,内存会迅速增加。并且由于 通常会被融合为 gate_up_proj up_proj(m, n) = (2048, 768) ,你通常会把两者一起物化,导致开销/峰值内存大致翻倍。 在内存方面,对于序列长度 s、E 个专家和选择的k

,两种方法共有以下常见项: # 所有这些值均为每个专家的量 最终输出:(s, n)

对于 Unsloth 的 Split LoRA 方法,我们执行以下操作:

Y @ loraB: (s, r) @ (r, n) # 同样对 k 个专家是稀疏的 = k s n 参数

把这些值代入,我们得到

s < 32K。 在计算量方面,对于序列长度 s

PEFT params:EmnUnsloth Split LoRA params:ks(r+n)In typical LoRA we have:rnSplit LoRA is better when:Emn>ksn  =  Em>ksFor Qwen3-30B-A3B, we haveE=128,k=8,m=2048,n=768So, Split LoRA is mathematically better whens<Emnkn=32K\begin{aligned} \text{PEFT params} &:\quad Emn \\ \text{Unsloth Split LoRA params} &:\quad ks(r+n) \\ \text{In typical LoRA we have} &:\quad r \ll n \\ \text{Split LoRA is better when} &:\quad Emn > ksn \;=\; Em > ks \\ \\ \text{For Qwen3-30B-A3B, we have} \\ E &= 128, \quad k = 8, \quad m = 2048, \quad n = 768 \\ \\ \text{So, Split LoRA is mathematically better when} \\ s &< \frac{Emn}{kn} = 32K \end{aligned}

、E 个专家和选择的前, k ,我们正在执行: # 所有这些值均为每个专家的量 在我们提到的 Unsloth split lora 情况下,我们有:

Δ=AB,ARm×r,  BRr×n2mnr flops per expert loraW=W+Δmn flopsXWXRs×m,  WRm×n2smn flopsMoE peft lora flops=E(2mnr+mn)+2ksmn\begin{aligned} \Delta = AB, A \in \mathbb{R}^{m \times r}, \; B \in \mathbb{R}^{r \times n} &\quad \Rightarrow \quad 2mnr \text{ flops per expert lora} \\ \\ W' = W + \Delta \quad &\Rightarrow \quad mn \text{ flops} \\ \\ XW' \quad | \quad X \in \mathbb{R}^{s \times m}, \; W' \in \mathbb{R}^{m \times n} \quad &\Rightarrow \quad 2smn \text{ flops} \\ \\ \text{MoE peft lora flops} &= E\big(2mnr + mn\big) + 2k\,smn \end{aligned}

从分析的角度看,Split LoRA 更优的临界点是当

XW=2smn flopsY=XA,=2smr(applied only to routed token–expert pairs) Z=YB=2srnMoE split lora flops=2k(smn+smr+srn)Crossover condition:2ksr(m+n)>2Emn(r+1/2)s>Emnk(m+n)×(1+12r)For Qwen3-30B-A3B with:E=128,  m=2048,  n=768,  k=8s    16K tokens\begin{aligned} XW &= 2smn \text{ flops} \\ Y = XA, &= 2smr \quad \text{(applied only to routed token--expert pairs)} \\ \ Z = YB &= 2srn \\ \text{MoE split lora flops} &= 2k\big(smn + smr + srn\big) \\ \text{Crossover condition} &:\quad 2ksr(m+n) > 2Emn(r+1/2) \Rightarrow s > \frac{Emn}{k(m+n)} \times (1+ \frac{1}{2r}) \\ \\ \text{For Qwen3-30B-A3B with} &: E = 128,\; m = 2048,\; n = 768,\; k = 8 \\ \\ \Rightarrow \quad s & \;\approx\; 16\text{K tokens} \end{aligned}

s > E m n / [k (m+n)] 时, 这大约是 16K token,对于 Qwen3-30B-A3B 风格的模型。

最后,部分加速来自于 减少的内存传输:现代 GPU 常常是 带宽受限的,因此传输更少的数据比 FLOPs 更重要。一个粗略的加速估计为 E m n / [k·s·(m+n)],所以它强烈依赖于 s、E、k以及矩阵形状。

🔮 模型支持

Unsloth 支持 Qwen、gpt-oss、DeepSeek 和 GLM 模型的更快 MoE 训练:

  • Qwen3 (Thinking 和 Instruct):VL • 2507 • Coder

  • gpt-oss:20B • 120B • safeguard

  • GLM:4.5 • 4.6 • 4.6-Air • 4.7 • 4.7-Flash

  • DeepSeek:V3 • R1 • V3.1 • V3.2

我们可能还没上传某些 MoE 模型,但 Unsloth 仍应支持它们。

📈 更多基准测试

gpt-oss BF16 基准

训练速度(含与 Transformers v4 的比较)

上下文长度
Unsloth(毫秒)
TF v5(毫秒)
TF v4(毫秒)
加速倍数

1024

275.35

376.99

2111.18

1.37 倍

2048

292.88

696.57

2626.80

2.38 倍

4096

370.30

1785.89

4027.93

4.82 倍

8192

712.33

5226.86

8513.52

7.34 倍

16384

1775.80

内存溢出(OOM)

内存溢出(OOM)

不适用(N/A)

显存使用(VRAM)

上下文长度
Unsloth 内存(GB)
TF v5 内存(GB)
TF v4 内存(GB)
显存节省

1024

40.91

43.88

89.75

6.76%

2048

41.83

44.93

90.47

6.89%

4096

43.68

49.86

92.72

12.39%

8192

47.43

73.80

100.3

35.73%

16384

55.13

内存溢出(OOM)

内存溢出(OOM)

不适用(N/A)

🎉 重要的 Unsloth 更新

  1. 作为我们 MoE 发布的一部分,我们还做了 Gemma-3 现在默认使用 Flex-Attention, 并且这在 float16 设置下也可工作(之前存在的无穷问题我们已解决)。 Gemma-3 现在使用 O(N) 内存而非 O(N^2),训练速度提高 >3 倍 (随上下文长度扩展时表现更好)。先前的 Unsloth 版本会出现 OOM。

上下文
旧峰值显存
新峰值显存
显存节省

1K

20.1 GB

20.1 GB

0 GB(0%)

2K

21.5 GB

21.1 GB

0.3 GB(2%)

4K

27.7 GB

23.3 GB

4.5 GB(16%)

8K

52.3 GB

27.5 GB

24.8 GB(47%)

16K

内存溢出(OOM)

36.0 GB

--

24K

内存溢出(OOM)

44.6 GB

--

32K

内存溢出(OOM)

53.1 GB

--

48K

内存溢出(OOM)

38.4 GB

--

64K

内存溢出(OOM)

44.7 GB

--

  1. 视觉微调现在接受仅包含图像和文本混合的数据!

  2. trl==0.27.1transformers==5.1.0 得到较好支持 — 之前覆盖了我们 120 个笔记本的 30%,现在覆盖率已超过 80% — 我们计划在接下来的几天内做到 100%。

circle-check

致谢

我们感谢 Hugging Face 团队与我们合作,为社区改进 MoE 训练。

我们也由衷感谢 torchao 团队,特别是 Vasily Kuznetsov (vkuzo),感谢他帮助我们使 grouped_mm 支持 float16,以便在 T4 上工作并与 A100 保持向后兼容。

最后更新于

这有帮助吗?