
记得我刚接触大模型微调时,一开始就被全参数微调劝退了。我们拿到一个几十亿、上百亿参数的基座大模型,如果想让它学会我们自己的业务任务,比如抽取合同信息、做领域问答、分类产品工单,第一想法就是把整个模型全部拉过来重新训练一遍。但现实问题非常扎心,大模型全量微调,需要多张高端显卡,训练一次的算力成本动辄几万甚至十几万,普通开发者、中小企业根本承担不起。
而且全参数微调还有额外隐患,训练过程很容易发生灾难性遗忘,模型在学习新任务的同时,把基座模型原本学到的通用知识丢掉;同时每新增一个业务任务,就要保存一整套完整的模型权重,多个任务会占用海量存储。于是摸索新的路径,探索有没有办法,不动大模型主体权重,只训练一小部分参数,就能让大模型学会新任务,后来发现P-Tuning,就是为了解决这个痛点诞生的参数高效微调方案。
基本我们都听过Prompt提示词工程,手写文字提示,引导大模型输出指定结果。但手写提示词有明显上限:人的语言表达有限,很难找到最优提示;不同模型对文字提示敏感度不一样,提示词稍微改动,效果就剧烈波动。P-Tuning跳出了纯文本提示的思路,提出提示不一定必须是人写的文字,可以是模型内部可学习的连续向量。我们不去修改大模型主干,只优化这一小批连续提示向量,就能完成下游任务适配。

大语言模型本质是一个预训练完成的巨大神经网络,预训练阶段,模型在海量通用文本上学习语言规律、常识、逻辑。预训练结束后,模型的权重已经固化了大量通用知识。
全参数微调过程:
如果算力足够、数据质量高,全量微调通常能拿到任务上的最优效果。但短板同样突出:
另一种方式提示词工程,不改动模型任何权重;直接在输入文本前拼接人工写好的提示,比如“你是合同抽取专家,请提取合同金额、签订日期”;零成本、上手简单,但缺点明显:
正是全量微调成本高、手写提示不稳定,于是演化出了折中方案:冻结基座大模型权重,只训练少量额外参数,实现高效适配。这一类技术统称为PEFT,全称Parameter-Efficient Fine-Tuning,即参数高效微调,P-Tuning就是PEFT大家族里非常经典的成员。
PEFT的核心思想统一:基座模型权重冻结;训练时只更新少量新增参数;训练完成后,只保存这一小部分参数;推理时把新增参数并入基座模型一起使用。
不同PEFT方案,新增参数的位置、形式各不相同,主流方案分为几类:
方案 | 参数插入位置 | 特点 |
|---|---|---|
Prefix Tuning | Transformer每一层的注意力模块,追加前缀向量 | 生成任务表现不错,但训练不稳定 |
P-Tuning | 输入层增加可学习连续伪提示向量,只作用在输入嵌入阶段 | 参数量最小,深层模型效果易衰减 |
P-Tuning v2 | P-Tuning升级版,每一层都加入可学习提示 | NLU任务效果好,工程最常用 |
LoRA | Attention权重旁增加低秩矩阵,只训练低秩矩阵 | 生成任务优秀,推理无额外开销 |
Adapter Tuning | Transformer层之间插入小型Adapter子网络 | 参数量可控,结构侵入性强 |
通常最容易混淆P-Tuning、Prefix Tuning、P-Tuning v2,先简单划清边界:最早P-Tuning只在输入嵌入层增加提示,属于浅层提示;Prefix Tuning每一层都添加前缀;P-Tuning v2吸收Prefix Tuning思想,把可学习提示放到Transformer全部层,性能大幅提升。现在工程里说P-Tuning,很多时候实际指P-Tuning v2,后面章节会详细对比。
PEFT方案共同优势:训练显存低、训练速度更快;不改动基座权重,遗忘风险低;任务切换只需要加载不同小参数文件,存储开销极小。但不同方案适用场景不一样,P-Tuning系列在NLU自然语言理解任务(文本分类、实体抽取)表现亮眼;LoRA在生成类任务,对话、续写、摘要更常用。
普通Prompt,输入全部是离散的文本Token。比如我们输入:
【请做情感分类】这句话:今天天气很差,我非常难过。输出标签:
这段文字会经过Embedding层,映射成一组固定的向量;这些向量由模型词表决定,不可训练;提示词是人写的自然语言,向量固定,训练过程不会变化。
P-Tuning做出了一个关键创新:引入可学习的连续伪提示(Continuous Prompt)。它不再完全依靠人类写的文字Token;在原始输入的前面,插入一段特殊的、不属于真实词表的虚拟token,一般叫伪提示token(pseudo prompt token);这些伪token同样经过Embedding,生成对应向量,这些向量是模型可以训练、可以优化的参数;原始基座大模型所有Transformer权重全部冻结,训练过程只更新这一小批伪提示向量。
用一个通俗的比喻帮助理解:

训练流程简化描述:

重点区分:伪提示向量不是人类可读文字。训练完成之后,我们无法把这组向量还原成一段中文句子。它是模型空间内的连续向量,只对这个基座模型有效,换一个模型,这组提示向量就失效。
示例:伪提示向量微调
示例实现了大模型的参数高效微调(PEFT)方案,属于Prompt Tuning类方法。核心思路是冻结基座大模型的全部参数,仅定义一个可学习的连续伪提示向量(20×768),在前向传播时将其拼接到真实输入embedding之前,再送入冻结的Transformer主干进行推理。相比全量微调,该方法可训练参数量极低(仅约 0.01%),大幅降低训练显存与存储开销,同时避免灾难性遗忘,适配多任务快速切换部署。
核心设计:
import torch
import torch.nn as nn
# 假设隐藏层维度为768,伪提示长度为20
HIDDEN_SIZE = 768
PSEUDO_LEN = 20
class PseudoPromptModel(nn.Module):
def __init__(self, backbone):
super().__init__()
self.backbone = backbone
# 1. 冻结基座大模型全部参数
for p in self.backbone.parameters():
p.requires_grad = False
# 2. 唯一可学习的连续伪提示向量
self.pseudo_prompt = nn.Parameter(
torch.randn(PSEUDO_LEN, HIDDEN_SIZE)
)
def forward(self, input_embeds, attention_mask):
# 3. 伪提示向量拼接在真实输入embedding之前
batch_size = input_embeds.size(0)
prompt = self.pseudo_prompt.unsqueeze(0).expand(batch_size, -1, -1)
concat_embeds = torch.cat([prompt, input_embeds], dim=1)
# 4. 送入冻结的Transformer主干前向计算
return self.backbone(inputs_embeds=concat_embeds)原版P-Tuning论文提出的架构,核心特点:可学习提示只加在输入Embedding层,Transformer中间层不增加参数。输入的完整embedding序列由三部分拼接而成:
[可学习伪提示] + [原始输入文本Embedding] + [可选的人工提示Token Embedding]
这里有几点设计细节:
原版P-Tuning有一个短板:
所以后续推出P-Tuning v2,专门解决这个短板。
P-Tuning v2是P-Tuning的升级版,也是应用落地最常用的版本,核心改动包括不再只在输入Embedding增加提示,在Transformer每一层的Attention模块,都增加独立的可学习前缀向量。
工作原理:

用代码直观理解“每层KV前缀”的形态:
import torch
import torch.nn as nn
class PTuningV2LayerPrefix(nn.Module):
"""P-Tuning v2:给每一层自注意力追加KV前缀"""
def __init__(self, hidden_size, prefix_len, num_layers):
super().__init__()
self.prefix_len = prefix_len
# 每一层都有一组独立的可学习前缀向量
# 结构: [层数, 前缀长度, 2(K和V), 隐藏维度]
self.prefix = nn.Parameter(
torch.randn(num_layers, prefix_len, 2, hidden_size)
)
def forward(self, layer_idx, key, value):
# 取第 layer_idx 层对应的前缀
kv = self.prefix[layer_idx] # [prefix_len, 2, hidden]
k_prefix = kv[:, 0, :].unsqueeze(0) # 前缀Key
v_prefix = kv[:, 1, :].unsqueeze(0) # 前缀Value
# 拼接到当前层的Key/Value前面,参与注意力计算
key = torch.cat([k_prefix, key], dim=1)
value = torch.cat([v_prefix, value], dim=1)
return key, valueP-Tuning v2的优势:
但代价是,相比原版P-Tuning,可训练参数量有所上升:
即便如此,可训练参数依然只占模型总参数0.1%~1%,对比全参数微调,算力消耗依然有数量级下降。
在选型时容易混淆这几个PEFT方法,这里做清晰对比:
P-Tuning(原版)
P-Tuning v2
Prefix Tuning
LoRA
总的来说,做文本理解、信息抽取优先P-Tuning v2;对话、文本生成优先LoRA。

第一步:环境与基座准备
第二步:初始化可学习提示参数
第三步:数据集预处理
第四步:前向传播
第五步:反向传播与参数更新
第六步:保存产物
下面是一段简化训练循环示例代码:
import torch.optim as optim
from transformers import AutoTokenizer, AutoModel
# 加载基座模型并冻结主干
backbone = AutoModel.from_pretrained("bert-base-chinese")
for p in backbone.parameters():
p.requires_grad = False
model = PseudoPromptModel(backbone) # 复用2.1节的封装
optimizer = optim.AdamW(model.parameters(), lr=1e-3) # 只含伪提示参数
for epoch in range(5):
for batch in train_dataloader:
input_ids, labels = batch
input_embeds = backbone.embeddings(input_ids) # 真实文本embedding
logits = model(input_embeds, attention_mask=None)
loss = criterion(logits, labels)
optimizer.zero_grad()
loss.backward() # 梯度只流向伪提示参数
optimizer.step()
# 只保存可学习提示向量,不保存大模型
torch.save(model.pseudo_prompt, "tuned_prompt.pt")推理阶段不需要重新训练,完整流程说明:

# 推理:加载基座 + 加载提示向量
backbone = AutoModel.from_pretrained("bert-base-chinese")
pseudo_prompt = torch.load("tuned_prompt.pt")
model = PseudoPromptModel(backbone)
model.pseudo_prompt.data = pseudo_prompt # 替换为训练好的提示
# 对单个样本推理
input_embeds = backbone.embeddings(input_ids.unsqueeze(0))
logits = model(input_embeds, attention_mask=None)
pred = logits.argmax(dim=-1)这里要注意一个工程细节:
P-Tuning训练有几个关键超参数,直接决定效果好坏:
- 伪提示Token长度:
- 学习率:
- 训练epoch
- 初始化策略:
推荐使用P-Tuning v2场景:
不推荐优先选用场景:
相信大家和我一样,初次接触会产生一个疑问,我也是核实了一些细节,这里分享一些总结:既然P-Tuning只是优化提示向量,那它到底是属于提示工程还是属于微调呢?
本质上,P-Tuning属于参数高效微调,不是单纯的提示词工程:手写提示词完全没有参数更新;P-Tuning通过反向传播优化可学习向量,利用标注数据拟合任务分布,属于训练过程;但它又和全参数微调不同,不触碰基座主干。
在实际工程选型上,不存在绝对最好的PEFT方法,只有最匹配业务目标的方案:如果任务是合同抽取、医疗文本实体识别,标注样本几百到几千条,显卡资源有限,P-Tuning v2是首选,效果上限高,成本可控;如果做智能客服对话、小说生成、翻译这类生成任务,优先LoRA,推理无额外开销,生成质量更好。
同时也要客观看待PEFT的边界,P-Tuning不是魔法:它不能凭空创造信息,数据质量依旧是核心;如果标注数据混乱、标注错误多,哪怕使用P-Tuning v2,也无法得到好效果;PEFT解决的是训练成本问题,无法弥补脏数据带来的缺陷。
P-Tuning和提示词工程可以结合使用:先用手写提示词做零样本测试,确认任务可行;再用P-Tuning基于标注数据训练连续提示,进一步稳定效果,降低对人工提示的依赖;很多业务落地,会采用这套组合路线。还有一个容易踩坑的点:模型架构适配。原版P-Tuning最早基于BERT编码器模型开发;解码器架构的GPT类模型虽然支持P-Tuning v2,但效果和稳定性不如编码器;选型前要提前做小实验验证。
全参数微调算力昂贵,手写离散提示词不稳定,这两个痛点催生了PEFT参数高效微调,P-Tuning就是其中代表方案。P-Tuning跳出了提示必须是人类文字的固有认知,提出可学习连续伪提示。原版P-Tuning仅在输入嵌入层增加可训练提示向量;升级后的P-Tuning v2在Transformer每一层增加KV前缀,解决深层信号衰减问题,在文本理解类任务上,效果可以逼近全参数微调。整个训练过程冻结基座大模型主干,只训练极少一部分提示参数,极大降低显存、算力、存储成本,适合小样本领域NLU任务。
P-Tuning最重要的思想启示:大模型的能力藏在模型的向量空间里,不一定非要修改模型主体权重,找到合适的指令信号,就可以调动基座模型已有的能力完成下游任务。这套思路也启发了后续大量提示学习、参数高效微调方向的研究。掌握P-Tuning原理,能更深理解大模型是如何接收指令、执行任务,在后续大模型项目选型、方案设计时,能做出更理性的判断。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。