5.11 节实验:用“默认输出 → 改过的版本”配对给小模型训 LoRA,和少样本提示基线对比并做盲评
| 文件 / 目录 | 说明 | 大小 |
|---|---|---|
| 📁 ../ | 返回上级目录 | - |
| 📁 data/ | 子目录 | - |
| 📁 sample_output/ | 子目录 | - |
| 📄 README.md | 6.5 KB | |
| 📄 common.py | 1.2 KB | |
| 📄 evaluate.py | 8.9 KB | |
| 📄 make_demo_data.py | 4.0 KB | |
| 📄 requirements-cuda.txt | 54 B | |
| 📄 requirements-mac.txt | 20 B | |
| 📄 train_mlx.py | 2.4 KB | |
| 📄 train_peft.py | 4.7 KB |
这份代码回答一个问题:模型默认写出来的东西,你每次都要改成自己的样子;把这些“默认输出 → 你改过的版本”攒成配对,拿来给一个小模型训 LoRA,它能不能学会你的改法,又该怎么判断它学会了没有。
整个配方分三步:
ai)和你改过的版本(original)。train_mlx.py),NVIDIA 显卡上用 PEFT(train_peft.py)。底座模型不动,只训练一小组附加权重,存下来几十 MB。evaluate.py):和“不训练、把几组例子直接写进上下文”的基线比,看谁更接近你改过的版本;生成一份 A/B 顺序打乱的盲评表让你自己判断;可选地再请一个 API 模型盲评,并检查有没有改动原意。data/ 里有一份现成的示例数据,用的是 5.11 文风 LoRA 那种“反向合成”做法:拿一位作者的原文,让大模型用它默认的写法把每段改写一遍,得到“AI 默认写法 → 作者原文”的配对。作者选了鲁迅(《朝花夕拾》和《呐喊》的 23 篇,已进入公有领域,原文取自维基文库并转成简体),默认写法由 AI Builder Space 上的 deepseek 生成。训练 455 对、验证 20 对、留出测试 20 对。生成过程见 make_demo_data.py,你不需要重跑。
--model Qwen/Qwen3-0.6B。--judge 盲评要用 AI Builder Space 的 key。
Mac:
cd 5_11_lora
uv venv && source .venv/bin/activate # 没有 uv 就用 python3 -m venv .venv
uv pip install -r requirements-mac.txt
python train_mlx.py # 约 3 分钟(M3 Ultra),LoRA 存到 adapters/mlx/
python evaluate.py --backend mlx # 生成留出例子的三种版本、相似度和盲评表
export AI_BUILDER_TOKEN=sk_你的key
python evaluate.py --backend mlx --judge gpt-5 # 另外请 gpt-5 盲评一遍
NVIDIA 显卡:
uv pip install -r requirements-cuda.txt
python train_peft.py # LoRA 存到 adapters/peft/
python evaluate.py --backend torch
为什么用 Qwen3 而不是模块 5 其他地方用的 Qwen3.5:Qwen3.5 的一部分层是线性注意力,目前在 MLX 上训练很慢(我们测到每秒 42–53 个 token,Qwen3-1.7B 约 600),还遇到过一次 macOS 报 GPU 卡死而中断。
我们的样例输出在 sample_output/(2026-10-23):训练日志、评估结果、盲评表和答案。
Mac Studio(M3 Ultra,MLX)上:验证集损失从 2.46 降到最低 0.51(第 200 步),训完 450 步是 0.55。留出的 20 条上:
| 与原文的逐字相似度 | 与默认输出的相似度(越低改得越多) | 比不改更接近原文的条数 | |
|---|---|---|---|
| 默认输出本身(不改) | 0.895 | 1.000 | — |
| 基线:3 组例子写进上下文,不训练 | 0.785 | 0.875 | 0/20 |
| LoRA | 0.892 | 0.970 | 8/20 |
一张 RTX 5090 上用 PEFT 训同一份数据(2 遍,134 秒),验证集损失从 2.19 降到 0.50。留出的 20 条上,与原文相似度:默认输出 0.895,基线 0.797,LoRA 0.892;LoRA 与默认输出的相似度 0.976,比不改更接近原文的有 5/20 条,逐条比基线更接近原文 16/20。gpt-5 盲评判 LoRA 更接近原文写法 18/20,判为改动了原意 LoRA 6/20、基线 11/20。
PEFT 这一版改得比 MLX 那一版更保守(“伊”一次也没出现)。主要原因是 LoRA 的缩放系数不同:train_peft.py 用的是常见的 lora_alpha = 2 × rank,相当于缩放 2;mlx-lm 默认的缩放是 20。想让 PEFT 改得更大胆,可以在 train_peft.py 里把 lora_alpha 调大,或者多训几遍。
这张表要和下面两样一起看才说得清:
字面相似度在这份数据上不太敏感,因为默认输出本来就接近原文;真正的判断要靠盲评。换成你自己的数据时也一样:先自己做一遍盲评表,再看数字。
把你的配对写成三个文件,放在一个目录里(例如 my_data/),每行一个 JSON:
{"ai": "模型默认写出来的一段", "original": "你改过的版本"}
pairs_train.jsonl:训练用,几百对比较合适,少于一百对效果很难看出来;pairs_valid.jsonl:训练时看损失用,十几二十对;pairs_test.jsonl:评估用,十几二十对,不能和训练集重复。然后:
python train_mlx.py --data my_data # 或 train_peft.py --data my_data
python evaluate.py --backend mlx --data my_data --markers "你常用的词1,你常用的词2"
配对从哪来:最直接的是把你平时改过的稿子攒下来,一边是模型给你的初稿,一边是你最后发出去的版本。攒不到那么多,可以学示例数据的做法:拿你自己写过的东西,让模型用它的默认写法改写一遍,配成“模型写法 → 你的原文”。提示格式(common.py 的 INSTRUCTION)在训练和推理时必须一致,要改就两边一起改。
盲评表在 results/ 下的 *_blind.md,答案在同名的 *_key.json。先自己选完再看答案。