- 人工智能
- 大模型
- 微调
- LoRA
【免费下载链接】peft
🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.
DeLoRA(Decoupled Low-Rank Adaptation,解耦低秩自适应)是 PEFT 库中新增的一种参数高效微调方法,其核心思想是在 Frobenius 范数有界(Frobenius-norm bounded)的设置下进行微调,通过对低秩矩阵 BA 进行归一化、引入可学习的缩放因子 λ、以及按层对原始权重范数 ‖W‖ 进行缩放,从而将"更新方向(角度)"与"更新强度(幅度)"的学习解耦,防止模型偏离预训练权重过远。本文以 examples/delora_finetuning/README.md 为主体,结合 DeloraConfig 源码、DeloraLayer 实现 与完整可运行的 delora_finetuning.py 示例脚本,从原理、API、训练、推理到调参实践,为你提供一份可直接上手的完整指南。
DeLoRA 的动机与核心机制
为什么需要"有界"微调
主流 PEFT 方法(如 LoRA)在超参数选择不恰当或训练轮次过长时,容易出现对超参数敏感、微调后模型偏离预训练分布过远的问题。而 ETHER 等有界方法虽然鲁棒性更好,但仅限于极低秩和固定强度变换,表达力受限。DeLoRA 的出发点正是在两者之间取得平衡:显式约束权重更新的 Frobenius 范数上界,在不牺牲表达力的前提下提升鲁棒性。
三项关键设计
根据原文档,DeLoRA 通过三个步骤实现上述目标(详见 DeloraLayer._compute_delta):
- BA 低秩矩阵归一化:对 A 矩阵的行范数与 B 矩阵的列范数进行归一化,从而为权重更新 ΔW 施加 Frobenius 范数边界;
- 可学习缩放参数 λ(delora_lambda):控制更新的边界/幅度,替代 LoRA 中的
lora_alpha,对每次更新的最大范数设上限; - 按层缩放 ‖W‖(delora_w_norm):在初始化时冻结记录每个被适配层原始权重的逐列范数,将更新幅度适配到原始权重的量级,避免"小范数层被大更新淹没"或反之。
从源码看,前向传播中的 ΔW 计算可以拆解为(对应 layer.py 的 forward 实现):
h = (x * w_norm) @ A.T # 步骤 1:逐输入通道按原始权重范数缩放 scaling = (λ / r) / (‖A_i‖ · ‖B^j‖) # 步骤 2:对角缩放矩阵 diag(λ/r / (‖A_i‖·‖B^j‖)) h = h @ B.T # 步骤 3:投影回输出空间其中An = clamp(‖A‖行范数, min=1e-4)、Bn = clamp(‖B‖列范数, min=1e-4)用于数值稳定性,最终 ΔW = B · diag(λ/r/(‖A_i‖·‖B^j‖)) · A,再乘以冻结的 w_norm。与 LoRA 的固定alpha/r缩放不同,这里的缩放因子随训练中 A、B 的范数动态变化,从而持续约束更新范数。
DeLoRA 与 DoRA 的对比
DoRA 与 DeLoRA 都旨在解耦"角度(方向)"与"幅度(magnitude)"的学习,但存在关键差异(原文档明确说明):
| 维度 | DoRA | DeLoRA |
|---|---|---|
| 归一化/缩放作用对象 | 全量微调后的权重W + ΔW | 权重更新ΔW本身 |
| 归一化空间 | 权重矩阵的列空间 | 内部的低维空间 |
| 防发散效果 | 较弱 | 直接在更新上设界,更好防止偏离预训练模型 |
简言之,DeLoRA 把边界约束直接加在更新量上,因此对"偏离预训练模型"的抑制更强。
快速开始:在 PEFT 中使用 DeLoRA
最小化训练示例
将标准的LoraConfig替换为DeloraConfig即可。注意:lora_alpha被delora_lambda取代,它给权重变化的 Frobenius 范数设置上界。原文档给出的完整示例(训练 + 推理):
import torch from peft import DeloraConfig, get_peft_model from transformers import AutoTokenizer, AutoModelForCausalLM from trl import SFTConfig, SFTTrainer from datasets import load_dataset model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3-8B", dtype=torch.bfloat16, device_map="auto") tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B") tokenizer.pad_token_id = tokenizer.eos_token_id delora_config = DeloraConfig(r=32, delora_lambda=15) peft_model = get_peft_model(model, delora_config) peft_model.print_trainable_parameters() dataset = load_dataset("imdb", split="train[:1%]") training_args = SFTConfig(dataset_text_field="text", max_length=128) trainer = SFTTrainer( model=peft_model, args=training_args, train_dataset=dataset, processing_class=tokenizer, ) trainer.train() peft_model.save_pretrained("delora-llama-3-8b")加载微调后的 DeLoRA 模块
微调产物与 LoRA 完全兼容同一套 PEFT 加载机制:
import torch from peft import PeftModel from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained( "meta-llama/Meta-Llama-3-8B", dtype=torch.bfloat16, device_map="auto" ) peft_model = PeftModel.from_pretrained(model, "delora-llama-3-8b")保存的权重包含delora_A、delora_B、delora_lambda以及持久化的delora_w_normbuffer(见 DeloraLayer 的参数定义),可直接用于推理或继续训练。
DeloraConfig 参数详解
以下是DeloraConfig的完整参数清单(依据 config.py 源码):
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
r | int | 8 | DeLoRA 适配器的秩,必须是正整数(r <= 0会抛ValueError) |
delora_lambda | int | 15 | 边界 λ 的初始值,给权重变化的 Frobenius 范数设上界,防止微调模型偏离原始模型过远 |
module_dropout | float | 0.0 | 训练中随机禁用 DeLoRA 模块的丢弃概率(不同于常规 dropout) |
target_modules | Optional[Union[list[str], str]] | None | 应用适配器的模块名;传字符串按正则匹配,传列表按精确/后缀匹配;'all-linear'匹配除输出层外所有 linear/Conv1D;不指定时按架构自动选择(未知架构会报错,需手动指定) |
exclude_modules | Optional[Union[list[str], str]] | None | 需要排除的模块名,规则同target_modules |
bias | Literal["none", "all", "delora_only"] | "none" | DeLoRA 的偏置训练策略;注意设为all/delora_only后,即使禁用适配器,模型输出也不会与基座模型完全一致 |
init_weights | bool | True | 为 True 时 A 用 kaiming uniform 初始化、B 用零初始化(初始 ΔW=0);为 False 时 A、B 均为 kaiming uniform,立即产生非零增量,一般不建议 |
layers_to_transform | Optional[Union[list[int], int]] | None | 只对指定索引的层施加适配器 |
layers_pattern | Optional[Union[list[str], str]] | None | 配合layers_to_transform使用,指向模型的nn.ModuleList(常为'layers'或'h');指定了layers_pattern却未指定layers_to_transform会报错 |
rank_pattern | dict | {} | 按层名/正则指定不同秩,如{'^model.decoder.layers.0.encoder_attn.k_proj': 16} |
lambda_pattern | dict | {} | 按层名/正则指定不同 λ,如{'^model.decoder.layers.0.encoder_attn.k_proj': 16} |
modules_to_save | Optional[list[str]] | None | 除适配器层外需要设为可训练并保存的模块(如分类头的classifier/score) |
另外两点来自源码的约束校验:
target_modules传入字符串(正则)时,不能同时使用layers_to_transform,否则抛ValueError(config.py 第 154-155 行);peft_type会被自动设为PeftType.DELORA,与LoraConfig等一同在 PeftConfig 体系 中注册。
当前实现约束
根据 docs/source/package_reference/delora.md 与 model.py 的_create_new_module,DeLoRA 目前有以下限制:
- 仅支持
torch.nn.Linear层,其他层类型会抛出TypeError; - 不支持量化层(如 bitsandbytes 的 4/8 bit 层);
- 若你的场景不满足上述约束,请改用其他 PEFT 方法(如标准 LoRA)。
使用完整脚本微调 Llama 系模型
仓库提供了开箱即用的命令行训练脚本 examples/delora_finetuning/delora_finetuning.py(基于 randlora 示例脚本改造),内部使用DeloraConfig+transformers.Trainer完成因果语言建模微调。
完整训练命令
原文档给出的完整参数示例:
python delora_finetuning.py \ --base_model "PATH_TO_MODEL" \ --data_path "PATH_TO_DATASET" \ --output_dir "PATH_TO_OUTPUT_DIR" \ --batch_size 1 \ --num_epochs 3 \ --learning_rate 3e-3 \ --cutoff_len 512 \ --val_set_size 500 \ --eval_step 10 \ --save_step 100 \ --device "auto" \ --rank 32 \ --delora_lambda 15 \ --module_dropout 0.1 \ --target_modules "q_proj,v_proj" \ --hub_model_id "YOUR_HF_REPO" \ --push_to_hub命令行参数与脚本默认值
结合 脚本 argparse 定义,各参数说明如下:
| 参数 | 默认值 | 说明 |
|---|---|---|
--base_model | huggyllama/llama-7b | 基座模型路径或 HF 名称 |
--data_path | timdettmers/openassistant-guanaco | 数据集路径或名称 |
--output_dir | path/to/output | 微调产物输出目录 |
--batch_size | 1 | 每设备批大小 |
--num_epochs | 1 | 训练轮数 |
--learning_rate | 3e-3 | 学习率 |
--cutoff_len | 512 | 分词截断长度 |
--val_set_size | 500 | 验证集大小 |
--eval_step | 10 | 评估间隔步数 |
--save_step | 100 | 保存间隔步数 |
--device | auto | 设备;auto时优先用torch.accelerator.current_accelerator(),否则回退cuda |
--rank | 32 | DeLoRA 基秩 |
--delora_lambda | 640 | 边界 λ 初始值(注意:脚本默认 640,原文档示例用 15,按需调整) |
--module_dropout | 0.05 | DeLoRA 模块丢弃率 |
--target_modules | None | 逗号分隔的目标模块列表;为 None 时按架构默认映射 |
--hub_model_id | path/to/repo | 推送到 HF Hub 的仓库名 |
--push_to_hub | False(store_true) | 是否推送到 HF Hub |
脚本内部实现要点
- 混合精度自动选择:脚本检测当前设备是否支持 bf16(
device_module.is_bf16_supported()),支持则用torch.bfloat16,否则回退torch.float32(脚本第 47-50 行); - DeLoRA 配置:
DeloraConfig(r=rank, delora_lambda=delora_lambda, target_modules=..., module_dropout=..., bias="none")(脚本第 59-65 行); - 训练参数:warmup 设为总步数的 10%,
gradient_accumulation_steps=16,weight_decay=0.0,save_total_limit=2(脚本第 91-107 行); - 保存:无论是否推送 Hub,都会在本地保存模型与 tokenizer(脚本第 129-131 行)。
自定义适配层:target_modules与lambda_pattern
默认情况下(不指定target_modules),DeLoRA 使用与 LoRA 相同的架构映射(见 src/peft/utils/constants.py 第 67-108 行),例如 Llama/Mistral/Qwen 系列默认只适配q_proj和v_proj。如果需要在更多层上添加适配器(注意会增加显存占用),可以显式指定,例如原文档中的:
python examples/delora_finetuning/delora_finetuning.py \ --base_model meta-llama/Meta-Llama-3-8B \ --target_modules "q_proj,k_proj,v_proj,o_proj"不同层还可以使用不同的 λ:通过lambda_pattern按层名或正则指定,例如{"^model.decoder.layers.0.encoder_attn.k_proj": 16};源码中通过get_pattern_key对当前层名匹配rank_pattern/lambda_pattern来决定该层实际的r与delora_lambda(见 model.py 的_create_and_replace)。同理可用rank_pattern为不同层设置不同秩。
调参最佳实践
原文档明确给出了两条经验法则:
- 使用比标准 LoRA 大 10~100 倍的学习率(典型值在 1e-3、1e-2 量级)。因为 DeLoRA 的更新范数被 λ 显式约束,较大的学习率不会导致更新失控,反而能加快收敛;
- λ 的初始值不要设得太小(典型值在 10、15 附近)。λ 是更新范数的上界,设得过小会过度限制表达力,导致欠拟合;同时可以为不同层分配不同的 λ 以获得更精细的控制。
官方文档(delora.md)还补充了超参数鲁棒性的设计目标:由于角度与幅度学习被解耦,DeLoRA 对超参数选择和训练时长的鲁棒性优于 LoRA,官方评估覆盖了主题驱动图像生成、自然语言理解与指令微调等任务。
源码中的实现细节与验证
权重初始化与 λ 的冻结记录
reset_delora_parameters(layer.py 第 128-154 行)完成三件事:
init_weights=True时:A 用kaiming_uniform_(a=sqrt(5)),B 用零初始化,保证初始 ΔW = 0(与 LoRA 类似,训练开始时模型行为与基座一致);delora_lambda填充为配置的初始值(一个可学习标量nn.Parameter);- 用
torch.no_grad()冻结记录基座权重W的逐列范数到delora_w_norm(meta 张量场景下退化为全 1),该值在训练中不参与梯度更新。
合并与解合并
DeloraLinear.merge/unmerge(layer.py 第 173-224 行)支持把适配器权重合入基座权重(safe_merge=True时先复制权重并检查 NaN)。这与 LoRA 的合并语义一致,方便在推理部署时零额外开销地使用微调结果。
多适配器支持
DeloraLayer继承自BaseTunerLayer,支持多适配器并存:delora_A、delora_B、delora_lambda均为ParameterDict,前向传播时遍历active_adapters累加各适配器输出(layer.py 第 242-262 行);新增非激活适配器时自动requires_grad_(False)(model.py 第 89-91 行)。
测试覆盖
仓库测试对 DeLoRA 有较完整覆盖,可作行为参考:
- tests/test_initialization.py 第 2801-2827 行:验证
init_weights=True/False两种初始化路径; - tests/test_custom_models.py 第 1151-1154 行:自定义 MLP 上
target_modules的字符串/列表/正则三种写法; - tests/regression/test_state_dict.py 第 246 行:
DeloraConfig参与 state_dict 回归测试; - 同时出现在 tests/test_decoder_models.py、tests/test_encoder_decoder_models.py、tests/test_seq_classifier.py 等模型族测试中,验证其对主流架构的兼容性。
引用
DeLoRA 论文(ICLR 2025):
@inproceedings{bini2025decouplinganglesstrengthlowrank, title={Decoupling Angles and Strength in Low-rank Adaptation}, author={Massimo Bini and Leander Girrbach and Zeynep Akata}, year={2025}, booktitle={International Conference on Learning Representations (ICLR)}, }更多 API 细节可查阅 docs/source/package_reference/delora.md(含论文摘要与DeloraConfig/DeloraModel的 autodoc)。
- 人工智能
- 大模型
- 微调
- LoRA
【免费下载链接】peft
🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.
相关推荐
PEFT 中的 PEANuT 微调实战:用权重感知神经网络 Tweaker 替代 LoRA 低秩分解
PEFT 中的 PEANuT 微调实战:用权重感知神经网络 Tweaker 替代 LoRA 低秩分解 本文基于仓库中的 PEANuT 微调示例文档 https:
人工智能大模型微调LoRATRL 中的 PEFT 集成:LoRA、QLoRA 与 Prompt Tuning 的低成本微调实战指南
TRL 中的 PEFT 集成:LoRA、QLoRA 与 Prompt Tuning 的低成本微调实战指南 本篇技术指南围绕 TRL 官方文档 docs/sour
人工智能大模型强化学习RLHF预训练微调LoRALabel Studio:多模态数据标注,Docker 一条命令启动
Label Studio:多模态数据标注,Docker 一条命令启动 3 万张商品图,外包报价拖了两周还没排上,项目排期直接卡死。Label Studio 是一
人工智能大模型微调LoRA
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考