摘要
面对 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 改成 PrefixTuningConfig、AdaLoraConfig、DoRAConfig 等。
最小完整脚手架(保存 / 加载)
# ——训练阶段——
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 源码。

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



