- 大模型
- 人工智能
- 教程
- 本地部署
- 微调
【免费下载链接】self-llm
《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调(全参数/Lora)、部署国内外开源大模型(LLM)/多模态大模型(MLLM)教程
本教程是《开源大模型食用指南》(self-llm)中 Qwen1.5 模型系列的第 8 篇,在前序 LoRA 微调训练的基础上,为 Qwen1.5-7B-Chat 的指令微调流程引入 SwanLab 实验管理平台,实现训练过程的云端可视化跟踪、指标比较与团队协作。读者学完后,将掌握一套"数据格式化 → LoRA 微调 → SwanLab 可视化 → 权重加载推理"的完整实战链路,并能在未来任何基于 transformers + peft 的微调任务中复用同样的实验管理方案。
配套的 Notebook 版本见 08-Qwen1.5-7B-chat LoRA微调接入实验管理.ipynb,不含实验管理的纯 LoRA 微调版本见 04-Qwen1.5-7B-chat Lora 微调.md,两者可对照学习。
环境配置
本文基础环境如下:
---------------- ubuntu 22.04 python 3.12 cuda 12.1 pytorch 2.3.0 ----------------本文默认学习者已安装好以上 PyTorch(CUDA)环境,如未安装请自行安装。仓库还在 AutoDL 平台提供了 Qwen1.5 环境镜像,该镜像适用于本仓库除 Qwen-GPTQ 和 vLLM 外的所有部署环境。
首先通过pip换源加速下载并安装依赖包(各依赖版本与 Notebook 中实际运行验证的版本保持一致):
# 升级pip python -m pip install --upgrade pip # 更换 pypi 源加速库的安装 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip install modelscope==1.16.1 pip install transformers==4.43.2 pip install accelerate==0.32.1 pip install peft==0.11.1 pip install datasets==2.20.0本节教程将微调数据集放置在仓库根目录 dataset/huanhuan.json,实际训练时按你自己的数据存放路径读取即可。
指令集构建
LLM 的微调一般指指令微调(Instruction Tuning)过程。所谓指令微调,是指我们使用的微调数据形如:
{ "instruction":"回答以下用户问题,仅输出答案。", "input":"1+1等于几?", "output":"2" }其中,instruction是用户指令,告知模型其需要完成的任务;input是用户输入,是完成用户指令所必需的输入内容;output是模型应该给出的输出。
核心训练目标是让模型具备理解并遵循用户指令的能力。因此,在指令集构建时,应针对目标任务针对性地构建任务指令集。例如,本节以模拟甄嬛对话风格的个性化 LLM 为目标(该数据集源自 Chat-嬛嬛 项目),构造的指令形如:
{ "instruction": "你是谁?", "input":"", "output":"家父是大理寺少卿甄远道。" }在 dataset/huanhuan.json 中可以看到这类对话样本的完整形态,例如:
{ "instruction": "皇上驾到!", "input": "", "output": "皇上万福金安。" }Notebook 中通过pd.read_json读取该 JSON 文件并转为 HuggingFaceDataset对象(代码路径 08-Qwen1.5-7B-chat LoRA微调接入实验管理.ipynb 第 34-36 行):
from datasets import Dataset import pandas as pd df = pd.read_json('./huanhuan.json') ds = Dataset.from_pandas(df)格式化后数据集共包含 3729 条训练样本,字段为instruction、input、output。
数据格式化
LoRA 训练的数据需要经过格式化、编码之后再输入给模型。熟悉 PyTorch 模型训练流程的同学知道,我们需要将输入文本编码为input_ids,将输出文本编码为labels,编码之后的结果都是多维向量。首先定义一个预处理函数,用于对每一个样本编码其输入、输出文本并返回一个编码后的字典:
def process_func(example): MAX_LENGTH = 384 # 分词器会将一个中文字切分为多个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_tokens=False) # add_special_tokens 不在开头加 special_tokens response = tokenizer(f"{example['output']}", add_special_tokens=False) 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 }这里有几个关键设计:
labels掩码:指令部分的 token 在labels中对应位置置为-100,损失函数计算时会忽略-100的位置,因此模型只学习"助手回复"部分的内容,避免把 system / user 提示也当成生成目标;attention_mask补 1:末尾拼接了pad_token_id(Qwen1.5 的 pad token 即<|endoftext|>),由于 EOS token 也需要被模型关注,所以对应的 attention mask 补充为 1;MAX_LENGTH = 384截断:BPE 分词器会把一个汉字拆成多个 token,中文对话拼接后序列较长,需要放宽最大长度并做截断,保证数据完整性。
随后使用Dataset.map批量处理并移除原始列:
tokenized_id = ds.map(process_func, remove_columns=ds.column_names)Notebook 中展示了格式化结果的验证(第 198-222 行):tokenizer.decode(tokenized_id[0]['input_ids'])还原出带<|im_start|>/<|im_end|>特殊 token 的完整训练文本;而tokenizer.decode(list(filter(lambda x: x != -100, tokenized_id[1]["labels"])))只解码出答案部分,印证了 labels 掩码的正确性。
Qwen1.5 采用的 ChatML Prompt Template 格式如下:
<|im_start|>system You are a helpful assistant.<|im_end|> <|im_start|>user 你是谁?<|im_end|> <|im_start|>assistant 我是一个有用的助手。<|im_end|>加载 tokenizer 与半精度模型
模型以半精度形式加载,如果显卡较新,可以用torch.bfloat16加载(Notebook 实测模型 dtype 为torch.bfloat16)。对于自定义模型一定要指定trust_remote_code=True:
tokenizer = AutoTokenizer.from_pretrained('./qwen/Qwen1.5-7B-Chat/', use_fast=False, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained('./qwen/Qwen1.5-7B-Chat/', device_map="auto", torch_dtype=torch.bfloat16)从 Notebook 第 9 个单元格打印的模型结构可以看到,Qwen1.5-7B-Chat在 transformers 4.43.2 中实际对应Qwen2ForCausalLM,由 32 层Qwen2DecoderLayer组成,每层包含:
self_attn(Qwen2Attention):q_proj、k_proj、v_proj输入输出均为 4096 维(带 bias),o_proj输出 4096 维(无 bias),并配备Qwen2RotaryEmbedding旋转位置编码;mlp(Qwen2MLP):gate_proj、up_proj将 4096 维映射到 11008 维,down_proj映射回 4096 维,激活函数为 SiLU;input_layernorm/post_attention_layernorm:均为Qwen2RMSNorm。
这个结构直接决定了下方LoraConfig中target_modules的取值——Qwen1.5 的全部 7 个线性投影层都是 LoRA 的可注入目标。
定义 LoraConfig
LoraConfig类中可以设置很多参数,但主要的参数不多。需要特别注意的是:LoRA 的缩放系数不是r(秩),而是lora_alpha / r。在本配置中缩放即为32 / 8 = 4倍。
config = LoraConfig( task_type=TaskType.CAUSAL_LM, target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], inference_mode=False, # 训练模式 r=8, # Lora 秩 lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理 lora_dropout=0.1 # Dropout 比例 )各参数要点:
task_type:模型类型,因果语言模型填TaskType.CAUSAL_LM;target_modules:需要训练的模型层名字,主要是 attention 与 MLP 中的投影层。不同模型的层名不同,可以传数组、字符串或正则表达式。对 Qwen1.5 而言,结合上文模型结构,7 个投影层q_proj / k_proj / v_proj / o_proj / gate_proj / up_proj / down_proj全部纳入;r:LoRA 的秩,控制低秩矩阵的维度,秩越大可学习参数量越多;lora_alpha:缩放超参数,最终缩放因子为lora_alpha / r;lora_dropout:LoRA 分支的 Dropout 比例,用于缓解过拟合。
将配置应用到模型并统计可训练参数:
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 亿总参数中,仅约 2000 万参数(0.26%)参与训练——这正是 LoRA 高效微调的核心价值:以极小的可训练参数量完成领域适配,显存与训练成本大幅低于全量微调。
自定义 TrainingArguments 参数
TrainingArguments的源码对每个参数的作用都有说明,这里讲解几个常用项:
output_dir:模型输出路径;per_device_train_batch_size:单设备 batch_size;gradient_accumulation_steps:梯度累加步数。如果显存较小,可以把batch_size调小、梯度累加调大;logging_steps:多少步输出一次 log;num_train_epochs:训练轮数;gradient_checkpointing:梯度检查点。一旦开启,模型必须执行model.enable_input_require_grads()(Notebook 第 10 个单元格有对应调用,并注释"开启梯度检查点时,要执行该方法")。
args = TrainingArguments( output_dir="./output/Qwen1.5", per_device_train_batch_size=4, gradient_accumulation_steps=4, logging_steps=10, num_train_epochs=3, save_steps=100, learning_rate=1e-4, save_on_each_node=True, gradient_checkpointing=True )提示:Notebook 实际运行中可以看到一条日志——
use_cache=Trueis incompatible with gradient checkpointing. Settinguse_cache=False...,即开启梯度检查点后 Trainer 会自动关闭 KV cache 以节省显存,这是预期行为,无需额外处理。
接入 SwanLab 实现模型实验管理
配置完训练参数后,推荐使用模型实验管理工具记录实验的训练情况,这样就不需要一直盯着服务器命令行的打印结果。
SwanLab 是一个开源的 AI 实验跟踪工具,提供跟踪、比较和协作实验的平台。接入流程只有三步:
第一步:安装 SwanLab
pip install swanlab第二步:注册账号并获取 API-Key
前往 SwanLab 官方网站注册账号(手机注册即可),然后进入个人设置界面获取 API-Key,这是将训练数据上传到云端的关键凭证:
第三步:确认框架集成支持
SwanLab 已对主流开源框架做了集成,其中就包括 HuggingFace Transformers 的 Trainer,官方文档给出了SwanLabCallback的接入示例:
使用 Trainer 训练
引入 SwanLab 后,只需要实例化一个回调类,再将其传入Trainer的callbacks列表,即可实现微调训练的实验追踪:
from swanlab.integration.huggingface import SwanLabCallback swanlab_callback = SwanLabCallback(project="hf-visualization") trainer = Trainer( model=model, args=args, train_dataset=tokenized_id, data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True), callbacks=[swanlab_callback], ) trainer.train()训练启动后会要求输入 SwanLab 的 API-Key,只需要输入在个人设置界面获取的 API-Key 即可。
Notebook 的示例运行记录显示(trainer.train()单元格输出),训练进度条推进到[134/699]、Epoch 0.57/3,每 10 步打印一次训练损失,例如 Step 10 的 loss 为 4.1535,到 Step 130 已波动下降至 2.9357 左右。这些数值会同步被 SwanLab 记录,供后续在云端查看与分析。
提示:
DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True)负责在批内按最长序列做动态 padding,保证同 batch 内 input_ids 长度一致,是序列到序列训练的标准配套组件。
查看训练进展
SwanLab 支持在 Jupyter 界面中直接开启看板,方便随时了解训练情况,无需离开 Notebook 环境。Notebook 运行trainer.train()后,单元格内会直接渲染出实验卡片、图表、日志与环境信息等面板,并显示Tracking run with swanlab version 0.3.8之类的跟踪信息:
当然也可以直接登录 SwanLab 官网,在个人账号下查看。图表视图会以折线图形式汇总展示train/loss、train/grad_norm、train/learning_rate、train/epoch等关键指标随训练步数的变化,支持多指标对比分析与多实验横向比较:
相比裸用命令行盯日志,这种方式的好处在于:训练结束后指标曲线、超参配置、环境信息等实验元数据都被持久化在云端,方便事后复盘、对比不同超参数组合的效果,也便于团队成员协作共享实验结果。
加载 LoRA 权重推理
训练好之后,可以使用如下方式加载 LoRA 权重进行推理:
from transformers import AutoModelForCausalLM, AutoTokenizer import torch from peft import PeftModel mode_path = './qwen/Qwen1.5-7B-Chat/' lora_path = 'lora_path' # 替换为你的 LoRA 权重保存路径,如 ./output/Qwen1.5/checkpoint-100 # 加载tokenizer tokenizer = AutoTokenizer.from_pretrained(mode_path) # 加载模型 model = AutoModelForCausalLM.from_pretrained(mode_path, device_map="auto", torch_dtype=torch.bfloat16) # 加载lora权重 model = PeftModel.from_pretrained(model, model_id=lora_path, config=config) prompt = "你是谁?" messages = [ {"role": "system", "content": "现在你要扮演皇帝身边的女人--甄嬛"}, {"role": "user", "content": prompt} ] text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) model_inputs = tokenizer([text], return_tensors="pt").to('cuda') generated_ids = model.generate( model_inputs.input_ids, max_new_tokens=512 ) 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_tokens=True)[0] print(response)要点说明:
PeftModel.from_pretrained(model, model_id=lora_path, config=config)将训练好的 LoRA 低秩适配权重叠加到基座模型上,基座模型权重本身不变;tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)会自动套用 Qwen1.5 的 ChatML 模板并追加 assistant 生成提示;generated_ids切片去掉了输入部分的 token,只保留新生成的内容,配合skip_special_tokens=True得到干净的回复文本。
总结
至此,我们完成了从环境搭建、指令数据构建、数据格式化、LoRA 配置到 SwanLab 可视化训练与推理验证的完整闭环。核心收获有三点:
- LoRA 高效微调范式:通过
get_peft_model仅注入约 0.26% 的可训练参数(约 2000 万 / 77.4 亿),即可在单一任务(模拟甄嬛对话风格)上实现领域适配,训练成本显著低于全量微调; - 一键接入实验管理:
SwanLabCallback作为 HuggingFace Trainer 的标准回调(callback)机制成员,只需实例化并传入callbacks=[swanlab_callback]即可自动采集 loss、learning_rate、grad_norm 等指标并上传云端,训练期间与训练结束后的复盘都无需值守命令行; - 全程可复现:本文所有代码与 Notebook 输出均可对照 08-Qwen1.5-7B-chat LoRA微调接入实验管理.ipynb 逐步验证,数据文件位于 dataset/huanhuan.json。
这一"微调 + 实验管理"的组合方案同样适用于仓库内其他模型的 LoRA/QLoRA 微调流程(例如 07-Qwen2.5-7B-Instruct Lora 微调 SwanLab可视化记录版.md),当你需要批量实验、对比超参数或与团队共享训练成果时,SwanLab 的实验管理能力将带来直接的效率提升。
- 大模型
- 人工智能
- 教程
- 本地部署
- 微调
【免费下载链接】self-llm
《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调(全参数/Lora)、部署国内外开源大模型(LLM)/多模态大模型(MLLM)教程
相关推荐
Datawhale self-llm 实战:Baichuan2-7B-Chat LoRA 高效微调全流程指南(transformers + peft)
Datawhale self llm 实战:Baichuan2 7B Chat LoRA 高效微调全流程指南(transformers + peft) 本篇技术
大模型人工智能教程本地部署微调Datawhale self-llm 实战:基于 transformers 与 peft 的 Atom-7B-Chat LoRA 指令微调全流程
Datawhale self llm 实战:基于 transformers 与 peft 的 Atom 7B Chat LoRA 指令微调全流程 本文是《开源大
大模型人工智能教程本地部署微调Datawhale self-llm 实战:基于 PEFT 对 XVERSE-7B-Chat 进行 LoRA 高效微调全流程指南
Datawhale self llm 实战:基于 PEFT 对 XVERSE 7B Chat 进行 LoRA 高效微调全流程指南 导读 本指南基于《开源大模型食
大模型人工智能教程本地部署微调
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考