LoRA + LLaMA-Factory 实战教程: 用3090实现微调Qwen2.5-7B
LoRA + LLaMA-Factory 是现在微调经典配套,如果你想用一张 3090 或者单卡环境做一个实用性很强的自己模型,那实在没法避免这套技术组合。
我将体系地分 10 步,手把手教你如何实现 LoRA 微调、合并权重、数据转换和数据包装,并将运行后的模型部署到 Ollama 进行本地推理。
1 一、LoRA 和 LLaMA-Factory 是啥?
- LoRA:Low-Rank Adaptation,用于高效微调,只训练小量参数,节省资源,效果也不错
- LLaMA-Factory:支持 LoRA/全量/给账/声援/女门/控调各种经典微调方法,支持 CLI + WebUI
用好它,直接能完成从 HuggingFace 拉模型、对接自己数据、模型调教、部署 Ollama 的全链路。
2 二、环境准备
- Python >= 3.10
- PyTorch >= 2.0 (GPU version)
- CUDA & cuDNN
- NVIDIA RTX3090 / 4090 (16G 显存起)
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -r requirements.txt
如果被 transformers 版本问题卡住,建议使用 transformers==4.35.0
3 三、下载预训练模型
以 Qwen2.5-7B Instruct 为例:
python src/download_model.py --model_name qwen2_5
或者手动 HuggingFace 下载:
from huggingface_hub import snapshot_download
snapshot_download(repo_id="Qwen/Qwen2.5-7B-Instruct")
HuggingFace 有时需要 token,在国内环境可能需要代理
4 四、数据集处理
格式类似 OpenAI-style,JSON数组
[
{
"instruction": "请解释相对论",
"input": "",
"output": "相对论是..."
}
]
如果来源是 CSV / Excel / Markdown,自己写 Python 脚本转换
5 五、断点配置文件 config.yaml
model_type: qwen2_5
finetuning_type: lora
lora_rank: 64
lora_alpha: 128
lora_dropout: 0.1
output_dir: ./saves/qwen2_5_lora
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 5e-5
num_train_epochs: 3
logging_steps: 10
save_steps: 500
如 batch size 过大,3090 很容易 OOM
6 六、启动训练
LoRA 微调训练命令
python src/train_bash.py \
--stage sft \ # 训练阶段:SFT(监督式微调)是最常用的微调方式
--do_train \ # 表示要执行训练任务
--model_name_or_path /path/to/qwen2_5 \ # 指定原始模型路径,比如你本地的 Qwen2.5-7B 模型
--dataset_dir data \ # 数据集目录,里面放你的 .json 数据文件
--dataset my_dataset \ # 数据集名称,对应 data/my_dataset.json 文件名
--template qwen \ # 使用哪个模板来处理输入输出格式,这里选的是 Qwen 自带的模板
--finetuning_type lora \ # 指定使用 LoRA 微调方法
--output_dir ./saves/qwen2_5_lora \ # 权重保存路径,训练完后会在这里生成 adapter_model.bin 等文件
--overwrite_cache \ # 覆盖缓存数据,避免因旧缓存导致训练失败
--per_device_train_batch_size 1 \ # 每个设备上的 batch size,显存小就设为 1
--gradient_accumulation_steps 8 \ # 梯度累积步数,用来弥补小 batch 的影响,总 batch = 1 * 8 = 8
--learning_rate 5e-5 \ # 学习率,别太大,不然容易不收敛或崩溃
--num_train_epochs 3 \ # 总共训练轮数,LoRA 不需要太多轮,3~5 就够了
--lr_scheduler_type cosine \ # 学习率调度器类型,cosine 效果较好
--logging_steps 10 \ # 每训练多少步打印一次日志,方便观察训练状态
--save_steps 500 \ # 每训练多少步保存一次 checkpoint,防止断电等意外
--plot_loss # 可视化损失曲线,训练完会在 output_dir 下生成 loss.png
6.1 最重要的几个参数:
参数 | 关键作用 | 注意事项 |
---|---|---|
--finetuning_type | 指定是否使用 LoRA | 必须为 lora 才能启用 LoRA 微调 |
--lora_rank 和 --lora_alpha | 控制 LoRA 的秩和缩放因子 | 推荐 rank=64 , alpha=128 |
--learning_rate | 学习率太大会导致训练不稳定 | 建议在 5e-5 ~ 1e-4 之间尝试 |
--gradient_accumulation_steps | 显存不够时救命稻草 | 可以适当调大,但别超过 16 |
--num_train_epochs | 训练轮数不要过多 | LoRA 一般 3~5 轮就够了,多了容易过拟合 |
首次运行可加上
--max_steps 10
,先演练一段进行添诊
7 七、合并 LoRA 权重
训练完成后有一个 adapter_model.bin
,必须合并到原始模型中:
python src/export_model.py \
--model_name_or_path /path/to/qwen2_5 \ # 原始模型路径,必须和训练时一致
--adapter_name_or_path ./saves/qwen2_5_lora \ # LoRA 权重路径,即训练完成后保存的 adapter_model.bin 所在目录
--export_dir ./merged_model \ # 导出后的完整模型保存路径
--finetuning_type lora # 同样指定为 lora,确保正确加载适配器权重
7.1 权重设置最重要的点:
必须使用相同的模型路径和 LoRA 配置
- 如果你在训练时用了某个版本的 Qwen2.5,那导出时也必须用这个版本,否则会报错“权重不匹配”。
- LoRA 参数(如 rank、alpha)也要一致,否则合并出来的模型推理效果可能有问题
合并后的模型可以直接给 Ollama 用吗?
- 可以,但你要先把它转换成 GGUF 格式,再通过 Modelfile 加载进 Ollama
- 否则你会发现 Ollama 无法识别 LoRA 模型,因为它是基于全量权重设计的
导出模型推理慢?
- 有用户反馈用 LLaMA-Factory 导出的模型比自己手动导出慢几十秒,可能是某些优化没开
- 建议检查是否启用了
--use_fast_tokenizer
或者做了量化压缩
8 八、部署到 Ollama 本地推理
# Modelfile 内容
FROM ./merged_model
ollama create qwen2_5_lora -f Modelfile
ollama run qwen2_5_lora
Ollama 不支持 LoRA 直接识别,必须合并后重新包装 GGUF
9 九、碰到的坑
10 1. 模型导出失败?路径写错了 or 参数不一致
这是我最常遇到的问题之一。
现象:
运行 export_model.py
报错,提示找不到模型文件、权重加载失败、参数不匹配等。
原因:
--model_name_or_path
写错了(不是训练用的原始模型)--adapter_name_or_path
指向的是空目录 or 不是训练输出的 adapter 文件夹finetuning_type
没有设为lora
,导致无法识别适配器
解决方法: 确保以下三点一致:
- 原始模型路径和训练时完全一样
- LoRA 权重路径指向训练输出的
output_dir
--finetuning_type
设置为lora
我有一次导出的时候,忘记改
--adapter_name_or_path
,结果合并出来的模型完全没有变化……还以为是训练没生效,后来才发现是导出漏掉了权重路径。
11 2. 训练显存爆炸?Batch Size 太大 or 梯度累积设置不当
现象:
训练过程中突然报错 CUDA out of memory
或者卡住不动。
原因:
per_device_train_batch_size
设置太高(比如 4)- 没有用梯度累积(
gradient_accumulation_steps
)
解决方法:
- 将
per_device_train_batch_size
设为 1 - 同时设置
gradient_accumulation_steps=8
或更高,这样总 batch size 还是 8,但显存压力小很多
我一开始图省事直接设成 batch_size=4,结果直接炸了显存。后来改成 1+8 的组合,稳如老狗。
12 3. 合并后的模型推理效果差?LoRA 没合并干净
现象: 训练完的模型在训练阶段表现不错,但导出后推理效果变差,甚至跟原模型差不多。
原因:
- LoRA 没有正确合并到主模型中
- 使用了量化模型做合并(LLaMA-Factory 不支持)
解决方法:
- 确保使用原始非量化模型进行合并
- 检查
export_model.py
是否正确执行,并确认输出目录中有合并后的权重文件
有人反馈说用了量化模型做合并,结果推理慢得离谱还不准,最后发现是因为某些层没合并进去。
13 4. Web UI 跑不起来?依赖版本冲突
现象:
运行 webui.py
报错,提示找不到模块、导入错误等。
原因:
- Python 包版本不对(比如 transformers、gradio、bitsandbytes 等)
- 安装命令没按官方推荐执行,自己乱装了一堆
解决方法:
- 严格按照文档安装依赖,最好新建一个虚拟环境
- 如果还是不行,可以试试手动降级某些包,比如:
pip install transformers==4.35.0
我之前就因为 pip 自动升级了 gradio,结果页面打不开,控制台一堆 TypeError,最后靠回滚才搞定。
14 5. LoRA 参数设置不合理,训练无效
现象: 训练完成之后,模型表现没有明显提升,甚至还不如原模型。
原因:
lora_rank
和lora_alpha
设置太低 or 不合理- 学习率过高 or 过低,导致模型不收敛或过拟合
解决方法:
- 推荐配置:
lora_rank=64
,lora_alpha=128
- 学习率控制在
5e-5 ~ 1e-4
之间尝试 - 训练轮数不要太多,一般 3~5 轮足够
有个朋友用 rank=8 做训练,结果模型几乎没变化……后来改成 64 才有点起色。
15 6. GGUF 导出失败 or Ollama 加载不了
现象: 导出 GGUF 格式时报错,或者 Ollama 加载模型失败。
原因:
- LLaMA-Factory 导出的模型格式不是标准 HF 格式
- 需要额外转换步骤才能给 llama.cpp 使用
解决方法:
- 使用
convert_hf_to_gguf.py
脚本进行转换 - 确保模型结构和 llama.cpp 支持的格式兼容
我试过直接丢进 Ollama,结果它说不认识这个模型类型……后来才知道中间还要走一步转换流程。
16 7. 长文本训练效果差?LongLoRA 反而更烂
现象: 想用 LongLoRA 扩展上下文长度,结果训练完反而效果更差。
原因:
- LongLoRA 对位置编码敏感
- 某些实现方式可能引入噪声 or 破坏原有结构
解决方法:
- 先用普通 LoRA 跑通基础效果
- 再逐步尝试 LongLoRA,并做充分验证
- 别一上来就上长序列,容易翻车
GitHub 上还有人专门提 issue 说用了 LongLoRA 后效果比原模型还差……所以这玩意儿真不是万能的。
17
问题 | 原因 | 解决建议 |
---|---|---|
导出失败 | 路径/参数不一致 | 检查 model path、adapter path、finetuning_type |
显存爆炸 | Batch size 太大 | 降低 batch size + 开梯度累积 |
推理效果差 | LoRA 没合并好 | 用原始模型合并,别用量化模型 |
Web UI 报错 | 依赖冲突 | 新建虚拟环境,按推荐版本装 |
LoRA 效果不好 | 参数设置不合理 | lora_rank=64, alpha=128,lr=5e-5 左右 |
GGUF 导出失败 | 格式不对 | 需要先转成 HF 格式,再用 llama.cpp 转换 |
LongLoRA 效果差 | 实现不稳定 | 先跑通普通 LoRA,再尝试扩展上下文 |
18 十、小型实用、内部定制
- LoRA + LLaMA-Factory 非常适合单卡环境展示性、小型实用、内部定制场景
- 配合 Ollama 可实现本地推理、接入 WebUI 或 API 调用