拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于 Qwen3-8B 的 LoRA 微调与 SwanLab 可视化实战:从环境搭建到角色扮演模型训练

基于 Qwen3-8B 的 LoRA 微调与 SwanLab 可视化实战从环境搭建到角色扮演模型训练【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm本教程是《开源大模型食用指南》self-llmQwen3 系列实战的一部分围绕 Qwen3-8B 这一稠密Dense混合推理模型完整演示环境配置 → 模型下载 → SFT 数据集构建 → Chat Template 数据预处理 → LoRA 参数配置 → Trainer 训练 → SwanLab 可视化 → LoRA 权重加载推理的全流程。读者完成本指南后将能够在单张消费级 GPU如 AutoDL 环境上以极低的可训练参数比例约 0.27%微调 8B 量级大模型并借助 SwanLab 实现训练过程的自动日志记录、loss 曲线可视化和多实验对比最终得到一个具备特定人格化对话风格的专属模型。一、教程背景与整体技术路线Qwen3 是通义千问推出的新一代大语言模型系列与 Qwen2 相比其在注意力层增加了q_norm与k_norm的 RMSNorm 归一化详见仓库中 Qwen3 模型结构解析并同时提供稠密Dense与 MoE 两种架构。本教程使用的 Qwen3-8B 属于稠密模型其Qwen3Attention与Qwen3MLP中暴露了q_proj、k_proj、v_proj、o_proj、gate_proj、up_proj、down_proj等线性层这为 LoRA 提供了天然的注入目标。由于 Qwen3 是混合推理模型用户可以手动选择是否开启思考模式thinking mode这给 SFT 数据格式与推理模板带来了新的注意点本教程会重点讲解。整体技术路线如下通过 ModelScope 下载 Qwen3-8B 权重构建instruction / input / output三字段的有监督微调SFT数据集编写process_func将文本按 Qwen3 Chat Template 编码为input_ids / attention_mask / labels通过 PEFT 的LoraConfig与get_peft_model注入低秩适配器使用 HFTrainer配合SwanLabCallback完成训练与可视化用PeftModel.from_pretrained加载 LoRA 权重进行推理验证。仓库中与本教程直接对应的可运行源码为 05-Qwen3-8B-LoRA.ipynb本教程的所有关键代码均可在此 notebook 中逐段复现。二、环境配置与依赖安装在开始训练之前需要准备一套与代码兼容的 Python 环境。推荐使用 Python 3.12 左右的版本notebook 元数据中记录的环境为 Python 3.12.3并安装以下依赖版本号与仓库实测一致# 换清华镜像源 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip install modelscope1.25.0 pip install transformers4.51.3 pip install accelerate1.6.0 pip install datasets3.5.1 pip install peft0.15.2 pip install swanlab0.5.7各依赖在流程中的职责依赖版本职责modelscope1.25.0国内镜像下载模型权重与数据集transformers4.51.3加载模型、Tokenizer、TrainingArguments、Traineraccelerate1.6.0分布式/多卡调度支撑device_mapautodatasets3.5.1加载并 map 处理本地 JSON 数据集peft0.15.2提供 LoraConfig、get_peft_model、PeftModelswanlab0.5.7训练过程可视化与自动日志记录考虑到部分同学配置环境可能会遇到一些问题仓库在 AutoDL 平台准备了 Qwen3 的环境镜像点击 codewithgpu 上的 Datawhale self-llm Qwen3 镜像链接并直接创建 AutoDL 实例即可省去逐条安装依赖的步骤。镜像内的环境版本与本教程完全对齐是新手最快的上手路径。三、模型下载通过 ModelScope 的snapshot_download即可下载 Qwen3-8B 的完整权重。需要特别注意的是必须将cache_dir修改为你自己的保存路径并将后续代码中的所有请修改我占位符替换为真实路径。# model_download.py # 注意修改cache_dir为保存的路径 from modelscope import snapshot_download model_dir snapshot_download(Qwen/Qwen3-8B, cache_dir请修改我, revisionmaster) print(f模型下载完成保存路径为{model_dir})下载完成后model_dir即为基础模型路径后续所有AutoTokenizer.from_pretrained/AutoModelForCausalLM.from_pretrained均指向该目录。在 AutoDL 等云平台上建议将模型放在/root/autodl-tmp/Qwen/Qwen3-8B之类的数据盘路径notebook 中即为该路径避免占用系统盘空间。四、数据集构建理解 SFT 数据格式对大语言模型进行supervised-finetuningsft有监督微调时数据采用如下三字段格式{ instruction: 回答以下用户问题仅输出答案。, input: 11等于几?, output: 2 }其中instruction是用户指令告知模型其需要完成的任务input是用户输入是完成用户指令所必须的输入内容可为空字符串output是模型应该给出的输出。有监督微调的目标是让模型具备理解并遵循用户指令的能力。因此在构建数据集时应针对目标任务构建针对性数据。比如如果目标是通过大量人物对话数据微调得到一个能够 role-play 甄嬛对话风格的模型数据示例如下{ instruction: 你父亲是谁, input: , output: 家父是大理寺少卿甄远道。 }仓库中提供了现成的示例数据集dataset/huanhuan.json完整版甄嬛对话数据集约 1.8 万行notebook 中ds.map后得到 3729 条编码样本涵盖大量甄嬛风格对话dataset/huanhuan-100.json100 条精简版适合快速跑通流程。在 notebook 中通过 pandas 读取 JSON 并转换为 HuggingFaceDataset对象from datasets import Dataset import pandas as pd # 将JSON文件转换为CSV文件 df pd.read_json(./huanhuan.json) # 注意修改 ds Dataset.from_pandas(df)执行ds[:3]可以看到数据集前三条样本例如{instruction: [小姐别的秀女都在求中选唯有咱们小姐想被撂牌子菩萨一定记得真真儿的——, ...], input: [, , ], output: [嘘——都说许愿说破是不灵的。, ...]}。五、数据预处理适配 Qwen3 的 Chat TemplateLoRALow-Rank Adaptation训练的数据需要先经过格式化、编码之后才能输入模型将输入文本编码为input_ids将输出文本编码为labels。我们定义一个预处理函数process_func对每个样本同时编码输入、输出文本并返回编码后的字典def process_func(example): MAX_LENGTH 1024 # 设置最大序列长度为1024个token input_ids, attention_mask, labels [], [], [] # 初始化返回值 # 适配chat_template instruction tokenizer( fs|im_start|system\n现在你要扮演皇帝身边的女人--甄嬛|im_end|\n f|im_start|user\n{example[instruction] example[input]}|im_end|\n f|im_start|assistant\nthink\n\n/think\n\n, add_special_tokensFalse ) response tokenizer(f{example[output]}, add_special_tokensFalse) # 将instructio部分和response部分的input_ids拼接并在末尾添加eos token作为标记结束的token input_ids instruction[input_ids] response[input_ids] [tokenizer.pad_token_id] # 注意力掩码表示模型需要关注的位置 attention_mask instruction[attention_mask] response[attention_mask] [1] # 对于instruction使用-100表示这些位置不计算loss即模型不需要预测这部分 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 }这段代码有三个关键设计-100掩码屏蔽 losslabels中instruction部分全部置为-100PyTorch 的交叉熵损失会忽略这些位置即模型只学习预测output部分不学习重复输入手动拼装 Qwen3 模板模板以s开头包含system / user / assistant三个角色段并显式加入think\n\n/think占位——这是为了让模型在训练时也见到思维链结构的输入形态详见下文 thinking mode 说明序列截断超过MAX_LENGTH 1024的样本被截断防止长样本拉爆显存。对数据集执行 map 后得到仅含三个编码字段的新数据集tokenized_id ds.map(process_func, remove_columnsds.column_names) tokenized_idnotebook 的实测输出为Dataset({features: [input_ids, attention_mask, labels], num_rows: 3729})。可以解码验证编码结果是否正确print(tokenizer.decode(tokenized_id[0][input_ids])) print(tokenizer.decode(list(filter(lambda x: x ! -100, tokenized_id[1][labels]))))第一条输出形如s|im_start|system\n现在你要扮演皇帝身边的女人--甄嬛|im_end|...|im_start|assistant\nthink\n\n/think\n\n嘘——都说许愿说破是不灵的。|endoftext|第二条输出仅包含labels中实际参与 loss 计算的输出文本。Qwen3 Chat Template 与思考模式Qwen3采用的 Chat Template 基于ChatML风格。由于 Qwen3 是混合推理模型可以手动选择是否开启思考模式thinking mode这一点在推理模板与训练模板中都至关重要。不开启thinking mode时apply_chat_template的输出为messages [ {role: system, content: system_message_test}, {role: user, content: user_message_test}, {role: assistant, content: assistant_message_test}, ] text tokenizer.apply_chat_template( messages, tokenizeFalse, add_generation_promptTrue, enable_thinkingFalse ) print(text)|im_start|system system_message_test|im_end| |im_start|user user_message_test|im_end| |im_start|assistant think /think assistant_message_test|im_end| |im_start|assistant think /think开启thinking mode时输出为text tokenizer.apply_chat_template( messages, tokenizeFalse, add_generation_promptTrue, enable_thinkingTrue ) print(text)|im_start|system system_message_test|im_end| |im_start|user user_message_test|im_end| |im_start|assistant think /think assistant_message_test|im_end| |im_start|assistant对比可见关闭 thinking 时模板会保留assistant_message_test这样的历史 assistant 内容notebook 实测输出即如此开启 thinking 时think块会成为模型生成或回答的一部分。在process_func中手动拼装think\n\n/think\n\n即为训练时开启思考模式的等价写法让模型学会在think块之后输出答案。而在后续推理时为了让角色扮演类任务输出更直接、不进入长思考过程本教程统一使用enable_thinkingFalse。六、加载模型与 Tokenizertokenizer AutoTokenizer.from_pretrained(请修改我/Qwen/Qwen3-8B) model AutoModelForCausalLM.from_pretrained(请修改我/Qwen/Qwen3-8B, device_mapauto, torch_dtypetorch.bfloat16)关键参数说明device_mapauto由 accelerate 自动将各层分配到可用设备多卡时自动切分单卡场景等价于全部放到该卡torch_dtypetorch.bfloat16以 bf16 半精度加载权重显著降低显存占用8B 模型 fp32 约 32GBbf16 约 16GB且 bf16 在训练中的数值稳定性优于 fp16若开启了梯度检查点本教程gradient_checkpointingTrue在包装 LoRA 前还需执行model.enable_input_require_grads()notebook 中有该调用用于让冻结的基座参数在反向传播时仍能收到输入梯度。从 notebook 中打印的模型结构可以看到 Qwen3-8B 的具体形态这也是理解target_modules的依据Qwen3ForCausalLM( (model): Qwen3Model( (embed_tokens): Embedding(151936, 4096) (layers): ModuleList( (0-35): 36 x Qwen3DecoderLayer( (self_attn): Qwen3Attention( (q_proj): Linear(in_features4096, out_features4096, biasFalse) (k_proj): Linear(in_features4096, out_features1024, biasFalse) (v_proj): Linear(in_features4096, out_features1024, biasFalse) (o_proj): Linear(in_features4096, out_features4096, biasFalse) (q_norm): Qwen3RMSNorm((128,), eps1e-06) (k_norm): Qwen3RMSNorm((128,), eps1e-06) ) (mlp): Qwen3MLP( (gate_proj): Linear(in_features4096, out_features12288, biasFalse) (up_proj): Linear(in_features4096, out_features12288, biasFalse) (down_proj): Linear(in_features12288, out_features4096, biasFalse) (act_fn): SiLU() ) ... ) ) ... ) (lm_head): Linear(in_features4096, out_features151936, biasFalse) )即36 层 DecoderLayer、隐藏维度 4096、注意力采用 GQAk/v 投影到 1024即 8 个 KV 头共享、MLP 中间维度 12288、词表 151936。这也解释了为何 LoRA 要同时覆盖注意力四投影与 MLP 三投影。七、配置 LoraConfigLoraConfig中可以设置很多参数比较重要的如下task_type模型类型现在绝大部分decoder_only的模型都是因果语言模型CAUSAL_LMtarget_modules需要训练的模型层的名字主要就是attention部分的层不同的模型对应的层的名字不同rLoRA的秩决定了低秩矩阵的维度较小的r意味着更少的参数lora_alpha缩放参数与r一起决定了LoRA更新的强度。实际缩放比例为lora_alpha/r在当前示例中是32 / 8 4倍lora_dropout应用于LoRA层的dropout rate用于防止过拟合。from peft import LoraConfig, TaskType, get_peft_model 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 alpha lora_dropout0.1 # Dropout 比例 )target_modules覆盖了 Qwen3 每一层 DecoderLayer 中注意力与 MLP 的全部 7 个线性层q/k/v/o_projgate/up/down_proj这也是本教程全模块 LoRA的做法。通过get_peft_model将配置套用到模型后可打印可训练参数规模model get_peft_model(model, config) model.print_trainable_parameters()notebook 的实测输出为trainable params: 21,823,488 || all params: 8,212,558,848 || trainable%: 0.2657只训练 2182 万个参数约占 0.27%这就是 LoRA 的核心价值——冻结 80 亿参数的基座仅优化低秩适配矩阵即可在单卡上完成微调同时保留了基座模型的通用能力。八、配置 TrainingArgumentsoutput_dir模型的输出路径per_device_train_batch_size每张卡上的batch_sizegradient_accumulation_steps梯度累计num_train_epochs顾名思义epochargs TrainingArguments( output_dir./output/Qwen3_8B_LoRA, # 注意修改 per_device_train_batch_size4, gradient_accumulation_steps4, logging_steps10, num_train_epochs3, save_steps100, learning_rate1e-4, save_on_each_nodeTrue, gradient_checkpointingTrue, report_tonone, )对本教程关键参数的解读等效批量大小per_device_train_batch_size4 × gradient_accumulation_steps4 16单卡即每 4 个小批次累积一次梯度更新既保证足够大的有效 batch又控制了瞬时显存峰值save_steps100每 100 步保存一次 checkpoint训练共 699 步因此得到checkpoint-100至checkpoint-699共 7 个存档点最后推理使用checkpoint-699gradient_checkpointingTrue以少量计算换显存配合上文提到的enable_input_require_grads()report_tonone关闭 HF 自带的实验报告日志统一交给 SwanLab 回调接管避免重复上报learning_rate1e-4LoRA 场景常用的学习率量级高于全量微调。九、SwanLab为什么需要记录训练过程SwanLab 是一个开源的模型训练记录工具面向 AI 研究者提供了训练可视化、自动日志记录、超参数记录、实验对比、多人协同等功能。在 SwanLab 上研究者能基于直观的可视化图表发现训练问题对比多个实验找到研究灵感并通过在线链接的分享与基于组织的多人协同训练打破团队沟通的壁垒。为什么要记录训练相较于软件开发模型训练更像一个实验科学。一个品质优秀的模型背后往往是成千上万次实验。研究者需要不断尝试、记录、对比积累经验才能找到最佳的模型结构、超参数与数据配比。在这之中如何高效进行记录与对比对于研究效率的提升至关重要。SwanLab 与 TransformersTrainer的集成方式为SwanLabCallback它会自动捕获训练过程中的 loss、学习率、吞吐量等指标并上传云端无需手动swanlab.log。十、实例化 SwanLabCallback 并开始训练建议先在 SwanLab 官网注册账号然后在训练初始化阶段选择(2) Use an existing SwanLab account并使用 private API Key 登录notebook 实测登录流程输出即为该选项登录后日志会显示Tracking run with swanlab version 0.5.7、Run data will be saved locally in .../swanlog/...以及云端项目/运行链接。import swanlab from swanlab.integration.transformers import SwanLabCallback # 实例化SwanLabCallback swanlab_callback SwanLabCallback( projectQwen3-Lora, # 注意修改 experiment_nameQwen3-8B-LoRA-experiment # 注意修改 )参数说明project对应云端项目名可在同一项目下聚合多个实验用于对比experiment_name为本次实验名。随后将回调传入Trainer并启动训练trainer Trainer( modelmodel, argsargs, train_datasettokenized_id, data_collatorDataCollatorForSeq2Seq(tokenizertokenizer, paddingTrue), callbacks[swanlab_callback] # 传入之前的swanlab_callback ) trainer.train()要点说明data_collatorDataCollatorForSeq2Seq(tokenizertokenizer, paddingTrue)对 batch 内不同长度的序列做 padding 对齐由于labels中的-100位置不参与 losspadding 不会污染训练notebook 训练日志中有提示use_cacheTrue is incompatible with gradient checkpointing. Setting use_cacheFalse.这是开启梯度检查点后的正常自动降级无需干预Trainer初始化时若出现 No label_names provided for model classPeftModelForCausalLM 的 warning同样属于 PEFT 包装模型的正常提示。训练结束后的实测输出TrainOutput(global_step699, training_loss2.6425710331557988, metrics{train_runtime: 879.9696, train_samples_per_second: 12.713, train_steps_per_second: 0.794, total_flos: 5.190619083415757e16, train_loss: 2.6425710331557988, epoch: 2.990353697749196})即共训练 699 步3 个 epoch 略未跑满、总耗时约 880 秒、训练 loss 收敛至约 2.64。从 notebook 记录的逐 step loss 可以看到loss 从第 10 步的 4.29 稳步下降到 600 步之后的 2.2 左右收敛趋势健康。训练完成后打开SwanLab即可查看训练过程中自动记录的参数与可视化的训练 loss 曲线SwanLab 的 loss 曲线横轴为训练步数0800纵轴为 loss 值约 1.54.5可直观观察到损失下降并趋于平稳的收敛过程。此外SwanLab 会自动记录超参数LoraConfig 与 TrainingArguments 中的全部配置、环境信息并支持在网页端对比不同实验这就是记录训练带来的效率提升。十一、加载 LoRA 权重进行推理训练完成后得到任意checkpoints之后即可加载lora权重进行推理from transformers import AutoModelForCausalLM, AutoTokenizer import torch from peft import PeftModel mode_path 请修改我/Qwen/Qwen3-8B # 注意修改 lora_path ./output/Qwen3_8B_lora/checkpoint-699 # 注意修改 # 加载tokenizer tokenizer AutoTokenizer.from_pretrained(mode_path) # 加载Qwen3 base model model AutoModelForCausalLM.from_pretrained(mode_path, device_mapauto,torch_dtypetorch.bfloat16, trust_remote_codeTrue) # 加载lora权重 model PeftModel.from_pretrained(model, model_idlora_path) prompt 你是谁 inputs tokenizer.apply_chat_template( [{role: user, content: 假设你是皇帝身边的女人--甄嬛。},{role: user, content: prompt}], add_generation_promptTrue, tokenizeTrue, return_tensorspt, return_dictTrue, enable_thinkingFalse ) # 采样参数设置 gen_kwargs {max_length: 2500, do_sample: True, top_k: 1} with torch.no_grad(): outputs model.generate(**inputs, **gen_kwargs) outputs outputs[:, inputs[input_ids].shape[1]:] print(tokenizer.decode(outputs[0], skip_special_tokensTrue))实测输出notebook 与文档一致我是甄嬛家父是大理寺少卿甄远道。推理环节的注意点PeftModel.from_pretrained(model, model_idlora_path)只加载训练产出的 adapter 权重约 2182 万个参数体积很小基座仍来自mode_path两者缺一不可apply_chat_template传入两条 user 消息先设定角色假设你是皇帝身边的女人--甄嬛再提问且指定enable_thinkingFalse使模型直接给出角色化回答而不进入冗长的思考过程gen_kwargs中do_sampleTrue, top_k1是接近贪心解码的保守采样保证角色扮演回复稳定max_length2500为最大生成长度解码前用outputs[:, inputs[input_ids].shape[1]:]裁剪掉输入 token只输出新生成部分skip_special_tokensTrue去除模板特殊符号。十二、训练记录参考与延伸学习本教程的示例训练记录公开链接为 SwanLab 上的「图表 | Qwen3-Lora/Qwen3-8B-LoRA-shufan.jiang」可在线查看完整的 loss 曲线、超参数与运行指标作为自己训练的对照基准若希望进一步理解 Qwen3 的架构细节q/k 归一化、MoE 门控等可阅读仓库中的 Qwen3 模型结构解析 Blog若想深入 Qwen3 的强化学习路径GRPO SwanLab可参考同目录的 Qwen3-8B GRPO 微调及通过 swanlab 可视化体验从 SFT 走向推理模型训练仓库其余模型目录如 Qwen2.5、GLM-4、DeepSeek 等均提供了同套路的 FastApi 部署、LangChain 接入、WebDemo、vLLM 与 Lora 微调教程可作为横向迁移参考。至此从环境搭建、数据构造、LoRA 微调到 SwanLab 可视化与权重加载推理的完整闭环已经跑通。基于本教程的代码骨架只需替换process_func中的系统提示词与数据集即可快速复用到任意角色扮演、对话风格迁移或领域指令跟随场景。【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调全参数/Lora、部署国内外开源大模型LLM/多模态大模型MLLM教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门