
Qwen-7B-Chat P-Tuning 微调实战基于 self-llm 冻结主干、只训练 Prompt 嵌入层的高效微调方案【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm本文是《开源大模型食用指南》self-llm 项目中 Qwen 系列微调教程的 P-Tuning 篇讲解如何基于 transformers、peft 等框架对 Qwen-7B-Chat 进行 P-Tuning前缀微调——冻结主模型全部参数仅训练一小段自动学习的 Soft Prompt 嵌入层以远低于全参微调的显存开销完成中文对话风格的定制。读完本文你将掌握 P-Tuning 与 Prompt-Tuning 的原理差异、PromptEncoderConfig各核心参数的语义与取值约束并能直接运行仓库提供的微调脚本完成从数据格式化、模型加载到 Trainer 训练与推理的完整流程。P-Tuning 原理为什么只训练 Prompt不碰主模型P-Tuning 属于参数高效微调PEFT家族。与上一节 Lora 微调 中往注意力矩阵旁挂低秩旁路不同P-Tuning 的基本思路是冻结主模型的全部参数在训练数据前加入一小段 Prompt只训练这段 Prompt 对应的嵌入层。也就是说整个训练过程中主模型权重一动不动需要学习的只有新增的那一小段可训练参数显存占用与可训练参数量都极小。P-Tuning 是在 Prompt-Tuning 基础上的演进两者的区别可以精炼地概括为两点Prompt-Tuning只在输入序列前面增加一个Prompt Embedding可训练的 prompt 嵌入向量直接拼接到输入嵌入上P-Tuning把简单的Prompt Embedding替换为Prompt Encoder即新引入LSTM/MLP Embedding结构先对可训练的 prompt 参数做一次编码再拼接进输入序列。在 P-Tuning 中这段 Prompt 是自动学习的即 Soft Prompt不需要人工设计具体的提示语文本因此不存在手工构造 prompt 的负担。下图清晰展示了 Prompt Embedding 与 Prompt EncoderLSTM/MLP的组合关系以及后续进入 Transformer Blocks 的整体流程引入编码器的动机在于加速收敛直接训练离散的 prompt 嵌入在早期往往收敛缓慢而经过 LSTM/MLP 重参数化reparameterization后的 Soft Prompt 携带了更强的归纳偏置训练更稳定、收敛更快。环境与数据准备数据加载与模型配置与 Lora 微调 完全一致这里不再赘述只需按 Lora 篇完成基础环境搭建并安装以下依赖即可pip install transformers4.35.2 pip install peft0.4.0 pip install datasets2.10.1 pip install accelerate0.20.3 pip install tiktoken pip install transformers_stream_generator微调数据集沿用仓库根目录下的 dataset/huanhuan.json每一条样本均为{instruction: ..., input: ..., output: ...}形式的指令数据。本教程的目标是构建一个能模拟甄嬛对话风格的个性化 LLM例如{ instruction: 现在你要扮演皇帝身边的女人--甄嬛, input: 你是谁, output: 家父是大理寺少卿甄远道。 }在微调脚本中通过pd.read_json(./dataset/huanhuan.json)将 JSON 读入 DataFrame再经Dataset.from_pandas(df)转为 HuggingFaceDataset对象供后续map使用。运行脚本前请将os.chdir(/root/self-llm)改为自己 self-llm 项目的绝对路径。数据格式化拼接 Qwen 原生 Chat 模板并构造 labelsP-Tuning 与 Lora 共用同一套process_func数据预处理逻辑。核心要点是遵循 Qwen 原生的 Chat 指令格式进行拼接——因为在原本模型指令微调的形式上进行高效微调效果最好。每条样本会被组织成如下形态|im_start|system 现在你要扮演皇帝身边的女人--甄嬛.|im_end| |im_start|user 小姐别的秀女都在求中选唯有咱们小姐想被撂牌子菩萨一定记得真真儿的——|im_end| |im_start|assistant 嘘——都说许愿说破是不灵的。|im_end| |endoftext|对应的预处理函数如下与 Lora 脚本 中完全一致def process_func(example): MAX_LENGTH 384 # 中文按 token 切分较碎需放开最大长度保证数据完整性 input_ids, attention_mask, labels [], [], [] instruction tokenizer(\n.join([|im_start|system, 现在你要扮演皇帝身边的女人--甄嬛.|im_end| \n|im_start|user\n example[instruction] example[input] |im_end|\n]).strip(), add_special_tokensFalse) response tokenizer(|im_start|assistant\n example[output] |im_end|\n, add_special_tokensFalse) input_ids instruction[input_ids] response[input_ids] [tokenizer.pad_token_id] attention_mask instruction[attention_mask] response[attention_mask] [1] # eos token 也要关注故补 1 labels [-100] * len(instruction[input_ids]) response[input_ids] [tokenizer.pad_token_id] # Qwen 的特殊构造 if len(input_ids) MAX_LENGTH: input_ids input_ids[:MAX_LENGTH] attention_mask attention_mask[:MAX_LENGTH] labels labels[:MAX_LENGTH] return {input_ids: input_ids, attention_mask: attention_mask, labels: labels}几点说明add_special_tokensFalse不额外添加特殊 token保证序列完全由手动拼接的 Chat 模板控制labels中系统与用户部分填充-100在交叉熵损失中被忽略只有assistant回答部分参与 loss 计算这正是指令微调只学回答的标准做法最后补tokenizer.pad_token_id作为序列结束符attention_mask对应位置补 1。之后用ds.map(process_func, remove_columnsds.column_names)将原始样本批量编码为input_ids、attention_mask、labels三个字段。加载 Tokenizer 与半精度模型模型以半精度torch.half形式加载若显卡较新也可改用torch.bfloat16。自定义模型必须设置trust_remote_codeTrue。Qwen 的eod_id与pad_token_id相同但需要显式指定tokenizer AutoTokenizer.from_pretrained(/root/autodl-tmp/qwen/Qwen-7B-Chat, use_fastFalse, trust_remote_codeTrue) tokenizer.pad_token_id tokenizer.eod_id model AutoModelForCausalLM.from_pretrained(/root/autodl-tmp/qwen/Qwen-7B-Chat, trust_remote_codeTrue, torch_dtypetorch.half, device_mapauto)脚本中通过os.environ[CUDA_VISIBLE_DEVICES] 1指定使用第 1 块 GPU。与 Lora 篇不同的是P-Tuning 脚本默认不开启gradient_checkpointing因此无需调用model.enable_input_require_grads()该行在脚本中处于注释状态。Ptuning PEFT 模块PromptEncoderConfig 参数详解P-Tuning 的核心配置类是 peft 库中的PromptEncoderConfig。其关键的取舍点由PromptEncoderReparameterizationType决定——到底用 LSTM 还是 MLP 来做 Prompt Encoder 的重参数化。from peft import PromptEncoderConfig, TaskType, get_peft_model, PromptEncoderReparameterizationType config PromptEncoderConfig(task_typeTaskType.CAUSAL_LM, num_virtual_tokens10, encoder_reparameterization_typePromptEncoderReparameterizationType.MLP, encoder_dropout0.1, encoder_num_layers5, encoder_hidden_size1024)可调参数及其含义如下表参数取值示例含义task_typeTaskType.CAUSAL_LM模型类型因果语言模型num_virtual_tokens10虚拟 token 数量即插入到输入前的 Soft Prompt 长度encoder_reparameterization_typePromptEncoderReparameterizationType.MLP重参数化编码器类型LSTM 或 MLPencoder_dropout0.1编码器的 Dropout 比例用于抑制过拟合encoder_num_layers5编码器层数encoder_hidden_size1024编码器隐藏层维度这里有一个非常容易踩坑的注意点encoder_num_layers设置的层数只在选用 LSTM 时生效若选用 MLP其层数固定为 2该参数不会起作用。读者在调参时应结合自己选择的编码器类型来判断该参数是否真正生效。构建config后打印可见其完整字段PromptEncoderConfig(peft_typePeftType.P_TUNING: P_TUNING, auto_mappingNone, base_model_name_or_pathNone, revisionNone, task_typeTaskType.CAUSAL_LM: CAUSAL_LM, inference_modeFalse, num_virtual_tokens10, token_dimNone, num_transformer_submodulesNone, num_attention_headsNone, num_layersNone, encoder_reparameterization_typePromptEncoderReparameterizationType.MLP: MLP, encoder_hidden_size1024, encoder_num_layers5, encoder_dropout0.1)其中peft_typePeftType.P_TUNING: P_TUNING表明这是 P-Tuning 适配器。与 Lora 不同P-Tuning不需要指定target_modules——因为它不向任何既有模块注入低秩旁路而是整体替换/新增输入侧的可训练嵌入因此无需关心c_attn、c_proj、w1、w2等注意力层命名。随后通过get_peft_model(model, config)将普通模型包装为 P-Tuning 模型此时主模型全部参数被冻结唯一可训练的是 prompt encoder 相关参数参数量远小于 Lora 方案。配置训练参数并使用 Trainer 训练训练参数仍使用TrainingArguments配置args TrainingArguments( output_dir./output/Qwen, per_device_train_batch_size2, gradient_accumulation_steps2, logging_steps10, num_train_epochs3, # gradient_checkpointingTrue, save_steps100, learning_rate1e-4, save_on_each_nodeTrue )与 Lora 篇per_device_train_batch_size8且开启gradient_checkpointing相比P-Tuning 脚本将单卡 batch size 调低至 2且默认不开启梯度检查点在显存占用上更加宽裕——这正是 P-Tuning 只训练少量 prompt 参数带来的红利。各参数作用output_dir为模型输出路径gradient_accumulation_steps做梯度累加显存小时可减小 batch、增大累加步数logging_steps控制日志打印频率num_train_epochs为训练轮数save_steps控制 checkpoint 保存频率learning_rate1e-4为学习率save_on_each_nodeTrue表示每个节点都保存权重。训练流程与 Lora 完全一致把模型、参数与数据集交给Trainer即可trainer Trainer( modelmodel, argsargs, train_datasettokenized_id, data_collatorDataCollatorForSeq2Seq(tokenizertokenizer, paddingTrue), ) trainer.train() # 开始训练DataCollatorForSeq2Seq负责在 batch 内将不等长序列 padding 对齐。训练完成后微调得到的 prompt encoder 参数会与主模型一起保存于output_dir。模型推理训练结束后可直接调用 Qwen 自带的model.chat接口验证微调效果response, history model.chat(tokenizer, 你是谁, history[], system现在你要扮演皇帝身边的女人--甄嬛.) print(response)若模型已收敛模型应能以甄嬛的口吻回答你是谁这类问题验证 P-Tuning 确实将对话风格注入到了可训练的 Soft Prompt 中。总结P-Tuning vs Lora 的选型建议原理层面Lora 通过低秩矩阵近似权重的增量可训练参数分布在注意力与前馈层的旁路中P-Tuning 则完全冻结主模型只训练输入侧一段由 LSTM/MLP 编码的 Soft Prompt。参数取舍P-Tuning 的encoder_num_layers仅对 LSTM 生效MLP 固定 2 层Lora 则需要针对具体模型设置target_modulesQwen-7B-Chat 为[c_attn, c_proj, w1, w2]。显存与效果权衡P-Tuning 可训练参数更少、显存占用更低适合硬件资源紧张、追求低成本风格定制的场景Lora 可训练参数量更大在复杂任务上通常具有更高的效果上限。数据与流程共性两者的数据格式化、tokenizer/模型加载、Trainer 训练流程完全一致切换方法时只需替换config与get_peft_model的调用方式这也正是本仓库将两篇教程并列编排的用意所在。如需进一步深入可对照阅读 04-Qwen-7B-Chat Lora 微调 及同级目录下的 微调脚本并结合 dataset/huanhuan.json 实际跑通完整流程。【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考