详细摘要 摘要
生成: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产生非零更新。
- 原因:训练开始时,由于B为零,
- 更新后的权重
- 评价: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)设置为可训练。
- 在LoRA配置中设置
- 实验表现与评价 (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)。
- 在SFTTrainer中添加参数
- 实验表现与评价 (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。
- 在DoRA配置基础上,SFTTrainer中添加
- 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)可能带来更大改进。
- 具体建议:
- Unsloth:如果模型受支持,推荐使用以获得速度提升。"it generally is a no-brainer to use that"。
- NEFT:推荐添加。这是一个简单的参数更改,似乎不会降低性能,且可能带来改善。
- DoRA:目前不推荐使用,因为它显著减慢了微调速度,除非它得到进一步优化并正式集成到Transformers库中。
- LoRA+:可能提供加速或性能提升,但需要用户愿意花时间优化B矩阵相对于A矩阵的学习率比例。除非进行非常长的训练任务并愿意前期进行超参数搜索,否则可能不值得投入精力。