⚡使用 Unsloth Kernels + Packing 让 LLM 训练速度提升 3 倍
了解 Unsloth 如何提升训练吞吐量,并消除微调中的填充浪费。
Unsloth 现在支持最高 快 5× (通常 3 倍)的训练,采用我们新的自定义 RoPE 和 MLP Triton 内核,再加上我们新的智能自动打包。Unsloth 的新内核 + 新特性不仅提升训练速度,还进一步 减少 VRAM 占用(30% - 90%) 且不损失准确率。 Unsloth GitHub 这意味着你现在可以训练像 Qwen3-4B 这样的 LLM,不仅只用 3GB 显存,而且还能快 3 倍。
我们的自动 无填充 无污染打包会在所有训练运行中智能启用,无需任何改动,并且适用于所有快速注意力后端(FlashAttention 3、xFormers、SDPA)。 基准测试 显示训练损失与不打包运行一致 完全.
快 2.3 倍的 QK Rotary Embedding 支持打包的融合 Triton 内核
更新后的 SwiGLU、GeGLU 内核,支持 用于长上下文的 int64 索引
无污染打包快 2.5 倍到 5 倍 适用于 xformers、SDPA、FA3 后端
无填充快 2.1 倍,VRAM 少用 50%,准确率变化 0%
Unsloth 现在还改进了 SFT 损失稳定性,并使 GPU 利用率更可预测。
这个新升级适用于 所有训练方法 例如完整微调、预训练等。
🥁带打包的融合 QK RoPE Triton 内核
早在 2023 年 12 月,我们在发布 Unsloth 时就引入了一个用 Triton 编写的 RoPE 内核。2024 年 3 月,一位社区成员通过优化 RoPE 内核,让为一组 head 启动一个 block 成为可能,使端到端训练快了 1-2%。见 PR 238.

其中一个问题是,对于每个 Q 和 K,都有 2 个 Triton 内核。我们现在把它们合并成 1 个 Triton 内核,并且 启用了可变长度 RoPE,这对无填充和打包支持至关重要。这使得 RoPE 内核在微基准测试中 在更长上下文长度下快 2.3 倍,在更短上下文长度下快 1.9 倍。
我们还消除了所有 clone 和连续转置操作,因此 RoPE 现在完全原地执行,进一步减少 GPU 内存。注意在反向传播中,我们看到 sin1 = -sin1 因为:
🚃用于 Triton 内核的 Int64 索引
在我们于以下内容中介绍的 50 万长上下文训练期间 500K Context Training,我们会遇到 CUDA 越界错误。这是因为 SwiGLU、GeGLU 的 MLP 内核使用的是 int32 索引,而 Triton 和 CUDA 默认都是如此。
我们不能直接这样做 tl.program_id(0).to(tl.int64) ,因为使用 int64 索引会让训练稍微变慢。我们改为把它做成一个 LONG_INDEXING: tl.constexpr 变量,这样 Triton 编译器就可以对此进行特化。这让更短和更长的上下文运行都能表现出色!
🧮为什么需要填充以及数学上的加速
计算机和 GPU 无法处理不同长度的数据集,所以我们必须用 0 来填充它们。这会造成浪费。假设我们有一个数据集,其中 50% 是短序列 S,50% 是长序列 L,那么在最坏情况下,填充会导致 token 使用量为 因为最长序列长度占主导。
通过将多个示例打包成一个长的一维张量,我们可以消除大量填充。实际上我们得到如下 token 使用量:
通过一些数学和代数,我们可以通过以下方式计算加速比:
假设 那么我们会得到 2 倍的理论加速,因为
通过把 50% 短序列的比例改掉,并假设我们有更多短序列,例如 20% 长序列和 80% 短序列,我们得到 所以训练快 5 倍!这意味着打包的加速效果取决于你的数据集里有多少短行(越短越多,速度越快)。
🎬默认无填充
除了在设置时可获得的大幅吞吐提升之外 packing = True 在你的 SFTConfig 中,我们将 会自动使用无填充批处理 以减少填充浪费、提高吞吐量并提升 tokens/s 吞吐,同时带来 完全相同的损失 与 Unsloth 之前的版本一致。
例如对于 Qwen3-8B 和 Qwen3-32B,我们看到显存占用下降了 60%,速度快 2 倍,并且损失和梯度范数曲线完全相同!






♠️无污染打包,训练快 2-5 倍
真实数据集可能包含不同的序列长度,因此把 batch size 增加到 32 之类会导致填充,使训练更慢并消耗更多 VRAM。
当我们把多个样本打包成一个一维张量时,我们会保留序列长度元数据,以便正确地对样本做掩码,而不会在样本之间泄露注意力。我们还需要在 New 3x Faster Training 中描述的 RoPE 内核来允许重置 position ids。


通过把 50% 短序列的比例改掉,并假设我们有更多短序列,例如 20% 长序列和 80% 长序列,我们得到 所以训练快 5 倍!这意味着打包的加速效果取决于你的数据集里有多少短行(越短越多,速度越快)。
🏖️分析与基准测试
为了展示使用我们的新内核和打包数据训练时的各种改进,我们使用 Qwen3-32B、Qwen3-8B、Llama 3 8B 在 yahma/alpaca-cleaned 数据集上进行了微调,并测量了各种 训练损失 吞吐量和效率指标。我们将新的运行与一个标准的优化训练运行进行了比较,后者开启了我们自己的内核/优化,并启用了 Flash Attention 3(FA3)等内核。我们固定 max_length = 1024 并将 batch size 设为 {1, 2, 4, 8, 16, 32} 进行变化。这使得每个 batch 的最大 token 数变化为 {1024, 2048, 4096, 8192, 16K, 32K}。

上面的图展示了新 Unsloth 在不同 batch size 下,每秒 token 数(tokens/s)训练吞吐量如何变化。这意味着你在一个数据集 epoch 上训练模型的速度会 快 1.7-3 倍(有时甚至快 5 倍或更多)!如果你的数据中有很多短序列,并且训练轮次更长,这些收益会更加明显,如中所述 New 3x Faster Training

上面的图展示了每个 batch 中有效 token(即非填充)的平均百分比。随着 batch size 的增长,在未打包的情况下会看到更多的填充 token,而在打包的情况下,无论最大序列长度如何,我们都能获得很高的打包效率。
注意,由于 batching 逻辑会将 batch 裁剪到该 batch 中看到的最大序列长度,因此当 batch size 为 1 时,未打包的数据全都是有效 token(即没有填充)。然而,随着更多示例加入 batch,平均填充会增加,在 batch size 为 8 时几乎达到 50% 的填充!我们的样本打包实现消除了这部分浪费。


第一张图(上图)绘制了 yahma/alpaca-cleaned 替换为 max_length = 2048上的进度,Unsloth 新版本带打包 + 内核(酒红色)与 Unsloth 旧版本(灰色)对比。两者都训练于 max_steps = 500,但我们把横轴绘制为实际时间。注意,在相同步数(以及只多一点实际时间)内,打包情况下我们几乎训练了一个 epoch 的 40%,而未打包情况下连 5% 的 epoch 都不到。
同样地,第二张图(上图)绘制了相同运行的损失,这次横轴是训练步数。注意,损失在规模和趋势上都匹配,但打包情况下的损失波动更小,因为模型在每个训练步骤看到的 token 更多。
✨如何启用打包?
先更新 Unsloth,默认就会启用无填充!所以所有训练都会立刻快 1.1 到 2 倍,至少减少 30% 的内存占用,而且损失曲线指标没有任何变化!
我们还通过 Xformers 支持 Flash Attention 3,也支持 SDPA、Flash Attention 2,而且这适用于旧 GPU(Tesla T4、RTX 2080)以及新的 GPU,如 H100、B200 等!样本打包适用于 无论选择哪种注意力后端或模型家族,所以可以享受之前这些快速注意力实现带来的相同加速!
如果你想启用显式打包,那么添加 packing = True 即可实现最多 5 倍更快的训练!
我们所有的 notebook 都会自动变得更快(无需做任何事情)。见 Unsloth 笔记本
Qwen3 14B 更快:
Llama 3.1 对话更快:
谢谢你!如果你感兴趣,请查看我们的 500K Context Training 博客, 内存高效的 RL 博客,以及 Long Context gpt-oss 博客,了解更多关于内核和性能提升的主题!
最后更新于
这有帮助吗?

