开箱即用的大模型微调工具,LLaMA-Factory 确实是绕不开的名字。从环境搭建到模型训练、评估、导出,一条龙全包,新手和老手都能在这套工具链里找到适合自己的节奏。这篇内容我按实际踩坑的顺序写,把完整流程、关键参数、常见报错一次性讲清楚,争取看完就能跑通自己的第一个 LoRA 微调。
1. 项目概述:LLaMA-Factory 到底解决了什么问题
1.1 为什么大模型微调需要“工厂化”流程
如果自己从零写训练脚本,你需要处理的事情非常多:数据格式转换、tokenizer 对齐、attention mask、梯度累积、学习率调度、断点续训、多卡并行、混合精度……这些代码写起来不难,但组合在一起调试起来非常折磨人。尤其当你只是想快速验证某个模型在当前业务数据上的效果,却被各种底层细节缠住,非常影响效率。
LLaMA-Factory 的本质,就是把微调这条流水线标准化。你只需要准备好数据、选好模型、点几个参数,它就能帮你把训练跑起来。它内置了数据格式校验、训练策略切换、评估脚本、模型导出这些模块,你不用自己重复造轮子。这一点对于项目周期紧张、需要快速出结果的场景特别重要。
另外一点是它覆盖了目前主流的微调方式,全参微调、LoRA、QLoRA、冻结训练,全部统一封装在同一个框架里。这意味着,你在不同显存条件下、不同数据规模下,可以用同一套流程切不同的策略,学习成本和切换成本都极低。
1.2 这套工具适合谁用
从我实际接触的用户来看,大致分三类。
第一类是刚接触大模型微调的新手。这类用户往往在 environment 上就卡了很久,LLaMA-Factory 提供了友好的命令行接口和 Web 界面,大大平滑了学习曲线。第二类是算法工程师或 AI 应用开发者,需要快速迭代业务模型,比如把模型适配到某个垂直领域,或者让模型学会特定格式的输出。第三类是科研场景下做实验对比的人,需要在不同基座模型、不同微调方法之间快速切换。无论哪类用户,核心诉求都一样:把精力聚焦在数据和效果上,而不是训练代码本身。
我个人的建议是,哪怕你之前已经写过不少微调代码,也先不要排斥这类封装好的工具。它省掉的是重复劳动,而不是你对原理的理解。用它对冲日常开发成本完全值得。
2. 环境搭建:从零到能跑通示例
2.1 硬件与基础软件准备
先说硬件。微调大模型的关键瓶颈是显存。如果你只是用 QLoRA 4bit 量化微调 7B 模型,一张 8GB 显存的显卡理论上能跑,但会非常紧张,实际体验不太好。想跑得宽松一点,建议 12GB 以上。如果目标模型是 14B 以上,或者你要用 LoRA 甚至全参微调,那就建议 24GB 以上了。
如果你手头没有 GPU,也可以先用 CPU 跑最小的 0.5B 模型来理解整个流程,但真正训练的速度会非常慢,只适合流程验证,不适合实际出结果。另外,黑苹果、普通轻薄本之类的环境,真心不建议折腾,浪费时间。
系统方面,Ubuntu 20.04 或 22.04 是我用得最顺的。Windows 用户建议直接用 WSL2,避免很多底层库在 Windows 原生环境下的兼容问题。macOS 的 M 系列芯片可以跑小规模实验,但很多加速库支持并不完整,不建议作为主力环境。
基础软件方面,需要提前装好 NVIDIA 驱动和 CUDA。这里有个经验:不要盲目追求最新 CUDA 版本,最好根据你要安装的 PyTorch 版本对应的 CUDA 版本来选择。比如稳定常用的是 CUDA 11.8 或 12.1。装完驱动后用nvidia-smi确认 GPU 能被正确识别。
2.2 创建独立 Conda 环境
强烈建议用 Conda 创建一个独立的 Python 环境。不要直接把依赖装到系统 Python 里,否则项目一多,各种包的版本冲突会让你怀疑人生。
conda create -n llamafactory python=3.10 -y conda activate llamafactoryPython 版本 3.10 是我目前用得最稳的,3.11 和 3.12 也可以,但部分依赖库的预编译轮子可能没那么全,遇到奇怪报错的可能性会高一些。既然目标是“保姆级教程”,那就选最稳的路径。
2.3 拉取代码并安装依赖
然后把 LLaMA-Factory 源码拉下来:
git clone https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory安装依赖时,官方推荐使用完整安装方式:
pip install -e .[torch]如果你不是在 GPU 环境下,可以用pip install -e .只装基础部分。但既然要训练,[torch]这个附加依赖组是必须的,它会把 torch、transformers、datasets、peft、trl 等一系列核心库一起装上,省得自己一个个配。
安装完成后,立马验证环境是否正常:
python -c "import torch; print(torch.__version__, torch.cuda.is_available())"如果输出类似2.4.0 True,说明 PyTorch 和 CUDA 都能正常使用。如果显示False,先检查驱动版本和 CUDA 版本是否匹配,再检查 PyTorch 安装的是不是 CUDA 版本。很多人在这里折腾很久,但问题往往就只是 PyTorch 装成了 CPU 版本。
2.4 推荐先跑通小模型
环境装好之后,我强烈建议不要直接上 7B、14B 这种大模型。先把流程跑通最重要。找一个 0.5B 或 1.5B 的模型,比如Qwen/Qwen2.5-0.5B-Instruct或Qwen/Qwen2.5-1.5B-Instruct,用它把加载模型、数据准备、训练、评估、导出整条链路走一遍。这样即使后续换大模型,也只是改模型路径和参数的问题,不会因为基础流程不熟而手忙脚乱。
模型权重下载方面,可以直接从 Hugging Face 下载,也可以使用 ModelScope 魔搭社区下载对应权重。下载后注意模型文件夹路径,后续所有命令都要通过--model_name_or_path指定这个路径。
3. 数据准备:训练集格式与 dataset_info 配置
3.1 两种主流数据格式
LLaMA-Factory 最常用的数据格式有两种,一种叫 alpaca 格式,另一种叫 sharegpt 格式。
alpaca 格式适合指令微调,每条数据有三个关键字段:instruction表示用户指令,input表示可选的补充输入,output表示期望模型输出的答案。举个例子:
{ "instruction": "将下面的句子翻译成英文", "input": "今天天气真好", "output": "The weather is really nice today." }如果你的任务是纯指令型,不需要额外输入,就把input字段留空或直接省略。
sharegpt 格式则更适合多轮对话场景,核心是conversations字段,里面每一轮都包含from和value,分别表示说话方和内容。from字段可能是human、gpt或system。这个格式很直观,一看就懂。
3.2 接入自定义数据集
把准备好的数据保存成 JSON 文件,放进 LLaMA-Factory 项目根目录下的data文件夹里。然后打开data/dataset_info.json,在文件末尾追加一条数据集注册信息:
{ "my_custom_dataset": { "file_name": "my_custom_dataset.json", "formatting": "alpaca", "columns": { "prompt": "instruction", "query": "input", "response": "output" } } }formatting要根据你的数据格式填,alpaca或sharegpt。columns是字段映射,意思是你 JSON 里的哪些键对应 LLaMA-Factory 需要的哪些字段。如果你的 JSON 键名就是标准的instruction、input、output,那columns可以简化。注册好之后,训练时把数据集名字传入参数即可。
如果你是使用 Web 界面操作,在数据集下拉框里就能看到新注册的数据集。这里特别提醒:改完dataset_info.json后,Web 界面需要刷新或重启才能生效,不然容易找半天找不到自己的数据集。
3.3 数据质量才是微调效果的天花板
数据格式正确只是第一步,数据质量直接决定微调效果。我见过不少人模型和数据都没问题,但因为数据的清洗不够细致,最终效果很差。几点经验:
- 数据量不是越多越好,质量优先。对于一个垂直领域任务,几千条高质量数据往往比几万条从网上爬来的脏数据效果好得多。
- 训练集和验证集要分开。训练时设置
val_size参数,比如 0.1,表示从数据集中切出 10% 作为验证集,用于观察模型是否过拟合。 - 注意不要混入大量重复数据,尤其是模板化的相似表述,否则模型会对特定句式过度拟合。
- 如果目标是让模型学会某种输出格式,那训练数据里的输出部分必须严格遵循格式要求,一点点不一致都会让模型学歪。
4. 选对微调方式:全参、LoRA、QLoRA、冻结训练怎么选
4.1 四种微调方式的原理差异
很多初学者面对四种微调方式会有点懵。我用一个生活化的类比解释一下。
全参微调相当于把整本教科书重新编排,模型的所有参数都会更新,效果上限最高,但显存占用也最大,因为优化器状态、梯度、参数副本都要占用显存。
LoRA 则更像是在教科书的空白处贴便签纸,不重新编排原有内容,而是额外添加一些小的可训练矩阵。这些矩阵的参数量远小于原始模型,训练时需要更新的参数大大减少,显存占用大幅下降,而效果在很多场景下能逼近全参微调。
QLoRA 是 LoRA 的进一步升级,它先把模型权重做 4bit 量化,再以极低的内存开销训练 LoRA 层。这样一张消费级显卡就能微调 7B 甚至 13B 模型,代价是训练速度略慢一些,但显存压力显著降低。
冻结训练则是一条折中路线,只更新模型的一部分参数,比如只更新分类头、只更新顶层若干层,其他参数全部冻结。这种方式适合某些特定场景,比如只是想让模型适配一个特定的输出头,或者训练资源有限时。
4.2 直观对比与选型建议
| 微调方式 | 更新参数量 | 显存占用 | 训练速度 | 效果上限 | 适用场景 |
|---|---|---|---|---|---|
| 全参微调 | 全部参数 | 最高 | 慢 | 最高 | 数据量大、资源充足、追求极致效果 |
| LoRA | 低秩矩阵 | 中等 | 较快 | 接近全参 | 10B 以下模型,资源和效果相对平衡 |
| QLoRA | 低秩矩阵 + 4bit 量化 | 最低 | 中等 | 较高 | 显存紧张,消费级显卡微调大模型 |
| 冻结训练 | 部分参数 | 较低 | 快 | 取决于冻结比例 | 只微调特定层、输出头适配 |
我的选型习惯是:如果你在一张 8GB 到 12GB 显存的卡上,优先考虑 QLoRA;如果显存在 16GB 到 24GB 之间,直接上 LoRA,训练速度和稳定性都会好很多;如果你有专业显卡且数据量足够大,才去考虑全参微调。冻结训练一般用于特殊情况,比如只让模型学习某种固定的输出风格,或者复用已有模型时不想破坏主干特征。
5. 实操训练:用 LLaMA-Factory 跑通一个 LoRA 微调
5.1 命令行方式的核心配置
我自己最常用的是命令行方式,因为方便写脚本批量跑实验。下面是一条完整的 LoRA 微调命令,以 Qwen2.5 模型为例:
llamafactory-cli train \ --model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \ --stage sft \ --do_train True \ --dataset my_custom_dataset \ --finetuning_type lora \ --lora_target all \ --output_dir output/qwen25_lora \ --per_device_train_batch_size 1 \ --gradient_accumulation_steps 8 \ --learning_rate 1e-4 \ --num_train_epochs 3.0 \ --lr_scheduler_type cosine \ --warmup_ratio 0.1 \ --bf16 True \ --logging_steps 10 \ --save_steps 500 \ --val_size 0.1 \ --eval_steps 200 \ --evaluation_strategy steps \ --load_best_model_at_end True简单解释几个关键参数。
--finetuning_type lora指定使用 LoRA。--lora_target all是让框架自动选择所有适合加 LoRA 的模块,这个参数特别方便,不同模型的模块名不一样,用all就不用自己去查了。
--per_device_train_batch_size是每张显卡上的 batch size。如果显存不够,就设成 1,然后用--gradient_accumulation_steps来累积梯度,等效于增大整体 batch size。8 步累积加 batch size 1,等效于 batch size 8,训练稳定性会好很多。
--learning_rate这里我用了1e-4,这是 LoRA 微调比较常用的学习率区间。如果全参微调,一般要降到1e-5甚至更低,这个区别是很多人不知道的。
--bf16 True表示使用 BF16 混合精度。如果你的显卡支持 BF16,优先用它。老一点的显卡不支持 BF16,则改为--fp16 True。
--load_best_model_at_end True会让训练结束时自动加载验证集上表现最好的模型,这是提升最终效果很关键的一个设置。
5.2 训练日志与 loss 变化观察
训练过程中,终端会持续打印日志,包含当前步数、训练 loss、学习率、每秒处理的样本数等。我自己一般重点关注两件事。
第一是训练 loss 是否整体呈下降趋势。如果 loss 一开始就很低,比如 0.1 以下,说明数据里可能有大量重复内容,模型很快就记住了;如果 loss 剧烈震荡、忽高忽低,通常说明学习率太高,可以尝试调低一点。第二是验证集 loss 是否随着训练在下降。如果训练 loss 一直降但验证 loss 在后期回升,那就是过拟合的信号,可以提前停止训练或减少 epoch 数。
训练完成后,output_dir下会生成 LoRA 适配器文件,比如adapter_model.safetensors和adapter_config.json,同时还有训练日志文件。这些都保留好,后面评估和导出都会用到。
5.3 用 Web 界面做可视化操作
如果你更习惯图形化界面,LLaMA-Factory 也自带 Web UI。启动方式很简单:
llamafactory-cli webui然后浏览器访问http://localhost:7860就能看到操作界面。在界面上选择模型路径、微调方式、数据集、训练参数,点开始就能跑训练。Web 界面对新手非常友好,不用记一大堆命令行参数。我一般是命令行跑正式实验,Web 界面用来快速看某个数据集的效果,两边互补。
5.4 单机多卡训练
如果有多张显卡,可以在命令里加上:
--accelerator_config '{"ddp_timeout": 1800}' --deepspeed ds_z3_config.json单机多卡时,使用 DeepSpeed ZeRO-3 方式可以显著分配显存压力。但这里我不建议新手一开始就上多卡,先用单卡跑通,再慢慢加复杂度。多卡不是简单的数字叠加,DDP 通信、超参调整、数据并行策略都会影响最终效果。
6. 模型评估:不只看 loss,还要看真实输出质量
6.1 离线指标与验证集评估
训练过程中的 loss 只能反映模型在训练数据上的拟合程度,不能完全说明模型好不好用。所以我习惯在训练完成后,单独跑一轮较全面的评估。
LLaMA-Factory 提供了命令行评估入口:
llamafactory-cli eval \ --model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \ --adapter_name_or_path output/qwen25_lora \ --template qwen \ --finetuning_type lora \ --dataset my_custom_test_dataset \ --task prediction--task prediction会加载你指定的评估数据,让模型逐条生成结果,并和标准答案进行对比。如果你做的是分类任务,可以直接在评估数据里准备一批带标签的样本,跑完看准确率、F1 等指标。
我们做分类评估时,常用这一段 Python 来计算关键指标:
from sklearn.metrics import classification_report, confusion_matrix y_true = [...] # 真实标签 y_pred = [...] # 模型预测标签 print(classification_report(y_true, y_pred)) print(confusion_matrix(y_true, y_pred))输出里会包含每个类别的 precision、recall、F1-score 和总体准确率。这样比只看 loss 要直观得多。
6.2 人工对话评估同样重要
离线指标只能衡量模型在已知数据上的表现,但很多问题是离线评估发现不了的。比如模型是否学会了指令格式、回答是否通顺、有没有胡编乱造。这些需要把模型加载起来,实际对话测试。
我自己通常保留一批未参与训练的真实业务问题,一个一个问模型,记录它的回答是否满足需求。通过这种“验收式”评估,经常能发现一些数据层面的问题。比如之前有一次模型总是回答得很简短,检查数据后发现训练数据里的输出大多只有一句话,模型就学会了“回答要短”这个隐含规律。
6.3 评估结果如何指导下一步迭代
评估并跑完并不算结束。我一般会根据评估结果决定下一步动作:
- 准确率低但回答通顺:大概率是数据不够,或者任务太难,需要补充更多高质量样本。
- 回答格式错误:检查训练数据的输出格式是否一致,尤其是 system prompt 与训练数据中的 system 字段是否冲突。
- 对某些类别特别差:检查该类别在训练数据中的样本量是否太少,考虑做数据增强或补充样本。
- 过拟合明显:减少训练轮数,增大验证集比例,或者适当降低 LoRA 的 rank 值。
评估的价值不在于得出一个分数,而是告诉你下一步该往哪个方向调整。这个思路贯穿了我所有微调项目。
7. 模型导出与部署
7.1 将 LoRA 适配器合并回基础模型
微调完成后,你手上的 LoRA 适配器只是额外训练出的低秩矩阵,它依赖原始基础模型存在。如果要部署,需要把 LoRA 权重合并回基础模型,生成一个完整的模型文件。
llamafactory-cli export \ --model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \ --adapter_name_or_path output/qwen25_lora \ --template qwen \ --finetuning_type lora \ --export_dir output/qwen25_merged \ --export_size 4 \ --export_legacy_format False--export_size 4表示将模型切分为每个 4GB 左右的文件块,方便分发和拷贝。--export_legacy_format False表示导出为新版格式,兼容性更好。
合并的原理其实很简单,就是把 LoRA 训练出来的低秩矩阵按权重加回到原始模型的权重矩阵上。这个操作是不可逆的,所以合并前最好保留原始 LoRA 适配器,以便后续继续调参。
7.2 部署方式与推理示例
合并后的模型可以直接用 Transformers 加载做推理,也可以用 vLLM、Ollama 这类推理框架部署成服务。这里给一个最基础的 Transformers 推理示例:
from transformers import AutoModelForCausalLM, AutoTokenizer model_path = "output/qwen25_merged" tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True, device_map="auto") messages = [ {"role": "system", "content": "你是智能客服助手,回答简洁准确。"}, {"role": "user", "content": "你们的退款政策是什么?"} ] text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) inputs = tokenizer(text, return_tensors="pt").to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) response = tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True) print(response)要注意,推理时使用的 system prompt 最好和训练时保持一致,否则模型可能因为上下文格式不匹配而出现回答质量下降的情况。这一点经常被忽略,但影响非常大。
8. 常见问题与避坑经验
8.1 高频报错排查表
| 现象 | 主要原因 | 解决办法 |
|---|---|---|
| 训练时提示 bitsandbytes 加载失败 | 4bit 量化库未正确安装 | pip install bitsandbytes,确认 CUDA 版本兼容 |
| 显存不足,训练中断 | batch size 过大或模型过大 | 调小per_device_train_batch_size,启用 QLoRA,或减小序列长度 |
| 中文乱码或模型只会输出英文 | 模板或 tokenizer 配置问题 | 检查--template参数是否与模型匹配,如 Qwen 选 qwen |
| 数据集找不到或读取报错 | dataset_info.json 配置错误 | 检查file_name路径和formatting类型,确认 JSON 格式正确 |
| 训练时 loss 为 NaN | 学习率过高或混合精度设置不当 | 降低学习率,检查bf16/fp16是否正确启用 |
| 模型回答很短 | 训练数据输出长度整体偏短 | 扩充训练数据中的长输出样本,提高max_new_tokens |
| 合并模型后无法对话 | 导出时模板参数错误或未合并成功 | 检查--template和--finetuning_type,重新导出 |
| eval 命令报错 | 评估数据格式与训练数据不一致 | 检查测试数据的字段格式,确保与训练数据一致 |
8.2 这几条经验能让你少走弯路
第一,任何新项目都先用小模型、小数据、少量 epoch 跑通全流程,确认没问题再上真实规模。这条规则帮我避开了无数次“跑了一晚上结果发现数据格式错了”的惨案。
第二,每个实验都单独建一个输出目录,并保留完整的训练日志。实验一多,如果你不记录,很容易混淆哪个模型是用哪份数据、哪组参数训出来的。我习惯在每个实验目录下建一个README.md,把模型路径、数据集、关键参数、最终 loss、验证指标写进去,两个星期后再回来看依然清晰。
第三,不要迷信“官方默认参数”。默认参数只是通用配置,不一定适合你的数据。我在实际项目中经常会把学习率调低到 5e-5 甚至 3e-5,把 epoch 数增加到 5 到 8 轮,反而效果更好。这些都要靠实验说话。
第四,数据准备阶段多做几轮人工抽检。格式对不代表内容对,尤其要注意输出字段里是否混入了特殊符号、HTML 标签或前后空格,这些细节都会影响模型学习效果。
第五,如果想压榨单卡显存,可以适当减小输入序列长度,比如把--max_length从默认的 1024 降到 768。这会在一定程度上影响长文本场景的效果,但很多业务数据并不会用到那么长的上下文,换来的是显存压力大幅减轻。
LLaMA-Factory 这套工具给我最大的感受是:它把你从繁重的训练编码中解放出来,让你把时间花在真正重要的事情上,也就是数据质量、任务设计和效果调优。一旦跑通一条完整的微调流程,之后换模型、换数据、换策略都只是参数层面的改动。希望这篇内容能帮你顺利跑通自己的第一个微调项目。