文件導航

在你自己的決策上微調 Laya

在 typed-decisions 基準上,基礎 checkpoint 零樣本的得分接近隨機 —— 0.36 和 0.35,對 0.318 的 隨機基線而言 —— 而微調後的 checkpoint 在同一批 2,000 個決策上達到 0.766,高於 TypeSafe Jev 已釋出的 0.727,也高於 0.735 的教師自一致上限。微調承載了大部分價值,公開的 微調 notebook 在 Kaggle 免費的 2xT4 GPU 上跑完整個迴圈:構建資料集、用 RLCD 訓練、擬合校準溫度、評估,並把 結果推到 Hub。這一頁講解那個 notebook,並指出當資料換成你自己的之後,哪些部分仍然關鍵。

另一個完整示例 —— 在單張 16 GB GPU、不花錢調 API 的情況下訓練一個瀏覽器智慧體決策頭 —— 在 把 Laya 微調成瀏覽器智慧體決策頭。

notebook 按順序做了什麼

# 步驟 發生的事
1 環境 斷言兩張 T4 GPU 都可見且已分配
2 安裝 laya、transformers、datasets 以及訓練依賴
3 預處理 1,200 個訓練用例(6,000 個型別化決策)變成帶軟目標的 tokenized 條目,寫成磁碟檔案供兩個 DDP rank 使用
4 訓練 在 torchrun --nproc_per_node=2 下跑 train_ddp.py,四個 epoch
5 校準 每種型別一個溫度,在訓練前就留出的切片上擬合(在訓練指令碼內部,最後一個 epoch 之後)
6 評估 微調後的 checkpoint 回答官方 test 劃分 —— 400 個用例、2,000 個決策 —— 並給出每用例延遲
7 指標 準確率、軟準確率、Brier、ECE、score MAE、檔位內一位、KL/TV 和延遲分位數;一張與 Jev 和教師上限正面比較的表
8 釋出 (可選)用這次執行自己的數字生成一張模型卡,把資料夾上傳到 Hub
9 報告 benchmark_report.json,含指標表和各工作流的準確率

Kaggle 設定:Accelerator 選 GPU T4 x2,Internet 設 On。輸出落在 /kaggle/working/laya_finetuned_typed_decisions。

訓練配方

RLCD 在基準的金標分佈上訓練,而不是在硬標籤上:每個條目都帶上教師給每個選項分配的機率, 損失的兩半都讀這個目標 ——

  • 一個策略梯度項,作用在取樣得到的帶噪 logit 投影上(GRPO 風格:每個條目四個樣本,探索 噪聲從 0.4 退火到 0.1),由適當的評分規則給獎勵(球面 0.75,排序機率 1.0);
  • 一個全權重的軟交叉熵項,對著同一個分佈。

notebook 為 16 GB 顯示卡設定的旋鈕:

epochs 4
有效批大小 64 個序列(每微批 8 個,2 張 GPU,4 步累積)
學習率 encoder 2.5e-5,head 1e-4 —— AdamW,餘弦排程
記憶體 fp16 autocast,encoder 和 head 上開梯度 checkpointing,梯度範數裁剪 1.0
序列預算 max_len 1024,head_max_len 256,max_tokens_per_batch 4096

2xT4 上的執行時間,演示是分鐘級,真實資料是小時級:演示的 6,000 個決策大約 4–6 分鐘,而對約 30k 個問題跑四個 epoch 大約 4–5 小時。

要把它指向你的資料,替換那兩個 load_dataset 呼叫,並保持行 schema:每個用例帶 state、 questions 和 gold(教師對每個問題給出的機率),前處理器把它們變成條目。問題型別是 choice、score 和 noul;任何你能用它們對某個狀態表達出來的東西都可以。

校準是這次執行的一部分

這是照搬迴圈時最容易被丟掉的一步,而一旦有人用置信度做門控,它就是關鍵。

notebook 在把訓練資料分片到各個 rank 之前,先切出一份校準切片(最多 400 個條目,或 10%, 固定種子,每個 rank 上完全一樣)。在執行已經訓練過的條目上擬合溫度,測的是擬合本身而不是校準 —— 模型在那些條目上幾乎必然正確,最佳化器沒有什麼需要軟化,於是返回一個退化的 scale。

最後一個 epoch 之後,rank 0 用 LBFGS 在 log 溫度上擬合每種問題型別一個溫度(choice、 score、noul),鉗制在 [0.1, 10](切片不足十個條目時為 1.0,擬合拋異常時為 1.2)。 這些值作為 temperature 寫進 rl_agent_config.json,notebook 在同一次寫入裡移除任何繼承來的 temperature_by_options:那些舊的分桶值在推理時優先,會靜默蓋掉新的擬合。

溫度縮放不改變 argmax —— 也不改變準確率;變的是置信度。checkpoint 按交付狀態是過度自信的, 所以依賴任何閾值之前先擬合,並在留出資料上評估結果,再聲稱有改進。配置持久化的迴歸測試不需要 下載或訓練就能跑:

python tests/test_calibration_persistence.py

信任它之前先評估

評估是對官方測試劃分的一次完整遍歷:400 個用例、2,000 個決策,橫跨 Agent Trace Observability、Customer Service、Invoice Processing 和 Security Incidents。它計算準確率、軟 準確率、Brier、ECE(通過 laya.common.ece_score)、score MAE、檔位內一位和延遲分位數,然後 構建一張正面比較表,其中的參考行是固定的:

model kind accuracy ECE
TypeSafe Jev 1.13.0 general 0.727 0.144
ModernBERT-base (149M) specialist 0.646 0.179
Teacher Self-Agreement ceiling 0.735 —
Laya (published checkpoint) fine-tuned 0.766 —

你自己執行裡的 Laya 行也以同樣方式計算 —— notebook 用這次執行自己的數字重建那張表。兩個值得 照搬的習慣:把你關心的切片(一種語言、一個工作流)留在留出資料裡,並把校準和準確率一起報告, 因為訓練訊號是一個分佈,而不只是一個標籤。等你有了數字,倉庫的 Discussions 是分享它們的地方;基準和已知 限制在倉庫根目錄的 BENCHMARKS.md 裡。

推到 Hub

釋出那一格是迴圈的最後一公里,它刻意做得無聊:

  1. 在 Kaggle 裡放一個可寫的 HF_TOKEN(Add-ons → Secrets)。缺了它那一格會丟擲錯誤,並給出 確切的指示。
  2. 設定目標倉庫 —— 交付的那一格預設用專案自己名稱空間裡的一個名字,所以執行前先改掉它。
  3. 執行它。它寫出一張模型卡,卡上的數字來自這次執行的對比表,然後上傳 model.safetensors、 encoder/、tokenizer/、rl_agent_config.json、那張卡和基準報告。

結果載入起來和任何其他 checkpoint 一樣 —— 沒有微調專用的 API:

import laya

agent = laya.load("your-org/your-checkpoint")   # the repo you just pushed
result = agent.predict(state, questions)

一個滾動更新的 checkpoint_latest/ 在每個 epoch 後會被覆蓋,所以 Kaggle 超時或 OOM 的代價是 一個 epoch,而不是整次執行。

要當心什麼

  • 迴圈的好壞取決於目標。 RLCD 在你的問題上模仿教師的分佈;訓練前(或訓練的同時)收集教師 置信度,並把它們的質量當作上限。
  • 校準切片小是故意的。 最多 400 個條目或 10% —— 夠擬合三個按型別的標量,不夠用來驗證。 自己留出一份評估資料。
  • 你的標籤必須能放進三種原語。 如果你的決策不是 choice、不是量表、也不是是非機率,先把 它塑造成其中一種。兩個尖銳的邊緣已經有記錄:選項多會削弱置信度的選擇 (#394),強制選擇的否定可能跟著問題走 而不是跟著狀態走(#377)。
  • 要交付配置,不只是權重。 被移除的 temperature_by_options 就是那種如果在一個照搬的配置 裡存活下來、就會靜默讓校準失效的東西。