LoRA+: Efficient Low Rank Adaptation of Large Models
24年2月12的论文,主要思想就是对LoRA进行了一些改进,提升了模型效果。
摘要
证明了对Lora的A和B使用相同的学习率无法有效的特征学习。还证明了通过以一个良好选择的固定比率设置不同的学习速率来修正,可以提升模型效果。这种算法为LoRA+。在实验中,LoRA+提高了性能(1%的−2%的提高)和微调速度,计算成本与LoRA相同。
代码实现
完整代码均放在了git代码仓库:https://github.com/mst272/simple-lora-plus
原理了解完开始从代码部分构建一下lora+。本次我们以使用deepseek-coder进行微调为例,在原始版本中加入lora以及lora+模块。
deepseek-coder微调代码部分取自官方的实现,相关说明大家可以自行去查找。改动主要是首先实现了lora微调,基于此进行了lora+的进一步改造。
正常的lora中A和B的学习率是一样的,简单来说Lora+原理即为对 lora中的A和B设置不同的学习率,且论文中给出了一些设置推荐。
现阶段训练代码大多都是用huggingface的transformers框架,基于此修改学习率,需要对trainer中进行一些魔改。
Trainer类概览
进入huggingface 的trainer类代码,真的是很复杂,不过我们这次的话只需要了解一下其create_optimizer方法即可。如下所示:
我们要做的就是写一个继承Trainer的新的Trainer类,重写create_optimizer方法,调整学习率就ok了。
查看其函数走向流程,前面的就是一些判定等,直接复制即可。optimizer_grouped_parameters就到了参数的相关设定,他这个源代码在这里没有设置学习率是因为都是统一的学习率,所以其直接在get_optimizer_cls_and_kwargs函数中设置了。
我们改写的话就直接在这里筛选出你要设置不同学习率的层即可,通过get_peft_model获取lora后的模型参数一般都是带有lora_a,lora_b部分的,我们即可通过model.parameters进行筛选层,分别设置不同学习率。(关于如何通过model.named_parameters()浏览模型层,改写等操作后续计划写一篇记录一下)。这一部分的改写在git中的lora_olus.py文件中的create_lorap_optimizer函数,详细的如何改写感兴趣的可以去看一下。
其他的重点就是如下两行,通过get_optimizer_cls_and_kwargs函数获取optimizer,大家对照Trainer源码点进去看一下这两行怎么实现的,基本就对如何改有数了。
optimizer_cls, optimizer_kwargs = Trainer.get_optimizer_cls_and_kwargs(self.args)
self.optimizer = optimizer_cls(optimizer_grouped_parameters, **optimizer_kwargs)
Trainer的继承与改写
最终我们创建一个新的Trainer类,改写其create_optimizer方法,然后在模型的脚本中调用即可。改写代码如下:
class LoraPlusTrainer(Trainer):
def create_optimizer(self):
opt_model = self.model_wrapped if is_sagemaker_mp_enabled() else self.model
if self.optimizer is None:
optimizer_cls, optimizer_kwargs = Trainer.get_optimizer_cls_and_kwargs(
self.args
)
lora_lr_ratio = LORA_LR_RATIO
lora_lr_embedding = LORA_LR_EMBEDDING
self.optimizer = create_lorap_optimizer(opt_model, lora_lr_ratio, optimizer_cls, optimizer_kwargs,
lora_lr_embedding)
if is_sagemaker_mp_enabled():
self.optimizer = smp.DistributedOptimizer(self.optimizer)
return self.optimizer
使用
使用也非常简单,覆盖即可,基本都不用动。另外要注意的是如果使用deepspeed进行训练,因为官方即使用deepspeed进行训练,zero3策略中的优化器及学习率等设置要进行删除。
#原始
# trainer = Trainer(model=model, tokenizer=tokenizer, args=training_args, **data_module)
# 加入lora+ Trainer
trainer = LoraPlusTrainer(model=model, tokenizer=tokenizer, args=training_args, **data_module)