Prompt Tuning
提示调优通过训练少量添加到输入中的软提示向量,让冻结的模型适应特定任务,从而使一个模型能够处理多种任务。
提示调优通过训练一小组称为软提示的向量,使预训练的基础模型适应新任务;这些向量会置于输入前,而所有模型权重都保持冻结。软提示与模型 token 的嵌入处于同一空间,但其向量通过反向传播学习得出,无需对应任何真实单词。Google 的 Brian Lester、Rami Al-Rfou 和 Noah Constant 在发表于 EMNLP 2021 的 The Power of Scale for Parameter-Efficient Prompt Tuning中介绍了这种方法。他们指出,针对拥有 110 亿参数的 T5-XXL 模型,五个 token 的提示每个任务只需 20,480 个参数;他们还表明,当模型规模超过数十亿参数后,提示调优的准确率可以媲美整个模型的调优。
提示调优的工作原理#
大型语言模型(LLM)会先将每个输入token转换为嵌入向量,然后才将其送入Transformer层。提示调优会在序列前添加 k 个额外向量;Lester 等人测试了 1 到 150 的长度,默认使用 100。训练期间,任务的损失函数会通过冻结的网络一路反向传播到输入,而优化器只更新提示向量。最终,每个任务都会得到一个小型张量。由于模型本身始终不变,移除提示即可恢复模型原有行为,不会有灾难性遗忘的风险;同一个已部署模型副本可以同时服务多个任务,每个批次请求都携带自己的软提示,这种方式被 Lester 等人称为混合任务推理。
下面的 PyTorch示例使用来自 Hugging Face Transformers 的冻结 GPT-2,以四条训练评论和八条留出评论为情感分析任务调优一个包含 8 个向量的软提示:
import torch
from torch.nn.functional import cross_entropy
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2").requires_grad_(False) # freeze all 124M weights
embed = model.get_input_embeddings()
# Soft prompt: 8 trainable vectors in GPT-2's embedding space, initialized from the word " review"
soft_prompt = torch.nn.Parameter(embed.weight[tokenizer.encode(" review")].repeat(8, 1).clone())
optimizer = torch.optim.Adam([soft_prompt], lr=0.01)
labels = tokenizer.encode(" positive negative") # token ids for label 0 and label 1
# Reviews alternate between positive (label 0) and negative (label 1)
train = ["Loved every minute.", "A waste of time.", "Great story and acting.", "Boring and slow."]
test = ["What a wonderful film.", "I fell asleep halfway.", "A fantastic ending.", "Terrible dialogue."]
test += ["A joy to watch.", "Dull and predictable.", "Superb from start to end.", "I want my money back."]
def label_scores(text):
"""Score both label tokens after the soft prompt and the review."""
ids = tokenizer.encode(f"{text} Sentiment:", return_tensors="pt")
return model(inputs_embeds=torch.cat([soft_prompt[None], embed(ids)], dim=1)).logits[0, -1, labels]
def correct():
"""Count held-out reviews whose higher-scoring label is right."""
with torch.no_grad():
return sum(int(label_scores(text).argmax()) == i % 2 for i, text in enumerate(test))
print(f"Held-out reviews correct before tuning: {correct()}/8")
for step in range(30):
loss = sum(cross_entropy(label_scores(text), torch.tensor(i % 2)) for i, text in enumerate(train))
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f"After tuning: {correct()}/8, training {soft_prompt.numel():,} of {model.num_parameters():,} parameters")它会先打印Held-out reviews correct before tuning: 5/8,然后打印After tuning: 7/8, training 6,144 of 124,439,808 parameters。在四个示例上运行 30 步 Adam后,只有 6,144 个数值发生变化,仅占模型的 0.005%;冻结的 GPT-2 还正确分类了另外两条未见过的评论。
前缀调优与视觉提示调优#
提示调优属于参数高效微调(PEFT)中的连续提示方法。Xiang Lisa Li 和 Percy Liang 提出的前缀调优会在每个 Transformer 层前添加学习得到的向量,参数量约为 GPT-2 或 BART 的 0.1%;在表格转文本生成和摘要任务上,其效果媲美完整微调。提示调优则进一步简化了这一方法,只在输入层学习向量。
这一思路也适用于视觉领域。Menglin Jia 及其同事提出的视觉提示调优(VPT)会在冻结的视觉 Transformer(ViT)的图像块 token 前添加可学习 token,训练的参数量不到 1%,并且在许多图像分类场景中优于完整微调。对于视觉语言模型,Kaiyang Zhou 及其同事提出的上下文优化(CoOp)会用学习得到的向量替换 CLIP提示中手写的词语,例如“a photo of a”。在 11 个数据集上,每类只提供一个或两个带标签的示例时,CoOp 的效果优于手工设计的提示;每类提供 16 个示例时,平均提升约 15%。
开放词汇检测器也会以相关方式进行适配。Ultralytics YOLOE会将类别名称转换为文本提示嵌入;其针对自定义数据集的线性探测方案会将数据集类别名称的嵌入融合到每个分类分支的最终卷积层中,然后只训练这些层,同时冻结骨干网络、颈部网络和检测头的其余部分。










