news 2026/9/20 14:15:57

HiRA 因果语言模型微调实战:基于 PEFT 的 Hadamard 高秩适配器(Alpaca 指令数据示例)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HiRA 因果语言模型微调实战:基于 PEFT 的 Hadamard 高秩适配器(Alpaca 指令数据示例)
  • 人工智能
  • 大模型
  • 微调
  • LoRA

【免费下载链接】peft

🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.

项目地址:https://gitcode.com/gh_mirrors/pe/peft
点击查看免费下载

HiRA(Hadamard High-Rank Adaptation,Hadamard 高秩适配)是 PEFT 中一种区别于 LoRA 的参数高效微调方法:它不再向权重矩阵叠加一个低秩增量,而是用低秩因子 (A、B) 构造调制矩阵,对原始权重做逐元素(Hadamard)乘性调制,从而以更少参数保留高秩更新能力。本文以 examples/hira_finetuning/hira_finetuning.py 为蓝本,完整讲解如何在yahma/alpaca-cleaned指令数据上用 HiRA 微调 Llama-3-8B-Instruct 这类因果语言模型:从命令行参数、数据预处理、HiraConfig配置到HiraLayer底层前向/合并/初始化实现,并给出可复制运行的完整命令与参数速查表。

HiRA 方法背景:从 LoRA 的加法增量到乘性调制

在深入脚本之前,先建立 HiRA 的数学直觉。LoRA 将权重更新建模为低秩加法:

[ W' = W_0 + B A ]

其中 (W_0) 是冻结的预训练权重,(A \in \mathbb{R}^{r \times \text{in}})、(B \in \mathbb{R}^{\text{out} \times r}) 是低秩因子,(r \ll \min(\text{in}, \text{out}))。低秩约束限制了表达空间,难以逼近满秩的适配需求。

HiRA 则改为逐元素乘性调制(见 API 文档):

[ W' = W_0 + W_0 \odot (B A) ]

调制项 (W_0 \odot (B A)) 仍然是低秩参数化(可训练参数量与 LoRA 同级),但通过与 (W_0) 的 Hadamard 积耦合后,其实际生效的更新不再是秩受限矩阵,从而保留高秩表达能力。这一机制在 HiRA 原论文中被验证为在多项任务上优于 LoRA 及其变体;本文档所在仓库仅作方法实现,具体评测结论请以论文为准。

从源码看,PEFT 将 HiRA 注册为独立 PEFT 方法(tuners/hira/init.py):

register_peft_method(name="hira", config_cls=HiraConfig, model_cls=HiraModel, is_mixed_compatible=True)

其中is_mixed_compatible=True意味着 HiRA 支持与 LoRA 等其他方法混合,也支持同一批内不同 adapter 的混合推理。

环境准备与脚本概览

示例脚本依赖以下主要包:

  • torch
  • transformers(模型、Tokenizer、Trainer
  • datasets(加载yahma/alpaca-cleaned
  • peftHiraConfigget_peft_modelPeftModel
  • 多机多卡场景下还需要accelerate(脚本会自动检测并使用)

脚本入口train()的参数及默认值如下表所示(与 hira_finetuning.py 一一对应):

参数默认值说明
base_model"path/to/model"基础模型 ID 或本地路径,必填,必须替换
data_pathyahma/alpaca-cleaned指令数据集(Hub 名称或本地目录)
output_dirhira适配器与检查点输出目录
batch_size16每设备训练 batch size
num_epochs1训练轮数
learning_rate3e-4AdamW 学习率
cutoff_len256截断长度
val_set_size16从训练集划分出的验证集样本数
eval_step/save_step100评估 / 保存间隔(步)
device_mapauto模型设备映射;多卡时自动改写为{"": process_index}
hira_r32HiRA 低秩因子维度(Hadamard 调制秩)
hira_dropout0.0HiRA 层 dropout 概率
hira_target_modulesNone逗号分隔的目标模块名;默认使用标准解码器模块集
dtypefloat16模型加载精度(float16/float32/bfloat16等)
seedNone随机种子(设置后调用set_seed
init_weightsTrue是否以 no-op 方式初始化 HiRA 权重

运行脚本:命令行全参数解析

README 给出的最小运行方式如下:

python examples/hira_finetuning/hira_finetuning.py \ --base_model meta-llama/Meta-Llama-3-8B-Instruct \ --data_path yahma/alpaca-cleaned \ --output_dir hira-alpaca \ --hira_r 16 \ --hira_dropout 0.05 \ --learning_rate 3e-4 \ --num_epochs 3

注意:--hira_r 16--hira_dropout 0.05--num_epochs 3是 README 示例的推荐配置,而脚本内置默认值为hira_r=32hira_dropout=0.0num_epochs=1,两者皆可运行,按需选择即可。

若想覆盖更多行为,可组合使用脚本支持的全部命令行参数(argparse 定义):

python examples/hira_finetuning/hira_finetuning.py \ --base_model meta-llama/Meta-Llama-3-8B-Instruct \ --data_path yahma/alpaca-cleaned \ --output_dir hira-alpaca \ --batch_size 8 \ --num_epochs 3 \ --learning_rate 3e-4 \ --cutoff_len 512 \ --val_set_size 64 \ --eval_step 50 \ --save_step 50 \ --hira_r 32 \ --hira_dropout 0.05 \ --hira_target_modules "q_proj,k_proj,v_proj,o_proj,gate_proj,down_proj,up_proj" \ --dtype bfloat16 \ --seed 42 \ --init_weights

几个值得注意的参数行为:

  • --hira_target_modules接收逗号分隔的字符串,脚本内部会按逗号切分并去除空白,得到目标模块名列表(实现)。
  • --init_weights--no_init_weights是一对互斥开关:默认开启(no-op 初始化);--no_init_weights则改用随机初始化,通常仅用于调试,训练前适配器不再是恒等映射。
  • --device_map默认auto;当检测到WORLD_SIZEPMI_SIZE大于 1(分布式训练)且device_map != "cpu"时,脚本会自动导入accelerate.Accelerator并把设备映射改写为{"": process_index},保证每个进程只占一张卡(实现)。

目标模块:默认覆盖注意力与 MLP 全投影

脚本内置的默认目标模块覆盖了解码器架构中典型的注意力投影和 MLP 块(default_target_modules):

default_target_modules = [ "q_proj", "k_proj", "v_proj", "o_proj", # 注意力四投影 "gate_proj", "down_proj", "up_proj", # SwiGLU MLP 三投影 ]

这一组合与 src/peft/utils/constants.py 中TRANSFORMERS_MODELS_TO_LORA_TARGET_MODULES_MAPPING对 llama / llama4 / mistral / qwen2 等架构的记录一致(TRANSFORMERS_MODELS_TO_HIRA_TARGET_MODULES_MAPPING正是该映射的副本,见 constants.py),因此对 Llama 系、Mistral、Qwen2 等常见模型可直接生效。若你的基础模型使用不同模块命名(例如 OPT 的fc1/fc2、GPT-2 的c_attn),务必通过--hira_target_modulesHiraConfig.target_modules显式指定。

target_modules也支持正则表达式字符串(如'.*decoder.*(SelfAttention|EncDecAttention).*(q|v)$')或通配符'all-linear'(匹配所有 Linear/Conv1D,若模型是PreTrainedModel则排除输出层),相关语义见 HiraConfig 定义。

核心流程拆解:从数据到 Trainer

train()的执行主线如下:

  1. 加载模型与 Tokenizer(L58-L63):以指定dtypedevice_map加载AutoModelForCausalLM;Tokenizer 以trust_remote_code=True加载,若pad_tokenNone则用eos_token兜底。

  2. Alpaca 式指令模板(generate_prompt):

return f"""Below is an instruction that describes a task. Write a response that appropriately completes the request. ### Instruction: {example["instruction"]} ### Response: {example["output"]}"""
  1. Tokenize(L65-L83):按cutoff_len截断;若未到截断长度且不以eos_token_id结尾,则手动追加 EOS;labelsinput_ids相同(标准 LM 自回归监督)。

  2. 构建 HiRA 适配器(L99-L106):

config = HiraConfig( r=hira_r, target_modules=hira_target_modules or default_target_modules, hira_dropout=hira_dropout, init_weights=init_weights, task_type="CAUSAL_LM", ) model = get_peft_model(model, config)
  1. 数据划分与映射(L108-L112):加载数据集后用train_test_split(test_size=val_set_size, seed=42)切出验证集,再对训练/验证集分别.map(generate_and_tokenize_prompt)

  2. Trainer 配置(L114-L137):关键设定包括warmup_steps=100optim="adamw_torch"、按步评估与保存、save_total_limit=3load_best_model_at_end=True;多卡时设置ddp_find_unused_parameters=False以提升 DDP 效率;DataCollatorForSeq2Seq使用pad_to_multiple_of=8对齐序列长度。

  3. 训练、保存与回载验证(L138-L143):训练结束后model.save_pretrained(output_dir)保存适配器;随后重新加载基础模型并用PeftModel.from_pretrained回载适配器,这一步即验证了保存/加载链路的正确性,也是后续推理的标准范式。

HiraConfig 参数详解(源码级)

HiraConfig继承自PeftConfig(config.py),__post_init__中把target_modules/exclude_modules转为set并设置peft_type = PeftType.HIRA。除脚本用到的rtarget_moduleshira_dropoutinit_weightstask_type外,还可配置:

参数默认值说明
exclude_modulesNone显式排除的模块名(支持正则),优先级高于target_modules
fan_in_fan_outFalse被替换层权重是否按(fan_in, fan_out)存储;GPT-2 的Conv1D需设为True,源码会自动校验并告警(dispatch_default)
modules_to_saveNone除适配层外还需可训练并保存的模块(如分类任务随机初始化的classifier/score头)
init_weightsTrue见下节初始化说明,支持True/False/"gaussian"
layers_to_transformNone仅对指定层索引(nn.ModuleList下标)施加适配;与字符串形式的target_modules互斥(会抛ValueError
layers_patternNonelayers_to_transform配合,指定模块列表名(常为"layers""h"
rank_pattern{}按层名/正则给不同层分配不同秩,例如{'^model.decoder.layers.0.encoder_attn.k_proj': 16}

rank_pattern的生效逻辑在 HiraModel._create_and_replace 中:通过get_pattern_key匹配当前层名,命中则用该层专用秩,否则回退到全局r

底层实现原理:HiraLayer 的前向、初始化与合并

前向计算

HiraLayer保存四类适配参数(layer.py):hira_Ahira_B(Linear/Conv)与hira_embedding_Ahira_embedding_B(Embedding)。Linear 层的前向(forward)可简化为:

hira_A, hira_B = self.hira_A[active_adapter], self.hira_B[active_adapter] _prod_AB = torch.mm(hira_A.T, hira_B.T) # (in, out) dropout_sub = self.hira_dropoutactive_adapter hira_result = F.linear( dropout_sub, transpose(base_weight, fan_in_fan_out) * _prod_AB.T # W0 ⊙ (B A) ) result = result + hira_result

即输出 = 基础层输出 + 输入经W_0 ⊙ (B A)的线性投影,与论文公式 (W' = W_0 + W_0 \odot (BA)) 严格对应。合并路径(HiraLayer._merge)同样遵循该公式:

merged_weight = weight.data + base_weight * new_delta # new_delta = B A

注意这里与 LoRA 合并(W + BA)的本质区别:HiRA 的增量是W_0 * (B A),依赖当前基座权重。因此Linear.supports_lora_conversion返回False(layer.py),PEFT 明确禁止把 HiRA 适配器转成 LoRA——转换出的 LoRA 无法保持 HiRA 的乘性行为。

权重初始化

reset_hira_parameters(layer.py)实现了三种初始化策略:

  • init_weights=True(默认):hira_Akaiming_uniform_(a=sqrt(5))(与nn.Linear默认初始化一致),hira_B置零。由于B=0,训练前调制项为零,适配器是精确的 no-op,不影响基座模型输出;
  • init_weights="gaussian"hira_Anormal_(std=1/r)高斯初始化,B仍置零;
  • init_weights=False:跳过重置,AB保持随机初值,训练前非恒等映射——仅用于调试,对应脚本的--no_init_weights

支持的目标层类型

dispatch_default(layer.py)按类型分派:nn.Linearnn.Embeddingnn.Conv1d/2d/3d、HuggingFaceConv1D均可替换。其中 Embedding 层的前向把调制矩阵作用于词嵌入查找(Embedding.forward),卷积层则逐元素调制卷积核权重(_ConvNd.forward),且不支持groups > 1的分组卷积(会抛NotImplementedError,layer.py)。

量化模型支持

当基座模型以 bitsandbytes 8bit/4bit 加载时,tuners/hira/bnb.py 提供Linear8bitLtLinear4bit:前向中先反量化权重再执行乘性调制(8bit 见 forward,4bit 见 forward);合并/反合并因涉及再量化,可能产生舍入误差,源码会显式告警。这为 QLoRA 风格的 HiRA 量化训练留出了路径——结合prepare_model_for_kbit_trainingBitsAndBytesConfig,可参考 API 文档中的 kbit 示例。

保存、加载与多适配器

  • 保存model.save_pretrained(output_dir)只保存适配器权重与adapter_config.json,基座权重不动,磁盘占用极小。
  • 加载:先加载基座模型,再PeftModel.from_pretrained(model, output_dir)(脚本 L142-L143 即此流程)。
  • 合并:训练后可用model.merge_and_unload()将 HiRA 调制权重并入基座以加速推理;safe_merge=True可检测 NaN。is_mixed_compatible=True还允许与其他 PEFT 方法共存,并在推理时通过adapter_names参数实现批内多适配器混合(4bit/8bit 层均有_mixed_batch_forward实现)。

测试覆盖与验证入口

仓库测试中已包含 HiRA 相关覆盖:HiraConfig的默认实例化校验位于 tests/test_config.py,此外tests/testing_common.py以及test_decoder_models.pytest_encoder_decoder_models.pytest_seq_classifier.pytest_custom_models.pytest_quantization.pytest_initialization.py等测试文件均涉及 HiRA 的通用测试路径(可搜索Hira关键字定位),可用于验证本示例之外更广泛的 HiRA 行为。

注意事项与限制

  1. 必须替换--base_model:脚本默认值为占位符"path/to/model",直接运行会失败。
  2. 模块命名要对齐:默认目标模块面向 Llama 系解码器;换架构时先通过model.named_modules()确认投影层命名,再传--hira_target_modules
  3. init_weights语义:默认 no-op 初始化意味着训练前输出与基座完全一致,这是特性而非 bug;调试异常时才建议--no_init_weights
  4. 不可转 LoRA:HiRA 的乘性更新依赖当前基座权重,supports_lora_conversion返回False,不要尝试将 HiRA 适配器转换为 LoRA。
  5. 分组卷积不支持:目标为Conv2d/3dgroups > 1时会直接报错。
  6. 量化合并有舍入:8bit/4bit 基座上的 merge/unmerge 因反量化与再量化可能存在精度损失,源码会发出警告。
  7. 超参数起点:README 推荐r=16dropout=0.05lr=3e-4epochs=3;脚本默认r=32dropout=0.0epochs=1。两者皆可作为起步配置,实际效果以你所在任务上的验证为准。

至此,你已具备从命令行到源码级的 HiRA 微调全链路知识:既能直接跑通 hira_finetuning.py 完成 Alpaca 指令数据上的模型微调,也能依据 HiraConfig、HiraLayer 与 HiraModel 深入定制自己的 HiRA 训练与推理流程。

  • 人工智能
  • 大模型
  • 微调
  • LoRA

【免费下载链接】peft

🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.

项目地址:https://gitcode.com/gh_mirrors/pe/peft
点击查看免费下载

相关推荐

上一篇:Vito故障排查手册:常见问题分析与解决方案
下一篇:Laguna XS 2.1的OpenMDW许可证解析:商业使用的完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 14:11:13

昇腾NPU上部署Dify:国产算力跑通LLM应用全链路

简介:面向国产昇腾推理服务器与加速卡的大模型部署场景,该可运行源码包提供了在华为硬件上搭建Dify平台的完整参考。内容涵盖大模型推理引擎MindIE以及Embedding、Rerank组件的部署测试,并给出Qwen模型在双卡环境下的配置与验证结果&#xff…

作者头像 李华
网站建设 2026/9/20 14:07:44

自考高级英语中英翻译:掌握长难句与汉译英技巧的备考指南

简介:这是一份面向自考本科英语专业考生的高级英语(上、下册)课文翻译资料,涵盖全册各课重点篇章的英汉对照内容,尤其适合需要逐句理解原文、积累词汇与句型表达的备考者。资源以单个doc文档形式打包,全包仅…

作者头像 李华
网站建设 2026/9/20 14:04:03

如何快速让 Lucky 对接物联网平台,用语音助手控制智能家居

如何快速让 Lucky 对接物联网平台,用语音助手控制智能家居 【免费下载链接】lucky 软硬路由公网神器,ipv6/ipv4 端口转发,反向代理,DDNS,WOL,ipv4 stun内网穿透,cron,acme,rclone,ftp,webdav,filebrowser 项目地址: https://gitcode.com/GitHub_Trending/luc/luck…

作者头像 李华