🚀 LoRA 微调与推理 | 从零开始的超详细教程
📋 目录
- 什么是 Qwen2-7B-Instruct?
- LoRA 是什么?为什么要用 LoRA?
- 环境配置 (包括 Python、库的安装)
- 显存优化(解决“显存不足”问题)
- 加载模型和分词器(详细讲解每个参数)
- 数据集来源与说明(为什么选择 huanhuan-chat 数据)
- 数据加载与预处理(逐行解释代码)
- 配置 LoRA 参数(每个参数的作用)
- 配置训练参数(一步步讲解每个参数)
- 使用 DataCollator 进行数据整理(为什么它很重要)
- 使用 Trainer 进行模型训练
- 保存模型(为什么保存模型很重要)
- 模型推理(使用 LoRA 微调后的模型生成文本)
- 模型优化与调优技巧
设备说明:本教程顺利跑通用的GPU是 RTX 4090
1️⃣ 什么是 Qwen2-7B-Instruct?
📖 Qwen2-7B-Instruct
Qwen2-7B-Instruct 是由阿里巴巴达摩院推出的中文对话大模型,支持多种任务如对话、问答、文本生成等。它具有以下优点:
✅ 中文理解和生成能力强
✅ 性能接近 GPT-3 级别,但参数更少、速度更快
✅ 专为对话、指令跟随等任务优化
2️⃣ 什么是 LoRA?为什么要用 LoRA?
📖 LoRA(Low-Rank Adaptation)
LoRA 是一种轻量化微调技术。
传统微调需要更新数十亿的模型参数,而 LoRA 只需更新一小部分参数,显著减少显存占用和计算开销。
🎯 为什么选择 LoRA?
✅ 适合显存较小的显卡
✅ 微调更快,训练时间大幅缩短
✅ 性能接近全参数微调
3️⃣ 环境配置
🔎 安装 Python
- Windows 用户:Python 官方下载
- Linux / Ubuntu 用户(推荐使用):
sudo apt update
sudo apt install python3 python3-pip
🔎 安装所需 Python 库
在终端中执行以下命令:
pip install transformers
pip install datasets
pip install peft
pip install torch
🚀 更换 PyPI 镜像(加速下载)
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
4️⃣ 显存优化(防止 GPU 内存不足)
显存是模型训练的关键资源。清理 GPU 显存可以有效防止训练中断。
复制以下代码,运行时将释放占用的显存资源:
import torch
torch.cuda.empty_cache() # 清空显存,释放 GPU 资源
5️⃣ 加载模型和分词器
📖 什么是 tokenizer
?
tokenizer
会将文本转化为模型能理解的「数字 ID」。
📖 什么是 bfloat16
?
bfloat16
是一种更节省显存的数值表示方法,比float32
更适合大模型训练。
🔎 加载模型和分词器的代码
from transformers import AutoTokenizer, AutoModelForCausalLM
# 加载分词器
tokenizer = AutoTokenizer.from_pretrained(
'/root/autodl-tmp/qwen/Qwen2-7B-Instruct/',
use_fast=False, # 防止中文数据切分异常
trust_remote_code=True,
padding_side="right" # 保证中文对齐时表现更稳定
)
# 加载模型
model = AutoModelForCausalLM.from_pretrained(
'/root/autodl-tmp/qwen/Qwen2-7B-Instruct/',
trust_remote_code=True,
torch_dtype=torch.bfloat16, # 使用 bfloat16 节省显存
device_map="auto" # 根据显存自动分配
)
# 关闭缓存并开启梯度检查点,减少显存消耗
model.config.use_cache = False
model.gradient_checkpointing_enable()
6️⃣ 数据集来源与说明
📚 数据集:huanhuan-chat
- 来源:Chat-甄嬛 (Huanhuan-Chat) 项目
- 描述:该数据集基于《甄嬛传》角色的风格,训练出一个能够模仿甄嬛说话方式的个性化模型。
🔎 示例数据
{
"instruction": "你是谁?",
"input": "",
"output": "家父是大理寺少卿甄远道。"
}
7️⃣ 数据加载与预处理
🔎 加载数据
import pandas as pd
from datasets import Dataset
# 加载数据
df = pd.read_json('huanhuan-chat/dataset/train/lora/huanhuan.json')
ds = Dataset.from_pandas(df)
🔎 数据预处理代码
def process_func(example):
MAX_LENGTH = 384
input_ids, attention_mask, labels = [], [], []
instruction = tokenizer(
f"<|im_start|>system\n现在你要扮演皇帝身边的女人--甄嬛<|im_end|>\n"
f"<|im_start|>user\n{example['instruction'] + example['input']}<|im_end|>\n"
f"<|im_start|>assistant\n",
add_special_tokens=False
)
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]
labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]
return {
"input_ids": input_ids,
"attention_mask": attention_mask,
"labels": labels
}
# 数据映射
tokenized_ds = ds.map(process_func, remove_columns=ds.column_names)
8️⃣ 配置 LoRA 参数
🧩 LoRA 参数详解
📄 LoraConfig
的参数列表
LoraConfig
用于配置 LoRA 的行为和参数。以下是每个参数的详细说明:
from peft import LoraConfig, get_peft_model, TaskType
config = LoraConfig(
task_type=TaskType.CAUSAL_LM, # 指定模型类型(例如:因果语言模型 CLM)
target_modules=["q_proj", "v_proj"], # 指定哪些模块要进行 LoRA 微调
inference_mode=False, # 设置是否仅用于推理
r=4, # LoRA 的秩 (rank)
lora_alpha=16, # LoRA 的缩放参数
lora_dropout=0.05, # LoRA 的 Dropout 防止过拟合
bias="none" # 偏置参数设置
)
model = get_peft_model(model, config)
model.print_trainable_parameters() # 输出可训练参数数目
📌 LoRA 参数详解(手把手解读每个参数)
参数名 | 解释 | 推荐值 |
---|---|---|
task_type | 指定模型类型,常见有:🔹 TaskType.CAUSAL_LM (如 GPT、Qwen)🔹 TaskType.SEQ2SEQ_LM (如 T5) | ✅ TaskType.CAUSAL_LM |
target_modules | 指定需要微调的 Transformer 模块:🔹 q_proj 、k_proj 、v_proj 控制注意力机制🔹 o_proj 、gate_proj 等控制输出💡 选择较少模块可减少显存占用 | ✅ ["q_proj", "v_proj"] |
inference_mode | 🔹 False :用于训练🔹 True :仅用于推理(不更新参数) | ✅ False |
r (秩) | 🔹 控制 LoRA 的秩(低秩分解的维度)🔹 r 越大,模型效果越好,但显存占用也会增加 | ✅ 推荐值 4 到 32 |
lora_alpha (缩放) | 🔹 控制 LoRA 的缩放比例🔹 lora_alpha / r 决定 LoRA 参数的最终权重 | ✅ 推荐值 8 到 32 |
lora_dropout (丢弃率) | 🔹 防止模型过拟合,较小的 Dropout 可增加模型的鲁棒性 | ✅ 推荐值 0.05 到 0.1 |
bias | 🔹 none :不更新偏置参数(推荐)🔹 all :更新全部偏置参数🔹 lora_only :仅更新 LoRA 相关偏置 | ✅ 推荐值 "none" |
🔎 如何选择 LoRA 参数?(经验推荐)
设备配置 | 模型大小 | 推荐参数 |
---|---|---|
8GB 显卡 | 7B 参数 | r=4 , lora_alpha=16 , lora_dropout=0.05 |
12GB 显卡 | 13B 参数 | r=8 , lora_alpha=32 , lora_dropout=0.05 |
24GB 显卡 | 30B 参数 | r=16 , lora_alpha=32 , lora_dropout=0.05 |
9️⃣ 配置训练参数
🛠️ 训练参数详解 (TrainingArguments
)
TrainingArguments
是 Hugging Face 提供的标准化训练参数类,负责控制训练的各种细节。
🔎 训练参数代码
from transformers import TrainingArguments
args = TrainingArguments(
output_dir="./output/Qwen2_instruct_lora", # 输出模型保存路径
per_device_train_batch_size=2, # 每个 GPU 的 batch_size
gradient_accumulation_steps=16, # 梯度累积步数
gradient_checkpointing=True, # 启用梯度检查点,节省显存
bf16=True, # 使用 `bfloat16` 数值表示(减少显存占用)
learning_rate=2e-5, # 学习率,控制模型学习的速度
num_train_epochs=3, # 训练的总轮数
logging_steps=10, # 每 10 步输出一次日志
save_strategy="steps", # 每隔几步保存模型
save_steps=100, # 每 100 步保存一次
optim="adamw_torch_fused", # 使用 `adamw_torch_fused` 提高训练速度
max_grad_norm=0.3 # 梯度裁剪,防止梯度爆炸
)
📌 训练参数详解
参数名 | 解释 | 推荐值 |
---|---|---|
output_dir | 指定模型保存路径 | "./output/Qwen2_instruct_lora" |
per_device_train_batch_size | 每个 GPU 的 batch_size(显存不足时应降低) | ✅ 2 到 8 |
gradient_accumulation_steps | 允许显存较小时,模拟更大 Batch Size(降低 batch_size 并提高此参数) | ✅ 4 到 16 |
gradient_checkpointing | 启用梯度检查点,减少显存占用(大模型训练推荐开启) | ✅ True |
bf16 | 使用 bfloat16 提高计算效率并节省显存(如设备不支持,可改为 fp16 ) | ✅ True |
learning_rate | 控制模型的学习速度,数值过大易发散,过小易收敛慢 | ✅ 推荐 2e-5 或 3e-5 |
num_train_epochs | 模型训练的轮数,若数据较小应适当增加 | ✅ 推荐 3 到 5 |
logging_steps | 每隔几步输出日志,方便实时观察训练状态 | ✅ 10 |
save_strategy | 控制模型保存方式,steps 表示每隔几步保存 | ✅ "steps" |
save_steps | 每训练多少步保存一次模型 | ✅ 100 |
optim | 优化器,adamw_torch_fused 是最新版本的 AdamW,速度更快 | ✅ "adamw_torch_fused" |
max_grad_norm | 控制梯度最大值,防止梯度爆炸 | ✅ 0.3 |
🔟 使用 Trainer 进行训练
from transformers import Trainer
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized_ds
)
trainer.train()
1️⃣1️⃣ 模型保存
model.save_pretrained("./output/Qwen2_instruct_lora/final")
1️⃣2️⃣ 推理 (Inference)
from peft import PeftModel
model = PeftModel.from_pretrained(model, "./output/Qwen2_instruct_lora/final")
prompt = "你是谁?"
messages = [
{"role": "system", "content": "现在你要扮演皇帝身边的女人--甄嬛"},
{"role": "user", "content": prompt}
]
outputs = model.generate(input_ids, max_new_tokens=128)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
运行截图
微调成功后调用模型
🌟 常见问题
✅ 显存不足怎么办?➡️ 降低 batch_size
并启用 gradient_checkpointing
✅ 模型输出不准确?➡️ 调整 temperature
、top_p
提高生成多样性