模型微调
LLaMA-Factory 大模型微调实操指南(实战版)
本指南基于实际项目经验编写,覆盖 环境安装 → 数据准备 → YAML 配置 → 训练启动 → 模型测试 → 合并导出 全流程。所有命令可直接执行,每个关键步骤附带预期输出。
下载微调工具LlamaFactory:https://github.com/hiyouga/LlamaFactory.git
1 环境安装
1.1 基础环境确认
# 确认 CUDA
cd ~
nvcc -V
预期输出:
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Cuda compilation tools, release 12.2, V12.2.140
1.2 创建虚拟环境
conda create -n llama_factory python=3.10
conda activate llama_factory
1.3 安装 PyTorch
conda install pytorch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 pytorch-cuda=12.1 -c pytorch -c nvidia
1.4 安装 LLaMA-Factory
cd ~
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
# 以可编辑模式安装当前目录下的 Python 包,并额外安装 torch 和 metrics 相关的依赖。
pip install -e ".[torch,metrics]"
预期输出:
Successfully installed llamafactory-0.x.x ...
1.5 验证安装
python -m llamafactory.cli train -h
预期输出(节选):
usage: llamafactory-cli train [-h] [ARGS...]
training arguments:
--stage {pt,sft,rm,ppo,dpo,kto}
--do_train {True,False}
--model_name_or_path MODEL_NAME_OR_PATH
...
说明:
python -m llamafactory.cli比llamafactory-cli更兼容,即使环境变量 PATH 没配好也能跑。
2 数据准备
2.1 创建数据集
cd ~/LLaMA-Factory/data
# 创建你的数据集文件
touch my_data.json
SFT 数据格式(Alpaca):
[
{
"instruction": "你是谁",
"input": "",
"output": "我是甄嬛,家父是大理寺少卿甄远道"
},
{
"instruction": "帮我写一封请假条",
"input": "",
"output": "尊敬的张老师:\n\n您好!因身体不适,特向您请假一天..."
}
]
DPO 偏好数据格式:
[
{
"instruction": "写一段关于春天的描写",
"input": "",
"chosen_output": "春风拂过柳梢,桃花映红了小桥流水,燕子在檐下呢喃。",
"rejected_output": "春天来了,花开了,树绿了。"
}
]
2.2 注册数据集
编辑 ~/LLaMA-Factory/data/dataset_info.json:
{
"my_data": {
"file_name": "my_data.json"
},
"my_data_dpo": {
"file_name": "my_data_dpo.json",
"ranking": true
}
}
关键: DPO 数据必须加
"ranking": true,否则 LLaMA-Factory 不会识别 chosen/rejected。
3 创建 YAML 配置文件
YAML 配置是最推荐的训练方式,可复用、可版本管理。
3.1 SFT 配置示例
创建 ~/LLaMA-Factory/my_train.yaml:
### model
model_name_or_path: Qwen/Qwen2.5-3B-Instruct
trust_remote_code: true
### method
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all
### dataset
dataset: my_data
template: qwen
cutoff_len: 1024
max_samples: 500
overwrite_cache: true
### output
output_dir: saves/my_model/lora/sft
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
report_to: none
### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 4
learning_rate: 1.0e-4
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
3.2 DPO 配置示例
### model
model_name_or_path: Qwen/Qwen2.5-3B-Instruct
adapter_name_or_path: saves/my_model/lora/sft # 基于 SFT 的 LoRA 继续训练
trust_remote_code: true
### method
stage: dpo
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all
### dataset
dataset: my_data_dpo
template: qwen
cutoff_len: 1024
max_samples: 500
overwrite_cache: true
### output
output_dir: saves/my_model/lora/dpo
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
report_to: none
### train
per_device_train_batch_size: 1
gradient_accumulation_steps: 4
learning_rate: 5.0e-5
num_train_epochs: 2.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
### dpo
dpo_beta: 0.1
3.3 核心参数详解
| 参数 | 作用 | 建议值 | 说明 |
|---|---|---|---|
model_name_or_path |
基础模型 | Qwen/Qwen2.5-3B-Instruct |
自动从 ModelScope 下载 |
trust_remote_code |
信任远程代码 | true |
Qwen 系列需要 |
stage |
训练阶段 | sft / dpo / pt |
|
finetuning_type |
微调方式 | lora |
个人练习首选 |
lora_rank |
LoRA 秩 | 8 |
效果与显存的平衡点 |
lora_target |
作用层 | all |
初学者用 all,只作用注意力层用 q_proj,v_proj |
dataset |
数据集名称 | my_data |
对应 dataset_info.json 中的 key |
template |
提示词模板 | qwen |
必须与模型匹配 |
cutoff_len |
最大序列长度 | 1024 |
根据数据长度调整 |
learning_rate |
学习率 | 1e-4 (LoRA) / 5e-5 (DPO) |
LoRA 用较大学习率 |
num_train_epochs |
训练轮数 | 3 |
数据量 1000 条左右时 3 轮 |
per_device_train_batch_size |
单卡 batch | 1 |
显存有限时设为 1 |
gradient_accumulation_steps |
梯度累积 | 4 |
等效 batch = 1×4=4 |
bf16 |
bfloat16 精度 | true |
Ampere 架构(30系/40系/A100)支持 |
dpo_beta |
DPO KL 系数 | 0.1 |
越大越保守 |
3.4 15GB 显存配置要点
# 15GB 显存稳妥配置
model_name_or_path: Qwen/Qwen2.5-3B-Instruct # 3B 模型约 6GB
finetuning_type: lora # LoRA 约 2GB
per_device_train_batch_size: 1 # 1GB
gradient_accumulation_steps: 4 # 不增加显存
cutoff_len: 1024 # 序列长度
bf16: true # 省显存
# 总计约 10GB,留 5GB 余量
15GB 跑 3B 模型很稳。想上 7B 需要 QLoRA(
quantization_bit: 4),但效果会打折。
4 启动训练
4.1 使用 ModelScope 下载模型(国内网络必备)
export USE_MODELSCOPE_HUB=1
cd ~/LLaMA-Factory
python -m llamafactory.cli train my_train.yaml
预期输出(首次运行会自动下载模型):
[INFO] Using ModelScope Hub
[INFO] Downloading model Qwen/Qwen2.5-3B-Instruct from ModelScope...
[INFO] Loading dataset my_data from data/my_data.json
[INFO] trainable params: 9,994,240 || all params: 3,000,000,000 || trainable%: 0.33
...
{'loss': 2.3451, 'learning_rate': 9.95e-05, 'epoch': 0.01}
{'loss': 1.8723, 'learning_rate': 9.50e-05, 'epoch': 0.05}
...
{'loss': 0.5891, 'learning_rate': 5.00e-07, 'epoch': 1.00}
...
***** train metrics *****
train_loss = 0.9876
train_runtime = 0:25:32
关键:
USE_MODELSCOPE_HUB=1让模型自动从 ModelScope(国内)下载,不走 HuggingFace(需要FQ)。
4.2 中断后继续训练
在 YAML 中增加:
resume_from_checkpoint: saves/my_model/lora/sft/checkpoint-500
或在命令行指定:
python -m llamafactory.cli train my_train.yaml \
--resume_from_checkpoint saves/my_model/lora/sft/checkpoint-500
4.3 多卡训练
CUDA_VISIBLE_DEVICES=0,1 python -m llamafactory.cli train my_train.yaml
LLaMA-Factory 会自动使用 PyTorch DDP 分布式训练。
5 测试微调后的模型
5.1 使用 transformers + peft 测试(推荐,可集成到代码)
创建 ~/LLaMA-Factory/test_my_model.py:
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
import torch
# 基础模型路径(从 ModelScope 缓存或本地)
BASE_PATH = "/root/.cache/modelscope/hub/models/Qwen/Qwen2___5-3B-Instruct"
ADAPTER_PATH = "saves/my_model/lora/sft"
# 加载 tokenizer
tokenizer = AutoTokenizer.from_pretrained(BASE_PATH, trust_remote_code=True)
# 加载基础模型
model = AutoModelForCausalLM.from_pretrained(
BASE_PATH,
torch_dtype=torch.bfloat16,
device_map="cuda",
trust_remote_code=True,
)
# 加载 LoRA 权重
model = PeftModel.from_pretrained(model, ADAPTER_PATH)
model.eval()
# 测试
prompt = "你是谁"
messages = [
{"role": "system", "content": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant."},
{"role": "user", "content": prompt},
]
# 构建 prompt
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
# 编码输入
inputs = tokenizer(text, return_tensors="pt").to("cuda")
# 生成
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=200,
do_sample=True,
temperature=0.7,
top_p=0.9,
)
# 解码输出(只取新生成的部分)
response = tokenizer.decode(
outputs[0][inputs["input_ids"].shape[1]:],
skip_special_tokens=True
)
print(response)
运行:
cd ~/LLaMA-Factory
python test_my_model.py
预期输出:
我是甄嬛,家父是大理寺少卿甄远道。
代码要点:
device_map="cuda"直接放 GPU(也可以"auto"自动分配)trust_remote_code=TrueQwen 系列必须加outputs[0][inputs["input_ids"].shape[1]:]只取新生成的 token,不重复输入
5.2 使用 LLaMA-Factory 命令行测试
CUDA_VISIBLE_DEVICES=0 python -m llamafactory.cli chat \
--model_name_or_path Qwen/Qwen2.5-3B-Instruct \
--adapter_name_or_path saves/my_model/lora/sft \
--template qwen \
--finetuning_type lora
预期交互:
User> 你是谁
Assistant> 我是甄嬛,家父是大理寺少卿甄远道
6 合并导出
LoRA 权重需要合并到基础模型才能独立使用。
6.1 使用 LLaMA-Factory 合并
CUDA_VISIBLE_DEVICES=0 python -m llamafactory.cli export \
--model_name_or_path Qwen/Qwen2.5-3B-Instruct \
--adapter_name_or_path saves/my_model/lora/sft \
--template qwen \
--finetuning_type lora \
--export_dir ./my-merged-model \
--export_size 2 \
--export_device cpu \
--export_legacy_format False
预期输出:
[INFO] Loading model from Qwen/Qwen2.5-3B-Instruct
[INFO] Loading adapter from saves/my_model/lora/sft
[INFO] Merging adapter weights into model
[INFO] Saving merged model to ./my-merged-model
model-00001-of-00002.safetensors
model-00002-of-00002.safetensors
config.json
tokenizer.json
6.2 合并后测试
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
MODEL_PATH = "./my-merged-model"
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
MODEL_PATH,
torch_dtype=torch.bfloat16,
device_map="cuda",
trust_remote_code=True,
)
model.eval()
# 直接推理,不需要 peft
messages = [{"role": "user", "content": "你是谁"}]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = tokenizer(text, return_tensors="pt").to("cuda")
with torch.no_grad():
outputs = model.generate(**inputs, max_new_tokens=200)
print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))
7 完整流程速查
# Step 1: 准备数据
cd ~/LLaMA-Factory/data
vim my_data.json # 写入数据
vim dataset_info.json # 注册数据集
# Step 2: 写 YAML 配置
cd ~/LLaMA-Factory
vim my_train.yaml # 写入训练配置
# Step 3: 启动训练
export USE_MODELSCOPE_HUB=1
python -m llamafactory.cli train my_train.yaml
# Step 4: 测试
python test_my_model.py
# Step 5: 合并导出
python -m llamafactory.cli export \
--model_name_or_path Qwen/Qwen2.5-3B-Instruct \
--adapter_name_or_path saves/my_model/lora/sft \
--template qwen --finetuning_type lora \
--export_dir ./my-merged-model --export_device cpu
8 常见问题
Q: 模型下载慢或失败?
- 确保加了
export USE_MODELSCOPE_HUB=1 - 或使用 ModelScope SDK 手动下载:
snapshot_download('qwen/Qwen2.5-3B-Instruct')
Q: trust_remote_code=True 有什么用?
- Qwen、ChatGLM 等非标准架构的模型需要加载自定义模型类,必须设为 true
- 标准架构模型(Llama、Mistral)不需要
Q: 显存溢出?
- 减小
cutoff_len(如 512) - 减小
per_device_train_batch_size(设为 1) - 增大
gradient_accumulation_steps(如 8) - 换更小的模型(3B → 1.5B)
Q: 测试时输出乱码?
- 检查
template是否与模型匹配(Qwen 用qwen,Llama 用llama3) - 检查
apply_chat_template的参数是否正确 - 检查 tokenizer 的
eos_token是否设置正确
Q: DPO 训练报错找不到 chosen/rejected?
- 检查
dataset_info.json中是否设置了"ranking": true - 检查数据文件字段名是否正确
Q: bf16: true 报错不支持?
- 只有 Ampere 架构(RTX 30系/40系、A100、A10、H100)支持 bf16
- 老显卡(RTX 20系、V100)改用
fp16: true

浙公网安备 33010602011771号