资讯详情

Qwen1.5-7B-Chat 高效微调实战:基于 transformers 与 peft 的 Lora 指令微调全流程指南(self-llm 项目)

📅 2026/9/20 5:39:16 | 华诺云谱 👁 阅读
Qwen1.5-7B-Chat 高效微调实战:基于 transformers 与 peft 的 Lora 指令微调全流程指南(self-llm 项目)
Qwen1.5-7B-Chat 高效微调实战基于 transformers 与 peft 的 Lora 指令微调全流程指南self-llm 项目【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/datawhalechina/self-llm本文是《开源大模型食用指南》Datawhale/self-llm中 Qwen1.5 系列教程的核心篇章完整讲解如何在 Linux PyTorch 环境下基于 transformers、peft、datasets 等框架对 Qwen1.5-7B-Chat 进行 Lora 指令微调并将其训练成具有甄嬛对话风格的人设化聊天模型。读完本文你将掌握从环境搭建、指令数据集构建、数据格式化、LoraConfig 与 TrainingArguments 参数设计到 Trainer 训练与 Lora 权重加载推理的端到端实战能力。概览Lora 微调的关键要素本节教程要解决的工程问题十分明确以最小的可训练参数量让 Qwen1.5-7B-Chat 具备理解并遵循特定指令人设对话的能力。LoraLow-Rank Adaptation通过冻结基座模型、仅训练注入的低秩矩阵来实现高效微调。本文涉及的完整链路如下环境配置与依赖安装transformers/peft/datasets/modelscope指令集构建设计instruction/input/output三元组数据数据格式化按 Qwen1.5 的 Chat Template 将文本编码为input_ids/attention_mask/labels加载半精度模型并定义LoraConfig配置TrainingArguments并使用Trainer训练加载训练好的 Lora 权重进行推理。配套的可运行示例代码位于仓库 models/Qwen1.5/Qwen1.5-7B-Chat Lora.ipynb建议读者跟随本文阅读时同步打开 notebook 逐 cell 执行验证。环境配置本文基础环境如下---------------- ubuntu 22.04 python 3.12 cuda 12.1 pytorch 2.3.0 ----------------本文默认学习者已安装好以上 PyTorch(cuda) 环境如未安装请自行安装。接下来开始环境配置、模型下载和运行演示。首先对pip换源加速下载并安装依赖包pip install --upgrade pip # 更换 pypi 源加速库的安装 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip install modelscope1.16.1 pip install transformers4.43.2 pip install accelerate0.32.1 pip install peft0.11.1 pip install datasets2.20.0各依赖的职责如下modelscope国内模型下载工具用于拉取 Qwen1.5-7B-Chat 权重transformers模型加载、Tokenizer 与训练器Trainer的底层框架acceleratedevice_mapauto多卡/显存自动分配与Trainer训练的底层加速库peftLora 适配器LoraConfig、get_peft_model、PeftModel所在库datasets数据集加载与map批量预处理。考虑到部分同学配置环境可能会遇到一些问题本项目在 AutoDL 平台准备了 Qwen1.5 的环境镜像该镜像适用于本仓库除 Qwen-GPTQ 和 vllm 外的所有部署环境可直接创建 AutoDL 示例使用。在本节教程里我们将微调数据集放置在根目录 dataset/huanhuan.json。模型下载微调前需要先获取 Qwen1.5-7B-Chat 的原始权重。仓库中 01-Qwen1.5-7B-Chat FastApi 部署调用.md 给出了使用modelscope的snapshot_download函数下载模型的完整方式第一个参数为模型名称参数cache_dir为自定义的模型下载路径参数revision为模型仓库分支版本master代表主分支也是一般模型上传的默认分支# model_download.py from modelscope import snapshot_download model_dir snapshot_download(qwen/Qwen1.5-7B-Chat, cache_dir/root/autodl-tmp, revisionmaster)注意记得修改cache_dir为你的模型下载路径。模型权重文件比较大需要耐心等待直到下载完成。下载完成后在后续代码中可将模型路径如./qwen/Qwen1.5-7B-Chat/替换为实际的本地目录。指令集构建LLM 的微调一般指指令微调过程。所谓指令微调是说我们使用的微调数据形如{ instruction:回答以下用户问题仅输出答案。, input:11等于几?, output:2 }其中instruction是用户指令告知模型其需要完成的任务input是用户输入是完成用户指令所必须的输入内容output是模型应该给出的输出。即我们的核心训练目标是让模型具有理解并遵循用户指令的能力。因此在指令集构建时我们应针对目标任务针对性构建任务指令集。例如在本节我们使用合作开源的 Chat-甄嬛huanhuan-chat项目作为示例目标是构建一个能够模拟甄嬛对话风格的个性化 LLM因此构造的指令形如{ instruction: 你是谁, input:, output:家父是大理寺少卿甄远道。 }本项目实际使用的全部指令数据集位于仓库 dataset/huanhuan.json共3729 条对话样本字段结构即为上述三元组。数据预览取自 notebook 中的ds[:3]输出{ instruction: [小姐别的秀女都在求中选唯有咱们小姐想被撂牌子菩萨一定记得真真儿的——, 这个温太医啊也是古怪谁不知太医不得皇命不能为皇族以外的人请脉诊病他倒好十天半月便往咱们府里跑。, 嬛妹妹刚刚我去府上请脉听甄伯母说你来这里进香了。], input: [, , ], output: [嘘——都说许愿说破是不灵的。, 你们俩话太多了我该和温太医要一剂药好好治治你们。, 出来走走也是散心。] }数据加载方式同样来自 notebookfrom datasets import Dataset import pandas as pd df pd.read_json(./huanhuan.json) ds Dataset.from_pandas(df)数据格式化Lora训练的数据是需要经过格式化、编码之后再输入给模型进行训练的。熟悉Pytorch模型训练流程的同学会知道我们一般需要将输入文本编码为 input_ids将输出文本编码为labels编码之后的结果都是多维的向量。我们首先定义一个预处理函数这个函数用于对每一个样本编码其输入、输出文本并返回一个编码后的字典def process_func(example): MAX_LENGTH 384 # Llama分词器会将一个中文字切分为多个token因此需要放开一些最大长度保证数据的完整性 input_ids, attention_mask, labels [], [], [] instruction tokenizer(f|im_start|system\n现在你要扮演皇帝身边的女人--甄嬛|im_end|\n|im_start|user\n{example[instruction] example[input]}|im_end|\n|im_start|assistant\n, add_special_tokensFalse) # add_special_tokens 不在开头加 special_tokens response tokenizer(f{example[output]}, 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] 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 }这段代码是理解 Lora 微调数据流的关键逐行解读如下MAX_LENGTH 384Qwen 分词器会将一个中文字切分为多个 token需要放开最大长度保证数据完整性超长样本直接截断到 384。instruction编码使用add_special_tokensFalse手动拼接 Qwen1.5 的 Chat Template避免 tokenizer 自动在开头追加 special token。input_ids拼接指令部分 回答部分 pad_token_id其中末尾的pad_token_id起到句子结束标记EOS的作用。attention_mask末尾补充1因为 EOS token 也需要被模型关注。labels指令部分的 label 全部置为-100表示不参与 loss 计算只有回答部分response[input_ids]参与损失这正是只学习回答、不学习提问的监督微调核心。随后通过datasets的map方法批量处理全部样本notebook 中该步骤实际处理了 3729 条样本tokenized_id ds.map(process_func, remove_columnsds.column_names)处理完成后可用tokenizer.decode验证编码正确性。notebook 中解码第一条样本得到的完整训练文本为|im_start|system 现在你要扮演皇帝身边的女人--甄嬛|im_end| |im_start|user 小姐别的秀女都在求中选唯有咱们小姐想被撂牌子菩萨一定记得真真儿的——|im_end| |im_start|assistant 嘘——都说许愿说破是不灵的。|endoftext|Qwen1.5采用的Prompt Template格式如下|im_start|system You are a helpful assistant.|im_end| |im_start|user 你是谁|im_end| |im_start|assistant 我是一个有用的助手。|im_end|从 notebook 加载的 tokenizer 信息可以看到Qwen1.5-7B-Chat 使用的是Qwen2Tokenizervocab_size151643model_max_length32768use_fastFalse其特殊 token 为|endoftext|同时作为 eos_token 与 pad_token、|im_start|、|im_end|。这解释了为什么在推理时可以使用tokenizer.apply_chat_template自动生成上述模板文本。加载tokenizer和半精度模型模型以半精度形式加载如果你的显卡比较新的话可以用torch.bfloat16形式加载。对于自定义的模型一定要指定trust_remote_code参数为Truetokenizer AutoTokenizer.from_pretrained(./qwen/Qwen1.5-7B-Chat/, use_fastFalse, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained(./qwen/Qwen1.5-7B-Chat/, device_mapauto,torch_dtypetorch.bfloat16)use_fastFalse使用慢速经典tokenizer 实现保证与仓库保存的 tokenizer 行为一致device_mapauto由accelerate自动将模型各层分配到可用 GPU/CPU 上显存不足时自动降级到 CPUtorch_dtypetorch.bfloat16以半精度 bfloat16 加载显存占用约为 fp32 的一半同时具备更大的指数范围更适合 7B 级别模型在单卡上的微调。notebook 中加载完成的模型结构model.print输出清晰展示了 Qwen1.5-7B-Chat 基于 Qwen2 架构的实现Qwen2ForCausalLM包含 32 层Qwen2DecoderLayer每层由self_attnq/k/v_proj 均为 4096 维o_proj 无 bias与mlpgate/up_proj 升维到 11008down_proj 降回 4096激活函数 SiLU构成lm_head映射到 151936 词表。这一结构也直接决定了下方LoraConfig中target_modules的选择范围。定义LoraConfigLoraConfig这个类中可以设置很多参数但主要的参数没多少简单讲一讲感兴趣的同学可以直接看 peft 源码。task_type模型类型target_modules需要训练的模型层的名字主要就是attention部分的层不同的模型对应的层的名字不同可以传入数组也可以字符串也可以正则表达式。rlora的秩具体可以看Lora原理lora_alphaLora alaph具体作用参见Lora原理Lora的缩放是啥嘞当然不是r秩这个缩放就是lora_alpha/r在这个LoraConfig中缩放就是 4 倍。config LoraConfig( task_typeTaskType.CAUSAL_LM, target_modules[q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj], inference_modeFalse, # 训练模式 r8, # Lora 秩 lora_alpha32, # Lora alaph具体作用参见 Lora 原理 lora_dropout0.1# Dropout 比例 )参数要点结合仓库 notebook 的实际运行结果展开target_modules这里同时覆盖了注意力层的q/k/v/o_proj与 MLP 层的gate/up/down_proj全部 7 个线性层与前面模型结构中观察到的Qwen2DecoderLayer内部层名一一对应。更激进的微调范围通常能带来更好的效果但也会增加可训练参数量。缩放系数lora_alpha/r 32/8 4即注入的低秩分支输出会乘上 4 的缩放因子。该值越大Lora 分支对最终输出的影响越强实践中常与r按 2~4 倍比例搭配。r8的含义每个被适配的线性层只训练一个秩为 8 的低秩矩阵对A、B而不是全量权重。将配置应用到模型notebook 中使用了get_peft_model随后打印可训练参数统计from peft import LoraConfig, TaskType, get_peft_model model get_peft_model(model, config) model.print_trainable_parameters()notebook 的真实运行结果为trainable params: 19,988,480 || all params: 7,741,313,024 || trainable%: 0.2582052933143348可以看到在 77.4 亿参数的 Qwen1.5-7B-Chat 上Lora 仅训练约2000 万参数可训练比例仅0.26%——这正是 Lora高效微调的直接体现显存与训练时间开销大幅下降同时保留基座模型的通用能力。自定义 TrainingArguments 参数TrainingArguments这个类的源码也介绍了每个参数的具体作用当然大家可以自行探索这里就简单说几个常用的。output_dir模型的输出路径per_device_train_batch_size顾名思义batch_sizegradient_accumulation_steps: 梯度累加如果你的显存比较小那可以把batch_size设置小一点梯度累加增大一些。logging_steps多少步输出一次lognum_train_epochs顾名思义epochgradient_checkpointing梯度检查这个一旦开启模型就必须执行model.enable_input_require_grads()这个原理大家可以自行探索这里就不细说了。args TrainingArguments( output_dir./output/Qwen1.5-7B-Chat, per_device_train_batch_size4, gradient_accumulation_steps4, logging_steps10, num_train_epochs3, save_steps100, learning_rate1e-4, save_on_each_nodeTrue, gradient_checkpointingTrue )参数组合的实际含义与显存影响有效 batch sizeper_device_train_batch_size(4) × gradient_accumulation_steps(4) 16。如果显存较小可以调低 batch_size 并相应增大梯度累加步数保持等效 batch 不变。gradient_checkpointingTrue以重计算换取显存训练时需配套执行model.enable_input_require_grads()notebook 中在加载模型后显式调用了该方法。同时开启后use_cache会被自动置为Falsenotebook 训练日志中有对应提示即推理缓存与梯度检查点不兼容。save_steps100每 100 步保存一次 checkpoint 到output_dir便于中断恢复与选取最优 checkpoint。learning_rate1e-4Lora 微调常用学习率区间为 1e-5 ~ 2e-41e-4是较为稳妥的默认选择全参微调则通常需要更小的学习率。save_on_each_nodeTrue多节点训练时每个节点均保存 checkpoint。使用 Trainer 训练trainer Trainer( modelmodel, argsargs, train_datasettokenized_id, data_collatorDataCollatorForSeq2Seq(tokenizertokenizer, paddingTrue), ) trainer.train()关键点说明train_dataset传入的是经过process_func编码后的tokenized_id仅含input_ids/attention_mask/labels三列原列已被remove_columns移除DataCollatorForSeq2Seq(tokenizertokenizer, paddingTrue)负责在 batch 内对不定长序列做 padding 对齐并正确处理labels侧的 pad token默认用-100填充避免 padding 位置参与 loss 计算。notebook 中实际训练了 3 个 epoch总计约 699 步其中记录了真实的收敛过程前 10 步训练损失约 4.15至 130 步时已降至约 2.94呈现平稳下降趋势说明模型正在逐步习得甄嬛风格回复这一目标分布。不同显存条件下训练时长会有差异可依据实际资源调整 batch、梯度累加与 epoch 数。加载 lora 权重推理训练好了之后可以使用如下方式加载lora权重进行推理from transformers import AutoModelForCausalLM, AutoTokenizer import torch from peft import PeftModel model_path ./qwen/Qwen1.5-7B-Chat/ lora_path lora_path # 加载tokenizer tokenizer AutoTokenizer.from_pretrained(model_path) # 加载模型 model AutoModelForCausalLM.from_pretrained(model_path, device_mapauto,torch_dtypetorch.bfloat16) # 加载lora权重 model PeftModel.from_pretrained(model, model_idlora_path, configconfig) prompt 你是谁 messages [ {role: system, content: 现在你要扮演皇帝身边的女人--甄嬛}, {role: user, content: prompt} ] text tokenizer.apply_chat_template(messages, tokenizeFalse, add_generation_promptTrue) model_inputs tokenizer([text], return_tensorspt).to(cuda) generated_ids model.generate( model_inputs.input_ids, max_new_tokens512 ) generated_ids [ output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids) ] response tokenizer.batch_decode(generated_ids, skip_special_tokensTrue)[0] print(response)推理链路要点PeftModel.from_pretrained(model, model_idlora_path)将训练好的 Lora 适配器权重挂载到原始基座模型上。lora_path应替换为你训练时的 checkpoint 目录例如./output/Qwen1.5-7B-Chat/checkpoint-xxx/。这一加载方式在本仓库的多个 Lora 微调教程中保持一致例如 CharacterGLM Lora 微调 与 ChatGLM3 Lora 微调 均采用同样的PeftModel.from_pretrained加载模式。tokenizer.apply_chat_template与训练时的数据格式化逻辑对应按 Qwen1.5 的 Chat Template 自动拼装system user消息并追加assistant起始标记add_generation_promptTrue无需手工拼接模板字符串。skip_special_tokensTrue解码时剔除|im_start|、|im_end|、|endoftext|等特殊 token只保留干净的回答文本。推理时 model 与 tokenizer 加载完成后即挂载 Lora 权重若希望永久合并 Lora 与基座权重可使用 peft 的save_pretrained/合并功能导出完整模型本仓库 Atom-7B-Chat Lora 微调 中给出了model.save_pretrained(training_args.output_dir)的保存参考。延伸学习本文配套的完整逐 cell 可执行版本见 Qwen1.5-7B-Chat Lora.ipynb其中包含每一步的真实输出数据集预览、模型结构、可训练参数统计、训练损失曲线等非常适合对照复现。想在微调过程中加入实验跟踪与指标可视化可参考同目录的 08-Qwen1.5-7B-chat LoRA微调接入实验管理.md在本文训练流程基础上无缝接入 SwanLab。训练完成后可将微调模型接入 FastApi 服务、WebDemo 或 LangChain 知识库相关教程见 Qwen1.5 系列文档 中列出的 01/02/03 号部署文档。Lora 的底层原理低秩分解、缩放系数、与全参微调的关系可进一步阅读 peft 源码或查阅《深入浅出 Lora》等公开技术博客深入理解。【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/datawhalechina/self-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。