资讯动态

Datawhale self-llm 实战:Baichuan2-7B-Chat LoRA 高效微调全流程指南(transformers + peft)

发布时间:2026/9/19 21:07:56 来源:尧图企业网站定制
Datawhale self-llm 实战Baichuan2-7B-Chat LoRA 高效微调全流程指南transformers peft【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/datawhalechina/self-llm本篇技术指南基于 Datawhale 开源项目《开源大模型食用指南》的 04-Baichuan2-7B-chat Lora 微调教程以 Baichuan2-7B-Chat 为例完整演示基于 transformers、peft 框架进行 LoRA 高效微调的全流程从依赖安装、ModelScope 模型下载、指令集构建与格式化到 LoraConfig / TrainingArguments 参数配置、Trainer 训练再到两种模型推理方式。读完本文你将具备在单卡 Linux 环境下独立完成一个中文大模型的对话风格个性化微调并用最少的显存开销训练与部署的能力。本文对应的仓库资源仓库为本文档提供了完整的配套资源建议边读边对照实战教程文档models/BaiChuan/04-Baichuan2-7B-chat Lora 微调.md可逐格运行的 Notebookmodels/BaiChuan/04-Baichuan2-7B-chat Lora 微调.ipynb包含每一步的真实运行输出甄嬛对话风格指令数据集dataset/huanhuan.json约 3729 条、dataset/huanhuan.jsonljsonl 格式以及用于快速验证的小样本集 dataset/huanhuan-100.json同思路的独立训练脚本示例examples/Chat-嬛嬛/train.py基于 Llama3.1-8B-Instruct 的变体可对照体会 target_modules 因模型结构而异为什么用 LoRA 微调 7B 模型大模型微调通常指指令微调Instruction Tuning其核心目标是让模型具备理解并遵循用户指令的能力。然而对 Baichuan2-7B-Chat 这样约 75 亿参数的模型做全参数微调单张消费级显卡几乎无法承载。LoRALow-Rank Adaptation通过冻结预训练权重仅在注意力与 MLP 的线性层旁插入可训练的低秩矩阵来学习增量从而把可训练参数量压缩到极小规模。从仓库 Notebook 的实际运行输出可以直观印证这一点04-Baichuan2-7B-chat Lora 微调.ipynb 中执行model.print_trainable_parameters()的结果trainable params: 17,891,328 || all params: 7,523,864,576 || trainable%: 0.23779439168895536在总参数约 75.2 亿的模型中LoRA 只训练约 1789 万参数占比仅0.238%这就是它能在普通显卡上完成微调的根本原因。环境与依赖安装教程基于 LinuxAutoDL 云环境执行先升级 pip 并切换到国内镜像源以加速安装# 升级pip python -m pip install --upgrade pip # 更换 pypi 源加速库的安装 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip install modelscope1.9.5 pip install streamlit1.24.0 pip install sentencepiece0.1.99 pip install accelerate0.24.1 pip install transformers_stream_generator0.0.4 pip install transformers4.33.1 pip install peft0.4.0 pip install datasets2.10.1 pip install accelerate0.20.3 pip install tiktoken pip install transformers_stream_generator其中值得注意的几个依赖modelscope国内模型下载与加载工具本文用它拉取 Baichuan2-7B-Chat 权重peftLoRA 微调的核心库提供LoraConfig、get_peft_model、PeftModel等接口transformersaccelerate模型加载、训练调度与多卡设备分配datasets指令集的读取与映射Dataset.map格式化sentencepieceBaichuan2 分词器依赖的分词后端tiktoken分词与编码相关工具库。模型下载ModelScope snapshot_download在/root/autodl-tmp路径下新建download.py文件写入以下内容import torch from modelscope import snapshot_download, AutoModel, AutoTokenizer import os model_dir snapshot_download(baichuan-inc/Baichuan2-7B-Chat,cache_dir/root/autodl-tmp, revisionv1.0.4)snapshot_download的第一个参数是模型名称baichuan-inc/Baichuan2-7B-Chatcache_dir指定模型的下载保存路径revision指定模型版本快照v1.0.4。保存后运行python /root/autodl-tmp/download.py模型大小约 15 GB根据网络情况一般需要 1020 分钟。下载完成后模型权重会缓存在/root/autodl-tmp下后续可通过名称baichuan-inc/Baichuan2-7B-Chat直接引用。指令集构建以甄嬛对话风格微调为例指令微调所使用的数据格式如下包含三个关键字段{ instrution:回答以下用户问题仅输出答案。, input:11等于几?, output:2 }instruction用户指令告知模型需要完成的任务input用户输入是完成任务所必需的输入内容可为空字符串output模型应该给出的标准输出。指令集应围绕目标任务针对性构建。本节使用甄嬛对话风格微调作为示例目标构建一个模拟甄嬛说话风格的个性化 LLM构造的指令形如{ instruction: 现在你要扮演皇帝身边的女人--甄嬛, input:你是谁, output:家父是大理寺少卿甄远道。 }仓库根目录的 dataset/huanhuan.json 存放了全部构造好的指令数据约 3729 条dataset/huanhuan.jsonl 为对应的 jsonl 版本。以真实数据为例{instruction:娘娘。,input:,output:你放心本宫到任何时候都不会自轻自贱委屈了这孩子。} {instruction:皇上驾到,input:,output:皇上万福金安。}Notebook 中通过 pandas 读取 json 再转换为datasets.Dataset对象随后ds[:3]可直接预览前 3 条样本04-Baichuan2-7B-chat Lora 微调.ipynb。数据格式化将文本编码为 input_ids 与 labelsLoRA 训练数据需要先格式化、编码再送入模型。熟悉 PyTorch 训练流程的同学知道输入文本需要编码为input_ids输出文本编码为labels编码结果是多维向量。下面定义一个预处理函数process_func对每个样本编码输入、输出文本并返回编码后的字典def process_func(example): MAX_LENGTH 256 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()\n\nAssistant: ,add_special_tokensFalse) # add_special_tokens 不在开头加 special_tokens response tokenizer(example[output]tokenizer.eos_token, add_special_tokensFalse) input_ids instruction[input_ids] response[input_ids] attention_mask instruction[attention_mask] response[attention_mask] labels [-100] * len(instruction[input_ids]) response[input_ids] 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 }该函数的几个关键设计点模板拼接将 system 提示、用户指令、输入拼成 Baichuan2 的对话模板末尾追加Assistant:引导模型生成回答。add_special_tokensFalse表示不在开头额外添加特殊 tokenlabels 掩码instruction部分输入与提示的 labels 全部置为-100在交叉熵损失中会被自动忽略只有response部分的 token id 参与 loss 计算——这正是只教模型学回答、不学提问的标准做法attention_maskresponse部分同样置 1因为 eos token 也需要被模型关注截断MAX_LENGTH 256超出部分直接裁剪。由于中文分词器会把一个字切分为多个 token若数据较长可适当放开该值以保证数据完整性。数据集映射完成后可以用tokenizer.decode验证编码结果是否正确还原出完整对话也可通过tokenizer.decode(list(filter(lambda x: x ! -100, tokenized_id[1][labels])))单独还原 labels 中被参与训练的输出部分Notebook 中两者的输出分别为 |im_start|system\n现在你要扮演皇帝身边的女人--甄嬛.|im_end|\n|im_start|user\n小姐别的秀女都在求中选唯有咱们小姐想被撂牌子菩萨一定记得真真儿的——|im_end|\n\nAssistant: 嘘——都说许愿说破是不灵的。/s 你们俩话太多了我该和温太医要一剂药好好治治你们。/s加载 tokenizer 与半精度模型Baichuan2 依赖自定义代码加载 tokenizer 时需指定use_fastFalse与trust_remote_codeTrueNotebook 中打印出的 tokenizer 信息显示词表大小 125696model_max_length4096pad token 与 unk token 相同。随后加载半精度模型import torch model AutoModelForCausalLM.from_pretrained(baichuan-inc/Baichuan2-7B-Chat, trust_remote_codeTrue, torch_dtypetorch.half, device_mapauto) model.generation_config GenerationConfig.from_pretrained(baichuan-inc/Baichuan2-7B-Chat/) modeltorch_dtypetorch.half以 FP16 半精度加载显存占用约为 BF16/FP32 的一半是 7B 模型单卡训练的关键device_mapauto由 accelerate 自动把各层分配到可用设备多卡时自动均衡generation_config加载模型自带的生成配置保证后续推理行为与官方一致。从 Notebook 输出的模型结构可以看到 Baichuan2-7B-Chat 的核心结构这直接决定了后面 LoraConfig 中target_modules的选择BaichuanForCausalLM( (model): BaichuanModel( (embed_tokens): Embedding(125696, 4096, padding_idx0) (layers): ModuleList( (0-31): 32 x DecoderLayer( (self_attn): Attention( (W_pack): Linear(in_features4096, out_features12288, biasFalse) (o_proj): Linear(in_features4096, out_features4096, biasFalse) (rotary_emb): RotaryEmbedding() ) (mlp): MLP( (gate_proj): Linear(in_features4096, out_features11008, biasFalse) (down_proj): Linear(in_features11008, out_features4096, biasFalse) (up_proj): Linear(in_features4096, out_features11008, biasFalse) (act_fn): SiLUActivation() ) (input_layernorm): RMSNorm() (post_attention_layernorm): RMSNorm() ) ) (norm): RMSNorm() ) (lm_head): NormHead() )模型共 32 层 DecoderLayer注意力部分采用W_pack将 Q/K/V 打包为一个 4096→12288 的投影与o_proj输出投影MLP 部分为 SwiGLU 结构的gate_proj/up_proj/down_proj。这正是 LoRA 需要插入低秩适配器的 5 个目标模块。另外若后续开启梯度检查点gradient_checkpointing必须先执行model.enable_input_require_grads()否则训练会报错——Notebook 中紧随模型加载之后即有该调用model.enable_input_require_grads() # 开启梯度检查点时要执行该方法配置 LoraConfig参数详解与目标模块选择LoraConfig类中可以设置很多参数但主要参数并不多参数作用本文取值task_type模型类型因果语言模型填TaskType.CAUSAL_LMTaskType.CAUSAL_LMtarget_modules需要插入 LoRA 的模块层名主要即 attention 与 MLP 的线性层可传数组、字符串或正则表达式[W_pack, o_proj, gate_proj, up_proj, down_proj]rLoRA 的秩rank决定低秩矩阵的维度与 LoRA 原理直接相关8lora_alphaLoRA 缩放系数实际作用参见 LoRA 原理32lora_dropoutLoRA 层的 Dropout 比例用于防止过拟合0.1inference_mode是否为推理模式训练时置FalseFalse配置代码如下from peft import LoraConfig, TaskType, get_peft_model config LoraConfig( task_typeTaskType.CAUSAL_LM, target_modules[W_pack, o_proj, gate_proj, up_proj, down_proj], inference_modeFalse, # 训练模式 r8, # Lora 秩 lora_alpha32, # Lora alaph具体作用参见 Lora 原理 lora_dropout0.1# Dropout 比例 ) config需要注意target_modules的模块名必须与模型真实结构匹配。上文模型结构输出显示 Baichuan2 的注意力层是W_packQKV 打包投影而非常见的q_proj/k_proj/v_proj分离结构——这正是本教程选择W_pack的原因。对比仓库中基于 Llama3.1 的 examples/Chat-嬛嬛/train.py其target_modules则写为[q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj]可见不同模型架构的目标模块并不相同配置前应先用结构打印确认。配置完成后通过get_peft_model将 LoRA 注入模型model get_peft_model(model, config) model.print_trainable_parameters()自定义 TrainingArguments训练超参详解TrainingArguments的源码对每个参数都有说明这里给出最常用的几个参数作用本文取值output_dir模型与检查点的输出路径./output/Baichuan2per_device_train_batch_size单卡 batch size8gradient_accumulation_steps梯度累加步数。显存较小时可调小 batch_size、调大该值2logging_steps每多少步输出一次训练日志10num_train_epochs训练轮数3save_steps每多少步保存一次 checkpoint100learning_rate学习率5e-5save_on_each_node多节点训练时每个节点都保存Truegradient_checkpointing梯度检查点以少量计算换取显存开启后必须执行model.enable_input_require_grads()Trueargs TrainingArguments( output_dir./output/Baichuan2, per_device_train_batch_size8, gradient_accumulation_steps2, logging_steps10, num_train_epochs3, save_steps100, learning_rate5e-5, save_on_each_nodeTrue, gradient_checkpointingTrue )结合仓库 Notebook 中另一组实际跑通的参数output_dir./output/Baichuan6、num_train_epochs4、learning_rate1e-4可以看到batch size、梯度累加、学习率、轮数等都属于可按显存与效果灵活调整的项。有效 batch size per_device_train_batch_size × gradient_accumulation_steps本文即为 8 × 2 16。使用 Trainer 训练与结果解读配置好数据集、模型与训练参数后用Trainer组装并启动训练trainer Trainer( modelmodel, argsargs, train_datasettokenized_id, data_collatorDataCollatorForSeq2Seq(tokenizertokenizer, paddingTrue), ) trainer.train()DataCollatorForSeq2Seq负责在 batch 内对不等长样本做 padding 对齐padding 位置因 labels 中 -100 掩码而不会计入 loss。Notebook 中的一次完整训练4 epoch、3729 条样本共 932 步耗时约 28 分钟训练 loss 从初期的 3.6 左右逐步下降到 1.61.8 区间最终train_loss2.32吞吐约 8.78 samples/s示例如下图。训练过程中会在output_dir下按save_steps自动保存 checkpoint如checkpoint-100、checkpoint-600等无需手动保存。模型推理两种方式方式一训练后直接推理训练完成后直接用当前模型对象推理这是一种比较经典的方式model.eval() inputs tokenizer(|im_start|system\n现在你要扮演皇帝身边的女人--甄嬛.|im_end|\n|im_start|user\n{}|im_end|\n.format(你是谁, ).strip() \nassistant\n , return_tensorspt) outputs model.generate(**inputs.to(model.device), max_new_tokens100, eos_token_id2) result tokenizer.decode(outputs[0], skip_special_tokensTrue) print(result)推理时构造的 prompt 必须与训练时process_func中的模板保持一致相同的 system 提示与|im_start|标记格式否则效果会明显变差。Notebook 中该方式的输出为|im_start|system 现在你要扮演皇帝身边的女人--甄嬛.|im_end| |im_start|user 你是谁|im_end| assistant 我是甄嬛家父是大理寺少卿甄远道。微调后的模型已经能按甄嬛的口吻自报家门说明对话风格已被成功注入见下图。方式二重新加载 checkpoint 推理如果想在训练结束、进程重启后加载已保存的 LoRA 权重进行推理使用PeftConfigPeftModelfrom transformers import AutoModelForSeq2SeqLM from peft import PeftModel, PeftConfig peft_model_id output/Baichuan3/checkpoint-600 # 这里我训练出效果最好的一版是 checkpoint-600所以调用了这个大家可以根据自己情况选择 config PeftConfig.from_pretrained(peft_model_id) model AutoModelForCausalLM.from_pretrained(baichuan-inc/Baichuan2-7B-Chat, use_fastFalse, trust_remote_codeTrue) model PeftModel.from_pretrained(model, peft_model_id) model.eval() input tokenizer(|im_start|system\n现在你要扮演皇帝身边的女人--甄嬛.|im_end|\n|im_start|user\n{}|im_end|\n.format(你是谁, ).strip() \nassistant\n , return_tensorspt).to(model.device) max_length 512 outputs model.generate( **input, max_lengthmax_length, eos_token_id2, do_sampleTrue, repetition_penalty1.3, no_repeat_ngram_size5, temperature0.1, top_k40, top_p0.8, ) print(tokenizer.decode(outputs[0], skip_special_tokensTrue))这段代码的关键点PeftConfig.from_pretrained读取 checkpoint 目录下的 LoRA 配置PeftModel.from_pretrained把微调好的低秩权重叠加到原始 Baichuan2-7B-Chat 权重之上推理阶段加入了采样参数do_sampleTrue开启随机采样temperature0.1压低随机性使输出更稳定top_k40与top_p0.8限制候选 token 范围repetition_penalty1.3与no_repeat_ngram_size5抑制重复生成注意peft_model_id请替换为你自己的实际输出目录与步数Notebook 中另一处加载示例为output/Baichuan5/checkpoint-1100需要提示的是文档与 Notebook 中该段首行导入写的是AutoModelForSeq2SeqLM而实际加载使用的是AutoModelForCausalLMBaichuan2 为因果语言模型从源码结构看属于笔误实际运行时以AutoModelForCausalLM为准或直接去掉该多余 import 即可。小结本文基于 Datawhale self-llm 仓库完整走通了 Baichuan2-7B-Chat 的 LoRA 微调链路依赖安装 → ModelScope 下载权重 → 构建甄嬛对话指令集 → 编码格式化 → 半精度加载 → 配置 LoraConfig 与 TrainingArguments → Trainer 训练 → 两种方式推理验证。整个流程可训练参数仅占 0.238%配合梯度检查点与 FP16 精度单张 24 GB 显存级显卡即可完成训练并成功让模型学会用甄嬛口吻回答问题。如果还需要将微调后的模型对外提供服务或继续扩展应用可以参考本仓库 BaiChuan 目录下的姊妹篇01-Baichuan2-7B-chat FastApi 部署调用、02-Baichuan-7B-chat WebDemo 部署、03-Baichuan2-7B-chat 接入 LangChain 框架从而形成从微调到落地的完整闭环。【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/datawhalechina/self-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价