0. 系列闭环
| 本篇位置 | 上游 | 本篇产出 | 下游 |
|---|---|---|---|
| 第 1/10 篇 | 业务场景定义 | 技术选型结论、项目边界 | 第 02 篇数据格式 → 第 05 篇训练脚本 |
本系列只走一条链路:JSONL 数据 → train_lora_single.py → final_lora → verify_lora.py → vLLM API。不包含多卡 DDP、不包含 LoRA 合并进基座(后续单开)。
1. 要解决的实际问题
1.1 基座模型的默认行为不符合场景
Qwen3.5-4B 作为通用对话模型,面对老年用户典型倾诉时,倾向于输出解决方案型回复:建议活动、建议就医、建议「保持积极」。这在逻辑上没错,但在情感陪伴场景里会被体验为说教。
训练数据里第一条 user 就是:
1 | |
期望的 assistant 风格(见 LoRA_Demo/data/elderly_chat.jsonl 第 1 行)是:
1 | |
关键词不是「怎么办」,而是共情 + 陪伴 + 不催促。这是风格迁移任务,不是知识注入任务。
1.2 五类心理模型决定数据边界
1000 条训练数据按五类划分(各 200 条),覆盖:
| 主题 | 典型 user 情绪 | 模型应避免 |
|---|---|---|
| 孤独 & 渴望陪伴 | 冷清、无人说话 | 立刻给「去社区活动」清单 |
| 健康焦虑 & 怕死 | 体检、失眠、怕拖累 | 诊断式表述、保证疗效 |
| 害怕添麻烦 & 自责 | 怕请假、怕花钱 | 讲道理式否定感受 |
| 怀旧 & 渴望认同 | 过去的好、不被理解 | dismiss 为「老观念」 |
| 情绪低落 & 渴望被需要 | 没用、多余 | 空洞鼓励「你要振作」 |
LoRA SFT 的作用:在不改变医学/法律等事实能力的前提下,把回复分布往「温柔陪伴」偏移。
2. 实现位置与仓库结构
1 | |
未纳入本系列的脚本(存在但暂不写):train_lora_multi.py(多卡)、merge_lora.py(合并权重)。
3. 为什么选 LoRA + SFT,而不是其他方案
3.1 与全量微调对比
| 维度 | 全量微调 4B | LoRA(本项目) |
|---|---|---|
| 可训练参数 | ~42 亿 | 10,616,832(0.2518%) — 见 all_logs.log 第 34 行 |
| 单次产出体积 | ~8 GB+ | adapter_model.safetensors ~41 MB |
| 实测训练时长 | 未做 | 2484 s(41 分 23 秒) |
| 数据规模匹配 | 通常需更大语料 | 1000 条风格样本即可见效 |
日志原文:
1 | |
3.2 与 Prompt-only 对比
仅靠 system prompt(verify_lora.py 里 SYSTEM_PROMPT 与训练一致)可以略微改善语气,但基座仍容易滑向「建议式」结构。SFT 把整段回复的 token 分布拉向数据里的共情模板,效果比纯 prompt 稳定。
3.3 与 LLaMA-Factory 等配置化框架对比
本项目刻意保留 250 行可读脚本(train_lora_single.py),注释里带 LoRA 原理与单卡 device_map 说明。目标是对照代码理解 TRL + PEFT 调用链,而不是隐藏在一层 YAML 后面。
技术栈锁定:
- TRL
SFTTrainer+SFTConfig(v1.5.1,见 checkpoint README) - PEFT
LoraConfig(v0.19.1,见final_lora/adapter_config.json) - Transformers 5.9.0 加载 Qwen3.5-4B
4. 端到端架构
1 | |
5. 一次真实训练的关键数字(可引用)
来源:LoRA_Demo/all_logs.log
| 指标 | 值 | 说明 |
|---|---|---|
| GPU | Tesla V100S-PCIE-32GB | 31.7 GB 显存 |
| 样本数 | 1000 | JSONL 加载日志第 31 行 |
| 有效 batch | 4 | 2 × 2 梯度累积 |
| 总步数 | 750 | 3 epochs |
| Step 1 loss | 2.8099 | token 准确率 43.6% |
| Step 250 loss | 0.2402 | 第 1 epoch 结束 |
| Step 750 loss | 0.1286 | 训练结束 |
| 平均 train_loss | 0.2587 | 汇总行 |
| 吞吐 | 1.208 samples/s |
这些数字说明:小数据 + 低秩适配器可以在 40 分钟内完成可观测的风格收敛,适合个人/小团队迭代。
6. 踩坑(立项阶段就要知道)
坑 1:把陪伴做成「健康问答」
若 assistant 回复充满医学建议,loss 同样会降,但产品定位偏了。数据里刻意不写诊断、不写「保证治好」。
坑 2:以为 4B 小模型「不用微调」
实测 Mac mini 上对 LoRA 模型跑 verify_lora.py(MPS + float16),「晚上睡不着」类问题能稳定输出「我陪着您呢」式回复;基座在同 prompt 下仍更易给建议清单。是否微调差别在语气结构,不是 IQ。
坑 3:训练与推理 system 不一致verify_lora.py 第 33–36 行 SYSTEM_PROMPT 必须与 JSONL 里 system 逐字一致,否则验证结论不可信。
7. 小结
- 场景是老年情感陪伴,核心是共情风格,不是通用聊天。
- LoRA SFT 在 1000 条数据、41 MB 权重、41 分钟训练的可复现成本下完成风格迁移。
- 代码入口是
train_lora_single.py,验证入口是verify_lora.py,部署走 vLLM 动态 LoRA。 - 本系列 10 篇按数据 → 原理 → 环境 → 代码 → 指标 → 验证 → 踩坑 → 部署顺序展开。
附录:训练脚本文件头(设计意图)
来源:LoRA_Demo/train_lora_single.py 第 1–33 行
1 | |
系列导航
| 篇目 | 链接 |
|---|---|
| 下一篇 | 02 · 训练集设计 |
| 索引 | README |