PEFT 总览:LoRA、Adapter、Prefix 等高效微调方法
什么是参数高效微调(PEFT)
参数高效微调(Parameter-Efficient Fine-Tuning,PEFT)是一类针对大规模预训练模型进行适配的技术框架。它的核心思想是:在保留原始模型全部参数不变的前提下,仅引入或调整少量额外参数,来使模型快速适应下游任务。相比于全量微调(Full Fine-Tuning),PEFT 方法通常只需训练原模型参数量的 0.01%~5%,在显著降低算力和存储成本的同时,取得接近甚至超越全量微调的表现。
PEFT 的典型优势包括:
- 资源友好:消费级 GPU 即可微调数十亿参数的大模型。
- 多任务存储高效:每个下游任务只需保存一份极小的权重增量,不用为每个任务复制整个模型。
- 灾难性遗忘缓解:由于基座模型参数冻结,较好地保留了预训练阶段学到的通用知识。
- 快速适配:训练时间大幅缩短,适合需要频繁迭代的场景。
目前,主流的 PEFT 方法可划分为以下几类:Additive(加法型)、Selective(选择型)、Reparameterization(重参数化) 以及 混合方法。下面详细介绍其中最核心的三种技术:Adapter、Prefix Tuning 和 LoRA。
Adapter:插入小模块的经典方法
核心思想
Adapter 是一种加法型 PEFT 方法,它在 Transformer 的子层之间插入轻量级的可训练模块(Adapter Layer)。这些模块通常是一个先降维再升维的小型瓶颈网络(bottleneck),并包含非线性激活函数。训练时,原始模型参数全部冻结,只更新这些插入的 Adapter 参数。
结构与工作流程
一个典型的 Adapter 层结构如下:
- 下投影(Down-Project):将输入特征维度
d映射到较小的瓶颈维度m(m << d)。 - 非线性激活(如 GeLU、ReLU)。
- 上投影(Up-Project):从
m维映射回原来的维度d。 - 残差连接:Adapter 的输出通过一个残差连接与原始输入相加,保证初始化时模型行为不变。
数学表达为:
Adapter(x) = W_up(σ(W_down(x))) + x
其中 W_down ∈ R^{d×m}, W_up ∈ R^{m×d}, σ 为激活函数。通常每个 Adapter 块的可训练参数量仅为 2dm,远小于原 Transformer 层的参数。
插入位置
初期工作(如 Houlsby et al.)将 Adapter 放置在注意力和前馈网络之后。后续研究表明,仅在前馈网络之后插入 Adapter,或者在注意力块和前馈块各插入一个,都能取得良好效果。插入位置可灵活调整,以平衡效率与性能。
优缺点
- 优点:实现简单,易于迁移到不同架构;训练稳定。
- 缺点:即使瓶颈维度很小,累加的 Adapter 层仍然会增加推理时的延迟(因引入额外串行计算)。对于大批量推理或低时延要求场景,这种额外开销可能不可忽视。
Prefix Tuning:可学习的虚拟 Token 前缀
核心思想
Prefix Tuning 属于加法型 PEFT,它的灵感来自语言模型的上下文提示。该方法在输入序列的前端拼接若干个连续的、可学习的虚拟 Token 向量(prefix),这些向量不映射到真实的词,但会被标准的 Transformer 层处理。训练时只优化这些前缀向量,基座模型保持冻结。
数学形式
设原始输入 Token 嵌入序列为 X = [x_1, x_2, ..., x_n],将其替换为:
[P_1, P_2, ..., P_k, x_1, x_2, ..., x_n]
其中 P_i 是可训练的前缀向量,共 k 个。在自回归语言模型的训练中,通常还会在目标一侧添加对应的可训练后缀(如 P-tuning v2 的做法),以增强对深层网络的影响。
训练稳定性与重参数化
直接优化前缀向量往往存在训练不稳定、优化困难的问题。因此,Prefix Tuning 常使用一个重参数化技巧:用一个较小的 MLP 网络生成前缀矩阵,再将其拆分给各层。训练时只保存 MLP 参数,推理时则用生成好的前缀替换该 MLP,降低存储和推理成本。
适用场景
Prefix Tuning 特别适用于生成任务,如摘要生成、机器翻译、对话生成等。因为它直接作用于每一层的注意力键和值,能够有效地引导模型行为。与 Adapter 不同,它不增加额外的层内计算,仅仅是增加了输入长度,因此推理时不会有明显的逐层延迟增加。
LoRA:低秩适配与重参数化
核心思想
LoRA(Low-Rank Adaptation)是目前最广泛使用的 PEFT 方法之一,属于重参数化方法。它基于这样的洞察:模型在适配下游任务时,权重的更新矩阵通常是低秩的。LoRA 将预训练权重冻结,并通过对权重矩阵添加一个低秩分解的可训练增量来实现微调。
数学原理
对于一个预训练权重矩阵 W_0 ∈ R^{d×k},LoRA 将其修改为:
h = W_0 x + ΔW x = W_0 x + B A x
其中 A ∈ R^{r×k}, B ∈ R^{d×r},秩 r << min(d, k)。矩阵 A 使用随机高斯初始化,B 初始化为零,从而保证训练开始时 ΔW = 0,模型行为与预训练完全一致。训练时只优化 A 和 B,前向计算相当于完成一次 W_0 x 的冻结计算和一次低秩分支的可训练计算。
通常我们会为 ΔW 乘以一个缩放因子 α/r 来调节更新幅度:
h = W_0 x + (α/r) B A x
其中 α 是常数超参数,r 为秩。
作用范围与配置
LoRA 一般只对 Transformer 中的注意力模块的查询(Q)和值(V)权重进行适配,有时也会扩展到键(K)和输出(O)权重,甚至前馈网络。只作用于 Q 和 V 已经能在多数任务上获得很好效果。秩 r 通常取 4、8、16 等较小值。
显著优势
- 不增加推理延迟:训练出的低秩矩阵可以合并(merge)回原始权重
W = W_0 + B A,推理时完全等价于原始模型计算,没有任何额外开销。 - 参数效率极高:对于 GPT-3 175B,使用
r=4的 LoRA 可训练参数仅占总参数的 0.01%。 - 易于存储和切换:每个任务只需保存
A和B矩阵,尺寸极小,可实现快速任务切换。
变体与发展
- LoRA+:对矩阵 A 和 B 采用不同的学习率,加速收敛。
- QLoRA:结合 4-bit 量化基础模型和 LoRA,进一步降低显存占用。
- DoRA:将权重分解为幅度和方向,仅对方向部分应用 LoRA,提升学习能力。
其他值得关注的 PEFT 方法
Prompt Tuning
直接在输入嵌入前拼接一段连续可学习向量,可以看作 Prefix Tuning 的特例(仅拼接在输入层,不介入每一层)。它极其简单,但只在超大模型(>10B)上表现稳定。对于中小模型,效果弱于 Prefix Tuning 或 LoRA。
P-Tuning & P-Tuning v2
P-Tuning 引入可学习的嵌入并在输入中添加 anchor 点,主要用于自然语言理解任务。P-Tuning v2 将可学习 token 应用到每一层,思想和 Prefix Tuning 深度对齐,但更强调面向各种尺度的 NLU 模型。
IA³
通过可学习的向量(可理解为缩放因子)来重新缩放 Transformer 中激活,分别作用在键、值和前馈网络的激活上,参数量比 LoRA 更少,但合并操作不如 LoRA 直接,推理时有轻微额外计算。
(Soft) Prompt 与 Hard Prompt 的区别
传统的手工构造离散 Prompt(Hard Prompt)难设计且不稳定。PEFT 中的连续提示(Soft Prompt)完全由数据驱动,优化空间连续,性能更加稳定和鲁棒。
如何选择 PEFT 方法
| 方法 | 额外参数规模 | 推理延迟影响 | 适用任务 | 典型优势 |
|---|---|---|---|---|
| Adapter | 中等(约 0.5-5%) | 略有增加 | NLU / NLG 通用 | 实现简单,稳定 |
| Prefix Tuning | 极小(<0.1%) | 微增(序列长度增加) | 生成任务为主 | 对生成控制力强 |
| LoRA | 极小(<1%) | 无(可合并) | 通用,尤其适合千亿级大模型 | 零推理成本,存储高效 |
| Prompt Tuning | 极小 | 极少 | 超大模型(>10B) | 绝对简单 |
| IA³ | 极小 | 微增 | 多任务前缀适配 | 参数最少的一类 |
实际选型建议:
- 若追求部署便利和零推理延迟,优先选 LoRA,它能直接合并回权重。
- 如果任务是生成类,且对控制能力要求高,可尝试 Prefix Tuning 或 P-Tuning v2。
- 若在多任务间频繁切换,且不能做大尺寸合并缓存,Adapter 或 prefix 类方法可动态加载。
- 对极低显存场景(如量化微调),可使用 QLoRA。
快速实践:用 Hugging Face PEFT 库运行 LoRA
Hugging Face 的 peft 库为上述方法提供了统一接口。以下以 LoRA 微调一个 causal LM 为例:
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model, TaskType
base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
# 配置 LoRA
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=8, # 秩
lora_alpha=32, # 缩放
lora_dropout=0.1,
target_modules=["q_proj", "v_proj"] # 作用于 attention 的 Q 和 V
)
# 注入 LoRA
peft_model = get_peft_model(base_model, lora_config)
peft_model.print_trainable_parameters()
# 输出: trainable params: 4,194,304 || all params: 6,742,609,920 || trainable%: 0.0622
后续只需像标准模型一样进行 Trainer 或自定义训练循环即可。训练完成后可合并权重:
merged_model = peft_model.merge_and_unload()
merged_model.save_pretrained("my_lora_merged")
对 Adapter 或 Prefix Tuning,只需更换配置类(如 PrefixTuningConfig、AdapterConfig),其余流程完全一致。
总结
参数高效微调(PEFT)为大模型的实际落地提供了经济、灵活的路径。LoRA 以其零推理开销和极高参数效率成为当前事实上的首选方案;Adapter 易于理解和实现,适合快速原型;Prefix Tuning 则在生成任务保持独特优势。配合不断成熟的工具生态,初学者也能在消费级硬件上轻松微调十亿、百亿参数模型。建议从 LoRA 入手实践,逐步探索其他方法的适用场景。