模型訓練的配置與路由
model_training 塊的每個鍵,執行如何排隊、打分和儲存,管理員與代理路由,以及常見執行錯誤的修復方法。
v2.14.0 新增
本頁是 Potato 配置中 model_training 塊的參考,也說明執行啟動之後會發生什麼。本頁寫給負責執行研究的人,他們想要限制執行、把執行傳送到另一臺機器、向標註者展示模型的預測,或從腳本里啟動訓練。下面的每個鍵、預設值、路由和訊息都對照 Potato 的程式碼核對過。第一次執行請從訓練你的第一個模型開始。訓練器及其參數列在訓練器裡。
完整配置
下面的配置在商品評論上訓練一個情感分類器。auto_retrain 在每 25 條新標註之後重新擬合 sklearn-text。使用預設的 TF-IDF 特徵時,sklearn-text 在 CPU 上訓練,只需要普通的 Potato 安裝,因此頻繁的自動執行開銷很小。回寫會向標註者展示每個置信度至少為 0.8 的預測。設定了 include_unlabeled 後,執行還會對無人標註的評論做預測。hf-text-classification 的預設值和 gpu-server 後端用於從訓練頁面手動啟動的執行:
annotation_task_name: "Review sentiment with model training"
task_dir: "."
data_files:
- "data/reviews.json"
item_properties:
id_key: "id"
text_key: "text"
output_annotation_dir: "annotation_output"
user_config:
allow_all_users: true
annotation_schemes:
- annotation_type: "radio"
name: "sentiment"
description: "Is this review positive or negative?"
labels: ["positive", "negative"]
model_training:
enabled: true
split_seed: 0
splits: {train: 0.7, val: 0.15, test: 0.15}
aggregation: consensus
retain_runs: 5
queue_max: 10
max_wall_seconds: 3600
max_ram_mb: 8192
num_threads: 4
trainer_params:
sklearn-text:
classifier: sklearn.linear_model.LogisticRegression
classifier_kwargs: {max_iter: 1000}
hf-text-classification:
model_name: answerdotai/ModernBERT-base
epochs: 4
lora: true
auto_retrain:
enabled: true
trainer: sklearn-text
schemas: [sentiment]
min_interval_s: 600
update_frequency: 25
writeback:
schemas: [sentiment]
min_confidence: 0.8
include_unlabeled: true
backends:
gpu-server:
type: ssh
host: gpu-server
python: /opt/conda/bin/python3
gpus: auto
min_free_gpu_mb: 4000在研究的整個生命週期裡,請保持 split_seed 不變。換一個種子會重新分配每個條目,原本留出的條目會進入訓練,之後的得分就無法與之前的得分比較。min_confidence 下限 0.8 只是一個起點,合適的下限取決於第一次留出得分。等這個得分足以支撐展示預標籤之後,再開啟 include_unlabeled,因為預標籤會把標註者錨定在模型的答案上。
model_training 中的鍵
每個鍵都位於 model_training 之下:
| 鍵 | 預設值 | 含義 |
|---|---|---|
enabled | false | 註冊訓練頁面、/admin/training 下的路由和 /api/training 下的代理路由。沒有 enabled: true,這些路由就不存在。 |
retain_runs | 5 | 在運行臺賬中保留的已完成執行數。較早的執行會離開臺賬,除非它的預測仍被儲存。執行目錄仍留在磁碟上。 |
grace_seconds | 20 | 已取消的執行在 Potato 殺掉程序之前獲得的退出秒數。0 或更大,並隨作業傳送給類型為 ssh、slurm 和 agent 的後端。 |
queue_max | 10 | 可以在進行中的執行後面等待的執行數。 |
split_seed | 0 | 把條目分配到 train、val 和 test 劃分的種子。 |
splits | {train: 0.7, val: 0.15, test: 0.15} | 各劃分的比例,會歸一化到總和為 1。名稱為 train、val 和 test,train 必須有。 |
aggregation | consensus | 多位標註者在一個條目上的標籤如何變成一個標籤。研究有多於一位標註者時,consensus 擬合 Dawid-Skene 模型,擬合失敗時退回多數投票。majority 取多數投票。 |
max_wall_seconds | 未設定 | 一次執行的時間上限。Potato 在本地執行每次報告事件時檢查,對 ssh 或代理執行則每秒檢查一次。 |
max_ram_mb | 未設定 | 訓練程序的地址空間上限,用 setrlimit 設定。在不支援該限制的平臺上,執行會記錄一條警告並繼續。 |
device | auto | auto、cpu、cuda、cuda:N 或 mps。auto 先選 CUDA,再選 Apple 的 Metal,最後選 CPU。 |
num_threads | 未設定 | 為這次執行設定 OMP_NUM_THREADS、MKL_NUM_THREADS 和 OPENBLAS_NUM_THREADS,除非環境已經設定了這些變數。 |
auto_retrain | 關 | 隨標註到來而重新訓練。見 auto_retrain。 |
writeback | 無 | 把預測釋出為預標籤。見 writeback。 |
backend | local | 未指定其他後端的執行所用的後端。 |
backends | 無 | 具名的 ssh、slurm 和 agent 後端。見後端。 |
max_predictions_mb | 512 | 遠端代理可以上傳的 predictions.jsonl 的最大體積。 |
trainer_params | 無 | 參數預設值,以訓練器名稱為鍵。 |
tiling | enabled: auto | 為檢測和分割訓練器把大影像切成圖塊。見 tiling。 |
一次執行自己的 params 覆蓋 trainer_params,後者又覆蓋訓練器的預設值。訓練器不接受的參數名,如果寫在 trainer_params 下,會在伺服器啟動時被拒絕,其他情況下則在執行啟動時被拒絕。訓練器用一個例子給出這個順序。
auto_retrain
自動重新訓練在每次儲存標註之後檢查是否需要新的執行:
| 鍵 | 預設值 | 含義 |
|---|---|---|
enabled | false | 開啟檢查。 |
trainer | 無 | 訓練器名稱。必填。 |
schemas | 無 | 要訓練的方案。必填。 |
min_interval_s | 600 | 自上次執行結束後經過多少秒才會啟動另一次執行。 |
update_frequency | 25 | 自上次自動執行以來要收到多少條新標註才會啟動另一次執行。 |
params | {} | 訓練器參數,與 API 執行的 params 相同。 |
backend | model_training.backend | 自動執行所用的後端。 |
accept_licence | false | 確認需要確認許可證的訓練器的許可證(ultralytics-detect、ultralytics-segment、layoutlmv3)。沒有這個確認,這些訓練器的自動執行會被跳過。 |
當某次檢查決定不執行時,原因會出現在 GET /admin/training/api/status 的 skip_reason 欄位裡,例如“waiting for 3 more annotation(s)”或“a run is already in progress”。自動執行從不加入執行佇列。佇列清空之後儲存的下一條標註會再次檢查,此時有更多標註可供訓練。Potato 把標註計數儲存在記憶體裡,因此重啟後,曾經訓練過的項目從重啟時開始統計新標註。
writeback
回寫決定標註者能看到哪些預測:
| 鍵 | 預設值 | 含義 |
|---|---|---|
schemas | [] | 其預測會被標註者看到的方案。空列表表示一個也不顯示。 |
min_confidence | 0.0 | 低於下限的預測會被儲存但不顯示。沒有置信度的預測可以通過。 |
field | predictions | 預標籤寫入的條目欄位。 |
include_unlabeled | false | 同時對無人標註的條目做預測,並給這些條目打上預標籤。沒有 include_unlabeled 時,執行只在自己的 val 和 test 條目上做預測。 |
tiling
檢測和分割訓練器把每幅影像縮放到幾百畫素。在這個尺寸下,全玻片影像或衛星場景上的目標會丟失。因此對於 image_annotation、microscopy 或 geo_annotation 方案,Potato 在構建這次執行的訓練資料時,會把每幅大影像切成圖塊。影像屬於哪個劃分,是在切塊之前決定的,所以同一張玻片的圖塊不會落入兩個劃分。預測會映射回整幅影像,留出得分在整幅影像上計算。視覺教程介紹玻片和地圖的實際操作。
| 鍵 | 預設值 | 含義 |
|---|---|---|
enabled | auto | auto 對玻片格式(.svs、.ndpi、.mrxs、.scn 等)和較長邊至少為 auto_min_side 的影像切塊。true 對每幅影像切塊,false 一幅也不切。 |
auto_min_side | 4096 | auto 開始對影像切塊的較長邊長度,單位為畫素。 |
tile_size | 1024 | 圖塊的邊長,單位是訓練器看到的畫素。 |
overlap | 128 | 相鄰圖塊共享的畫素數,最多為 tile_size 的一半。重疊至少要與目標一樣大,否則大目標會被分成幾塊找到。 |
downsample | 1 | 每個圖塊畫素對應的全解析度畫素數。 |
mpp | 無 | 每個圖塊畫素對應的微米數。對記錄了自身解析度的玻片,它會覆蓋 downsample。 |
background | 0.25 | 每個含目標的圖塊對應取樣的空圖塊數。對只標註了一部分的玻片,請設定 background: 0。 |
max_predict_tiles | 2000 | 每幅影像最多預測的圖塊數。保留組織最多的圖塊。 |
min_visible | 0.4 | 目標必須有多大比例落在圖塊內,才會在該圖塊裡用於訓練。 |
tissue_threshold | 0.05 | 玻片圖塊中必須有多大比例是組織,模型才會在該圖塊上做預測。 |
玻片由 openslide 讀取,它通過 pip install "potato-annotation[wsi]" 安裝,安裝在構建訓練資料的機器上。遠端後端下載的是圖塊,從不下載玻片。
執行佇列
同一時間只執行一次執行。在另一次執行進行時從訓練頁面或 API 啟動的執行會等待,而不是被拒絕。啟動請求返回 202,帶有 queued: true 和這次執行的 position,Runs 表把這次執行列為 waiting #N,並帶有 Cancel run 按鈕。進行中的執行結束後,最早等待的執行開始。
等待中的執行是運行臺賬裡的記錄,所以佇列在重啟後依然存在,伺服器回來時第一個等待中的執行會啟動。上一個伺服器正在進行的執行,同時被標記為 interrupted。等待中的執行的訓練資料在這次執行開始時才構建,所以它用的是那一刻已有的標註。本該被拒絕的啟動,例如指定了未知方案的啟動,會立即被拒絕,而不是等輪到它時才拒絕。如果一次執行的方案或訓練器在它等待期間從配置裡消失,它會以 invalid_when_dequeued 失敗,隨後下一次執行開始。
在請求體裡傳送 "queue": false,就會得到 409,而不是排進佇列。已經有 queue_max 個執行在等待時,新的啟動會得到 429。GET /admin/training/api/status 在 queue 下按順序列出等待中的執行。
執行前的檢查
potato validate 一次報告 model_training 塊裡的所有問題,伺服器遇到同樣的問題也會拒絕啟動:
potato validate config.yaml --strict這些檢查涵蓋以下情形:
splits的名稱不是train、val和test,比例小於 0 或不是數字,比例總和為 0,或沒有train。writeback或auto_retrain沒有的鍵,不是方案的writeback.schemas條目,或 0 到 1 之外的min_confidence。accept_license會被報告為accept_licence的拼寫錯誤。- 已啟用的
pre_annotation塊的field與writeback.field不同。這樣的塊之下不會顯示任何訓練預標籤。 - 在
auto_retrain.enabled下,不存在的訓練器或方案,訓練器無法學習的方案,訓練器不接受或類型錯誤的參數,backends裡沒有的backend,或local之外的後端上的decision-calibrate。 trainer_params下訓練器不接受的參數,或類型錯誤的參數。在dp之內,檢查還覆蓋每個鍵以及該鍵的取值範圍。- 小於 0 或不是數字的
grace_seconds,或小於 0 或不是整數的retain_runs或split_seed。 - 在
backends下,缺失或未知的type,該類型沒有的鍵,沒有host的 ssh 後端,auto、none或 GPU 編號之外的gpus值,名為local的遠端後端,或未定義的model_training.backend。
potato training check 在執行使用某個後端之前測試這個後端。對 local,該命令列印執行會使用的裝置,例如在 Apple 晶片的 Mac 上是 local: this machine, Apple Metal (mps)。對 ssh 後端,該命令報告 Python 版本、每塊 GPU 及其空閒視訊記憶體、執行會分到的 GPU,以及遠端直譯器缺少的訓練包。訓練頁面上的 Check 按鈕運行同樣的測試,--json 以 JSON 列印報告:
potato training check local config.yaml
potato training check gpu-server config.yaml從訓練頁面或 API 啟動的執行,在執行開始時會再檢查一次。狀態碼列在路由之下。
後端
執行在一個後端上執行,訓練頁面的 Runs on 選單列出已配置的後端。model_training.backend 設定預設值,API 執行或 auto_retrain 可以用 backend 指定另一個後端。Potato 有四種後端類型:
| 類型 | 訓練器在哪裡執行 | 誰啟動訓練器 |
|---|---|---|
local | 這臺機器,以子程序執行。始終可用,是預設值。 | Potato |
ssh | Potato 能通過 ssh 連上的另一臺機器,例如 GPU 伺服器。 | Potato,通過 ssh |
slurm | 叢集的計算節點,作為批處理作業。 | Potato,先 ssh 到登入節點,再用 sbatch |
agent | Potato 連不上的機器,例如 NAT 後面的工作站。 | 人,用 potato training agent |
ssh 後端使用金鑰認證,並開啟 BatchMode,因此密碼提示會直接失敗而不是掛起。slurm 後端只使用 sbatch、squeue 和 scancel,在提供 scontrol 的叢集上還會使用 scontrol,並且需要計算節點共享的儲存上的 remote_dir。agent 後端不需要入站埠,因為每個連線都由代理發起。local 這個名稱保留給這臺機器,decision-calibrate 只在 local 上執行。在 GPU 伺服器、SLURM 叢集或 NAT 後的機器上訓練逐一演示這三種遠端類型及其鍵。
留出得分
每次執行都在 val 和 test 條目上,對照合併後的人工標籤,給這次執行自己的預測打分。指標名帶有劃分,例如 val_macro_f1 或 test_f1。有標籤而沒有預測的條目算作錯誤,因此丟掉難條目無法抬高訓練器的得分。<split>_coverage 報告得到預測的條目所佔的比例。
主得分顯示在 Runs 表的 Held-out score 列裡,提示框裡帶有劃分和指標。主得分是第一個方案的主指標,取自 val 和 test 中第一個有條目的劃分。當訓練器按 val 得分挑選了最佳檢查點時,Potato 優先嚐試 test,因為訓練器已經見過 val 得分。保留最佳 epoch 的微調訓練器,例如 hf-text-classification、torchvision-detect 和 llm-sft,主得分取自 test。sklearn-text、setfit、rdkit-property、決策模型訓練器和推理橋不在 val 上做任何選擇,這些訓練器的執行只要 val 有條目,主得分就取自 val。沒有 val 或 test 條目的執行顯示為“not scored”。
主指標取決於方案的標註類型,下表列出常見類型:
| 標註類型 | 主指標 |
|---|---|
radio, select, likert | macro-F1(另有準確率,數值型 likert 標籤另有平均絕對誤差) |
multiselect | micro-F1(另有 macro-F1 和完全匹配) |
span | 起點、終點和標籤都匹配的跨度上的 F1 |
text | token F1(另有完全匹配) |
binary 模式下的 pairwise | 在未作為平局回答的條目上的準確率 |
ranking | Kendall's tau |
image_annotation, microscopy, geo_annotation | IoU 0.5 下的 COCO mAP(map_50),同時記錄 map_50_95 |
audio_annotation | IoU 至少 0.5 且標籤相同的片段上的 F1 |
speech_transcript | word_accuracy,即 1 減去詞錯誤率 |
volume_annotation | mean_dice |
token F1 會給用詞正確但順序錯誤的答案記分,所以請把 token F1 與完全匹配一起看。檢測的主指標用 IoU 0.5,而不是 0.5 到 0.95 的平均,因為兩位標註者給同一目標畫的框很少在 IoU 0.9 上重合。上游留出得分表列出每種標註類型的指標。
回寫
一次執行成功之後,Potato 儲存這次執行的預測,並把通過四項檢查的預測寫入每個條目的 predictions 欄位,或 writeback.field 指定的欄位。這些檢查按以下順序進行,執行的回寫報告會統計每一項跳過了多少:
- train 劃分的條目永遠不會被打預標籤。 這項檢查覆蓋臺賬中仍保留的每次執行的 train 劃分,較早一次執行留在某個條目上的預標籤,在後來的執行用這個條目訓練時會被撤下。
- 只發布
writeback.schemas裡的方案。 列表預設為空,所以開啟訓練不會改變標註者看到的任何內容。 - 被拒絕的配對會被跳過。 在模型稽核中得到
reject判定的條目與方案配對不會再次顯示。 - 應用置信度下限。 低於
min_confidence的預測會被儲存但不釋出。
回寫從不改動人工標籤,因為預測進入條目資料,而標註儲存在每位標註者的使用者狀態裡。預標籤顯示為標註者可以編輯的預填答案,例如選擇題顯示為選中的選項,自由文本答案顯示在方案的文本框裡,並且不需要 pre_annotation 塊。只有當標註者編輯了預標籤或轉到下一個條目時,預標籤才會成為標註者的答案。因此沒人編輯過、也沒人越過的預標籤永遠不會變成訓練標籤。被 ai_support.holdout 放進研究的無輔助對照組的標註者與條目配對不顯示預標籤,為這個配對傳送的條目資料也同時去掉 writeback.field 和 pre_annotation.field。回寫報告是 GET /admin/training/api/status 的 writeback 欄位,報告的 summary 會說明一次執行為什麼什麼也沒釋出。
Potato 為每個條目和方案只保留一個預測,較新執行的預測會替換較早執行的預測。當較新的預測被儲存卻不顯示,原因是它低於 min_confidence、為空或已被拒絕時,較早執行的預標籤會立即從條目上撤下,回寫報告會把這個條目計入 n_superseded_cleared。隨資料一起提供的預標籤不受影響。啟動時,writeback.schemas 裡各方案已儲存的預測會按同樣的四項檢查寫回條目資料,所以預標籤能在重啟後保留。要撤回一次執行的預標籤,請傳送 DELETE /admin/training/api/runs/<run_id>/predictions。該請求會移除儲存的預測,並把預標籤從條目上撤下。
修正過的條目和固定的條目始終參與訓練
兩類條目會進入之後每次執行的 train 劃分,無論它們在穩定劃分中的位置如何:
- 稽核者修正過的條目。 模型稽核中的
correct判定表示有人改正了模型的答案。修正來自模型最不擅長的條目,所以val或test中被修正的條目,會在模型自己的錯誤樣本上給模型打分。accept和reject判定讓條目留在原處。 - 固定的條目。 目錄頁面上某個切片旁邊的 Train on these 會固定這個切片所匹配的條目,例如內建的
model-found-nothing切片。被固定的條目一旦有人標註就會參與訓練。
把留出條目移入 train 的執行會記錄一條帶數量的警告。這次執行的留出得分是在去掉這些條目之後算出的,因此不能與較早執行的得分直接比較。數量在訓練資料的 manifest.json 的 stats.forced_train 下。
把一個劃分儲存為資料集版本
執行頁面上的 Keep this split as a dataset 會把這次執行的 val、test 或 train 條目連同其一致的人工標籤,儲存為一個資料集的新版本。資料集版本此後不再改變,所以之後的模型和 LLM 提示詞可以在恰好這些條目上比較。這個功能需要 datasets.enabled: true。每個儲存的版本只包含一個劃分,並且從零開始,而不是追加到資料集的上一個版本之後。否則,把第 2 次執行的 val 條目加到第 1 次執行的版本上,就會包含第 2 次執行訓練過的條目。每個樣例的 inputs 都不含預標籤欄位,所以評估讀不到模型的答案。
預標籤從哪裡來
GET /admin/model-review 為稽核佇列中每個預標籤由訓練執行寫入的條目都包含 provenance。對每個方案,這一項給出執行 id、訓練器和這次執行的留出得分。隨資料一起提供的預標籤沒有這一項。
執行存放在哪裡
每次執行在 <task_dir>/<output_annotation_dir>/training/runs/<run_id>/ 有一個目錄:
| 路徑 | 內容 |
|---|---|
bundle/ | 訓練資料:train.jsonl、val.jsonl、test.jsonl、帶 include_unlabeled 時的 unlabeled.jsonl、labels.json、manifest.json 和 media/。 |
artifacts/ | model_card.json、predictions.jsonl 和模型,例如 sklearn-text 的 model.pkl,或 transformer 訓練器的 model/ 目錄。 |
spec.json | 這次執行被要求做什麼。 |
events.jsonl, stdout.log, stderr.log | 這次執行的進度事件和輸出。 |
agent.log | 在 ssh 後端上,遠端代理自己的輸出。 |
bundle.tar.gz | 在遠端後端上,代理下載的訓練資料,包括媒體。 |
運行臺賬位於項目資料庫 <task_dir>/project.sqlite 中,記錄各次執行、每次執行中每個條目的劃分、固定用於訓練的條目、儲存的預測、代理令牌,以及向 Hugging Face Hub 的推送。retain_runs 會修剪臺賬,但從不修剪預測仍被儲存的執行,因此每個預標籤都能追溯到寫下它的那次執行。修剪不會刪除磁碟上的執行目錄。
LoRA 執行只儲存介面卡,幾 MB 到幾百 MB,在執行做預測時按 model_name 載入基礎模型。完整微調則儲存整個模型。把 POTATO_MODEL_CACHE 環境變數設為某個目錄,訓練程序就會把該目錄用作 HF_HOME、TRANSFORMERS_CACHE 和 SENTENCE_TRANSFORMERS_HOME,除非這些變數已經設定。在斷網機器上,請預先把訓練器指定的模型放進該目錄。
路由
訓練頁面及其 JSON 路由位於 /admin/training 之下,需要管理員許可權。管理員許可權指管理員會話或 X-API-Key 請求頭。來自瀏覽器的 POST 和 DELETE 請求必須同源。Potato 的 OpenAPI 規範用 x-potato-requires-config: model_training.enabled: true 標記了全部 26 個訓練操作:
| 路由 | 用途 |
|---|---|
GET /admin/training | 訓練頁面,帶有執行表單、執行列表和訓練器。 |
GET /admin/training/runs/<run_id> | 一次執行的頁面,帶有狀態、指標、事件和每個條目的劃分。 |
GET /admin/training/api/trainers | 每個訓練器,帶有訓練器的種類、模態、許可證和安裝狀態。 |
GET /admin/training/api/schemas | 研究的方案、每個方案的種類,以及適合每個方案的訓練器。 |
GET /admin/training/api/status | 當前或最近一次執行,帶有狀態、進度、指標、警告、skip_reason、writeback 和 queue。 |
GET /admin/training/api/runs | 執行歷史。?limit= 預設為 50,最大為 500。 |
POST /admin/training/api/runs | 啟動一次執行。執行開始時返回 200,執行等待時返回 202,帶有 queued: true 和 position。 |
GET /admin/training/api/runs/<run_id> | 一次執行的記錄,外加 review,即這次執行的預測在稽核判定下的精確率。 |
GET /admin/training/api/runs/<run_id>/events | 這次執行的事件日誌。?limit= 預設為 200。 |
POST /admin/training/api/runs/<run_id>/cancel | 取消進行中的執行或等待中的執行。對任何其他執行 id 返回 400。 |
DELETE /admin/training/api/runs/<run_id>/predictions | 撤回這次執行儲存的預測和預標籤。 |
POST /admin/training/api/runs/<run_id>/push-to-hub | 把這次執行的模型釋出到 Hugging Face Hub。見釋出到 Hugging Face Hub。 |
POST /admin/training/api/runs/<run_id>/pin-split | 把一個劃分儲存為資料集版本,請求體為 {"dataset": name, "split": "val"}。 |
GET /admin/training/api/backends | 已配置的後端。 |
POST /admin/training/api/backends/<name>/check | 測試一個後端,與 potato training check 相同。 |
GET /admin/training/api/pinned | 被固定的條目,按原因分組。 |
POST /admin/training/api/pinned | 把條目固定到 train,用 {"slice": name} 或 {"instance_ids": [...]}。 |
DELETE /admin/training/api/pinned | 取消固定所列的 instance_ids,請求體沒有列出時則取消固定每個被固定的條目。 |
執行請求接受 trainer、schemas(列表或單個名稱)、params、backend、accept_licence 和 queue。每個訓練器只擬合所指定的第一個方案。下面的請求在示例的 sentiment 方案上啟動一次 sklearn-text 執行:
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
http://localhost:8000/admin/training/api/runs \
-d '{"trainer": "sklearn-text", "schemas": ["sentiment"]}'被拒絕的啟動會在 error 裡給出原因:
| 狀態 | 何時 |
|---|---|
400 | 請求體裡沒有訓練器或沒有方案,訓練器或方案未知,訓練器無法學習該方案,項目無法執行該訓練器,或訓練器的許可證需要確認,此時帶有 needs_licence_ack: true,直到請求設定了 accept_licence: true |
409 | 訓練器不接受的參數,或類型、取值範圍錯誤的參數,未知的後端,local 之外的後端上的 decision-calibrate,或已有執行在進行而請求帶有 "queue": false |
429 | 已有 queue_max 個執行在等待 |
代理協議
model_training.enabled 還會註冊訓練代理所呼叫的路由,位於 /api/training 之下。代理把自己的令牌作為 Authorization: Bearer <token> 傳送,缺失或無效的令牌會得到 401。註冊後端則需要管理員 API 金鑰。potato/training/protocol.py 為編寫新代理的人描述了協議,potato/training/agent.py 是參考實現:
| 路由 | 用途 |
|---|---|
POST /api/training/backends/register | 憑 X-API-Key 為一個後端名稱簽發代理令牌。potato training register 呼叫這個路由。 |
POST /api/training/backends/<name>/heartbeat | 空閒的代理報告自己還活著。給其他後端簽發的令牌返回 403。 |
GET /api/training/jobs/next?wait=30 | 長輪詢。有作業時返回 200,在 wait 秒內沒有作業到來時返回 204。 |
GET /api/training/jobs/<run_id> | 作業、作業的規格,以及作業是否已被取消。 |
GET /api/training/jobs/<run_id>/bundle | tar.gz 形式的訓練資料,包括媒體。該路由響應 Range 請求,因此代理可以恢復中斷的下載,最多嘗試五次。資料包已不存在時返回 410。 |
POST /api/training/jobs/<run_id>/progress | 進度事件。取消的資訊會在響應裡返回。 |
POST /api/training/jobs/<run_id>/predictions | predictions.jsonl。超過 max_predictions_mb 時返回 413。 |
POST /api/training/jobs/<run_id>/complete | 退出碼和最終事件。 |
QLoRA
llm-sft、llm-dpo、hf-text-classification、vlm-sft 和 reward-model 接受 lora: {quantize: 4bit},這是 QLoRA(Dettmers 等,2023)的設定。基礎模型以 4 位 NF4 權重和雙重量化載入,在 GPU 支援 bf16 的情況下,LoRA 介面卡在其上以 bf16 訓練。quantize: 8bit 是折中的選項,預測時以同樣的方式載入基礎模型。
model_training:
trainer_params:
llm-sft:
model_name: Qwen/Qwen2.5-7B-Instruct
lora: {quantize: 4bit}在 4 位下,基礎權重佔用的記憶體是同樣的權重在 bf16 下的四分之一,啟用、介面卡和最佳化器狀態則要另加。Potato 還沒有在 GPU 上測量過一次 QLoRA 執行的記憶體,所以請根據這次執行自己的“Peak GPU memory”一行來規劃。每次 transformer 執行都會在結束時記錄這一行。QLoRA 需要 CUDA GPU,以及與該機器的 CUDA 匹配的 bitsandbytes 構建。執行在載入模型之前,會通過在 GPU 上量化幾個數來檢查這兩者,當兩者的版本不匹配時,錯誤資訊會寫出兩個版本。LLM 微調教程把 QLoRA 用在 SFT 和 DPO 執行上。
釋出到 Hugging Face Hub
模型位於 Potato 伺服器上的成功執行,在執行頁面上有 Publish to the Hugging Face Hub。推送會上傳模型,以及一份根據這次執行寫成的 README.md 模型卡,卡里寫明訓練器、基礎模型和介面卡、方案和標籤、各劃分的大小、留出得分及測得該得分的劃分,以及執行 id 和資料包 id。dp 執行的模型卡還有一行“Differential privacy”,給出相對於目標已花費的 epsilon、delta,以及該保證所覆蓋的 train 劃分。執行沒有記錄目標或 delta 的值時,這一行會省略它。
上傳的是一份固定的檔案列表,而不是整個 artifacts/ 目錄。這份列表包含權重檔案,例如 .safetensors、.bin、.pt 和 .pkl,儲存的 model/ 目錄裡的配置和分詞器檔案,本地路徑已換成檔名的 model_card.json,以及 calibration.json。模型在項目條目上的答案(predictions.jsonl,決策模型還有 raw_answers.jsonl)留在伺服器上。檢查點、最佳化器狀態、某些訓練器生成的訓練資料副本(yolo_data/、wev_data/、laya_data/),以及任何指向 artifacts/ 之外的符號連結,同樣不會上傳。
這個表單從多個方面防止誤推送或公開推送:
- 倉庫名要輸入兩次,兩次一致時推送才會進行。
- Private 預設勾選。勾選 Private 時,Potato 不會推送到已存在的公開倉庫,API 會回答
409。 - 表單指定伺服器上的一個環境變數,預設是
HF_TOKEN,其中儲存 Hugging Face 的寫入令牌。令牌本身從不輸入到頁面裡。變數名必須包含TOKEN或以HF_開頭,變數值必須以hf_開頭,因此其他變數的值都無法到達 Hub。 - 當 Hub 無法確定倉庫是否存在時,什麼也不會推送,推送建立的倉庫如果後來上傳失敗,會被再次刪除。
- 模型卡的許可證是你給出的 Hub 許可證 id,例如
apache-2.0。沒有給出時,卡片會說明適用基礎模型的許可證。需要確認許可證的訓練器,例如ultralytics-detect(AGPL-3.0),推送時也需要同樣的確認。 - 留在設定了
fetch_artifacts: false的遠端主機上的模型,或在 agent 後端上訓練的模型,無法從伺服器推送,錯誤資訊會說明模型在哪裡。
每次推送是一個提交。執行頁面列出每次推送的倉庫、可見性和提交,臺賬記錄是誰做的推送。通過 API,POST /admin/training/api/runs/<run_id>/push-to-hub 的請求體接受 repo_id、confirm_repo_id、private(預設 true)、token_env(預設 HF_TOKEN)、licence 和 accept_licence。該路由成功時返回帶有提交的 201,名稱不一致、缺少令牌變數、沒有模型檔案或許可證未確認時返回 400,Hub 拒絕時返回 502。
故障排查
下面的條目涵蓋第一次設定時最可能遇到的錯誤。上游故障排查列表涵蓋 GPU 驅動、CUDA 構建和各訓練器專有的訊息。
/admin/training返回 404。model_training.enabled不是true,Potato 只有在這個鍵為true時才註冊這些路由。- “Only N items in the train split”。 請標註更多條目,或降低這次執行
params裡的min_instances。train 劃分預設佔已標註條目的 70%。 - “Schema 'x' has 1 distinct label(s) in the data”。 分類器需要至少使用兩個標籤。
- “No resolved annotations to train on”。 執行裡指定的方案與正在標註的方案不同,或者還沒有人標註任何內容。
- 這次執行沒有釋出任何預標籤。 請檢視
GET /admin/training/api/status裡的writeback報告。“No predictions were published: write-back is not enabled for any schema”表示writeback.schemas為空,跳過計數顯示每項檢查移除了多少預測。 <trainer> does not take <name>。 執行裡或trainer_params下的某個參數拼錯了,或屬於另一個訓練器。訊息會列出該訓練器接受的名字。- 機器記憶體耗盡後執行被殺掉。 程序因 SIGKILL 退出,通常來自記憶體不足時的 OOM 殺手。請換更小的模型或使用更少的條目,或設定
max_ram_mb,讓執行在自己的限制內失敗。 - “Stopped: the run took longer than model_training.max_wall_seconds”。 執行達到了時間上限。請提高
max_wall_seconds,或用更少的條目訓練。 - “The GPU ran out of memory”。 降低
batch_size並提高gradient_accumulation以保持有效批大小,設定lora: true或lora: {quantize: 4bit},對llm-sft則設定gradient_checkpointing: true或選用更小的模型。 - “ssh to host failed: Permission denied”。 Potato 以
BatchMode=yes執行ssh,所以從伺服器的賬戶執行ssh <host> true必須無需提示即可成功。當ssh-agent持有金鑰時,帶口令的金鑰也能工作。 - agent 後端上的執行一直在排隊。 沒有使用該後端名稱的代理在輪詢。請用
potato training agent --backend <name>啟動代理,並用訓練頁面上的 Check 檢查令牌。
延伸閱讀
- 用你自己的標註訓練模型:訓練迴圈、訓練頁面和快速開始。
- 訓練器:每個訓練器、每個訓練器學習的方案和安裝命令。
- 在 GPU 伺服器、SLURM 叢集或 NAT 後的機器上訓練:逐步設定 ssh、SLURM 和輪詢代理後端。
- 迴圈中的模型:在同一項研究裡使用回寫、稽核、
auto_retrain和資料集版本。 - 主動學習:按模型的不確定性給條目排序。
- 識別橡皮圖章式預標籤:檢查標註者是否不讀預標籤就接受。
- 上游參考:每個訓練器的完整參數列。
參考文獻
- Dawid, A. P., and Skene, A. M. (1979). Maximum Likelihood Estimation of Observer Error-Rates Using the EM Algorithm. Applied Statistics, 28(1). https://doi.org/10.2307/2346806
- Dettmers, T., Pagnoni, A., Holtzman, A., and Zettlemoyer, L. (2023). QLoRA: Efficient Finetuning of Quantized LLMs. Advances in Neural Information Processing Systems 36 (NeurIPS 2023). https://proceedings.neurips.cc/paper_files/paper/2023/hash/1feb87871436031bdc0f2beaa62a049b-Abstract-Conference.html