🧠LoRA 微调超参数指南

逐步学习最佳的 LLM 微调设置——LoRA 的秩与 alpha、训练轮数、批量大小 + 梯度累积、QLoRA 与 LoRA、目标模块等。

LoRA 超参数是可调设置,用来决定低秩适配(Low-Rank Adaptation)如何 微调 大型语言模型(LLM)。在众多选项(例如学习率和轮次)以及无数组合下,选择正确的数值对准确性、稳定性、质量和减少幻觉至关重要。如果做得好, LoRA 可以匹配完整微调的性能 同时使用少 4 倍的显存(VRAM)。

你将学习基于数百篇研究论文和实验的见解所推荐的这些参数的最佳实践,并看到它们如何影响模型。 虽然我们建议使用 Unsloth 的默认值,但理解这些概念会让你完全掌控参数。 目标是通过更改超参数数值来提高准确性,同时对抗 过拟合或欠拟合。过拟合发生在模型记住了训练数据,损害了其对新的、未见输入的泛化能力。目标是得到一个具有良好泛化能力的模型,而不是一个仅仅会记忆的模型。

那什么是 LoRA?

在 LLM 中,我们有模型权重。Llama 70B 有 700 亿个数值。与其改变所有 700 亿个数值,我们改为在每个权重上添加细小矩阵 A 和 B,并优化这些矩阵。这样我们只优化约 1% 的权重。

我们不是优化模型权重(黄色),而是优化两个细小矩阵 A 和 B。

🔢 关键微调超参数

学习率

定义模型在每个训练步中权重调整的幅度。

  • 更高的学习率:导致更快的初始收敛,但如果设置过高可能使训练不稳定或无法找到最佳极小值。

  • 更低的学习率:导致训练更稳定且更精确,但可能需要更多轮次才能收敛,从而增加总体训练时间。虽然低学习率通常被认为会导致欠拟合,但它们实际上可能导致 过拟合 甚至阻止模型学习。

  • 典型范围: 2e-4 (0.0002)到 5e-6 (0.000005). 🟩 对于常规的 LoRA/QLoRA 微调, 我们建议 2e-4 作为起点。 🟦 对于强化学习 (DPO、GRPO 等),我们建议 5e-6 . 对于完整微调, 通常更适合使用更低的学习率。

轮次(Epochs)

模型看到完整训练数据集的次数。

  • 更多的轮次: 可以帮助模型更好地学习,但过多的轮次可能导致它 记住训练数据,从而削弱其在新任务上的表现。

  • 更少的轮次: 减少训练时间并可以防止过拟合,但如果轮次不足以让模型学习到数据集的底层模式,则可能导致训练不足的模型。

  • 推荐: 1-3 个轮次。对于大多数基于指令的数据集,超过 3 个轮次的训练收益递减并增加过拟合风险。

LoRA 或 QLoRA

LoRA 使用 16 位精度,而 QLoRA 是一种 4 位的微调方法。

  • LoRA: 16 位微调。它稍微更快且略微更准确,但消耗显著更多显存(比 QLoRA 多 4 倍)。推荐在 16 位环境或需要最高准确性的场景使用。

  • QLoRA: 4 位微调。稍慢且略微不如 LoRA 精确,但使用的显存远少(少 4 倍)。 🦥 70B LLaMA 在 Unsloth 中使用 QLoRA 可适配 <48GB 显存 —— 更多细节在此arrow-up-right.

超参数与建议:

超参数
功能
推荐设置

LoRA 秩(Rank) (r)

控制 LoRA 适配器矩阵中可训练参数的数量。较高的秩增加模型容量但也增加内存使用。

8、16、32、64、128 选择 16 或 32

LoRA Alpha (lora_alpha)

按秩缩放微调调整的强度(r).

r (标准)或 r * 2 (常用启发式)。 更多细节在此.

LoRA Dropout

一种正则化技术,在训练期间随机将一部分 LoRA 激活置为零以防止过拟合。 不太有用,所以我们默认将其设为 0。

0(默认)到 0.1

权重衰减(Weight Decay)

一种正则化项,用于惩罚过大的权重以防止过拟合并改善泛化。不要使用过大的数值!

0.01(推荐)- 0.1

预热步数(Warmup Steps)

在训练开始时逐步增加学习率。

总步数的 5-10%

调度器类型(Scheduler Type)

在训练期间动态调整学习率。

线性(linear)余弦(cosine)

种子(random_state)

一个固定数值以确保结果可复现。 42, 3407)

任何整数(例如,

目标模块(Target Modules)

指定要在哪些模型部分应用 LoRA 适配器——注意力(attention)、MLP 或两者兼顾。 注意力: q_proj、k_proj、v_proj、o_proj MLP:

gate_proj、up_proj、down_proj 建议针对所有主要线性层:.

🌳 q_proj、k_proj、v_proj、o_proj、gate_proj、up_proj、down_proj

梯度累加与批量大小等价性

有效批量大小(Effective Batch Size) 梯度累加与批量大小等价性. 梯度累加与批量大小等价性 = 正确配置你的批量大小对于在训练稳定性与 GPU 显存限制之间取得平衡至关重要。这由两个参数管理,其乘积为

  • batch_size * gradient_accumulation_steps 一个 较大的有效批量大小

  • batch_size * gradient_accumulation_steps 通常会带来更平滑、更稳定的训练。 较小的有效批量大小

可能引入更多方差。 梯度累加与批量大小等价性 尽管每个任务不同,下面的配置为在现代 GPU 上实现稳定的

16,是一个很好的起点,适用于大多数微调任务。
参数
描述

推荐设置 (批量大小(Batch Size))

batch_size 在单个 GPU 上一次前向/反向传播中处理的样本数量。显存使用的主要驱动因素

2

。更高的值可以提高硬件利用率并加快训练,但前提是它们能装入内存。 (梯度累加(Gradient Accumulation))

gradient_accumulation_steps 在执行一次模型权重更新之前需处理的微批次数。 训练时间的主要驱动因素。 批量大小(Batch Size) 允许模拟更大的

8

梯度累加与批量大小等价性 以节省显存。更高的值会增加每个轮次的训练时间。

(计算得出)

每次梯度更新使用的真实批量大小。它直接影响训练稳定性、质量和最终模型性能。

4 到 16 推荐:16(从 2 * 8)

显存与性能的权衡

  • 假设你希望每个训练步有 32 个样本。那么你可以使用以下任一配置:

  • batch_size = 32,gradient_accumulation_steps = 1

  • batch_size = 16,gradient_accumulation_steps = 2

  • batch_size = 8,gradient_accumulation_steps = 4

  • batch_size = 4,gradient_accumulation_steps = 8

  • batch_size = 2,gradient_accumulation_steps = 16

batch_size = 1,gradient_accumulation_steps = 32

虽然对于模型的权重更新这些配置等价,但它们对硬件的要求差异很大。第一个配置(batch_size = 32 )使用 最多的显存并且在大多数 GPU 上可能会失败。最后一个配置(batch_size = 32 batch_size = 1 )使用最少显存,. 但代价是训练速度会略慢一些 批量大小(Batch Size) 为避免 OOM(显存不足)错误,始终优先设置较小的 梯度累加(Gradient Accumulation) 并增加 梯度累加与批量大小等价性.

🦥 以达到你的目标

Unsloth 梯度累加修复 梯度累加和批量大小 由于我们对梯度累加的错误修复。我们已实现针对梯度累加的特定错误修复,解决了一个常见问题,即两种方法未能产生相同结果。这是更广泛社区中的一个已知挑战,但对于 Unsloth 用户而言,这两种方法现在可互换。

阅读我们的博客文章arrow-up-right 以获取更多细节。

在我们修复之前, 批量大小(Batch Size)梯度累加(Gradient Accumulation) 的组合虽然产生相同的 梯度累加与批量大小等价性 (即, batch_size × gradient_accumulation_steps = 16),但并未导致等效的训练行为。例如,像 b1/g16, b2/g8, b4/g4, b8/g2,以及 b16/g1 都具有 梯度累加与批量大小等价性 为 16,但如图所示,在使用标准梯度累加时损失曲线并未对齐:

(修复前 - 标准梯度累加)

在应用我们的修复后,损失曲线现在会正确对齐,无论如何实现 梯度累加与批量大小等价性 为 16:

(修复后 - 🦥 Unsloth 梯度累加)

🦥 Unsloth 中的 LoRA 超参数

以下演示了一个标准配置。 虽然 Unsloth 提供了优化的默认值,但理解这些参数对手动调优至关重要。

  1. 微调过程的秩(r)。更大的秩使用更多内存且会更慢,但可以在复杂任务上提高准确性。我们建议使用像 8 或 16(用于快速微调)等秩,最大可到 128。使用过大的秩可能导致过拟合并损害模型质量。\

  2. 为获得最佳性能, 应将 LoRA 应用于所有主要线性层. 研究表明 针对所有主要层对于匹配完整微调的性能至关重要。虽然可以移除某些模块以减少内存使用,但我们强烈不建议这样做以保留最大质量,因为节省是微乎其微的。\

  3. 一个缩放因子,用于控制微调调整的强度。将其设置为等于秩(r)是一个可靠的基线。一个流行且有效的启发式是将其设置为秩的两倍(r * 2),这会通过给 LoRA 更新赋予更大权重使模型学习更积极。 更多细节在此.\

  4. 一种正则化技术,帮助 防止过拟合 ,通过在每个训练步随机将一部分 LoRA 激活置为零来实现。 近期研究表明arrow-up-right 对于 在微调中常见的短训练运行lora_dropout 可能不是一个可靠的正则化手段。 🦥 lora_dropout = 0时,Unsloth 的内部代码可以在训练时进行优化,速度略快一些,但如果你怀疑存在过拟合,我们建议使用非零值。\

  5. 保持此项为 "none" 以加快训练并减少内存使用。此设置避免训练线性层中的偏置项,因为这会增加可训练参数但在实际中几乎没有收益。\

  6. 选项有 True, False,以及 "unsloth". 🦥 我们推荐 "unsloth" 因为它额外减少约 30% 的内存使用并支持极长上下文的微调。你可以在 我们关于长上下文训练的博客文章arrow-up-right.\

  7. 用于确保确定性、可复现运行的随机种子。训练涉及随机数,因此设置固定种子对获得一致的实验结果至关重要。\

  8. 一个高级功能,实现了 秩稳定的 LoRAarrow-up-right。如果设置为 True,有效缩放变为 lora_alpha / sqrt(r) 而不是标准的 lora_alpha / r。这有时可以提高稳定性,特别是在较高秩时。 更多细节在此.\

  9. 一种高级技术,如 LoftQarrow-up-right所提出的那样,用预训练权重的前 'r' 个奇异向量初始化 LoRA 矩阵。这可以提高准确性,但可能在训练开始时导致显著的内存峰值。

验证 LoRA 权重更新:

在验证 LoRA 适配器权重在微调后已更新时,请避免使用 np.allclose() 进行比较。该方法可能会错过细微但有意义的变化,尤其是在 LoRA A中,它以较小的高斯值初始化。在宽松的数值容差下,这些变化可能不会被视为显著。感谢 贡献者arrow-up-right 提供本节内容。

为了可靠地确认权重更新,我们建议:

  • 使用 校验和或哈希比较 (例如,MD5)

  • 计算 张量之间绝对差值的和 之间的张量

  • 检查张量统计 (例如,均值、方差)手动查看

  • 或使用 np.array_equal() 如果期望精确相等

📐LoRA Alpha 与 秩 的关系

circle-check
W^=W+αrank×AB\hat{W} = W + \frac{\alpha}{\text{rank}} \times AB
rsLoRA 的其他缩放选项。sqrt(r) 是最好的。
W^rslora=W+αrank×AB\hat{W}_{\text{rslora}} = W + \frac{\alpha}{\sqrt{\text{rank}}} \times AB

LoRA 的公式在左侧。我们需要将细矩阵 A 和 B 乘以 alpha 除以秩来缩放。 这意味着我们应保持 alpha/秩 至少 = 1.

根据 rsLoRA(秩稳定 LoRA)论文arrow-up-right,我们应改为按秩的平方根来缩放 alpha。还有其他选项,但理论上这是最优的。左图展示了其他秩及其困惑度(越低越好)。要启用此项,请设置 use_rslora = True 在 Unsloth 中。

我们的建议是将 alpha 设为等于秩,或至少为秩的 2 倍。 这意味着 alpha/秩 = 1 或 2。

🎯 LoRA 目标模块与 QLoRA 对比 LoRA

circle-check

根据经验实验和像原始 QLoRA 论文arrow-up-right这样的研究,最好将 LoRA 应用于注意力和 MLP 层两者。

图表显示了不同目标模块配置下的 RougeL 分数(越高越好),对比 LoRA 与 QLoRA。

前三个点显示:

  1. QLoRA-All: 将 LoRA 应用于所有 FFN/MLP 和注意力层。 🔥 这总体上表现最佳。

  2. QLoRA-FFN:仅在 FFN 上使用 LoRA。 等价于: gate_proj, up_proj, down_proj。

  3. QLoRA-Attention:仅在注意力层上应用 LoRA。 等价于: q_proj, k_proj, v_proj, o_proj.

😎 仅在完成部分上训练,屏蔽输入

QLoRA 论文arrow-up-right 显示,屏蔽输入并 仅在完成部分上训练 (输出或助理消息)可以进一步 提高准确性 几个百分点(1%)。下面演示了在 Unsloth 中如何实现:

不是 仅在完成部分上训练:

用户: 你好,2+2 等于多少? 助理: 答案是 4。 用户: 你好,3+3 等于多少? 助理: 答案是 6。

在完成部分上训练: 答案是 6

用户: 你好,2+2 等于多少? 助理: 答案是 4。 用户: 你好,3+3 等于多少? 助理: QLoRA 论文指出,.

仅在完成部分上训练 能显著提高准确性,尤其适用于多轮对话微调!我们在 我们的对话笔记本中这样做 要启用arrow-up-right.

仅在完成部分上训练 在 Unsloth 中,你需要定义指令和助理部分。 我们计划未来为你进一步自动化这一步! 🦥 对于 Llama 3、3.1、3.2、3.3 和 4 模型,你按如下方式定义部分:

from unsloth.chat_templates import train_on_responses_only

instruction_part = "<start_of_turn>user\n",

🔎对于语言模型,我们可以如前所述使用

。对于视觉模型,将额外参数作为 trainer = train_on_responses_only( UnslothVisionDataCollator 的一部分使用,就像之前一样! class UnslothVisionDataCollator:

UnslothVisionDataCollator(

🔑 过拟合

(泛化差/过于专门化) 模型记住了训练数据,包括其中的统计噪声,因此无法很好地泛化到未见的数据。

如果你的训练损失降到 0.2 以下,你的模型很可能

circle-check

调整学习率:

  • 较高的学习率常常导致过拟合,尤其是在短期训练中。对于更长的训练,较高的学习率可能更有效。最好尝试两种设置以找出最佳表现。 减少训练轮数

  • 。在 1、2 或 3 个 epoch 后停止训练。增加

  • weight_decay 。一个的值是一个好的起点。 0.010.1 。使用像

  • weight_decay lora_dropout这样的值来增加正则化。 0.1 增加批量大小或梯度累积步数

  • 扩展数据集.

  • - 通过将开源数据集与您的数据集合并或串联来增大数据集规模。选择更高质量的集合。 提前停止评估

  • - 启用评估并在评估损失连续上升若干步时停止。 LoRA Alpha 缩放

  • - 在训练后及推理期间缩小 alpha — 这会使微调效果不那么显著。 权重平均

  • - 直接将原始 instruct 模型和微调权重相加,然后将权重除以 2。 欠拟合

(过于通用) 模型未能捕捉训练数据中的潜在模式,通常是由于模型复杂度或训练时长不足造成的。

调整学习率:

调整学习率:

  • 如果当前学习率过低,增加学习率可能会加快收敛,尤其是在短期训练中。对于较长训练,尝试降低学习率。测试两种方法以确定哪种更有效。 增加训练轮数:

  • 训练更多 epoch,但监控验证损失以避免过拟合。 增加 LoRA 秩

  • )和 alpha:秩应至少等于 alpha 数量,对于较小模型/更复杂的数据集应使用更大的秩;通常在 4 到 64 之间。 (r使用更符合领域的数据集

  • :确保训练数据高质量并与目标任务直接相关。将批量大小减小到 1

  • 。这将导致模型更新更为剧烈。微调没有单一的“最佳”方法,只有最佳实践。实验是为你的具体需求找到有效方法的关键。我们的笔记本基于大量论文研究和我们的实验自动设置了最佳参数,为你提供了一个很好的起点。祝微调愉快!

circle-check

致谢: 非常感谢 Eyeraarrow-up-right 为本指南做出贡献!

最后更新于

这有帮助吗?