ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

深入解析 PEFT 中的 RandLora:全秩参数高效微调的原理与实战

深入解析 PEFT 中的 RandLora:全秩参数高效微调的原理与实战 深入解析 PEFT 中的 RandLora全秩参数高效微调的原理与实战【免费下载链接】peft PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.项目地址: https://gitcode.com/gh_mirrors/pe/peftRandLoraRandLoRA是 PEFT 内置的一种参数高效微调方法它用多个固定随机低秩基的线性组合来构造全秩权重更新在保留 LoRA 参数量与内存效率的同时突破低秩约束对性能的天花板。本文以examples/randlora_finetuning/下的官方指南与训练脚本为核心结合src/peft/tuners/randlora/的源码实现完整讲解 RandLora 的设计动机、配置项、训练脚本用法、与 LoRA/VeRA 的对比以及底层实现细节读完即可用一行命令复现 RandLora 微调并完成与 LoRA 的对比实验。一、RandLora 是什么一次对低秩范式的挑战RandLora 是发表于 ICLR 2025 的参数高效微调PEFT方法与 LoRA、VeRA 同属随机基 可训练缩放家族但核心差异在于它执行的是全秩full-rank权重更新。原文档 examples/randlora_finetuning/README.md 对这一动机有清晰交代LoRA 及其变体通过低秩分解大幅压缩可训练参数量但低秩更新的表示能力本身存在上限——当任务复杂、需要表达更丰富的权重变化时低秩约束会限制性能增益即使提高 LoRA 的秩rank也是如此。RandLora 正是为了回答论文中提出的关键问题LoRA 与全量微调之间的性能差距究竟来自可训练参数变少还是来自更新矩阵的秩不足RandLora 的答案是通过线性缩放随机基linearly scaling random bases构造全秩更新随机基是多个低秩矩阵的集合这些低秩矩阵的秩之和 ≥ 被适配权重矩阵的满秩可训练参数只有两个对角缩放矩阵向量分别记为randlora_lambdaλ与randlora_gammaγ它们与随机基相乘的方式与 VeRA 的更新类似为了维持低内存占用RandLora 使用自定义的反向传播函数UniqueBaseGrad避免为反向传播在内存中保存不必要的基。在 PEFT 仓库中该方法的注册、配置、层实现与量化支持分别位于 src/peft/tuners/randlora/config.py、src/peft/tuners/randlora/layer.py、src/peft/tuners/randlora/model.py 与 src/peft/tuners/randlora/bnb.py并在 src/peft/tuners/randlora/init.py 中通过register_peft_method(namerandlora, ...)注册为RANDLORA类型。完整 API 文档见 docs/source/package_reference/randlora.md。二、核心原理多个低秩随机基如何拼出全秩更新2.1 基的数量与秩的反比关系假设被适配的线性层最小维度为min_dim配置的基秩为r则需要的随机基数量num_bases在 src/peft/tuners/randlora/layer.py 中计算num_bases min(self.in_features, self.out_features) / r self.num_bases int(num_bases) if num_bases.is_integer() else int(num_bases) 1 # Full rank即num_bases × r ≥ min_dim保证所有基的秩之和不小于被适配矩阵的满秩。这一设计带来一个与 LoRA完全相反的特性原文档与 docs/source/package_reference/randlora.md 均强调RandLora 的可训练参数量与秩r成反比num_bases × r恒定降低r会增加基的数量进而增加基特有的可训练对角矩阵数量提高r则减少可训练参数。因此使用RandLoraConfig时r不再是越大越好的旋钮而是需要按目标参数量反向调节。2.2 可训练参数两个对角缩放矩阵每个适配器只包含两个可训练参数layer.pyself.randlora_lambda[adapter_name] nn.Parameter(torch.randn(r, self.num_bases), requires_gradTrue) self.randlora_gamma[adapter_name] nn.Parameter( torch.ones(self.num_bases, min(self.out_features, self.in_features)) / max(self.out_features, self.in_features), requires_gradTrue, )初始化时randlora_lambda置零、randlora_gamma设为常数见 layer.py 的reset_randlora_parameters保证训练初期适配器输出为零、模型行为与基座一致这也是标准 LoRA 式初始化惯例。缩放系数scaling randlora_alpha / rlayer.py与 LoRA 的alpha/r形式一致。2.3 共享随机基与切片与 VeRA 类似RandLora 的randlora_A/randlora_B随机基是全局共享的按所有被适配层中每个维度的最大尺寸初始化前向时对每个层切片出所需子矩阵src/peft/tuners/randlora/model.py 初始化layer.py 切片。文档中的示例适配形状为 (100, 20) 与 (80, 50) 的两个线性层会生成形状 (rank, 50) 与 (100, rank) 的共享 A/B 矩阵再为 (100, 20) 层切出 (rank, 20) 与 (100, rank) 的子矩阵。_find_dimmodel.py遍历被适配模块求出最大 in/out 维度若未找到兼容层会抛出 No layers types compatible with RandLora were found 错误。2.4 内存优化自定义反传函数为了不在反向传播中保存冗余中间张量RandLora 在 layer.py 定义了UniqueBaseGrad自定义 autograd 函数class UniqueBaseGrad(torch.autograd.Function): staticmethod def forward(ctx, randlora_A, randlora_lambda, randlora_gamma): out randlora_lambda[:, :, None] * randlora_A * randlora_gamma[None,] ctx.save_for_backward(randlora_A, randlora_lambda, randlora_gamma) return out staticmethod def backward(ctx, grad_output): randlora_A, randlora_lambda, randlora_gamma ctx.saved_tensors ... grad_randlora_lambda torch.einsum(kbj,kvj,bj-kb, grad_output, randlora_A, randlora_gamma) grad_randlora_gamma torch.einsum(kbj,kvj,kb-bj, grad_output, randlora_A, randlora_lambda) return None, grad_randlora_lambda, grad_randlora_gamma其巧妙之处在于同一组随机基被所有被适配层共享因此对randlora_lambda/randlora_gamma的梯度可跨层batch 维 k聚合无需为每层单独保留一份基的副本这正是原文档所说的随机基共享策略带来内存优势。三、配置详解RandLoraConfig 全参数RandLoraConfigsrc/peft/tuners/randlora/config.py继承自PeftConfigpeft_type自动设为RANDLORA。核心参数如下参数默认值说明r32随机基的秩。与可训练参数量成反比调低r增加参数调高r减少参数target_modulesNone要应用 RandLora 的模块名列表或正则仅支持线性层例如[q_proj, v_proj]或.*decoder.*(SelfAttention|EncDecAttention).*(q\|v)$randlora_alpha640缩放系数通常取基秩的 20 倍过大会导致数值不稳定此时应降低学习率或该系数randlora_dropout0.0适配器层 dropout 概率sparseFalse使用三元稀疏随机基仅含 -1、0、1-1/1 的赋值概率各 1/6、0 为 2/3有助减少过拟合见下方原理very_sparseFalse高度稀疏随机基-1/1 的赋值概率为1/√DD 为最小维度可进一步减少过拟合但通常会降低性能需谨慎使用save_projectionTrue是否把全局randlora_A/randlora_B存入 state dict。设为False可显著缩小 checkpoint但恢复时依赖projection_prng_key的固定随机种子无法在所有设备与 PyTorch 版本上保证可复现projection_prng_key0用于确定性初始化 A/B 基的 PRNG 种子新增适配器时所有适配器必须使用相同 keyfan_in_fan_outFalse目标层是否以 (fan_in, fan_out) 存储权重GPT-2 的Conv1D需设为Truebiasnone可选none、all、randlora_only注意设all/randlora_only后即使禁用适配器输出也不再等价于基座模型modules_to_saveNone除 RandLora 层外需置为可训练并保存的模块如分类头init_weightsTrue是否用默认初始化初始化 RandLora 层权重非明确原因不要改动layers_to_transform/layers_patternNone指定仅对部分层索引应用变换layers_pattern仅在该索引列表非常见层模式时使用两个关键配置的底层行为值得展开稀疏基的生成model.py_init_randlora_A_randlora_B_sparse先生成均匀随机张量按阈值1/(2*sparsity)置为 -1/0/1 三元基再做标准差归一化。sparse模式下sparsity3very_sparse模式下sparsity√min_dimmodel.py 的_pre_injection_hook据此分发。原文档指出目前实现属于 proof-of-concept稀疏性并未用于加速或省内存但其矩阵元素多为 0的结构天然起到正则化作用、可缓解过拟合。checkpoint 体积与可复现性save_projectionFalse时A/B 基从 state dict 中排除通过BufferDict(persistentconfig.save_projection)见 model.py加载时依据projection_prng_key重建。__post_init__会在该配置下给出警告config.py。仓库测试 tests/test_randlora.py 中的test_multiple_adapters_save_projection_false_contains_no_randlora_A_randlora_B验证了该模式下 state dict 确实不含randlora_A/randlora_B。四、快速开始三行切换 LoRA → RandLora原文档给出的最小示例已修正其中get_peft_model(model, lora_config)的笔误为randlora_configimport torch from peft import RandLoraConfig, get_peft_model from transformers import AutoTokenizer, AutoModelForCausalLM, Trainer from datasets import load_dataset model AutoModelForCausalLM.from_pretrained(huggyllama/llama-7b, device_mapauto) tokenizer AutoTokenizer.from_pretrained(huggyllama/llama-7b) dataset load_dataset(timdettmers/openassistant-guanaco, splittrain) randlora_config RandLoraConfig() peft_model get_peft_model(model, randlora_config) trainer Trainer( modelpeft_model, train_datasetdataset, dataset_text_fieldtext, max_length2048, processing_classtokenizer, ) trainer.train() peft_model.save_pretrained(randlora-llama-7b)要点与原文档一致无需改变任何标准 PEFT 训练流程只需把LoraConfig换成RandLoraConfig。唯一的反直觉点在于可训练参数量与r成反比——降低r增加参数提高r减少参数规划参数量预算时务必注意。五、实战脚本randlora_finetuning.py 全参数指南仓库在 examples/randlora_finetuning/randlora_finetuning.py 提供了完整可运行的微调脚本基于examples/dora_finetuning/dora_finetuning.py改写。直接运行python examples/randlora_finetuning/randlora_finetuning.py --base_model meta-llama/Meta-Llama-3-8B --data_path timdettmers/openassistant-guanaco默认即加载 RandLora 配置的 PEFT 模型。脚本支持的参数与默认值如下对应argparse定义见 randlora_finetuning.py参数默认值说明--base_modelhuggyllama/llama-7b基座模型路径或名称--data_pathtimdettmers/openassistant-guanaco数据集路径或名称--output_dirpath/to/output微调输出目录--batch_size1批大小--num_epochs1训练轮数--learning_rate3e-4学习率--cutoff_len512分词截断长度--val_set_size500验证集大小--use_loraFalseflag改用 LoRA 而非 RandLora--quantizeFalseflag使用 4-bit 量化--eval_step10评估间隔--save_step100保存间隔--deviceauto训练设备auto时自动探测加速器--rank32RandLora 基秩--randlora_alpha640RandLora alpha--randlora_dropout0.05dropout--randlora_target_modulesNone默认 k_proj,v_proj逗号分隔的目标模块列表--sparseFalseflag使用稀疏随机基--very_sparseFalseflag使用高度稀疏随机基--hub_model_id/--push_to_hub—推送模型到 Hub5.1 与 LoRA 快速对比原文档强调想快速和 LoRA 对比只需加--use_lora并把--randlora_alpha降到 2 倍秩python examples/randlora_finetuning/randlora_finetuning.py --base_model meta-llama/Meta-Llama-3-8B --data_path timdettmers/openassistant-guanaco --use_lora --rank 32 --randlora_alpha 64脚本内部randlora_finetuning.py在--use_lora时构造LoraConfig(rrank, lora_alpharandlora_alpha, target_modules..., lora_dropoutrandlora_dropout, biasnone)否则构造RandLoraConfig(...)——两个分支共用同一组命令行参数保证对比时除方法本身外其余设置完全一致。5.2 稀疏基与量化稀疏训练--sparse稀疏或--very_sparse高度稀疏脚本会原样传入RandLoraConfig。原文档提示稀疏矩阵有助减少过拟合。4-bit 量化QRandLora加--quantize脚本内部使用BitsAndBytesConfig(load_in_4bitTrue, bnb_4bit_use_double_quantTrue, bnb_4bit_quant_typenf4)加载基座并通过prepare_model_for_kbit_training做 k-bit 训练准备randlora_finetuning.py。PEFT 为量化场景提供了Linear8bitLt与Linear4bit实现src/peft/tuners/randlora/bnb.py二者通过 model.py 的_create_new_module按目标层类型自动分发。5.3 自定义目标模块默认只适配 Llama 的k_proj、v_projREADME 中也说明默认是 key/value 层。向更多层添加适配器会线性增加内存与参数开销可自定义python examples/randlora_finetuning/randlora_finetuning.py --randlora_target_modules q_proj,k_proj,v_proj脚本按逗号拆分传入target_modules。由于 RandLora 的目标模块映射直接复用 LoRA 的映射表TRANSFORMERS_MODELS_TO_RANDLORA_TARGET_MODULES_MAPPING TRANSFORMERS_MODELS_TO_LORA_TARGET_MODULES_MAPPING.copy()见 src/peft/utils/constants.py各主流架构的默认目标模块与 LoRA 一致且支持target_modulesNone时自动应用默认映射。5.4 完整示例命令python examples/randlora_finetuning/randlora_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-4 \ --cutoff_len 512 \ --val_set_size 500 \ --quantize \ --eval_step 10 \ --save_step 100 \ --device auto \ --rank 32 \ --randlora_alpha 640 \ --randlora_dropout 0.05 \ --randlora_target_modules k_proj,v_proj \ --hub_model_id YOUR_HF_REPO \ --push_to_hub该脚本的训练配置也值得留意warmup_steps取总步数的 10%weight_decay0.01并且通过gradient_accumulation_steps 16 // batch_size保证累积后批大小不小于 16脚本注释明确建议维持这一最小批量以获得良好性能randlora_finetuning.py。六、RandLora vs. LoRA为什么值得换原文档对二者的定位非常明确挑战低秩范式RandLora 学习全秩更新。论文实验表明 LoRA 的低秩约束会在可训练参数增加秩提高时限制性能增益而 RandLora 用固定随机基的线性组合突破这一瓶颈。适用场景优先推荐用于 LoRA 欠拟合的困难任务同时如果提高 LoRA 的秩能改善你的任务表现RandLora 大概率会表现更好。预期收益在可训练参数量相当时RandLora 预计优于 LoRA尤其是等效 LoRA 秩大于 4 的较大参数量区间。代价是两点限制对缩放系数敏感性能依赖较大的randlora_alpha通常取基秩的 20 倍即默认640/32。过大的缩放系数可能使训练不稳定此时应降低学习率或调小randlora_alpha。极低秩下训练变慢降低r会增加基数量RandLora 在非常低的秩典型如r 4下训练时间相比 LoRA 会明显增加。不过这不影响推理——适配器可以合并回预训练权重矩阵merge/unmerge实现见 layer.py量化层对应实现见 bnb.py。七、RandLora vs. VeRA同门不同路RandLora 与 VeRA 都用随机基组合来回应 LoRA 的某些局限但解决的问题不同VeRA的目标是超越 rank-1 LoRA 进一步压缩可训练参数RandLora的目标是消除随可训练参数增长而出现的低秩性能瓶颈。由此得到两个预期结论原文档原话在需要更多可训练参数的困难任务上RandLora 预计优于 VeRA得益于随机基共享策略RandLora 相比 VeRA 具有更低的内存占用。从实现看这一内存优势确有依据A/B 基在RandLoraModel层面全局共享一份self.randlora_A/self.randlora_B模型级 BufferDict各层只保存自己的randlora_lambda/randlora_gamma。仓库测试test_randlora_A_randlora_B_share_memory断言了不同层之间randlora_A/randlora_B的data_ptr()相同即共享同一份内存而test_randlora_lambda_dont_share_memory验证了每个适配器/每层的 λ、γ 各自独立tests/test_randlora.py。八、底层实现共享基、多适配器与保存加载8.1 前向计算路径被适配层的前向layer.py可概括为result self.base_layer(x, *args, **kwargs) for active_adapter in self.active_adapters: dropout self.randlora_dropout[active_adapter] update_B, update_A self.get_scaled_bases(active_adapter, devicex.device) scaling self.scaling[active_adapter] result result F.linear(F.linear(dropout(x), update_B), update_A) * scalingget_scaled_baseslayer.py完成三件事从共享 A/B 基切片出当前层所需子矩阵、通过UniqueBaseGrad把 λ/γ 应用到最小的基randlora_A上、展平矩阵维度以减少内存随后根据min_dim与 in/out 维度的关系决定update_A/update_B的相乘顺序以最小化可训练参数。get_delta_weight用于合并则计算(update_B.T update_A.T).T * scaling。8.2 多适配器约束由于 A/B 基全局唯一新增第二个适配器时layer.py会复用已有适配器的基并做形状兼容校验若新适配器需要更大的基更高的r或更大的层维度会抛出明确的 ValueError提示加载适配器时按逆序加载可能解决。同时 model.py 的_check_new_adapter_config强制要求所有适配器的projection_prng_key必须一致、save_projection取值必须统一否则直接报错。这些约束正是为了维护一份共享基、多个可训练对角矩阵的数据结构的正确性。8.3 初始化细节普通模式model.pyA/B 基用带显式torch.Generator(devicecpu).manual_seed(config.projection_prng_key)的 Kaiming Uniform 初始化_kaiming_inita√5保证给定 key 时结果完全确定随后除以自身标准差做归一化源码注释说明这是经验上最优的归一化方式。稀疏模式三元稀疏基 标准差归一化如 5.2 节所述。8.4 仓库基准与测试验证仓库method_comparison目录中提供了 RandLora 在 MetaMathQALlama-3.2-3B与图像生成FLUX.2 klein上的真实基准记录配置快照 method_comparison/MetaMathQA/experiments/randlora/llama-3.2-3B-default/adapter_config.jsonr32、randlora_alpha640、randlora_dropout0.0、save_projectiontrue、target_modules[q_proj,v_proj]与本文所述默认配置一致。运行记录 method_comparison/MetaMathQA/results/randlora--llama-3.2-3B-default.json在 L40S 上 5000 步训练成功num_trainable_params9,289,728约 929 万num_total_params3,222,039,552约 32.2 亿即可训练参数占比约 0.29%——可作为理解参数高效的直观参考。注意这些是仓库内单次实验记录不宜推广为普适结论。单元测试方面tests/test_randlora.py 覆盖了共享内存语义、多适配器 PRNG 一致性校验、save_projectionFalse的保存/加载与 state dict 内容、不同形状层的共享基切片test_randlora_different_shapes断言randlora_A.shape (r, 1, in_features)、randlora_B.shape (out_features, 1, r)以及多种 dtype 下的训练/推理可作为理解实现语义的补充材料。九、限制与注意事项小结综合原文档与源码使用 RandLora 前请确认以下约束仅支持nn.Linear层含Conv1D后者需fan_in_fan_outTrue不支持卷积等其它层类型可训练参数随r反比变化与 LoRA 直觉相反规划预算时勿照搬 LoRA 的调参习惯randlora_alpha默认较大640高学习率下易数值不稳训练发散时优先降学习率或降 alpha极低秩r 4训练速度明显慢于 LoRA但合并后推理无额外开销多适配器共享同一份随机基projection_prng_key与save_projection必须在所有适配器间保持一致若追求 checkpoint 最小化可设save_projectionFalse但可复现性依赖 PRNG 种子跨设备/跨 PyTorch 版本无法保证默认True更稳妥。十、引用使用 RandLora 开展研究时可引用原论文inproceedings{2025_ICLR_RandLoRA, title{RandLoRA: Full rank parameter-efficient fine-tuning of large models}, authorAlbert, Paul and Zhang, Frederic Z. and Saratchandran, Hemanth and Rodriguez-Opazo, Cristian and van den Hengel, Anton and Abbasnejad, Ehsan, booktitle{International Conference on Learning Representations (ICLR)}, year2025 }总结RandLora 用多个固定低秩随机基之和达到满秩 仅训练两个对角缩放矩阵的设计在维持 LoRA 级参数效率的同时提供全秩更新的表达能力。无论你是在复现论文、为困难任务寻找比 LoRA 更强的 PEFT 基线还是想快速对比稀疏基与量化组合的效果都可以从 examples/randlora_finetuning/randlora_finetuning.py 出发一行命令开始实验。【免费下载链接】peft PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.项目地址: https://gitcode.com/gh_mirrors/pe/peft创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表