Prefix-Tuning:为 Transformer 每层添加可学习前缀

FreeGuideOnline 最新 2026-06-22

什么是 Prefix-Tuning?

Prefix-Tuning 是一种针对预训练语言模型的参数高效微调方法。
它的核心思想极其简洁:在 Transformer 每一层的输入序列前,拼接上若干可学习的连续向量(前缀),而在训练过程中保持原始预训练模型的所有参数完全冻结

这一小段“前缀”相当于给模型下达了任务指令,指引生成方向,而无需修改模型本身的海量参数。
与全参数微调相比,Prefix-Tuning 需要的存储和计算开销减少上千倍,同时在下游任务上达到极具竞争力的效果。


为什么需要 Prefix-Tuning?

全参数微调的痛点

  • 巨大存储成本:每个下游任务都需要保存一份完整的模型副本(例如 GPT-2 的 1.5B 参数需要 ~6GB),当服务数十个任务时几乎不可行。
  • 灾难性遗忘风险:微调会扭曲预训练权重,导致模型丧失通用能力,且难以持续学习新任务。
  • 部署复杂性:为每个任务维护独立的大型模型实例,推理延迟和资源占用极高。

参数高效微调的兴起

为解决上述问题,研究者提出只训练极少量附加参数(通常 < 原始参数的 1%)。
Prefix-Tuning 是该方向的一次优雅突破:它不为模型引入新结构,而是直接在层输入端注入“虚拟 token”,这些虚拟 token 的向量就是唯一的可训练参数。


核心原理:将“提示工程”连续化

从离散提示到连续前缀

人工设计的提示(Prompt)需要精心选择词汇,且受限于离散词汇空间,优化困难。
Prefix-Tuning 借鉴了提示的直觉,但将离散的文本提示变成一组可微的自由向量——它们不需要对应任何真实的单词,仅通过梯度下降进行优化。这些向量就像是“软提示”,在模型内部被处理。

前缀作用于每一层

对于 Transformer 的每一层,Prefix-Tuning 在该层的键(Key)和值(Value)矩阵之前分别拼接前缀向量。
以自回归模型(如 GPT-2)为例,原本的注意力计算是:

[ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right)V ]

引入前缀后,键、值矩阵变为:

[ K_{\text{prefix}} = [P_K ; K], \quad V_{\text{prefix}} = [P_V ; V] ]

其中 ( P_K, P_V \in \mathbb{R}^{l \times d} ) 是长度为 ( l ) 的可学习前缀向量(( d ) 是隐藏维度),; 表示拼接。
查询 ( Q ) 矩阵保持不变,因此注意力机制会自然地让原始序列去“关注”前缀,前缀扮演了上下文指导的角色。

如何稳定训练:重参数化技巧

直接优化前缀矩阵 ( P ) 在低资源任务上会不稳定,并且对学习率和初始化敏感。
Prefix-Tuning 采用一个**重参数化(Reparameterization)**策略:用一个小的 MLP 网络重新生成前缀矩阵。即:

[ P = \text{MLP}_{\theta}(P') ]

其中 ( P' ) 是一个维度更小的可学习矩阵。训练时只保存和优化 ( P' ) 和 MLP 参数,推理时丢弃 MLP,仅保留等价的前缀矩阵 ( P )。这样做相当于在优化过程中引入了平滑约束,大幅提升训练稳定性。


与传统微调的对比

对比维度 全参数微调 Prefix-Tuning
可训练参数量 100% 模型参数(数十亿) 仅前缀向量 + 小型 MLP(通常 < 0.1%)
任务存储 每个任务一份完整模型 每个任务仅需保存前缀(~几百 KB)
推理时计算 不变 微增(仅多处理前缀 token 的注意力)
灾难性遗忘 风险高 极低(原始参数冻结)
多任务服务 需要加载多个完整模型 可在同一模型上动态切换前缀
训练稳定性 依赖大量数据 采用重参数化后,小样本也能稳定训练

逐步理解:Prefix-Tuning 的工作流程

步骤 1:准备预训练模型

选择一个冻结参数的预训练 Transformer(如 GPT-2、BART)。模型权重在训练中完全不更新。

步骤 2:定义前缀参数

为每一层(或某些层)初始化两组可学习矩阵:( P_K, P_V ),形状为 (prefix_len, hidden_dim)
同时构建对应的小型 MLP:输入为 P'(形状 (prefix_len, bottleneck_dim)),输出为 P

步骤 3:构建输入

对于训练样本 [x1, x2, ..., xn](这里以自回归生成任务为例),在输入序列前拼接前缀占位符。
实际计算时,前缀对应的隐藏状态直接从 ( P ) 中提取,而原始序列保持正常嵌入。

步骤 4:前向传播与注意力计算

每层计算注意力时,( K, V ) 都被替换为前缀 + 真实序列的组合。
这迫使模型去“适应”前缀的内容,学习到有利于下游任务的行为模式。

步骤 5:反向传播与优化

仅计算前缀和 MLP 参数的梯度,冻结模型其余部分。使用标准语言建模损失进行优化。

步骤 6:部署与推理

训练收敛后,舍弃 MLP,直接存储最终的 ( P_K, P_V ) 矩阵。
推理时,将此前缀矩阵永久性地拼接到每一层的 ( K, V ) 前端。同一模型通过加载不同的前缀文件即可立刻切换任务。


代码模拟:Prefix-Tuning 的实现要点

下面以自回归生成模型为例,展示概念化的实现要点(使用类 PyTorch 伪代码)。

class PrefixTuningLayer:
    def __init__(self, hidden_dim, prefix_len, bottleneck_dim):
        self.prefix_K = nn.Parameter(torch.randn(prefix_len, hidden_dim))
        self.prefix_V = nn.Parameter(torch.randn(prefix_len, hidden_dim))
        # 重参数化 MLP
        self.mlp = nn.Sequential(
            nn.Linear(bottleneck_dim, hidden_dim),
            nn.Tanh(),
            nn.Linear(hidden_dim, hidden_dim * 2)  # 输出 K 和 V 拼接
        )
    def get_prefix(self, P_prime):
        # 通过 MLP 生成稳定的前缀
        combined = self.mlp(P_prime)
        K_part, V_part = combined.chunk(2, dim=-1)
        return K_part, V_part
    def forward(self, hidden_states, P_prime=None):
        K_pre, V_pre = self.get_prefix(P_prime) if P_prime else (self.prefix_K, self.prefix_V)
        # hidden_states: seq_len x batch x hidden_dim
        # 扩展前缀到 batch 维度
        K_pre = K_pre.unsqueeze(1).expand(-1, hidden_states.size(1), -1)
        V_pre = V_pre.unsqueeze(1).expand(-1, hidden_states.size(1), -1)
        # 键值拼接
        key = torch.cat([K_pre, hidden_states], dim=0)
        value = torch.cat([V_pre, hidden_states], dim=0)
        query = hidden_states  # 查询仍然只用原始序列
        # 后续执行标准注意力...

实际工程中需注意:

  • 前缀向量通常与原始序列的 hidden_states 直接拼接在层的输入端。
  • 推理时直接保存训练好的 prefix_Kprefix_V,不需要 mlp
  • 前缀长度 prefix_len 一般设置在 5~200 之间,视任务复杂度而定。

前缀长度的选择与影响

前缀长度是一个关键超参数:

  • 过短(如 <5):表达能力不足,难以捕捉复杂任务结构。
  • 过长(如 >200):增加额外计算开销,且可能过拟合小样本任务。
  • 一般规律:摘要生成、表格到文本等结构化任务中,10~50 的前缀长度已能取得优异性能;简单的分类任务甚至只需 5~10。

可以通过在验证集上扫描前缀长度,平衡效果与效率来选择。


进阶技巧与常见问题

初始化策略

前缀向量的初始化对收敛影响显著。常见做法是使用一个服从正态分布的小随机值,或者利用预训练模型词嵌入的均值进行初始化。

多层共享前缀

在低资源场景下,可以让所有 Transformer 层共享同一组前缀参数,进一步减少可训练参数,有时还能提升泛化能力。

适配编码器-解码器模型

对于 BART、T5 等模型,前缀可同时应用于编码器和解码器。通常编码器的前缀帮助理解源句子,解码器的前缀控制生成风格。也可单独为编码器或解码器添加前缀,灵活性很高。

训练不稳定怎么办?

  • 务必使用重参数化(MLP),它能有效平滑损失空间。
  • 适当降低前缀部分的学习率(例如设为基本学习率的 0.1~1 倍)。
  • 使用线性 warmup 和余弦退火调度。

应用场景与扩展

Prefix-Tuning 在多种 NLP 生成任务上表现亮眼:

  • 表格到文本生成:如 E2E、WebNLG 数据集,前缀能准确捕捉结构信息。
  • 摘要生成:前缀提供语言风格和重点提示。
  • 对话系统:不同前缀可对应不同人格或情绪,实现多风格对话。
  • 多任务持续学习:只需串接新的前缀序列,旧前缀不受影响,完美避免遗忘。

此外,该思想已延伸出 P-Tuning v2 等方法,将可学习向量从输入层推广到整个模型的前缀,形成一个通用的参数高效微调范式。


总结

Prefix-Tuning 将对预训练模型的干预精确地限制在每一层的前缀输入,用极小的参数代价实现了任务适配。
它让部署数十种许语言功能在一个不变的底座模型上成为现实,是实现多任务、低存储、可插拔 NLP 系统的关键组件。

对于初学者,建议优先尝试在小型 GPT-2 上实现前缀调优,直观感受“冻结模型 + 可学习前缀”的强大与优雅。