Prefix / Prompt Tuning:连续提示向量替代手工模板
什么是 Prefix / Prompt Tuning
在提示工程中,我们通常需要手动设计文本指令或示例来引导大语言模型完成特定任务。Prefix Tuning 和 Prompt Tuning 提供了一种替代方案:不再依赖手工编写的离散模板,而是直接在模型输入层添加一组可学习的连续向量,仅通过微调这些少量参数就能高效适配下游任务。两者本质上都是参数高效微调(Parameter‑Efficient Fine‑Tuning)技术,但设计哲学与粒度不同。
连续提示向量:区别于自然语言的 Token,它们是在连续空间中不断优化的实数向量,能与原始输入 Token 的 Embedding 拼接后共同送入模型。它们不直接对应任何实际单词,却能被模型“理解”为任务指令。
为什么要用连续提示替代手工模板
- 手工模板的局限性:自然语言模板高度依赖语言直觉,一个小词的变化可能导致性能剧烈波动,且无法保证最优。不同任务往往需要反复试错。
- 参数爆炸问题:全参数微调需要为每个任务保存一整套模型副本,存储和部署成本极高。
- 连续向量的优势:将提示“参数化”,让模型自己学会最优的输入表示,从而规避了离散搜索的不可导问题。同时,只需存储极少的任务专属参数(通常占总参数的 0.01%~0.1%),即可实现接近全量微调的效果。
Prefix Tuning:为 Transformer 添加任务前缀
核心思想
Prefix Tuning 在 Transformer 每一层的键(Key)和值(Value)状态上拼接一组可学习的向量,这些向量充当“虚拟 Token”的前缀,引导自注意力机制将上下文偏向目标任务。
假设原始输入序列长度为 L,我们在每一层的 K、V 前添加长度为 P 的前缀向量,那么注意力计算将变为:
$$ \text{Attention} = \text{softmax}\left( \frac{Q [K_{\text{prefix}} ; K]^\top}{\sqrt{d}} \right) [V_{\text{prefix}} ; V] $$
其中 $K_{\text{prefix}}, V_{\text{prefix}}$ 为可训练参数,$[;]$ 表示拼接。
结构细节
- 每层独立存储 $P \times d$ 维度的前缀矩阵($P$ 为前缀长度,$d$ 为隐藏维度)。
- 为避免直接优化高维矩阵不稳定,实际会通过一个小型神经网络(通常是一层 MLP)重新参数化生成前缀,训练时仅更新该小网络的参数,推理时直接保存生成的前缀。
- 前缀长度 $P$ 是超参数,典型值在 5~200 之间,任务越复杂可能需要更长的前缀。
训练与推理
- 冻结预训练模型的所有原始参数。
- 仅优化前缀生成网络的参数。
- 不同任务只需保存对应的最终生成前缀,切换任务时替换前缀即可,无需加载多个完整模型。
Prompt Tuning:更轻量的输入层微调
与 Prefix Tuning 的区别
Prompt Tuning 更加简洁:它只在输入层的 Embedding 前添加一组可学习的连续向量,而不修改 Transformer 每一层的内部状态。其余模型参数全部冻结。
实现方式
- 定义可训练的 Embedding 矩阵 $E_{\text{soft}} \in \mathbb{R}^{Q \times d}$,其中 $Q$ 是软提示 Token 数量。
- 将原始输入的 Embedding 与 $E_{\text{soft}}$ 拼接,再传递到冻结的语言模型。
- 训练过程中,反向传播仅更新软提示 Embedding。
关键挑战与对策
- 初始化敏感:随机初始化可能导致训练不稳定。常用策略有:
- 使用已有词汇的 Embedding 作为初始化(例如“分类任务”对应 Token 的嵌入)。
- 从任务标签的 Embedding 开始微调。
- 模型规模依赖:在较小模型上效果可能欠佳,但随模型参数增大(尤其达到百亿级别),Prompt Tuning 的表现逼近全参数微调。
Prefix / Prompt Tuning 对比
| 特性 | Prefix Tuning | Prompt Tuning |
|---|---|---|
| 干预位置 | 所有层的 K、V | 仅输入层 Embedding |
| 可训练参数量 | 每层独立前缀 + 重参数 MLP | 单个软提示 Embedding 矩阵 |
| 表达能力 | 更强,能逐层控制注意力偏向 | 较弱,仅改变输入表示 |
| 训练稳定性 | 一般通过重参数化稳定 | 依赖初始化技巧 |
| 存储效率 | 较高 | 极高 |
| 适用场景 | 复杂生成任务、多任务学习 | 分类、简单理解任务,超大模型 |
实战教程:使用 PEFT 库实现 Prompt Tuning
下面以 Hugging Face 的 peft 库为例,展示如何对因果语言模型应用 Prompt Tuning。
环境准备
pip install torch transformers peft datasets
加载模型与数据
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PromptTuningConfig, get_peft_model, TaskType
model_name = "bigscience/bloomz-560m"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
配置软提示
peft_config = PromptTuningConfig(
task_type=TaskType.CAUSAL_LM,
num_virtual_tokens=8, # 软提示 Token 数量
prompt_tuning_init="TEXT", # 使用文本初始化
prompt_tuning_init_text="将下面的句子翻译成英文:",
tokenizer_name_or_path=model_name,
)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters() # 查看可训练参数量
训练与推理
from transformers import Trainer, TrainingArguments
from datasets import Dataset
# 准备少量示例数据
train_data = [
{"input": "今天天气很好。", "target": "The weather is nice today."}
]
# 构建数据集(省略格式化细节,实际需对齐模型输入)
# ...
training_args = TrainingArguments(
output_dir="./prompt_tuning_output",
num_train_epochs=3,
per_device_train_batch_size=4,
logging_steps=10,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
)
trainer.train()
# 保存软提示权重
model.save_pretrained("my_prompt_tuning")
推理时只需加载基础模型和保存的软提示:
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(model_name)
model = PeftModel.from_pretrained(base_model, "my_prompt_tuning")
inputs = tokenizer("今天下雨。", return_tensors="pt")
outputs = model.generate(**inputs, max_new_tokens=20)
print(tokenizer.decode(outputs[0]))
注意事项
- 构造训练样本时,确保
labels与输入对齐,通常将软提示部分的标签设为 -100 忽略计算。 - 训练时务必冻结基础模型,
peft库会默认处理,但仍需确认model.requires_grad状态。 - 若使用因果语言模型,软提示 Token 会占用序列长度,请在截断时预留空间。
常见问题与调优建议
Q:软提示长度如何选择?
A:从 8 开始实验,复杂任务可尝试 20~100。过长会增加训练成本且可能过拟合,过短则信息容量不足。
Q:Prefix Tuning 是不是总是优于 Prompt Tuning?
A:不是。在超大模型(如 100B+)上,Prompt Tuning 足够媲美 Prefix Tuning,且更轻量。Prefix Tuning 在中等规模模型或生成类任务上优势更明显。
Q:训练不稳定怎么办?
A:检查学习率(推荐 1e-4~5e-2,视模型大小调整),使用 warmup,并尝试更换软提示初始化方式。对于 Prompt Tuning,分类任务可以用类别标签 Embedding 初始化。
Q:保存的软提示能否跨模型使用?
A:不能。软提示与特定模型权重紧密耦合,更换不同基础模型需要重新训练。
总结
Prefix Tuning 和 Prompt Tuning 用少量连续向量代替手工提示模板,既保留了预训练模型的强大能力,又实现了极低成本的任务切换。Prompt Tuning 因其实现简洁、存储高效,成为大规模服务场景的热门选择;而 Prefix Tuning 在表达力和训练稳定性上更胜一筹。结合 PEFT 等工具,开发者可以在几分钟内完成适配,为微调范式带来了新的可能。