Adapter与Prefix-Tuning
Adapter 原理与结构
Adapter(适配器)是一种经典的参数高效微调方法,通过在Transformer层中插入小的Adapter模块,只训练Adapter参数,冻结原模型参数。
核心结构
每个Adapter包含:
- Down-project层:将高维特征映射到低维隐空间,降低计算量
- 非线性激活:引入非线性能力
- Up-project层:将低维特征映射回原来的高维维度
- Skip-Connection:残差连接,最差情况退化为恒等映射
结构图示:
输入 x → Down-project (d → r) → 非线性 → Up-project (r → d) → 加残差 → 输出
x ────────────────────────────→ +
插入位置
通常在每个Transformer层的:
- 注意力层之后
- FFN层之后
插入Adapter模块。
特点
- 优点:参数量少,原模型冻结,不容易遗忘,每个任务只保存少量Adapter参数
- 缺点:推理时每个Adapter都增加额外计算,引入推理延迟,无法像LoRA那样合并权重消除延迟
Adapter变体
AdapterFusion
- 在Adapter基础上优化,融合多任务信息
- 将学习分为两个阶段,提升下游任务表现
- 学习不同任务Adapter的组合权重
AdapterDrop
- 动态移除不重要的Adapter来提高效率
- 从较低的Transformer层删除可变数量的Adapter
- 在不影响性能的前提下,减少运行时计算开销,提高推理速度
MAM Adapter
- 统一Adapter、Prefix Tuning和LoRA的方法
- 最终模型是用于FFN的并行Adapter + 软提示的组合
- 效果优于单个高效微调方法
Prefix-Tuning / P-Tuning / P-Tuning v2
Prefix-Tuning(前缀微调)
思想
- 在输入token之前构造一段任务相关的virtual tokens作为Prefix
- 训练时只更新Prefix部分参数,Transformer其他参数全部固定
- 为了防止训练不稳定,在Prefix层前面加MLP进行重参数化
优点
- 相比人工设计离散Prompts,可以学习隐式提示
- 相比全参数微调,只更新少量参数,参数高效
- 支持一个批次处理多个任务样本
缺点
- 占用序列长度,减少了可用输入空间
- 在每层都加prompt参数,改动较大,有额外计算开销
- 主要针对NLG任务,对GPT架构设计
P-tuning
针对GPT-3的人工prompt模板对结果非常敏感,人工模板质量波动大,因此提出P-tuning(也叫Prompt Tuning v1)。
思想
- 将Prompt转换为可学习的Embedding层
- 使用Prompt Encoder(双向LSTM + 两层MLP)对Prompt Embedding编码,建模伪token的依赖关系,提供更好的初始化
- 允许prompt伪token不连续插入输入序列中
优点
- 自动学习prompt,不需要人工设计模板
- 相比离散prompt,效果更稳定
缺点
P-tuning v2
P-tuning v2是对P-tuning的改进,目标是让Prompt Tuning在不同参数规模的模型上都能达到媲美Fine-tuning的效果。
关键改进
- Deep Prompt Encoding:采用Prefix-tuning的做法,在输入前面的每层都加入可微调的Prompt tokens作为输入
- 移除重参数化编码器:去掉Prefix-tuning中的MLP和P-tuning中的LSTM重参数化,虽然减少了训练速度和鲁棒性,但对小模型效果提升更明显
- 不同任务不同提示长度:提示长度在超参搜索中起核心作用,不同任务最佳长度不同
- 支持多任务预训练:先在多任务prompt上预训练,再适配下游任务
- 回归传统分类范式:抛弃verbalizer,直接使用Classification Head,适配序列标注等任务
优点
- 更多可学习参数(从0.01%增加到0.1%-3%),仍然参数高效
- 深层Prompt对预测影响更直接
- 解决了Prompt Tuning在小模型上效果不佳的问题
- 拓展到NER等序列标注任务
缺点
- 抛弃verbalizer某种程度上弱化了prompt的理念
Prompt Tuning
Prompt Tuning(指示微调)是将prompt扩展到连续空间的方法。
核心思想
- 仅在输入层添加连续prompt向量,通过反向传播更新参数学习prompts,不需要人工设计
- 冻结模型原始权重,只训练prompts参数
- 推理时,同一个基础模型可以做多任务推理,切换任务只需要切换prompts
- 使用LSTM建模prompt向量之间的关联性
优点
- 只在输入层加入prompt tokens,不需要MLP调整,结构简单
- 随着预训练模型参数量增加,Prompt Tuning效果逼近全参数微调
- 支持prompt ensembling:一个批次训练同一个任务的不同prompt,成本低效果好
缺点
- 训练难度大,省显存但不一定省时间
- 多个prompt token之间相互独立,可能影响效果
- 在小模型上表现不佳
- 难以处理复杂的序列标注任务
Prompt Tuning vs Prefix-Tuning 区别
| 维度 | Prompt Tuning | Prefix-Tuning |
|---|
| 适用任务 | 所有类型任务 | 主要针对NLG任务,GPT架构 |
| 添加位置 | 只在输入层添加 | 每一层都添加 |
| 可训练参数 | 少 | 多 |
Prompt Tuning vs Fine-tuning 区别
- Fine-tuning改变所有预训练参数,可能带来灾难性遗忘
- Prompt Tuning不改变预训练参数,只微调连续prompt来引导已有知识使用,参数高效,不遗忘
各方法对比(LoRA vs Adapter vs Prefix)
参数对比
| 方法 | 可训练参数占比 | 推理延迟 | 能否合并消除延迟 | 参数量存储 |
|---|
| 全参数微调 | 100% | 无 | - | 每个任务完整模型 |
| LoRA | 0.1%-1% | 可合并为无 | 可以 | 只有低秩矩阵,很小 |
| Adapter | 0.5%-5% | 有额外延迟 | 不可合并 | 只有Adapter,很小 |
| Prefix-Tuning | 0.1%-3% | 占用序列长度 | 不可合并 | 只有prefix,很小 |
| Prompt Tuning | <0.1% | 无额外计算 | 不可合并 | 只有embedding,极小 |
场景选择
- 显存极度受限:Prompt Tuning > Prefix > LoRA > Adapter > 全参数
- 追求推理速度:LoRA(可合并) > Prompt Tuning > Prefix > Adapter
- 效果优先:全参数 > AdaLoRA > LoRA > Adapter > Prompt Tuning
- 多任务部署:LoRA(可切换) > Adapter > 全参数(每个任务一个模型)
总体评估
LoRA是目前工业界最流行的选择,因为:
- 设计简洁,易实现
- 效果稳定
- 可以合并消除推理延迟
- 可以切换多任务
- 生态完善,HuggingFace PEFT原生支持
面试常见问题
Q: Adapter为什么能减少参数更新?
A: Adapter通过插入小瓶颈结构,将参数更新限制在新增的小模块中,原模型全部冻结。Down-project到低维再升回来,使得新增参数量远小于原模型,所以整体可训练参数量很少。
Q: Adapter的推理延迟问题怎么解决?
A: Adapter本身无法像LoRA那样合并到原权重,所以必然增加推理计算量。AdapterDrop通过动态移除不重要层的Adapter来减少计算,在精度损失很小的情况下提高推理速度。
Q: Prefix-Tuning和Prompt Tuning有什么关系?
A: Prompt Tuning可以看作是Prefix-Tuning的简化版本,Prefix-Tuning在每一层都加prefix,而Prompt Tuning只在输入层加,参数更少。
Q: 为什么P-tuning v2要在每一层都加prompt?
A: 因为浅层的prompt对深层预测影响有限,在每一层都加入可学习prompt能让提示信息直接影响每一层的预测,效果更好,尤其对小模型提升明显。
Q: 参数高效微调都有哪几大类?
A:
- 增加额外参数:Prefix Tuning、Prompt Tuning、Adapter Tuning及其变体
- 选择部分参数更新:BitFit只偏置更新
- 重参数化:LoRA、AdaLoRA、QLoRA
- 混合方法:MAM Adapter、UniPELT组合多种方法