800 条样本跑了 10 个 epoch,训练 loss 从 1.8 一路降到 0.3,验证 loss 在第 4 个 epoch 之后掉头向上,上线测试时模型开始一字不差地背训练集里的原句。

一开始怀疑是「默认学习率对中小数据集偏高,几步就越过最优点」,查了一圈,方向不对。

原因不止一个,得分开看。样本量偏小的时候 epoch 越多越容易记住原句而不是规律。还有一种是验证集和训练集同源,指标好看但泛化能力差。

另外,训练集里重复样本多,等效样本数比文件行数少。

上来先把每个 step 的 train_loss 与 valid_loss 拉出来

curl -s https://api.openai.com/v1/fine_tuning/jobs/ftjob_abc/events -H "Authorization: Bearer $OPENAI_API_KEY" | jq -r '.data[]|"\(.data.step) \(.data.train_loss) \(.data.valid_loss)"'

然后用 3 个 epoch 重训一版做对照

curl https://api.openai.com/v1/fine_tuning/jobs -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","training_file":"file-abc","validation_file":"file-val","hyperparameters":{"n_epochs":3}}'

固定一批留出问题做盲测

python eval_compare.py --questions holdout.jsonl --models ft:v1,ft:v2

末了统计训练集重复率再决定数据量

python -c "import hashlib;ls=[hashlib.md5(l.encode()).hexdigest() for l in open('train.jsonl') if l.strip()];print(len(ls),len(set(ls)))"

别只看报错消失,验证要多做一步。3 个 epoch 的版本 valid_loss 最低点更低且不回升,留出集准确率高于 10 个 epoch 那版,抽样回答不再出现训练原句。

valid_loss 掉头就是最直接的停止信号,别拿训练 loss 当效果指标,样本不到一千条时 3 到 4 个 epoch 通常已经够用。这类问题最好一次改到位,反复小改反而容易把原因搅混。

作者 9823189