先看 Boss:考古題背誦魔
你有沒有遇過這樣的同學:歷屆考古題背得滾瓜爛熟,題目一換就不會?考古題背誦魔就是這種模型。它在訓練資料上的 loss(損失,可以想成答錯的程度)一路降到接近 0,換一份沒看過的病歷,卻開始亂答。
這一關要完成你的第一次 fine-tune,同時學會看出牠什麼時候出現。
訓練任務與資料
任務很單純:輸入一份中英夾雜的合成病歷,輸出一個 PHI 清單 JSON(格式見 LV11)。遮蔽由程式執行。資料是你在 LV11 切好的 train.jsonl 與 valid.jsonl。
基底模型是 Gemma 4 E2B(Apache-2.0 授權)。截至 2026-10,本站在 Mac 使用 4-bit 的 MLX 版本,在 Colab 使用 Unsloth 的 Gemma 4 E2B。
🍎 Mac:mlx_lm lora
下面是作者實測 E1 使用的設定(M5、32GB、mlx-lm 0.32.0)。--model 等路徑請換成你自己的。
mlx_lm lora \
--model ./models/gemma-4-E2B-it-MLX-4bit \
--train \
--data ./data/sft \
--adapter-path ./adapters/chartkeeper \
--iters 100 \
--batch-size 4 \
--max-seq-length 2048 \
--learning-rate 1e-4 \
--mask-prompt \
--grad-checkpoint
逐個參數解釋:
mlx_lm lora:呼叫 mlx-lm 的 LoRA 訓練功能。--model:要微調的底座模型。這個是 4-bit 量化版,因此整個流程屬於 QLoRA。--train:告訴它要訓練(不加則不訓練)。--data:資料夾,裡面要有train.jsonl、valid.jsonl(需要時還有test.jsonl)。--adapter-path:訓練出的 LoRA adapter 存放處。adapter 只有幾 MB,原模型沒有被改動。--iters 100:訓練 100 次更新。每次看 4 筆,大約等於看了 400 筆次。資料量比這小時,同一筆資料會被重複看到。--batch-size 4:一次看 4 筆再更新。數字大,每步更穩,但吃更多記憶體。--max-seq-length 2048:每筆資料最多算 2048 個 token,超過的截掉。一份病歷加答案要能放進去,不然會被截斷。--learning-rate 1e-4:每次更新的步伐大小,1e-4 就是 0.0001。太大容易震盪、太小學得慢。--mask-prompt:只對回答的部分計算 loss,不對 system 與 user 的部分。因為我們要模型學的是「看到病歷後該輸出什麼」,不是去學怎麼複誦病歷。--grad-checkpoint:用時間換記憶體。只保留一部分中間計算結果,需要時重算。
作者在 M5 32GB 的實測。先看冒煙測試(FINDINGS E1,--iters 100,只用來確認流程跑得通,不是正式訓練):
- 可訓練參數 6.8M,占總參數 4,628M 的 0.147%。
- 100 次迭代用 1076 秒,約 18 分鐘,吞吐約每秒 60–66 個 token。
- peak memory footprint 為 14.8GB。
- 備註:訓練期間同時有網路下載,速度可能偏低。
正式訓練(公開資料集 v1.0,train 700 份,--iters 350,約 2 個 epoch,其餘參數同上):
- 總時間 3361 秒,約 56 分鐘(M5 32GB,同時沒有其他重負載)。
- peak memory footprint 為 15.3GB。
- val loss 由 0.564 降到 0.047(iter 50)、再到 0.015(iter 350),這 350 次迭代中沒有看到 val loss 回升。
- 提醒:val loss 很低只代表模型在驗證集上擬合得好;合成資料分布單純,仍需用 LV14 的 span recall 評估,不能只看 loss。
16GB Mac 的降配建議(【待實測】)
冒煙測試的 14.8GB、正式訓練的 15.3GB 在 32GB 機器上輕鬆,在 16GB 上餘裕很小,系統與其他程式也要用記憶體。方向是降低以下設定,但具體能否順利跑完【實測數據待補】:
--batch-size 1--num-layers 8(只在最後 8 層加 LoRA;mlx-lm 預設為 16 層)--max-seq-length 1024(先確認你的資料長度夠用,否則答案會被截掉)
建議關掉其他大型程式後再試,若出現記憶體錯誤,再往下調。
☁️ Colab:Unsloth
本站改寫的 notebook 對應如下,打開後由上往下逐格執行(Runtime 選 T4 GPU):
FastModel.from_pretrained("unsloth/gemma-4-E2B-it", max_seq_length=2048, load_in_4bit=False):載入模型。T4 若出現 CUDA out of memory,把load_in_4bit改成True。FastModel.get_peft_model(..., r=16, lora_alpha=16, ...):加上 LoRA adapter。這裡只訓練語言層,關閉視覺層。SFTTrainer與SFTConfig:批次大小 2、gradient accumulation 4(等效 batch 8)、2 個 epoch、learning rate 1e-4。train_on_responses_only(trainer):和 Mac 的--mask-prompt目的相同,只對回答計 loss。- 每個 epoch 結束會在 valid 集上算一次 loss(
eval_strategy="epoch")。
Colab 免費 T4 實測(2026-10,Unsloth 2026.10.1):
- Unsloth 會提示 Gemma 4 在 T4 改用 float32(T4 無 bf16),模型在訓練前就佔約 10.3GB。
- 可訓練參數 25.3M(0.49%);176 steps(2 epochs)訓練 1419 秒(23.7 分鐘);peak reserved 11.41GB(78%)。
- 推論很慢:逐份生成下 base 約 45 秒/份、LoRA 約 25 秒/份,所以 notebook 預設只評估 20 份(
EVAL_LIMIT = 20),全測 200 份需數小時。
評估結果(test 前 20 份):
| span recall(95% CI) | valid JSON | precision | |
|---|---|---|---|
| base(float32) | 0.837(0.692–0.942) | 90% | 0.958 |
| + LoRA | 1.000(1.000–1.000) | 100% | 1.000 |
解讀時要注意:
- 樣本只有 20 份,與 Mac 的 200 份結果不可直接比較。
- LoRA 的 CI 為 1.000–1.000,是因為 20 份全部答對、bootstrap 沒有變異,不代表真實表現完美;在合成資料上的小樣本結果,不能推論到真實病歷。
- Colab 未量化的 base(0.837)遠好於 Mac 的 4-bit base,可能與量化或推論框架差異有關,但原因未驗證,樣本也不同。
看 loss 曲線
訓練時,終端機或 notebook 會印出 train loss 與 valid loss。把它們畫成曲線:
| 現象 | 解讀 | 常見處理 |
|---|---|---|
| train 與 valid 都下降並趨於平穩 | 正常學習 | 可停止 |
| train 持續下降,valid 下降後轉為上升 | overfitting(考古題背誦魔) | 提早停止、減少 epoch、增加資料多樣性、降低 rank |
| 兩者都降不下去 | under-fitting 或資料有問題 | 檢查格式與 mask、調整 learning rate |
| loss 上下劇烈震盪 | learning rate 可能太大 | 降低 learning rate |
兩個提醒:
- 合成資料很容易 overfit,因為句型單純。這是為什麼 LV11 要以骨架切分,這樣 valid loss 才有參考價值。
- loss 低不等於好用。loss 只是語言模型的猜字誤差,能不能找出 PHI,要看下一關的評估指標。
本關重點
- 設定:
--mask-prompt讓 loss 只計回答;--grad-checkpoint用時間換記憶體;batch 與 max seq 決定記憶體用量。 - 作者實測(M5 32GB、Gemma 4 E2B 4-bit):100 iter 約 18 分鐘、峰值 14.8GB、可訓練參數 0.147%。
- 16GB Mac 的降配設定只是方向,本站標示【待實測】;Colab T4 實測訓練約 24 分鐘、peak 11.41GB(見上)。
- 看曲線:train 降、valid 升 = overfitting,也就是考古題背誦魔。
- loss 低只代表擬合訓練資料,要用獨立 test 集與評估指標才能說有沒有學會。