详细摘要 摘要

生成:2025-05-31 19:44

摘要详情

音频文件
Trelis Research | Fine tuning Optimizations - DoRA, NEFT, LoRA+, Unsloth
摘要类型
详细摘要
LLM 提供商
openai
LLM 模型
gemini-2.5-pro-exp-03-25
已创建
2025-05-31 19:44:39

概览/核心摘要 (Executive Summary)

该内容详细介绍了LoRA (Low-Rank Adaptation) 及其多种微调优化技术,包括DoRA (Directional LoRA)、NEFT (Noisy Embeddings Fine-Tuning)、LoRA+ (LoRA Plus) 和 Unsloth。LoRA通过训练小型适配器矩阵来高效微调大语言模型,但有时性能不及全量微调。DoRA试图通过分解权重为幅度和方向,并对方向进行LoRA式调整,同时训练幅度,以期接近全量微调效果,但目前实现版本较慢。LoRA+则为LoRA的A、B矩阵设置不同学习率,B矩阵使用更高学习率以加速收敛,但需要调优学习率比例。NEFT通过在嵌入层添加噪声来减少过拟合,提升模型对高层特征的感知,实现简单且有效。Unsloth是一套底层优化技术,旨在显著提升微调速度(宣称2倍以上),主要支持Llama系列模型,但对代码有一定修改要求。

演讲者通过Jupyter Notebook展示了这些技术的实现和初步效果。实验表明,NEFT添加噪声能带来轻微的验证损失降低且不增加训练时间。Unsloth确实能带来速度提升,但在短时评估为主的实验中不明显。DoRA当前版本因未优化而导致训练时间显著增加,性能提升不明显。LoRA+的效果在初步实验中不突出,且需要额外调优学习率比例。最终建议,在模型支持的情况下优先使用Unsloth提升速度,并考虑加入NEFT提升性能;DoRA待优化和官方集成后再考虑;LoRA+则适用于愿意投入时间进行超参数搜索的较长任务。

LoRA 基础回顾

Speaker 1 首先回顾了LoRA的工作原理,它是目前一种常见的语言模型微调方法。

  • 工作原理
    • 避免微调语言模型中的所有参数。语言模型包含多个模块,每个模块都有权重矩阵。
    • 针对模型中的每个大型权重矩阵W(例如1000x1000,100万参数),LoRA的做法是冻结原始权重W。
    • 引入两个较小的可训练矩阵A(例如1000x8)和B(例如8x1000),它们的乘积 B_transpose * A 形成对原始矩阵W的更新。
    • 这样,仅需训练A和B中的参数(此例中约16000参数),远少于原始矩阵的参数量。
    • 这种方式不仅减少了训练参数,还因训练适配器而产生一种平滑效果,使更新更均匀。
  • 关键方程与初始化
    • 更新后的权重 W_new = W_original + B_transpose * A
    • 训练结束后,适配器的权重会合并到原始权重W中。
    • 初始化:矩阵B初始化为零,矩阵A初始化为随机值。
      • 原因:训练开始时,由于B为零,B * A 也为零,模型等同于原始模型。随着训练进行,A和B被更新,B * A 产生非零更新。
  • 评价:Speaker 1 认为 "LoRA works very well, and it still works very well. So if you're happy using LoRA, in most cases, I would stick with that."

DoRA (Directional LoRA)

DoRA 是对 LoRA 的一种改进,旨在使性能更接近全量微调。

  • 核心思想与机制
    • 将原始权重矩阵W分解为一个幅度(magnitude)(可视为标量或向量)和一个方向(direction)矩阵。
    • W_original ≈ m * Directional_Matrix
    • LoRA的微调(即A、B矩阵)不再直接应用于W,而是应用于分解后的方向矩阵
    • 同时,幅度 m 本身也成为可训练的参数
    • 因此,DoRA可以看作是:允许原始权重矩阵的幅度可调,并使用LoRA来训练其方向。
    • 公式化表述:W_new ≈ trainable_m * (Directional_Matrix_original + B*A)
  • 实现方式 (Hugging Face Trainer):
    • 在LoRA配置中设置 use_dora=True
    • 将LoRA的幅度向量(即 m)设置为可训练。
  • 实验表现与评价 (Speaker 1)
    • 性能:在演讲者的聊天微调实验中,验证损失略差于原始LoRA (1.127 vs 1.121)。在另一次函数调用微调中,DoRA得分略有提升 (0.856 vs LoRA的0.86),正确答案百分比略高。
    • 速度:训练时间显著增加(约27分钟 vs LoRA的12分钟),因为 "Dora is not yet fully optimized"。
    • 结论:Speaker 1 认为 "until Dora is optimized a bit more and it'd be nice when it's merged into transformers, I don't think that using it is justified because of the slowdown. And also, there's not a very significant improvement"。

LoRA+ (LoRA Plus)

LoRA+ 是对LoRA的另一种修改,关注优化器层面。

  • 核心思想与机制
    • 为LoRA的两个矩阵A和B设置不同的学习率
    • 通常优化时,所有矩阵使用相同学习率。
    • LoRA+ 提出,对于初始化为零的矩阵B,可以使用相对更高的学习率。
    • 直觉解释 (演讲者称 "slightly inexact"): 矩阵B从零开始,需要更快达到非零稳态,因此可以承受更高的学习率。
    • 论文建议B的学习率最高可达A的16倍。
    • 目标:实现LoRA训练中更快的收敛。
  • 实现方式
    • 不改变LoRA本身的配置,而是修改优化器。
    • 演讲者展示了自定义优化器代码,该代码将参数分为A组和B组,并为B组应用一个学习率乘数。
  • 实验表现与评价 (Speaker 1)
    • 演讲者尝试了20倍的学习率比例,发现模型不稳定,验证损失很高。后改为2倍。
    • 在使用Unsloth和LoRA+(学习率比例为2)的组合实验中,验证损失为1.10,优于基准LoRA的1.121。
    • 但与单独使用Unsloth(验证损失1.105)相比,提升不明显。
    • 结论:Speaker 1 认为 "the performance is not really changing all that much whether I use Unsloth or whether I use the optimizer with Laura B being trained at a faster rate." 可能需要更多步骤或更细致的比例调整才能看到明显效果。由于需要调优学习率比例,"that makes it quite a bit less practical for when you just want to get a fine tuning done"。

NEFT (Noisy Embeddings Fine-Tuning)

NEFT 是一种通过在嵌入层添加噪声来改进微调效果的技术。

  • 核心思想与机制
    • 在微调过程中,向模型的嵌入层(embedding layers)添加噪声(通常是高斯噪声)。
    • 嵌入层负责将token转换为向量表示。
    • 非LoRA特定技术,可以与其他微调方法结合。
  • 益处
    • 使语言模型更好地理解训练数据的高层特征。
    • 减少对可能导致过拟合的“一次性粒度 (one-off granularity)”的过度关注。
    • 通过添加少量噪声改善微调性能。
  • 实现方式 (SFTTrainer):
    • 在SFTTrainer中添加参数 neftune_noise_alpha (例如设置为5)。
  • 实验表现与评价 (Speaker 1)
    • 在DoRA的基础上添加NEFT,验证损失从DoRA的1.127(或LoRA基准的1.121)降低到约1.116/1.117。
    • 训练时间没有明显增加。
    • 结论:Speaker 1 认为 "it's a parameter that's worth adding in... It's quite a simple ad."

Unsloth

Unsloth 是一个专注于提升微调速度的项目。

  • 核心思想与机制
    • 并非LoRA的直接修改,但支持与LoRA一同使用。
    • 通过深入研究微调过程的细节,应用大量小的底层优化(如矩阵乘法优化、计算合并)来实现整体加速。
    • 目标是达到 "at least usually a two x speed up"。
  • 集成与限制 (Hugging Face Transformers):
    • 加载模型:需使用 FastLanguageModel 替代 AutoModelForCausalLM
    • 应用LoRA适配器 (PEFT):同样需要使用 FastLanguageModel
    • 模型支持:主要支持Llama类型的模型(包括Mistral及模型的Llama化版本)。
    • 技术差异:例如,不能应用LoRA dropout(一种防止过拟合的技术)。
    • 兼容性:可与SFTTrainer等工具配合使用,也可叠加NEFT或LoRA+等优化。
  • 实验表现与评价 (Speaker 1)
    • 在演讲者的短时(20步)实验中,标准LoRA耗时约12分钟,Unsloth耗时略少于11分钟。
    • 速度提升未达2倍的原因:实验运行时间短,且包含多次评估,评估时间占比较大,掩盖了训练本身的加速效果。
    • 结论:Speaker 1 肯定 "Unsloth is bringing a speed up though. And so generally, I would recommend if the model is supported by Unsloth, it generally is a no-brainer to use that as a form of training."

各项优化技术对比概览 (Speaker 1 观点)

特性 DoRA LoRA+ NEFT Unsloth
模型支持 几乎所有Hugging Face支持的模型 几乎所有Hugging Face支持的模型 几乎所有Hugging Face支持的模型 有限,主要是Llama类型模型
质量提升 有一些提升潜力 有一些提升潜力 有一些提升 主要是速度提升 (约2倍)
设置难度 简单 (一个参数 + 设置幅度向量可训练) 较难 (需要自定义优化器代码,调优学习率比例) 非常简单 (SFTTrainer中一个标志位) 相对简单运行,但安装可能涉及CUDA驱动问题,代码需修改模型加载方式

Notebook 实践与关键配置

Speaker 1 使用了Mistral 7B基础模型进行聊天微调实验,并在RunPod的A6000 GPU (CUDA 12.1) 环境下运行Jupyter Notebook。所有实验仅运行20个训练步骤以便比较。

  • 实验环境
    • GPU: NVIDIA A6000
    • 平台: RunPod (CUDA 12.1 one-click template)
    • 基础模型: Mistral 7B base model
    • 数据类型: bfloat16
    • 关键库: Transformers, PEFT, Accelerate, TRL (SFTTrainer)
    • 数据集: openassistant-guanaco (已适配Llama/Mistral聊天格式)
  • 基准 LoRA 配置与结果
    • 目标模块: q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj
    • use_dora=False
    • 重要补充: 将 embed_tokens 和各类 norm 层 (如 input_layernorm, post_attention_layernorm) 设置为完全可训练 (非LoRA),Speaker 1 强调这对于聊天微调获取良好性能非常重要。
    • 训练参数: batch_size=4, gradient_accumulation_steps=8 (有效批次32), AdamW优化器, 学习率 1e-4
    • 结果 (20步): 训练耗时约 12分钟,验证损失约 1.121
  • DoRA 配置与结果
    • 安装特定PEFT分支以支持DoRA。
    • use_dora=True,确保 lora_magnitude_vector 可训练。
    • 结果 (20步): 训练耗时约 27分钟,验证损失 1.127
  • NEFT (结合DoRA) 配置与结果
    • 在DoRA配置基础上,SFTTrainer中添加 neftune_noise_alpha=5
    • 结果 (20步): 训练耗时约 27分钟,验证损失 1.116 / 1.117
  • LoRA+ (结合Unsloth) 配置与结果
    • 使用Unsloth加载模型。
    • 自定义优化器,设置LoRA B矩阵学习率是A矩阵的2倍 (loraplus_lr_ratio=2)。
    • 结果 (20步): 验证损失 1.10
  • Unsloth 单独表现
    • 使用Unsloth加载模型,标准AdamW优化器。
    • 结果 (20步): 训练耗时略少于 11分钟,验证损失 1.105

数据与统计信息

以下为演讲者在20步短时聊天微调实验中观察到的主要数据:

  • LoRA (基准):
    • 训练时间: ~12 分钟
    • 验证损失: ~1.121
  • DoRA:
    • 训练时间: ~27 分钟
    • 验证损失: 1.127
  • DoRA + NEFT (noise_alpha=5):
    • 训练时间: ~27 分钟
    • 验证损失: ~1.116 - 1.117
  • Unsloth + LoRA+ (lr_ratio=2):
    • 训练时间: [原文未明确与Unsloth单独比较的时间差异,但Unsloth本身约11分钟]
    • 验证损失: 1.10
  • Unsloth (单独):
    • 训练时间: < 11 分钟
    • 验证损失: 1.105

核心观点与最终建议 (Speaker 1)

  • 通用观察
    • 各项优化的效果和所需努力不尽相同,并非所有技术都能带来明确收益。
    • 结果高度依赖于具体的微调任务。对于更复杂的任务,这些优化(尤其是LoRA+和DoRA)可能带来更大改进。
  • 具体建议
    1. Unsloth:如果模型受支持,推荐使用以获得速度提升。"it generally is a no-brainer to use that"。
    2. NEFT推荐添加。这是一个简单的参数更改,似乎不会降低性能,且可能带来改善。
    3. DoRA目前不推荐使用,因为它显著减慢了微调速度,除非它得到进一步优化并正式集成到Transformers库中。
    4. LoRA+可能提供加速或性能提升,但需要用户愿意花时间优化B矩阵相对于A矩阵的学习率比例。除非进行非常长的训练任务并愿意前期进行超参数搜索,否则可能不值得投入精力。