【大模型微调】3万字详解大模型PEFT高效微调:从 P-Tuning 到 LoRA/QLoRA/AdaLoRA/DoRA/EDoRA 附代码使用详解

摘要

面对 10 亿到千亿参数的大模型,企业通常不再做“全量微调”,而是用 PEFT(Parameter-Efficient Fine-Tuning):冻结 97 %+ 的权重,只训练少量“外挂”。三条主流线路按时间先后是 Adapter-Tuning (2019)Prefix/Prompt-Tuning (2021)LoRA / QLoRA (2021-2023)。它们分别在 层内插小网络、在输入或注意力前加可训练前缀、给线性层加低秩旁路。下面先讲提出背景与原理,再用 GPT-2 的最简伪代码示范「定义 → 训练 → 推理」,并列出优缺点与典型应用。所有方法都可用 Hugging Face peft 一行集成。

在 2019 – 2025 这 7 年里,参数高效微调 (PEFT) 把「全量微调」拆解成一系列只训练 0.05 % – 3 % 权重的“外挂”:Adapter → Prefix/Prompt → LoRA → QLoRA → AdaLoRA → DoRA / EDoRA。

它们全部落在 Transformer 每层的 6 个线性矩阵(Q/K/V/O + FFN 两线性)上,通过冻结 97 %+ 预训练参数、额外插入小模块,让消费级硬件即可调千亿模型,同时保持与全量微调相当的效果。下文按时间线梳理每一招提出背景、核心公式与优缺点,再给出 GPT-2 + 🤗 PEFT ≥ 0.10 的统一伪代码(训练 → 保存 → 加载 → 推理)。最后给出当前的工程选型速查表。


1 时间线:谁在什么痛点上发明了什么?

年份 方法 论文 / 团队 解决痛点 额外参数&延迟
2019 Adapter-Tuning Houlsby et al., Google Brain (arXiv) 全量微调太重,插两个瓶颈 FFN 只训 1–3 % +1 前向;1–3 %
2021 Prefix-Tuning Li & Liang, Stanford (ACL Anthology) Prompt-Tuning 仅底层有效 → 前缀影响每层注意力 0.1–1 %; 零延迟
2021 Prompt-Tuning Lester et al., Google (arXiv) 仅在 Embedding 端插伪 token,极简 0.05 %
2022 LoRA Hu et al., Microsoft (arXiv) 低秩 ΔW=A·B;推理可合并,零延迟 0.05–1 %
2022 IA³ Liu et al., UW (arXiv) 只乘 3 条 γ 向量,显存≈BitFit 0.1 %
2023 QLoRA Dettmers et al., UW + HF (arXiv) 先 4-bit 量化再插 LoRA → 24 GB GPU 可训 65 B 同 LoRA
2023 AdaLoRA Zhang et al., MSR (arXiv) 资源动态:梯度大层涨 r,小层减 r 动态
2024 DoRA Liu et al., THU (arXiv) 将权重拆“方向+幅度”,只学方向,收敛稳 0.05–0.5 %
2025 EDoRA Wu et al., Meta (arXiv) 用 SVD 主奇向量初始化 DoRA → 再提速 同 DoRA

2 为什么要用 PEFT(Parameter-Efficient Fine-Tuning)

  • 算力 / 显存:全量微调 GPT-2-Large(774 M)要 > 24 GB GPU,而 LoRA 只需 < 3 GBGitHub

  • 多任务复用:一套基座模型 + 多个小补丁(前缀 / 适配器 / LoRA 权重)即可随时热插拔arXiv

  • 性能:最新报告显示,LoRA / Prefix-Tuning 在 GLUE、SuperGLUE 上与全量微调几乎持平


3.核心总结(先看这一段就够)

  • Adapter-Tuning 在 Transformer 每层插 两个 “瓶颈 FFN”:①多头注意力后的 Adapter;②前馈 FFN 后的 Adapter;仅训练这两个小矩阵,典型降维 r≈𝑑/16~𝑑/32,可同时得到非线性表达与极低参数量。arXivMedium

  • Prefix-Tuning 为每层注意力预先学出 r 行“伪 Key/Value”(KV 前缀)并 在序列维度拼接 到真 KV;r 指“前缀长度”而非维度,一般 5-100 token。Prompt-Tuning 只在最底层词嵌入端插伪 token。MediumMedium

  • LoRA每个线性层(Q/K/V/O 投影 + MLP 的两次线性)挂 ΔW = (B · A)/α;A∈ℝ^{d×r}, B∈ℝ^{r×d}。推理时一次 matmul 完成,无延迟。arXivAdapterHub 文档

  • AdaLoRA 先用低秩 r₀(如 4)训练,再按梯度重要度把总秩 R_total 动态分给不同层,r_l 最终可从 4 涨到 32 不等。arXiv

  • IA³ 仅给 Q/K/V 输出各乘一个长度 d 的缩放向量 γ_Q, γ_K, γ_V——三条向量×层数而已,显存≈BitFit。Sebastian Raschka's Magazine

  • DoRA / EDoRA 把权重分解成 “幅度(‖W‖) × 方向(W/‖W‖)”,只用 LoRA 学方向;EDoRA 用一次 SVD 把主方向当作初始化,收敛更快。Sebastian Raschka, PhD

最常见换挡代码

from peft import PromptTuningConfig, get_peft_model
from peft.utils.peft_types import TaskType

from peft import (
    PrefixTuningConfig,  # 前缀调优
    LoraConfig,         # LoRA 与 DoRA
    AdaLoraConfig       # 自适应 LoRA
)
from peft.utils.peft_types import TaskType

# P-Tuning
# P-Tuning 自动在连续空间中搜索最优 prompt,相当于学习一段软 prompt,以少量参数完成下游任务
peft_config = PromptTuningConfig(
    peft_type="P_TUNING",            # 指定 P-Tuning
    task_type=TaskType.SEQ_2_SEQ_LM, # 序列到序列语言建模
    num_virtual_tokens=20,           # prompt 长度
    encoder_hidden_size=1024         # 与模型隐藏维度一致(可选)
)

# Prefix-Tuning
# Prefix Tuning 将一段可学习的“虚拟 token”前缀插到模型每一层,保持预训练权重冻结,只优化前缀向量
peft_config = PrefixTuningConfig(
    task_type=TaskType.CAUSAL_LM,   # 自回归语言模型
    num_virtual_tokens=30,          # 虚拟前缀长度
    prefix_projection=True,         # 使用小型 MLP 投影生成前缀
    inference_mode=False            # 训练模式
)

# LoRA
# LoRA 将大型矩阵分解为两组低秩矩阵,在注意力层插入可训练参数;DoRA(EDoRA)在此基础上将权重更新拆分为“方向”和“幅度”,仅对方向部分应用低秩适配,通过 use_dora=True 开启 
# 在低秩(如 r=8)时,DoRA 往往取得优于标准 LoRA 的表现
peft_config = LoraConfig(
    task_type       = TaskType.CAUSAL_LM,
    r               = 8,              # 低秩秩值
    lora_alpha      = 16,             # 缩放系数
    target_modules  = ["c_attn","q_proj","v_proj"],
    lora_dropout    = 0.05,           # 默认即可
    bias            = "none",         # 默认即可
    normalize_input = True,           # 对输入做归一化
    use_dora        = False           # 是否启用 DoRA
)



# DoRA(通过 LoraConfig)
# 在低秩(如 r=8)时,DoRA 往往取得优于标准 LoRA 的表现
peft_config = LoraConfig(
    task_type       = TaskType.CAUSAL_LM,
    r               = 8,              # 低秩秩值
    lora_alpha      = 16,             # 缩放系数
    target_modules  = ["c_attn","q_proj","v_proj"],
    lora_dropout    = 0.05,
    bias            = "none",
    normalize_input = True,           # 对输入做归一化
    use_dora        = True            # 启用 DoRA
)

#EDoRA
# 	EDoRA(Efficient Weight-Decomposed Low-Rank Adaptation)是 2025 年由 Nasiri 等人提出的独立 PEFT 方法,通过 SVD 初始化并冻结低秩矩阵,仅在两者之间插入极小可训练矩阵,显著减少可训练参数  
# Hugging Face PEFT 尚未将 EDoRA 集成到 LoraConfig 中,还得等一会
# 	若需使用 EDoRA,需要额外引入其官方代码库(如 pip install git+https://github.com/Hamid-Nasiri/EDoRA.git)并调用特别接口(如 find_and_initialize)来完成 SVD 初始化和冻结策略  



# AdaLoRA
# AdaLoRA 动态分配各层的秩预算,通过训练过程中的重要性度量对不同层进行裁剪或增补,实现更优的参数利用率 。
# 适用于模型各层重要性差异较大的场景,可进一步压缩训练参数 。
peft_config = AdaLoraConfig(
    task_type  = TaskType.CAUSAL_LM,
    r          = 8,
    lora_alpha = 16,
    init_r     = 4,    # 初始秩
    tinit      = 200,  # 动态调整开始步数
    tfinal     = 1200  # 调整结束步数
)

model = get_peft_model(model, peft_config)

 换完 peft_cfg其余训练 / 推理代码完全不动——这就是 PEFT 的“一键切换”体验。

只需换 peft_cfg,其它代码不变。 以下示例展示 定义 → 训练 → 保存 / 加载 → 推理
你可把 peft_cfg 改成 PrefixTuningConfigAdaLoraConfigDoRAConfig 等。

最小完整脚手架(保存 / 加载)

# ——训练阶段——
model.save_pretrained("gpt2_lora")      # 只存 Base + LoRA 权重
tokenizer.save_pretrained("gpt2_lora")

# ——部署阶段——
tok = AutoTokenizer.from_pretrained("gpt2_lora")
base = GPT2LMHeadModel.from_pretrained("gpt2")      # 只需一份基座
model= GPT2LMHeadModel.from_pretrained("gpt2_lora") # 自动merge ΔW→W
model.eval()

🤗 PEFT 会在加载时自动解析模型类,找到 q_proj/k_proj/... 并插入对应外挂(也就是找到Q,K, V, O 的位置插入 );常用模型都已手工注册 target-module map。自定义模型可以传 target_modules 名单。

 PEFT 是怎么“自动插层”的?

  • 每种 Config 都包含 target_modules;库会 递归遍历 model.named_modules() 找到匹配 Linear 并 wrap。

  • 对常见骨干(GPT-2/Llama/Bloom…)官方已预置正则,无需手写。

  • 新模型只要给出 target_modules=["W_q","W_k",…] 等关键词即可;不需要手改源码。文档示例见 PrefixTuningConfig & LoRAConfig 源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值