0. 系列闭环
| 本篇位置 | 上游 | 本篇产出 | 下游 |
|---|---|---|---|
| 第 8/10 篇 | 第 07 篇 loss 收敛 | 定性结论:是否「更温柔、少说教」 | 第 09 篇 Qwen 特有问题 · 第 10 篇 vLLM 上线 |
loss 低 ≠ 产品可用。 本篇是上线前最后一道人工可读的关卡。
1. 要解决的实际问题
第 07 篇:token 准确率 96%,loss 0.13。
仍无法回答:
- 基座在同 system 下会不会仍给「建议清单」?
- LoRA 是否只对训练集 user 复读?
- Mac 上能否不租 GPU 做冒烟测试?
verify_lora.py 设计目标(文件头第 10–12 行):
- 读
trainer_state.json看 loss - 同一 user,对比微调前/后生成(可选)
- 人工判断是否符合「老年陪伴」
2. 实现位置
| 符号 | 行号 | 作用 |
|---|---|---|
SYSTEM_PROMPT |
33–36 | 与 JSONL system 一致 |
DEFAULT_QUESTIONS |
38–42 | 三主题冒烟题 |
print_training_metrics |
60–94 | 读 checkpoint loss |
get_device_and_dtype |
101–107 | CUDA / MPS / CPU |
load_base_model / load_lora_model |
110–134 | 分载,避显存峰值 |
generate_reply |
152–176 | chat_template + generate |
extract_final_reply |
137–149 | 剥 thinking 块 |
verify_questions |
188–218 | 主流程 |
路径常量:
1 | |
3. 命令行模式
1 | |
Mac mini 上用户实测为 自定义多题 + LoRA 推理(终端显示 测试 1/1 与 MPS),说明 --lora-only 或单题模式在 Apple Silicon 可行。
4. 显存策略:先后加载、显式释放
1 | |
free_model(179–185 行):del model + gc.collect() + cuda.empty_cache() / mps.empty_cache()。
原因: 4B 基座 + 4B 基座+LoRA 同时驻留,16GB Mac 必爆。即使 32GB V100,顺序加载也更稳。
5. generate_reply 与训练的关键差异
1 | |
| 项 | 训练 (train_lora_single.py) |
验证 (本篇) |
|---|---|---|
| add_generation_prompt | False | True |
| enable_thinking | — | False |
| 目标 | 拟合整段 text | 生成新 token |
enable_thinking=False 漏设时,输出可能全为英文 Thinking Process(第 09 篇)。
6. Mac MPS 实测记录(项目真实输出)
环境:Mac mini · LoRA_Demo · .venv · mps + torch.float16
日志片段:
1 | |
与 flash-attn 警告(回退 torch 实现)同时出现,不影响生成。
6.1 样例 1:失眠 / 孤独
| 内容 | |
|---|---|
| user | 晚上睡不着 |
| LoRA | 夜里孤单最熬人了,我陪着您呢,您不用着急睡,咱们慢慢聊,聊困了再歇。 |
评价: 与训练集高频句式一致,共情 + 陪伴 + 不催促。✅
6.2 样例 2:健康焦虑(训练集外 phrasing)
| 内容 | |
|---|---|
| user | 我怕自己体检单不敢看,看了就睡不着。 |
| LoRA | 怕自己动不了、拖累别人,这种担心我特别理解。但咱们现在好好锻炼、好好保养……我陪着您。 |
评价: 情绪大类(健康焦虑 + 怕拖累)正确,但未精准复述「体检单」——模板化泛化,产品可接受,写文档勿夸大「句句定制」。⚠️
6.3 样例 3:自责 / 怕添麻烦
| 内容 | |
|---|---|
| user | 我有时候觉得,我不该再让他们为我请假。 |
| LoRA | 您太节省、太体谅孩子了……您该花就花、该吃就吃……就是给孩子最好的回报,我陪着您。 |
评价: 对齐「害怕添麻烦」类数据。✅
脚本结束语(218 行):
1 | |
7. 微调前 vs 微调后(预期差异)
完整对比需 **不加 --lora-only**,且 Mac 需足够内存加载基座一次。
| 维度 | 基座 Qwen3.5-4B | + LoRA |
|---|---|---|
| 开头 | 易「理解您的感受,建议…」 | 易「我懂 / 我特别理解…」 |
| 结构 | 建议列表 | 短句共情 + 陪伴 |
| 禁忌 | 可能出现「应该」 | 数据偏「我陪着您」 |
默认题 1(DEFAULT_QUESTIONS[0]):
1 | |
应用此题在 V100 或 Mac 上跑完整 verify_lora.py 截图,可作为文章配图。
8. 验证 rubric(可执行)
| 检查项 | 通过标准 |
|---|---|
| loss | 首尾下降(metrics 模式) |
| 共情 | 先接情绪,非直接方案 |
| 陪伴 | 出现「陪着您」「慢慢聊」类 |
| 不说教 | 无「您应该」「建议您」堆砌 |
| 泛化 | 训练集外 user 不整段复读 |
| 安全 | 无诊断、无承诺疗效 |
9. 踩坑
坑 1:Mac 上 device_map="auto" + PeftModel
脚本注释 102 行:会报错。必须 .to(device) 再挂 LoRA。
坑 2:SYSTEM_PROMPT 与 JSONL 不一致
验证通过但上线 vLLM 用另一套 system,用户感知「又变回说教」。
坑 3:--lora-only 当完整验证
只能证明 adapter 加载成功 + 风格像训练集,不能证明相对基座有提升。
坑 4:单次 generate 否定模型sampling 有随机性,同一题多跑 2–3 次或 temporarily do_sample=False 对比。
10. 小结
- verify_lora.py = metrics + 可选 A/B 生成。
- 顺序加载 + free_model 是显存关键。
- enable_thinking=False 与训练 template 差异必须掌握。
- Mac MPS 实测可行,适合本地冒烟。
- 健康类 user 可能套相近话术 — 诚实写进产品预期。
附录:extract_final_reply
1 | |
系列导航
| 篇目 | 链接 |
|---|---|
| 上一篇 | 07 · 训练曲线 |
| 下一篇 | 09 · Qwen3.5 踩坑 |
| 索引 | README |