來自你已在執行的模型的預標籤和留出得分
在研究的標籤上給由 vLLM、Ollama、Hugging Face、Roboflow、CVAT 或 Label Studio ML 後端提供服務的模型評分,再把它的答案作為預標籤來稽核。
v2.14.0 新增
本教程面向已經在 Potato 之外執行某個模型的團隊,他們想在把模型的答案展示給任何人之前,先了解該模型與團隊自己的標註者有多一致。Potato 的模型訓練包含五個稱為橋接器的訓練器,它們什麼也不訓練。橋接器把研究的留出條目傳送給在別處提供服務的模型,對照研究的標籤給答案評分,並把答案作為預標籤回寫供稽核,與訓練出的模型的一次執行相同。下面的步驟涵蓋 OpenAI 相容 API 背後的視覺語言模型、Roboflow 模型、CVAT 無伺服器函式、Hugging Face 模型和 Label Studio ML 後端,每一種都附有經過驗證的配置。
橋接器執行傳送和評分的內容
橋接器是一種訓練器,它的擬合步驟只檢查服務是否應答。隨後執行把該次執行 val 和 test 劃分中的條目傳送給服務,在 writeback.include_unlabeled: true 時,還包括沒有人標註過的條目。Potato 把答案轉換為方案自己的形狀、片段或選項,並對照合併後的人工標籤,在留出條目上給答案評分,使用的留出指標與訓練出的模型相同(框用 mAP50,片段用 span F1,單選用 macro-F1)。回寫、模型稽核佇列和每個預標籤的執行 id,與在任何其他執行之後一樣工作。
| 訓練器 | 方案 | 它呼叫的模型 |
|---|---|---|
openai-vlm-boxes | image_annotation | OpenAI 相容聊天 API 背後的視覺語言模型(vLLM、Ollama、LM Studio、llama.cpp 的伺服器、OpenAI) |
roboflow | image_annotation | Roboflow 檢測或實例分割模型,託管在雲端或執行在自託管的 Inference 伺服器上 |
cvat-nuclio | image_annotation | 執行在 Nuclio 上的 CVAT 無伺服器函式 |
hf-inference | radio、select、multiselect、span、image_annotation | Hugging Face Inference Endpoint,或無伺服器 HF Inference API 上的模型 |
label-studio-ml | radio、select、multiselect、span、image_annotation | 正在執行的 Label Studio ML 後端 |
條目屬於哪個劃分只取決於條目的 id 和 model_training.split_seed,所以只要種子不變,橋接器執行和訓練出的模型的執行就在同樣的 val 和 test 條目上評分。於是 /admin/training 上的 Runs 表可以把你已有的模型與在研究標籤上訓練的模型並排比較。train 劃分中的條目不會從橋接器得到預測,回寫也永遠不會給 train 劃分的條目加預標籤。因此在預設的 70/15/15 劃分下,橋接器大約在 30% 的已標註條目上評分。
開始之前
除 label-studio-ml 之外的四個橋接器需要 Potato 伺服器上有 requests 和 Pillow,在這兩個包都能匯入之前,訓練頁面會把橋接器列為“not installed”。label-studio-ml 除 Potato 之外什麼都不需要。五個橋接器都不會安裝模型、GPU 庫或 torch,因為模型執行在服務裡。
與每個影像訓練器一樣,影像必須是項目內的本地檔案。橋接器會排除影像為遠端 http(s) URL 的條目,有標籤而沒有預測的條目在留出得分中算作錯誤。執行把得到預測的留出條目所佔的比例報告為 val_coverage 和 test_coverage,所以覆蓋率偏低說明有橋接器無法傳送的影像。
金鑰儲存在環境變數中
金鑰永遠不放在配置裡。每個傳送金鑰的橋接器都有一個參數,用來指明儲存金鑰的環境變數(api_key_env,Hugging Face 用 token_env,Label Studio 用兩個 basic_auth_*_env 名稱),該變數必須在伺服器啟動之前設定在 Potato 伺服器的環境中。cvat-nuclio 不傳送金鑰,也沒有這樣的參數。接受金鑰的四個橋接器會拒絕不是變數名的值,錯誤資訊不會重複該值,因為出現在這裡的值很可能就是金鑰本身。服務的錯誤正文或連線錯誤回顯了請求時,橋接器在顯示錯誤之前,會把金鑰的值替換為 [redacted]。Label Studio ML 後端 /predict 的錯誤正文也以同樣方式清理。查詢字串或 Authorization 頭中任何形似金鑰的內容同樣會被替換。
hf-inference 和 roboflow 的執行只能在本地進行。這兩個橋接器都在 Potato 伺服器上讀取金鑰,而在 ssh、SLURM 或 agent 後端上執行就必須把金鑰送到那臺主機,所以 Potato 拒絕在那裡啟動這樣的執行。openai-vlm-boxes、cvat-nuclio 和 label-studio-ml 可以在任何能訪問該服務的後端上執行,金鑰的變數設在該後端的主機上。
步驟 1:用三個橋接器處理影像研究
下面的配置建立一項現場照片研究,標註者為每個安全帽和每個沒戴帽的頭畫框。model_training.trainer_params 同時儲存多個訓練器的預設值,所以這一份配置攜帶全部三個影像橋接器的設定,每次執行使用自己訓練器的那一塊。選擇訓練器時,訓練頁面的 Parameters 欄位會用這些預設值填充。
annotation_task_name: "Hard hats on site photos"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
admin_api_key: "replace-with-a-long-random-string"
data_files:
- data/photos.jsonl
item_properties:
id_key: id
text_key: image_url
annotation_schemes:
- annotation_type: image_annotation
name: ppe
description: "Box every hard hat and every bare head."
source_field: image_url
tools: [bbox, polygon]
labels:
- name: helmet
- name: head
model_training:
enabled: true
writeback:
schemas: [ppe]
include_unlabeled: true
trainer_params:
openai-vlm-boxes:
url: http://localhost:8000/v1
model: Qwen/Qwen2.5-VL-7B-Instruct
coordinate_format: pixels
roboflow:
model_id: site-safety/3 # your Roboflow project and version
url: https://detect.roboflow.com
api_key_env: ROBOFLOW_API_KEY
confidence: 0.4
label_map: {hardhat: helmet, no-hardhat: head} # the model's class names on the left
cvat-nuclio:
url: http://localhost:32768
threshold: 0.5
label_map: {person: null}data/photos.jsonl 的每一行指明 media/ 下的一張影像:
{"id": "site_001", "image_url": "media/site_001.jpg"}writeback.schemas 讓模型的框對標註者可見,include_unlabeled 則把沒有人標註過的照片也傳送給服務。如果你想在任何人看到預標籤之前先拿到留出得分,第一次執行時請去掉這兩個鍵。label_map 把服務的類別名對映到方案的標籤,對映到 null 的類別會被丟棄。沒有條目的類別會歸到同名的標籤,匹配不區分大小寫。屬於其他類別的框會被排除,執行日誌會統計被排除的框數。
步驟 2:用 openai-vlm-boxes 呼叫視覺語言模型
openai-vlm-boxes 把每張影像縮小到長邊最多 1,280 畫素(max_image_side),並把影像連同點出方案標籤的提示傳送到 chat completions 路由。Potato 把回覆讀作 JSON 框。任何帶 OpenAI 相容 API 的伺服器都可以使用。下面的命令用 vLLM 為 Qwen2.5-VL 提供服務,其文件讓客戶端連線 http://localhost:8000/v1:
vllm serve Qwen/Qwen2.5-VL-7B-InstructvLLM 使用 8000 埠時,請在另一個埠啟動 Potato:
potato start config.yaml -p 9000無論提示怎麼要求,視覺語言模型都按自己的座標約定作答,有兩個參數告訴 Potato 如何讀這些數字。coordinate_format 可以是 fraction(影像的 0 到 1)、per_mille(0 到 1,000),或所傳送影像的 pixels。box_order 對 [x0, y0, x1, y1] 是 xyxy,對 [y0, x0, y1, x1] 是 yxyx。Qwen2.5-VL 以畫素作答,所以上面的配置設定 coordinate_format: pixels。在 auto 下,Potato 根據數字的大小對每條回覆猜一次格式。不超過 1.05 的值讀作比例,超出所傳送影像尺寸的值讀作千分比,其餘讀作畫素。因此落在大圖之內的千分比框會被讀成畫素,所以只要知道模型的約定,就請指明格式。
Gemma 和 Gemini 即使提示要求比例,也以 y 在前的千分比框 [ymin, xmin, ymax, xmax] 作答。兩個參數都是 auto 時,Potato 把名稱含 gemma 或 gemini 的模型的框讀作 y 在前的千分比。在一個由紅藍方塊組成的 Gemma 4 12B 測試項目上,Potato 團隊測得按 x 在前讀框時 mAP50 為 0.0,按 y 在前讀框時為 1.0。Ollama 以含 gemma 的名稱提供 Gemma 3,所以 auto 適用:
ollama run gemma3:12b請把配置中的 openai-vlm-boxes 塊替換為下面的塊:
model_training:
trainer_params:
openai-vlm-boxes:
url: http://localhost:11434/v1
model: gemma3:12b
json_mode: object以不含這兩個詞的名稱提供服務的 Gemma 或 Gemini 微調模型,在 auto 下會按 x 在前讀取。對這樣的模型,請設定 coordinate_format: per_mille 和 box_order: yxyx。json_mode: object 以 response_format: json_object 向 Ollama 請求 JSON。預設的 schema 會發送以標籤為列舉的 JSON schema。vLLM 和 OpenAI 遵守該 schema。沒有任何回覆能解析為 JSON 的執行會失敗,錯誤資訊建議使用 json_mode: object 或更簡單的提示(prompt,其中的 {labels} 會變成方案的標籤)。
視覺語言模型不會隨框給出得分,所以這些框沒有置信度。writeback.min_confidence 會放行每個 openai-vlm-boxes 預測,模型稽核也無法把預測按置信度從低到高排序。openai-vlm-boxes 參考列出託管 API 的 api_key_env,以及令牌和超時設定。
步驟 3:開始一次執行並檢視得分
開啟 http://localhost:9000/admin/training,選擇 openai-vlm-boxes 和 ppe 方案,然後點選 Train now。同樣的執行也可以從 API 啟動:
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
http://localhost:9000/admin/training/api/runs \
-d '{"trainer": "openai-vlm-boxes", "schemas": ["ppe"]}'擬合步驟通過 /models 列出伺服器的模型,並記錄該次執行請求哪個模型,以及如何讀取模型的框。隨後預測階段每次請求傳送一張影像。執行結束後,留出的 mAP50 顯示在 Runs 表中,執行頁面列出 val_map_50、test_map_50、覆蓋率數字,以及一條“Not used”警告,統計不是 JSON 的回覆、屬於方案沒有的標籤的框,以及超出影像的框。得分接近 0、覆蓋率很高而警告為空時,請先檢查 coordinate_format 和 box_order。
Roboflow 模型
roboflow 把每張影像 POST 到 <url>/<model_id>,其中 model_id 是 project/version 形式的項目和版本。金鑰預設放在 ROBOFLOW_API_KEY 中(api_key_env),沒有金鑰時執行拒絕啟動:
export ROBOFLOW_API_KEY=... # in the shell that starts Potato
potato start config.yaml -p 9000Potato 預設的 url 是 https://detect.roboflow.com,上面的配置寫的是預設值。實例分割的執行要設定 url: https://outline.roboflow.com。url 是一個參數,所以執行也可以寫 https://serverless.roboflow.com,這是 Roboflow 的目標檢測參考為同一 project/version 路由給出的主機。Potato 團隊沒有用這個橋接器測試過該主機。自託管的 Roboflow Inference 伺服器預設監聽 9001 埠(url: http://localhost:9001)。
Roboflow 的 API 通過查詢字串接收金鑰。Potato 不會把請求 URL 寫入執行日誌或錯誤資訊。Potato 以百分比向 API 傳送 confidence 和 overlap(預設 0.4 和 0.3),Roboflow 的參考文件說明這兩者的範圍是 0 到 100。shapes: auto 在模型返回輪廓而方案有多邊形工具時寫出輪廓,否則寫出框。健康檢查會 POST 一張 8 × 8 的白色影像,Roboflow 會把這次請求計入賬戶的用量。
CVAT 無伺服器函式
cvat-nuclio 使用已經作為 Nuclio 函式部署給 CVAT 的檢測器,例如 cvat/serverless 中的 YOLOv7 或 Faster R-CNN 函式。Potato 不經過 CVAT,把每張影像以 {"image": <base64>, "threshold": t} 的形式 POST 到函式自己的 URL。nuctl get functions 列出已部署的函式及其埠,下面的命令是 CVAT 文件給出的形式:
nuctl get functions --platform local函式以畫素為單位返回形狀。rectangle 變成框,polygon 變成多邊形,方案沒有多邊形工具時則變成多邊形的外接框。mask 形狀會被排除並計數。函式會丟棄得分低於 threshold(預設 0.5)的形狀。方案中沒有 person 標籤,所以配置中的 label_map: {person: null} 會丟棄 COCO 檢測器檢出的人。
用 hf-inference 呼叫 Hugging Face 模型
hf-inference 呼叫部署在 Hugging Face 上的模型,可以通過 https:// URL(endpoint_url)呼叫專用的 Inference Endpoint,也可以通過模型 id(model)呼叫無伺服器的 HF Inference API。請設定 endpoint_url 或 model,不要兩者都設。任務取決於方案的類型:
- 文本分類對應
radio、select和multiselect。單選方案取模型得分最高的標籤。該標籤經過label_map之後不是方案的標籤時,該條目沒有預測,而不是取次高的標籤。multiselect方案取得分至少為threshold(預設 0.5)的每個標籤。 - 詞元分類對應
span,由aggregation_strategy(simple、first、average或max)把詞片段聚合成實體,字元偏移取自模型。 - 目標檢測對應
image_annotation。得分低於threshold的框會被丟棄。
下面的配置向 dslim/bert-base-NER 請求片段。該模型卡描述這是一個在英文 CoNLL-2003 上針對命名實體微調的 BERT 模型。HF Inference 只提供 Hub 上一部分模型的服務,所以在依賴無伺服器 API 之前,請確認該模型的頁面列出了 HF Inference。
annotation_task_name: "Named entities in news sentences"
task_dir: .
output_annotation_dir: annotation_output
admin_api_key: "replace-with-a-long-random-string"
data_files:
- data/sentences.jsonl
item_properties:
id_key: id
text_key: text
annotation_schemes:
- annotation_type: span
name: entities
description: "Highlight every person, organization, and place."
labels: [person, organization, location]
model_training:
enabled: true
writeback:
schemas: [entities]
include_unlabeled: true
trainer_params:
hf-inference:
model: dslim/bert-base-NER
token_env: HF_TOKEN
aggregation_strategy: simple
label_map: {PER: person, ORG: organization, LOC: location, MISC: null}模型的 PER、ORG 和 LOC 實體對映到方案的標籤,MISC 被丟棄,因為方案沒有這樣的標籤。實體的完整名稱沒有匹配項時,Potato 會去掉 B- 或 I- 字首再試一次。以 LABEL_0 和 LABEL_1 作答的情感分類器,同樣需要 label_map: {LABEL_0: negative, LABEL_1: positive}。健康檢查是一次真實的請求,即一個短句或一張 8 × 8 的影像,wait_for_model: true(預設)會在無伺服器模型載入時等待,而不是以 503 失敗。
Label Studio ML 後端
label-studio-ml 使用正在執行的 Label Studio ML 後端。用倉庫示例中的 docker-compose up 啟動的後端,通過 HTTP 在 http://localhost:9090 提供模型服務。執行會檢查後端的 GET /health,以每批 16 個(batch_size)把條目傳送到 POST /predict,並用 potato import -f label_studio 所用的同一個轉換器讀取返回的區域。Label Studio 的 UTF-16 片段偏移會變成碼點,百分比座標會變成影像控制元件的座標。
annotation_task_name: "Review sentiment"
task_dir: .
output_annotation_dir: annotation_output
admin_api_key: "replace-with-a-long-random-string"
data_files:
- data/reviews.jsonl
item_properties:
id_key: id
text_key: text
annotation_schemes:
- annotation_type: radio
name: sentiment
description: "Is this review positive or negative?"
labels: [positive, negative]
model_training:
enabled: true
writeback:
schemas: [sentiment]
include_unlabeled: true
min_confidence: 0.6
trainer_params:
label-studio-ml:
url: http://localhost:9090
basic_auth_user_env: LS_ML_USER
basic_auth_pass_env: LS_ML_PASS標準後端唯一的認證是 HTTP Basic,由後端上的 BASIC_AUTH_USER 和 BASIC_AUTH_PASS 設定。basic_auth_user_env 和 basic_auth_pass_env 指明 Potato 伺服器上儲存這兩個值的變數,這兩個參數要一起使用。api_key_env 改為傳送 Authorization: Token <value>,用於位於期望令牌的代理之後的後端。標準後端對這個頭會返回 500。Potato 根據方案生成隨每次請求傳送的標註配置(Choices、Labels、RectangleLabels 或 PolygonLabels),label_config 會把生成的 XML 替換為你自己的。
影像後端還需要多一項設定。沒有 media_url_prefix 時,Potato 把每張影像作為 Potato 機器上的絕對路徑傳送,而基於 Label Studio SDK 構建的後端把 data.image 讀作 URL,遇到裸路徑就會失敗。對於同一臺機器上的後端,請新增下面的字首,並在設定了 LOCAL_FILES_DOCUMENT_ROOT 為任務目錄的情況下啟動後端:
model_training:
trainer_params:
label-studio-ml:
url: http://localhost:9090
media_url_prefix: /data/local-files/?d=對於另一臺機器上的後端,請通過 HTTP 提供任務目錄,並把該伺服器的 URL 作為字首。任務目錄之外的影像沒有相對於該目錄的路徑,所以 Potato 不會發送這張影像,執行日誌會給出被排除的數量。
Potato 向後端傳送預測請求,不傳送標註事件,所以後端在其 /webhook 處理程序中的自身訓練不會由 Potato 觸發。potato import -f label_studio 把整個 Label Studio 項目連同項目的標註配置、標註者的答案和已儲存的預測移入 Potato(匯入項目)。從 Label Studio 遷移到 Potato 介紹匯入器不處理的標籤。
稽核預標籤
橋接器的預測與訓練出的模型的預測經過同樣的回寫檢查。回寫會跳過 train 劃分的條目和不在 writeback.schemas 中的方案,跳過稽核者拒絕過的條目與方案的組合,並扣下低於 writeback.min_confidence 的預測。對框和片段,一個預測的置信度是其中置信度最低的形狀或片段的置信度,所以只要條目上任何一個框或片段的得分更低,下限就會扣下該條目的整個預測。Roboflow 的 confidence 和 CVAT 的 threshold 則在服務端按框起作用,hf-inference 的 threshold 按框或按 multiselect 標籤起作用。模型在環教程介紹稽核佇列、接受和拒絕的判定,以及重新訓練。佇列和判定對橋接器的工作方式相同。
每個條目和方案只保留一個預測,所以另一個橋接器或訓練出的模型的後續執行會替換之前那次執行的預標籤。要撤回一次執行的預標籤,請傳送 DELETE /admin/training/api/runs/<run_id>/predictions。推理橋接器參考列出四個橋接器的全部參數,label-studio-ml 參考列出 Label Studio 的參數。