Llama-Factory 训练中文小说续写模型的实践心得
通用大模型在中文小说续写任务中常存在风格不符、逻辑断裂等问题,而从头训练专属模型又面临显存与代码门槛。本文分享使用 Llama-Factory 结合 QLoRA 技术,在单张 RTX 3090 上对 Baichuan2-7B 进行高效微调的实践经验,实现具备古风韵味的垂直领域模型。
为什么选择 Llama-Factory?
相比手动基于 Hugging Face Transformers 搭建流程,Llama-Factory 提供了开箱即用的解决方案:
- 统一接口:适配多种主流架构(Qwen, Baichuan, ChatGLM, LLaMA 等);
- 多模式微调集成:支持全参数、LoRA、QLoRA,切换仅需修改参数;
- WebUI 可视化操作:浏览器即可完成数据导入、配置、训练及监控;
- 端到端闭环:覆盖从预处理到合并导出的全流程。
技术底座:LoRA 与 QLoRA
传统全参数微调显存占用高(7B 模型需>80GB)。LoRA 通过引入低秩矩阵 $ A \in \mathbb{R}^{d \times r} $、$ B \in \mathbb{R}^{r \times k} $,仅更新少量参数,大幅降低显存需求。QLoRA 在此基础上增加 4-bit 量化、双重量化及 Paged Optimizers,使消费级显卡(如 RTX 3090)也能运行。
| 微调方式 | 显存占用 | 可训练参数比例 | 是否适合消费级 GPU |
|---|---|---|---|
| 全参数微调 | >80GB | 100% | ❌ |
| LoRA | ~20GB | ~0.5% | ⚠️ |
| QLoRA | <24GB | ~0.5% | ✅ |
实战流程
1. 数据准备
构建'上下文 → 续写'样本对,采用 JSONL 格式:
{"instruction": "请续写以下小说段落", "input": "夜色如墨,山风呼啸。林间小道上,一道黑影疾驰而过……", "output": "他脚步轻盈,仿佛踏叶无痕。忽然,前方传来一阵铃声,清脆却透着诡异……"}
Llama-Factory 默认将其拼接为 Alpaca 模板。
2. 模型选择与训练配置
选用 Baichuan2-7B-Base,启动命令如下:
CUDA_VISIBLE_DEVICES=0 python src/train_bash.py \
--stage sft \
--do_train \
--model_name_or_path baichuan-inc/Baichuan2-7B-Base \
--dataset chinese_novel_demo \
--template baichuan2 \
--finetuning_type lora \
--lora_target W_pack \
--output_dir ./output/chinese_novel_lora \
--per_device_train_batch_size 1 \
--gradient_accumulation_steps 8 \
--lr_scheduler_type cosine \
--learning_rate 5e-5 \
--num_train_epochs 3.0 \
--fp16 \
--plot_loss \
--quantization_bit 4 \
--device_map auto
关键参数说明:
--quantization_bit 4:启用 4-bit 量化;--lora_target W_pack:针对 Baichuan 模型结构注入;--gradient_accumulation_steps 8:模拟全局 batch size。
3. 模型合并与导出
训练完成后合并权重:
python src/export_model.py \
--model_name_or_path baichuan-inc/Baichuan2-7B-Base \
--adapter_name_or_path ./output/chinese_novel_lora \
--export_dir ./merged_model \
--export_quantization_bit 4 \
--export_device cuda
输出标准 HuggingFace 格式目录,可直接推理。
4. 推理测试
加载合并后模型,输入开头生成续写内容。测试表明模型能模仿古龙或玄幻风格,逻辑通顺。
5. 部署上线
使用 FastAPI 包装推理接口,前端用 Gradio 搭建交互页面:
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
model = AutoModelForCausalLM.from_pretrained("./merged_model", device_map="auto")
tokenizer = AutoTokenizer.from_pretrained("./merged_model")
def generate(text, max_new_tokens=200):
inputs = tokenizer(text, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=max_new_tokens, do_sample=True, temperature=0.8, top_p=0.9)
return tokenizer.decode(outputs[0], skip_special_tokens=True)
常见问题与优化
- 生成内容口语化:剔除网络用语样本,Prompt 中加入风格锚点(如'仿明代话本笔法')。
- 长文本连贯性差:控制生成长度(<200 token),引入滑动窗口机制重复关键句。
- 小规模数据过拟合:设置早停机制,dropout=0.05,epoch 控制在 2~3 轮。
设计权衡思考
- LoRA 秩(rank):对比 r=32/64/128,选定 r=64 配合 alpha=128 作为平衡点。
- 学习率:尝试 1e-4 发散,最终采用 5e-5 配合 cosine 衰减。
- 数据质量 vs 数量:清洗数据删除语病样本,虽总量减少但效果显著提升。
总结
本项目验证了利用 Llama-Factory + QLoRA 在消费级硬件上微调垂直领域模型的可行性。通过合理配置参数与高质量数据清洗,开发者可低成本打造具备特定风格的 AI 创作助手。
