Llama-Factory训练中文小说续写模型的实践心得

Llama-Factory训练中文小说续写模型的实践心得

夜深人静,键盘轻响。你正为一部玄幻小说卡文发愁——主角刚踏入秘境,剧情却断了线。如果有个“写作搭子”,能顺着你的笔触自然延展情节,会是怎样一种体验?这并非幻想,而是如今借助大语言模型微调技术即可实现的现实。

但问题来了:通用大模型写出来的续章,要么太现代、要么没韵味,风格完全不对味;自己从头训练一个专属模型?动辄几十GB显存、复杂的代码流程,让多数开发者望而却步。有没有一条更平滑的技术路径?

答案是肯定的。在过去几个月里,我尝试用 Llama-Factory 搭建了一个专精于中文武侠与玄幻小说续写的定制化模型。整个过程无需编写复杂训练脚本,仅靠可视化界面和几行配置,就在单张RTX 3090上完成了对 Baichuan2-7B 的高效微调。最终生成的内容不仅语义连贯,还能模仿出类似《雪中悍刀行》那种冷峻苍茫的文风。

这套方案的核心,正是 Llama-Factory + QLoRA 的黄金组合。它不是实验室里的理论玩具,而是一套真正能让中小团队或独立开发者快速落地AI创作能力的实用工具链。


为什么选择 Llama-Factory?

在接触这个框架之前,我也走过不少弯路。最初试图基于 Hugging Face Transformers 手动搭建微调流程:写数据加载器、定义训练循环、处理 tokenizer 对齐……每一步都容易踩坑,调试成本极高。更麻烦的是,换一个模型(比如从 LLaMA 切到 ChatGLM),几乎要重写一半逻辑。

直到遇见 Llama-Factory,才真正体会到什么叫“开箱即用”。

这个开源项目由国内团队维护,深度适配中文生态,支持包括 Qwen、Baichuan、ChatGLM、LLaMA 等数十种主流架构。它的设计理念很明确:把大模型微调变成一件普通人也能操作的事

其核心优势体现在四个方面:

  • 统一接口:无论底层是哪种模型,训练命令和配置基本一致;
  • 多模式微调集成:全参数微调、LoRA、QLoRA 都已内置,切换只需改个参数;
  • WebUI 可视化操作:通过浏览器就能完成数据导入、参数设置、启动训练和监控指标;
  • 端到端闭环:从数据预处理到模型合并导出,全流程覆盖,省去大量胶水代码。

尤其对于中文小说这类小众但高价值的应用场景,这种一体化平台的价值尤为突出。


技术底座:LoRA 与 QLoRA 如何改变游戏规则?

传统全参数微调的问题在于“太重”——以 7B 参数模型为例,光是 optimizer state 就可能占用超过 80GB 显存,必须依赖 A100 集群才能跑起来。这对个体开发者来说几乎是不可逾越的门槛。

LoRA(Low-Rank Adaptation)的出现改变了这一点。它的思想非常巧妙:不直接更新原始权重矩阵 $ W $,而是在旁边引入两个低秩矩阵 $ A \in \mathbb{R}^{d \times r} $、$ B \in \mathbb{R}^{r \times k} $,其中 $ r \ll d,k $,通常取 8~64。前向传播变为:

$$
h = (W + BA)x
$$

训练时只更新 $ A $ 和 $ B $,冻结主干参数。这样一来,可训练参数数量从数十亿降到百万级,显存消耗大幅下降,且推理时仍能恢复完整计算图。

而 QLoRA 更进一步,在 LoRA 基础上加入了三项关键技术:

  1. 4-bit 量化:使用 NF4(NormalFloat4)格式压缩预训练权重,显存减少约 60%;
  2. 双重量化(Double Quantization):对 LoRA 适配器中的量化常数也进行压缩,节省额外内存;
  3. Paged Optimizers:利用 CUDA Unified Memory,当 GPU 显存不足时自动将优化器状态卸载至 CPU 内存,避免 OOM。

这三者结合,使得原本需要多张专业卡的任务,现在一张 RTX 3090(24GB)就能搞定。我在实际测试中,使用 Baichuan2-7B-Base 模型配合 QLoRA,峰值显存控制在 18GB 左右,训练稳定流畅。

微调方式显存占用可训练参数比例是否适合消费级GPU
全参数微调>80GB100%
LoRA~20GB~0.5%⚠️(需大显存卡)
QLoRA<24GB~0.5%

可以说,QLoRA 是当前性价比最高的微调范式,特别适合像中文小说续写这样资源敏感但需快速迭代的场景。


实战:如何用 Llama-Factory 训练一个会写古风小说的AI?

整个流程可以分为五个阶段,全部可通过 WebUI 或命令行完成。

1. 数据准备:构建“上下文 → 续写”样本对

关键是要模拟真实写作场景。我收集了约 5,000 段来自《斗破苍穹》《凡人修仙传》《剑来》等热门作品的连续段落,提取“前一段 + 后一段”的结构,并构造如下 JSONL 格式的数据:

{"instruction": "请续写以下小说段落", "input": "夜色如墨,山风呼啸。林间小道上,一道黑影疾驰而过……", "output": "他脚步轻盈,仿佛踏叶无痕。忽然,前方传来一阵铃声,清脆却透着诡异……"} 

Llama-Factory 默认会按照 Alpaca 模板将其拼接为:

Below is an instruction that describes a task. Write a response that appropriately completes the request. ### Instruction: 请续写以下小说段落 ### Input: 夜色如墨,山风呼啸。林间小道上,一道黑影疾驰而过…… ### Response: 他脚步轻盈,仿佛踏叶无痕。忽然,前方传来一阵铃声,清脆却透着诡异…… 

如果你希望加入风格控制,还可以自定义模板,例如插入提示词:“请以金庸武侠风格续写”。

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 量化,开启 QLoRA;
  • --lora_target W_pack:Baichuan 模型将 q/v/k 投影层融合为一个 W_pack,需针对性注入;
  • --gradient_accumulation_steps 8:虽 batch_size=1,但累积 8 步相当于全局 batch=8,保证梯度稳定性;
  • --device_map auto:自动分片加载模型,支持显存不足时的 offload。

整个训练过程约耗时 6 小时(RTX 3090),loss 曲线平稳下降,未见震荡。

3. 模型合并与导出

训练完成后,使用内置工具将 LoRA 权重合并回原模型:

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 格式的模型目录,包含 config.jsontokenizer.modelpytorch_model.bin,可直接用于推理。

4. 推理测试:看看它会不会“写故事”

加载合并后的模型,输入一段开头:

“残阳如血,黄沙漫天。边关城楼上,一名白衣剑客负手而立……”

模型续写如下:

“他的目光遥望着远方的地平线,那里有一骑快马正疾驰而来。风吹动他的衣角,发出猎猎声响。他知道,那个人终于来了——十年之约,今日终须一战。”

语气沉郁、节奏紧凑,颇有几分古龙风味。再试一次,换成玄幻风:

“灵根被废,丹田尽毁。少年跪在宗门广场,任雨水冲刷脸庞……”

续写:

“但他眼中没有屈服,只有燃烧的怒火。那一夜,他在禁地深处挖出了一块刻满符文的石碑,传说那是上古炼气士留下的传承……”

逻辑通顺,情绪递进合理,甚至出现了“禁地”“符文”“炼气士”等典型设定词汇——说明模型已经学会了该类文本的表达范式。

5. 部署上线:打造一个小说续写API服务

最后一步是部署。我用 FastAPI 包装了一个简单的推理接口:

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) 

前端则用 Gradio 搭了个交互页面,供编辑试用。反馈相当积极:比起原来通用模型的“塑料感”输出,这个定制模型更像是“懂行”的写手。


遇到了哪些坑?又是怎么解决的?

任何项目都不会一帆风顺。以下是我在实践中总结的几点经验教训:

问题1:生成内容口语化严重,缺乏“古意”

初期训练后发现,模型喜欢用“然后”“所以”“我觉得”这类现代口语连接句式,破坏氛围。

解决方案
- 在训练数据中剔除夹杂网络用语的段落;
- 在 prompt 中加入风格锚点,如“仿明代话本笔法”;
- 使用更高阶的模板机制,在输入中注入风格标记。

问题2:长文本连贯性差,写着写着就偏题

小说续写不同于问答,要求长时间维持角色设定和情节走向。

改进措施
- 控制生成长度(建议不超过 200 token),避免失控;
- 引入滑动窗口机制,在后续生成中重复输入前文关键句;
- 后期可考虑接入 RAG,动态检索相关背景知识辅助生成。

问题3:小规模数据下容易过拟合

5,000 条样本看似不少,但对于 7B 模型仍是杯水车薪。

应对策略:
- 设置早停机制(early stopping),观察验证集 loss;
- 使用 dropout=0.05 进行正则化;
- epoch 数控制在 2~3 轮,避免反复扫同一数据。


设计背后的权衡思考

在整个过程中,有几个关键决策点值得深入探讨:

LoRA 秩(rank)选多大?

我对比了 r=3264128 三种设置:

  • r=32:显存友好,但风格捕捉能力弱,生成较平淡;
  • r=64:平衡点,既能学习复杂语义,又不会过度拟合;
  • r=128:性能略优,但显存逼近上限,训练变慢。

最终选定 r=64,并配合 alpha=128(即缩放比为 2),符合 LoRA 论文推荐的经验公式。

学习率该怎么设?

QLoRA 对学习率更敏感。尝试过 1e-4,结果 early divergence;降到 5e-5 后收敛平稳。最终采用 cosine 衰减,在第 2 个 epoch 末尾进入平台期,正好停止。

数据质量 vs 数量?

与其堆数量,不如提质量。我花三天时间人工清洗数据,删除语病明显、风格混杂的样本,虽然总量少了 30%,但训练效果反而提升显著。这也印证了一个观点:在领域微调中,干净、一致的数据比海量噪声更有价值


写在最后:平民化AIGC的时代正在到来

回顾整个项目,最让我感慨的不是技术本身,而是它的“可及性”。几年前,训练一个大模型意味着组建团队、申请算力、熬代码;而现在,一个人、一台消费级显卡、一个开源框架,就能做出具备实用价值的垂直模型。

Llama-Factory 正是这一趋势的缩影。它降低了大模型微调的认知门槛和工程成本,让更多创作者、产品经理、独立开发者能够亲手打造属于自己的“AI写手”“AI编剧”“AI助手”。

未来,随着更多高质量中文语料的释放、微调算法的持续演进,我们或许会看到一批“风格化模型”涌现:专写悬疑的、擅长宫斗的、精通科幻的……每一个都像是某个作家的精神分身。

而这一切的起点,也许就是你现在打开终端,运行的那一行 train_bash.py

Read more

HarmonyOS6 ArkTS Tabs 设置TabBar的布局模式

HarmonyOS6 ArkTS Tabs 设置TabBar的布局模式

文章目录 * Tabs与TabBar基础 * 核心属性:barMode * 两种布局模式 * 1. BarMode.Fixed(固定均分模式) * 核心特性 * 适用场景 * 代码配置 * 2. BarMode.Scrollable(可滚动模式) * 核心特性 * 适用场景 * 代码配置 * 完整代码 * 模式效果对比 * 效果对比表 * 总结 Tabs与TabBar基础 Tabs组件由TabBar(页签导航栏)和TabContent(对应内容区)两部分组成。TabBar作为导航入口,其布局模式直接影响页面美观与操作流畅度。 核心属性:barMode * 作用:定义TabBar的布局规则,控制页签宽度分配与滚动能力 * 类型:BarMode枚举,包含两种核心模式 * BarMode.Fixed:固定均分模式(默认值) * BarMode.Scrollable:可滚动模式 * 配置位置:Tabs组件的链式调用属性 两种布局模式 1.

分布式仓储机器人数据采集物联网解决方案

某智慧仓储设备商从事于各类仓储机器人的生产、制造和销售,产品包括搬运机器人、料箱机器人、堆垛机器人和无人叉车等设备,既支持单机设备的销售,也支持整套智慧仓储系统的搭建。随着项目越来越多,规模越来越大,企业在售后运维付出的时间、精力和成本也越来越高,成为企业数字化转型和降本增效必须解决的问题之一。 痛点分析 1、不同类型、不同型号的仓储机器人所采集的数据格式和接口标准各不相同,缺乏统一的数据采集系统,难以对设备运行数据进行全面、准确的采集和分析, 2、众多仓储机器人分布在不同省市、不同区域,管理粗放,设备出现故障无法及时知晓,难以做到实时、全面的监控,无法及时发现设备故障隐患。 3、大量设备带来繁重的售后工作量,不仅增加了企业的人员成本和差旅成本,而且由于缺乏信息化的运维管理机制,还可能导致运维资源的浪费。 解决方案 通过接入控制器PLC,工业智能网关能够实时采集仓储机器人的运行状态、工作参数、故障信息等数据,并实现5G/4G等方式对接到设备运维管理平台中,生成各种报表和图表,为企业提供直观、全面的设备运行状态展示,从而实现远程监控、故障告警、运维管理、远程维

组建龙虾团队——OpenClaw多机器人构建

组建龙虾团队——OpenClaw多机器人构建

成功搭建了OpenClaw,也成功建立的自己的每日服务,这时候发现,似乎不太敢在当前的机器人中让他做别的事情,生怕会话太多会让他出现遗忘。(尽管我们配置了QMD记忆增强,但毋庸置疑任何技术都是有上限的)。 换做同样的情况,比如在DeepSeek或者豆包之类的对话窗口,我们会习惯性地新建一个对话。那么我们是否可以新建一个机器人,或者多个机器人,让他们各司其职,各尽所能,形成一个相互配合的团队呢~开干吧,没什么不可能的!! 🦞新建一个机器人 来到飞书开发者后台,新创建一个应用,在这里我们以短视频剪辑脚本应用为例。 创建之后,由于我们的openclaw绑定的是之前的飞书渠道,并没有链接到这个应用的APP ID,所以暂时不做其他操作,只需要记录一下他的APP ID和APP Secret。 🦞配置OpenClaw 如果还是按照claw的命令行安装,每一步都有些让人担心害怕,毕竟我们先前已经配置过一次了,接下来的操作,需要小心是否会把以前的配置给覆盖掉。 为了避免这样的不确定性,我们直接去操作他的配置文件 在WSL2终端中进入openclaw目录 cd .openclaw

RTAB-Map学习记录(1)--论文阅读

RTAB-Map学习记录(1)--论文阅读

前言 RTAB-Map(全称 Real-Time Appearance-Based Mapping)是一个开源的 RGB-D SLAM框架,主要用于机器人导航、3D 重建和环境建图。这个项目目前还在积极的维护和更新,也可以进行实际环境的部署。所以先学习一下相关的原理和论文,为之后的使用打下基础。 文章目录 * 前言 * 1.主要贡献 * 2.关键内容 * 2.1 里程计 * 2.1.1 视觉里程计 * 2.1.2 激光雷达里程计 * 2.2 同步性 * 2.3 STM * 2.4 回环检测与优化 * 2.5 全局地图组成 1.主要贡献 首先看一下该方法的主要贡献有哪些,现有一个基本的了解: 1.