Llama-Factory 微调 Qwen 实战:让 0.5B 小模型学会信息抽取
Llama-Factory 微调 Qwen 实战:让 0.5B 小模型学会信息抽取
**副标题:手把手带你走完 LoRA 微调全流程——下模型、造数据、训练、合并、Ollama 部署,一篇文章跑通"
你有没有过这样的崩溃瞬间——好不容易把一个开源大模型跑起来了,问它「帮我抽出这句话里的实体关系」,它却给你编了一通漂亮但没用的废话?模型明明能跟你谈天说地,可一到结构化信息抽取这种"正经活儿"就集体"装傻"。
这不是模型笨,是它没学过这门手艺。预训练让它读完了"互联网这所大学",指令微调让它学会了"听人话、说人话",但它从来没见过你公司那种「从一句话里抠出主语-谓词-宾语」的业务范例。想让它会,得给它补一节岗前培训课——这就是微调干的事。
而全量微调动辄几十上百 GB 显存,普通开发者根本玩不起。好在有 LoRA:不用回炉重造整个模型,只在旁边贴一叠"岗位专用便利贴"就行。这篇就用 LLaMA-Factory 框架,带你对 Qwen2.5-0.5B-Instruct 做一次完整的 LoRA 微调,让它学会信息抽取,最后还能用 Ollama 在本地跑起来。
我会用一个贯穿全文的比喻把每一步串起来:把 Qwen2.5-0.5B-Instruct 想成一个刚通识毕业的实习生——基础扎实、懂礼貌,但还没学过你公司的业务;我们要做的不是让他回炉重造,而是给他一份岗前培训手册 + 一叠便利贴小抄,让他快速上岗。
一、先认识工具:LLaMA-Factory 是个什么"培训学校"
自己从零写微调脚本,要处理数据加载、对话模板、梯度累积、显存优化、断点续训……每一项都能让你 debug 到天亮。LLaMA-Factory 就是把这些脏活累活全打包好的"培训学校",它整合了主流的高效微调技术,适配 Qwen、LLaMA、Baichuan 等一堆开源模型,还附带一个可视化 WebUI,点点鼠标就能训练。
它有几个让人心动的特点:
- 多阶段训练:支持预训练(PT)、监督微调(SFT)、人类反馈对齐(RLHF),覆盖大模型成长的每个阶段。
- 高层次接口:训练、推理、评测、API 服务一条龙,不用自己拼。
- 高效微调:内置 LoRA 等技术,把显存门槛从"几十 G"压到"一张 T4 就能跑"。
- WebUI 可视化:英文不好的同学也能上手,参数都有中文说明。
1. 三种"培训方式"怎么选
LLaMA-Factory 给了三种微调方法,对应三种"带实习生"的策略:
| 微调方法 | 比喻 | 训练什么 | 显存需求 | 适用场景 |
|---|---|---|---|---|
| full(全量微调) | 让实习生回炉重造,所有知识重学 | 模型全部权重 | 极高(几十 G+) | 算力充足、任务差异大 |
| freeze(冻结微调) | 只让实习生改某几科目的学习方法,其余冻结 | 部分层权重 | 中等 | 折中方案 |
| lora(LoRA 微调) | 不动实习生脑子,给他配一叠"岗位便利贴" | 旁路小矩阵(adapter) | 低(T4 16G 够用) | 普通开发者首选 |
💡 为什么我们选 LoRA? 它只训练一叠"便利贴"(低秩适配矩阵),不动原始模型一根毫毛,显存占用低、训练快、还能随时插拔。对 0.5B 这种小模型,LoRA 几乎是性价比之王。
2. 这次要走的完整流水线
先把整条路画出来,心里有个全景,后面每一步都不慌:
我们就按这条线,一步步走完。
二、开学准备:装环境、下模型、先"面试"一下
1. 装好 LLaMA-Factory 这所"培训学校"
硬件要求:建议 T4、RTX 3090 或 4090(16GB 显存)就能跑 0.5B~1.5B 的 LoRA 训练。先确认你的"车间"开没开:
nvidia-smi # 查看显卡状态和 CUDA 版本,能看到卡型号就说明驱动 OK
安装步骤:
# 1. 拉取框架源码
git clone https://github.com/hiyouga/LLaMA-Factory.git
# 2. (可选)建个干净的虚拟环境,避免污染全局
# conda create -n llama_factory python=3.10
# conda activate llama_factory
# 3. 进入目录,安装框架(含 torch 和 metrics 依赖)
cd LLaMA-Factory
pip install -e '.[torch,metrics]'
⚠️ 注意:
pip install -e '.[torch,metrics]'里的-e是"可编辑安装",意思是后续改框架源码会即时生效。如果只是用,不打算改源码,去掉-e也行。安装时间较长(要拉 PyTorch),耐心等。
2. 把"实习生"请进来:下载 Qwen2.5-0.5B-Instruct
国内访问 HuggingFace 不稳定,推荐用 ModelScope(魔搭) 下载:
# 第一步:装 modelscope 工具
pip install modelscope
# 第二步:下载 Qwen2.5-0.5B-Instruct
modelscope download --model Qwen/Qwen2.5-0.5B-Instruct
# 第三步:把模型从缓存目录挪到工作区(方便管理)
mv /root/.cache/modelscope/hub/models/Qwen/Qwen2.5-0.5B-Instruct .
💡 为什么选 0.5B? 不是因为它最强,而是因为它小——下载快、显存友好、训练快,特别适合教学和练手。跑通流程后,把模型名换成更大的(比如 Qwen2.5-7B-Instruct),整套步骤一模一样。
3. 启动 WebUI 并"面试"原始模型
启动 LLaMA-Factory 的可视化界面:
cd LLaMA-Factory
llamafactory-cli webui
看到这行就说明启动成功了:
* Running on local URL: http://0.0.0.0:7860
浏览器打开 http://0.0.0.0:7860(如果你在云服务器上,换成服务器公网 IP),就能看到 WebUI 界面。语言选 zh(中文),英语不好的同学不用慌。
面试环节:训练前先加载模型进 Chat 模式,看看这个"实习生"原本啥水平。在 WebUI 里切到 Chat 标签,选好模型名称(Qwen2.5)和模型路径(刚才下载的绝对路径),加载后问它:
你现在是一个很厉害的阅读理解器,严格按照人类指令进行回答。
帮我抽出这句话里的实体关系,用 JSON 回答:
白胸三刺角蝉是属于同翅目的一种动物。
原始模型的回答大概率是"车轱辘话"——它能理解这句话,但不会按你要求的 JSON 格式做信息抽取。这正是我们要通过微调解决的问题:让它学会"读一句话→吐出结构化 SPO(主-谓-宾)"这门手艺。
🕳️ 陷阱:很多人一上来就训练,结果模型没学会还以为是参数不对。其实先"面试"原始模型很重要——你得先知道它不会什么,才能判断微调到底有没有效果。训练后再用同样的问题问一遍,对比才直观。
三、编写"培训手册":数据集准备
微调的核心是数据。再好的模型,喂垃圾数据也练废。LLaMA-Factory 支持 alpaca 数据格式,我们以 SFT(监督微调)阶段为例。
1. alpaca 格式:一份"培训手册"长什么样
alpaca 格式是一个 JSON 对象的列表,每条数据就是一道"培训题":
[
{
"instruction": "用户指令(必填,师傅出的题)",
"input": "用户输入(选填,题目材料)",
"output": "模型回答(必填,标准答案)",
"system": "系统提示词(选填,岗位守则)",
"history": [
["第一轮指令(选填)", "第一轮回答(选填)"],
["第二轮指令(选填)", "第二轮回答(选填)"]
]
}
]
用"师傅带徒弟"的比喻理解每个字段:
| 字段 | 比喻 | 作用 | 是否必填 |
|---|---|---|---|
instruction | 师傅出的题(“帮我抽取实体”) | 告诉模型这题要干啥 | 必填 |
input | 题目材料(那句话本身) | 这题要处理的具体内容 | 选填 |
output | 标准答案(抽出的 JSON) | 模型该学会的回答方式 | 必填 |
system | 岗位守则(“你是阅读理解器”) | 给模型设定角色和规则 | 选填 |
history | 之前几轮的问答记录 | 多轮对话的上下文 | 选填 |
单轮对话示例(一问一答,最常见):
{
"instruction": "写一个有效的比较语句",
"input": "篮球和足球",
"output": "篮球和足球都是受欢迎的运动。"
}
多轮对话示例(带上下文,模型要"接着聊"):
{
"instruction": "谢谢",
"input": "",
"output": "不用谢! 很高兴我提供的信息能够帮助到你!",
"history": [
[
"请你给我写一个面试准备计划,我想要去面试微软的程序员岗位",
"首先,你可以去微软官网寻找招聘信息并申请面试……"
]
]
}
2. 我们的信息抽取数据集长啥样
本次任务是教模型做信息抽取——给定一句话,抽取出其中的 SPO(主语-谓词-宾语)三元组,输出 JSON。一条典型的训练数据:
{
"instruction": "你现在是一个很厉害的阅读理解器,严格按照人类指令进行回答。",
"input": "句子中包含了哪些信息,输出json:\n\n白胸三刺角蝉是属于同翅目的一种动物。",
"output": "[{\"predicate\": \"目\", \"object_type\": \"目\", \"subject_type\": \"生物\", \"object\": \"同翅目\", \"subject\": \"白胸三刺角蝉\"}]"
}
拆开看这道"培训题":
instruction:岗位守则——“你是个阅读理解器,要听指令”。input:题目——“从这句话里抽信息,输出 JSON:白胸三刺角蝉属于同翅目……”output:标准答案——一个 JSON 数组,里面是主语-谓词-宾语的结构化三元组。
💡 直觉补充:信息抽取本质上就是高级版的"语文阅读理解里划主谓宾"。
subject(白胸三刺角蝉)是主语,predicate(目)是谓词关系,object(同翅目)是宾语。模型要学会的就是把自然语言句子"翻译"成这种结构化 JSON。
3. 注册数据集:把手册录入"学校系统"
光有数据文件还不够,得在 LLaMA-Factory 的"系统"里登记,框架才知道去哪找它。两步操作:
第一步:把你的数据集文件(比如 ner_dataset.json)复制到 LLaMA-Factory 的 data/ 目录下。
第二步:打开 data/dataset_info.json,在里面注册一条:
"ner_dataset": {
"file_name": "ner_dataset.json"
}
就这样,ner_dataset 这个名字就会出现在 WebUI 的数据集下拉框里。
⚠️ 注意:
dataset_info.json是个 JSON 文件,编辑时别忘了逗号。"ner_dataset"前面那行如果有内容,记得加逗号分隔,否则 JSON 解析报错,WebUI 会加载不出数据集列表。
四、正式上岗前培训:LoRA 微调训练
数据准备好了,现在让"实习生"开始上课。整个训练过程都在 WebUI 里操作,不用手敲命令(但可以看生成的命令学习)。
训练目标:让 Qwen2.5-0.5B-Instruct 学会 ner_dataset 数据集里的信息抽取能力。
1. 在 WebUI 里选数据集
切到 Train 标签:
- 模型名称选 Qwen2.5(这会自动匹配它的对话模板,不用自己设)。
- 模型路径填下载好的绝对路径(比如
/workspace/Qwen2.5-0.5B-Instruct)。 - 微调方法选 lora。
- 数据集勾选 ner_dataset,可以点"预览数据集"看看数据对不对。
2. 配置训练参数
WebUI 里能可视化调参,调完点"预览命令"会生成完整的训练命令。因为本次数据量较少,为了让模型学扎实,训练轮数(epoch)建议设大一点,比如 15 轮。
生成的训练命令长这样(关键参数我都注释了):
llamafactory-cli train \
--stage sft \ # 训练阶段:监督微调
--do_train True \ # 启用训练模式
--model_name_or_path /workspace/Qwen2.5-0.5B-Instruct \ # 基座模型路径
--preprocessing_num_workers 16 \ # 数据预处理线程数
--finetuning_type lora \ # 微调方法:LoRA(贴便利贴)
--template qwen \ # 对话模板:Qwen 专用
--flash_attn auto \ # Flash Attention 自动启用(加速)
--dataset_dir data \ # 数据集目录
--dataset ner_dataset \ # 数据集名称
--cutoff_len 2048 \ # 单条数据最大长度(超了截断)
--learning_rate 5e-05 \ # 学习率
--num_train_epochs 3.0 \ # 训练轮数(数据少时建议调大到 15)
--max_samples 100000 \ # 每个数据集最大采样数
--per_device_train_batch_size 4 \ # 每卡批次大小
--gradient_accumulation_steps 2 \ # 梯度累积步数(显存不够时调大)
--lr_scheduler_type cosine \ # 学习率调度:余弦退火
--max_grad_norm 1.0 \ # 梯度裁剪阈值
--logging_steps 5 \ # 每 5 步打印一次日志
--save_steps 100 \ # 每 100 步存一次检查点
--warmup_steps 0 \ # 预热步数
--packing False \ # 是否打包短序列
--report_to none \ # 不上报到 wandb 等
--output_dir saves/Qwen2.5-0.5B-Instruct/lora/train_2025-05-03-08-10-32 \ # 输出目录
--bf16 True \ # 用 bf16 半精度训练(省显存)
--plot_loss True \ # 绘制 Loss 曲线
--trust_remote_code True \ # 信任远程代码
--optim adamw_torch \ # 优化器
--lora_rank 8 \ # LoRA 秩(便利贴的"宽度")
--lora_alpha 16 \ # LoRA 缩放系数
--lora_dropout 0 \ # LoRA dropout
--lora_target all # LoRA 作用到所有线性层
3. 关键参数速查表
参数太多记不住?挑最关键的几个理解透就行:
| 参数 | 比喻 | 说明 | 调参建议 |
|---|---|---|---|
stage | 培训阶段 | sft = 监督微调 | 信息抽取任务用 sft |
finetuning_type | 培训方式 | lora = 贴便利贴 | 普通开发者首选 lora |
template | 对话模板 | 必须匹配模型 | Qwen 模型就选 qwen |
num_train_epochs | 培训几轮 | 整个数据集过几遍 | 数据少就调大(如 15) |
learning_rate | 学习步子多大 | 每次更新幅度 | 5e-5 是 LoRA 常用值 |
per_device_train_batch_size | 一批学几道题 | 每卡 batch size | 显存够就调大 |
gradient_accumulation_steps | 凑几批再更新 | 梯度累积 | 显存不够时调大补偿 |
cutoff_len | 一道题最多多长 | 序列截断长度 | 2048 够大多数任务 |
lora_rank | 便利贴多宽 | LoRA 秩 r | 8/16 常用,越大越能学但越费 |
lora_alpha | 便利贴权重多大 | 缩放系数 | 通常设为 rank 的 2 倍 |
bf16 | 用半精度省显存 | 混合精度训练 | T4 之后都支持 |
⚠️ 注意:老显卡(如 V100)不支持
bf16,得改成--fp16 True。如果训练直接报错崩掉,先怀疑这个。
💡 关于 LoRA 的
lora_rank:lora_rank(r)就是那叠"便利贴"的宽度。r 越大,模型能学的东西越复杂,但参数也越多、越费显存。r=8 是个很稳的起点;任务复杂、数据多时可以调到 16、32。lora_alpha一般设成 r 的 2 倍(r=8 → alpha=16),这是社区经验值。
4. LoRA 到底在干什么(一张图看懂)
原始权重 W 是冻结的(实习生的通识知识不动),LoRA 在旁边加一条小路:用一个低秩矩阵 A·B(便利贴)算出一个增量,加到原始输出上。训练时只更新 A 和 B,所以参数量极小、显存友好。这就像不动实习生的脑子,只让他多带一叠随时可换的便利贴。
5. 开始训练 & 观察 Loss
在 WebUI 里点 “开始” 按钮,服务器终端会打印训练过程。训练完成后,output_dir 下会保存这些内容:
adapter*:LoRA 模型权重(就是那叠训练好的"便利贴",体积很小)。training_loss、trainer_log:训练损失和日志。- 其他:训练参数备份。
Loss 趋势是判断训练效果的关键指标:
训练 Loss 理想走势(示意):
步数 5 50 100 200 300 400 500
Loss 3.20 → 2.10 → 1.50 → 1.05 → 0.72 → 0.55 → 0.48
↘ ↘ ↘ ↘ ↘ ↘ ↘
高开,逐渐下降,趋于平稳 ← 理想:降到 1 以下
💡 Loss 怎么看? Loss 应该逐渐下降并趋于平稳。理想情况下能降到 1 以下。如果 Loss 一直不降,可能是学习率太小或数据有问题;如果 Loss 降得太狠甚至接近 0,要警惕过拟合——模型把训练集"背"下来了,但换个问题就不会。
⚠️ 注意:WebUI 训练完成后界面会展示完成状态。如果你勾选了
--plot_loss True,还能看到 Loss 曲线图,直观判断训练是否收敛。
五、考核转正:合并模型 + 验证效果
训练完得到的只是"便利贴"(LoRA adapter),推理时可以动态加载它,也可以把便利贴"誊抄"进模型脑子里——这就是合并(merge)。合并后得到一个完整的独立模型,部署更方便。
1. 合并模型:把便利贴正式誊抄进脑子
在 WebUI 切到 Export 标签:
- 检查点路径:选之前训练保存的 LoRA 模型路径(
output_dir下的那个)。 - 导出目录:自定义合并后完整模型的保存路径(比如
/workspace/qwen-ner-merged)。 - 点 “导出”,等它把 LoRA 权重合并进基座模型,存成一个完整的模型目录。
💡 为什么要合并? 动态加载 LoRA 推理时需要同时带上基座模型 + adapter 两个东西;合并后只有一个完整模型,部署、转换格式(如 GGUF)都更省事。
2. 验证效果:让"转正"的模型做题
合并完,切回 Chat 标签测试。关键一步:模型路径改成合并后的完整模型绝对路径(比如 /workspace/qwen-merged),而不是原来的基座路径。
加载模型后,用之前"面试"时问过的同样问题再问一遍,对比效果:
你现在是一个很厉害的阅读理解器,严格按照人类指令进行回答。
帮我抽出SPO,用JSON回答。
《武汉这些天一直在下雨》是钟立风的音乐作品,收录在《她为我编织毛衣》专辑中。
微调后,模型应该能稳定输出结构化 JSON,比如:
[
{"predicate": "所属专辑", "subject": "武汉这些天一直在下雨", "object": "她为我编织毛衣"},
{"predicate": "创作者", "subject": "武汉这些天一直在下雨", "object": "钟立风"}
]
🎮 对比验证小技巧:把微调前后对同一问题的回答截图并排放,是写技术博客和汇报时最有说服力的素材。微调前是一堆废话,微调后是干净的结构化 JSON——这种"前后对比"比任何文字描述都直观。
🕳️ 陷阱:如果合并后效果还是不行,别急着调参数。先检查三件事:① 数据集质量(标注对不对);② 训练轮数够不够(数据少就多训几轮);③ 模型路径有没有指对(指向了基座而非合并模型)。90% 的"没学会"都是这三个原因。
六、外派上岗:导出 GGUF + Ollama 部署(扩展)
合并后的模型是 HuggingFace 格式(.safetensors),要在本地轻量化部署,还得转成 GGUF 格式,再用 Ollama 跑起来——相当于把这个"转正员工"打包成"可外派的版本",派到任何机器都能用。
1. 为什么要 GGUF + Ollama?
| 方案 | 格式 | 部署复杂度 | 资源占用 | 适用场景 |
|---|---|---|---|---|
| HuggingFace 原版 | .safetensors | 高(需 Python + transformers) | 大 | 研究、二次开发 |
| GGUF + Ollama | .gguf | 低(一行命令) | 小(支持量化) | 本地部署、生产使用 |
GGUF 是 llama.cpp 生态的模型格式,支持量化(把模型体积压到原来的 1/4 甚至更小),Ollama 则提供了最简单的本地运行方式。
2. 转换为 GGUF 格式
先装好 llama.cpp 的 GGUF 工具库:
# 1. 拉取 llama.cpp 源码
git clone https://github.com/ggerganov/llama.cpp.git
# 2. 安装 gguf Python 库
cd llama.cpp/gguf-py
pip install --editable .
# 3. 回到 llama.cpp 目录
cd ..
执行格式转换:
# 把合并后的 HF 模型转成 GGUF
python convert-hf-to-gguf.py /workspace/qwen-merged
执行完会在模型目录下生成一个 .gguf 文件,这就是打包好的"外派版"模型。
⚠️ 注意:如果转换时报缺少某个权重或配置的错,多半是合并模型不完整。回去检查 Export 步骤有没有把所有文件(
config.json、tokenizer等)都导全了。
3. 用 Ollama 跑起来
安装 Ollama:
curl -fsSL https://ollama.com/install.sh | sh
注册模型:写一个 Modelfile(类似 Dockerfile),告诉 Ollama 用哪个 GGUF 文件:
ollama create chat-merged -f /workspace/qwen-merged/gguf-model.gguf
启动对话:
ollama run chat-merged
进入交互式问答,直接输入信息抽取的指令就能用了。输入 /bye 退出。
到这一步,从"下载一个啥也不会的实习生",到"训练、转正、打包外派上岗"的完整闭环就跑通了。
核心要点小结
- LLaMA-Factory 是大模型微调的"培训学校":把数据加载、对话模板、训练循环等脏活全打包,WebUI 可视化操作,普通开发者也能上手。
- LoRA = 不回炉重造,只贴便利贴:只训练旁路的低秩矩阵,不动原始权重,显存友好、训练快,是普通开发者的首选微调方法。
- 数据是微调的灵魂:alpaca 格式 =
instruction(出题)+input(材料)+output(标准答案),数据集要在data/dataset_info.json里注册才能被框架识别。 - 关键参数记三个:
finetuning_type=lora(贴便利贴)、num_train_epochs(数据少就调大)、learning_rate(5e-5 是 LoRA 常用值);老显卡记得把bf16换成fp16。 - 训练完要"转正"再"外派":先用 Export 合并 LoRA 得到完整模型,再转 GGUF 用 Ollama 部署,一条龙跑通从训练到本地上线。
- 效果验证靠前后对比:用同一问题问微调前后的模型,结构化输出 vs 废话,对比最直观。
动手思考题
- 如果把
lora_rank从 8 调到 32,训练参数量会增加多少?模型效果一定会变好吗?什么情况下反而会过拟合? - 你的训练 Loss 降到 0.05 了,但换一批没见过的测试数据,模型却胡言乱语——这是出了什么问题?该怎么解决?
- 如果想让模型同时学会「信息抽取」和「身份认知」(知道自己是某某公司开发的助手),数据集和训练参数要怎么调整?
- 0.5B 模型跑通后,你想换 7B 模型微调,除了改模型路径,还需要调整哪些参数?显存不够时第一步该调什么?
📚 关于本系列
本文是 「大模型微调实战」 系列中的一篇。所有文章在我的个人博客上都有 可交互动画 + 完整学习路线 版本,建议配合食用 👇
🗺️ 查看完整 AI 学习路线
👉 bestsdz.xyz觉得有帮助的话,欢迎去博客点个收藏 ⭐,你的支持是我更新的最大动力!
更多推荐


所有评论(0)