在標註資料上訓練模型
把多位標註者的標籤合併成訓練目標,讓留出的 test 劃分在各輪之間保持固定,記錄每個模型見過什麼,並估算第一次執行所需的資料量。
要在標註資料上訓練模型,就把每個條目的標籤合併為一個目標或標註者的投票分佈,用一條在各輪之間保持固定的規則把條目分配到 train、驗證和 test 劃分,並在驗證劃分選出了檢查點時報告 test 得分。Potato 的模型訓練在研究自己的標註上執行每一步,並記錄每次執行訓練過哪些條目。
v2.14.0 新增
標註資料很少恰好是訓練器所讀取的形狀。有重疊的研究,每個條目有多個標籤,而這些標籤往往不一致。仍在進行中的研究每天都在增加標籤,每一輪重新訓練看到的條目都比上一輪更多。訓練器需要每個條目一個目標,以及一組固定的條目來評分,下面的這些決定正好提供這兩樣東西。下面的每一節都會寫明做出該決定的 Potato 設定。關於訓練頁面本身,請參閱模型訓練概覽,以及訓練第一個模型的教程。如果想在自己的程式碼中訓練,匯出標註用於機器學習介紹了各種匯出格式,同樣的決定也適用於匯出的檔案。
把多位標註者合併為一個標籤
聚合會把幾位標註者給同一個條目的標籤,變成模型據以訓練的單一標籤。最簡單的方法是多數投票。多數投票把每位標註者的答案只計一次,並保留最常見的答案。Dawid and Skene (1979) 用期望最大化為每位標註者估計一個混淆矩陣,並按估計出的標註者可靠性給每一票加權。這樣,粗心的標註者對結果的左右程度就比認真的標註者小。聚合眾包標籤比較了這兩種方法,以及建立在 Dawid-Skene 之上的各種模型。
Potato 中的訓練執行用 model_training.aggregation 合併標籤。預設值 consensus 在項目有多於一位標註者時執行 Dawid-Skene,並在估計失敗時退回多數投票。另一個值 majority 只執行多數投票。兩種方法都把標註者在一個方案上的整個答案算作一票。因此,兩個 multiselect 答案只有在勾選的標籤集合完全相同時,才算同一票。
執行的 consensus 設定與共識匯出是兩個不同的功能。共識匯出給每位標註者一票,報告每個條目上每個答案的計數和比例,並把每個條目標記為 retired 或 needs_review。想逐條目檢視標註者在哪裡出現分歧時,請在訓練之前閱讀該匯出。MACE 則根據同樣的投票為每位標註者估計一個能力得分。
從分歧中學習
在冒犯性或情感這類主觀任務上,標註者可能因為各自對條目的理解不同而產生分歧,而單一的投票標籤會丟掉這種分佈。Uma et al. (2021) 綜述了在分歧上訓練而不是在一個聚合標籤上訓練的方法。這些方法中有一類在軟標籤上訓練。軟標籤是標籤上的機率分佈,由選擇每個標籤的標註者所佔比例構成。
hf-text-classification 接受參數 soft_targets: true。設定該參數後,被兩位或更多標註者標註過的條目,會以對該分佈的交叉熵,朝著標註者的分佈訓練。當三位標註者中有兩位說 positive 時,目標是 0.67 的 positive 和 0.33 的 negative。對於 multiselect 方案,每個標籤朝著勾選了該標籤的標註者所佔的比例訓練。只有一位標註者的條目,仍照舊在那位標註者的標籤上訓練。這樣,模型會在人們意見分歧的地方保持不確定,每個預測都包含模型的 probabilities。在存在投票分佈的留出條目上,執行還會報告另外三項指標:
| 指標 | 該指標衡量什麼 |
|---|---|
soft_jsd | 模型的分佈與標註者的分佈之間的 Jensen-Shannon 散度,以位元為單位,取值 0 到 1 |
soft_cross_entropy | 標註者的分佈在模型分佈下的交叉熵 |
ece | 頂部標籤相對於投票標籤的期望校準誤差,按 10 個置信度分箱計算 |
在軟標籤方案中,每位標註者用滑塊給出一個分佈。hf-text-classification 總是讓 soft_label 方案朝著標註者的平均分佈訓練,預標籤則把滑塊設定為預測的分佈。軟目標要求一個條目上有兩個或更多標籤。因此,打算在分歧上訓練的研究,從一開始就要收集有重疊的標籤,需要多少標註者?討論了重疊設定。分歧是訊號,而非噪聲闡述了把分佈保留在資料中的理由。
train、驗證和 test 劃分
訓練、驗證和 test 劃分承擔三項不同的工作。訓練劃分擬合模型的權重。驗證劃分在候選模型之間做選擇,例如選擇在哪個 epoch 停止。test 劃分估計在未見資料上的效能,並且不參與上述任何一項選擇。在驗證上選擇檢查點,是在擬合驗證集的一種形式。因最佳驗證得分而保留下來的檢查點,其驗證得分偏高,只有 test 得分來自選擇過程從未參考過的條目。
Potato 的一次執行預設按 70/15/15 劃分已標註的條目(splits)。每個條目所在的劃分,來自對條目 ID 做的帶種子雜湊(split_seed)。因此,只要 split_seed 和 splits 保持不變,在一次執行中被留出的條目,在下一次執行中仍然被留出。更改任何一項設定都可能把留出條目移入訓練,此後的每個得分便都部分地衡量了記憶。請在研究開始時一次性設定好這兩項。
微調訓練器(如 hf-text-classification)保留在驗證上得分最高的那個 epoch 的檢查點。這類執行的主得分來自 test。sklearn-text、setfit、rdkit-property、決策模型訓練器和推理橋在驗證上不做任何選擇,只要驗證劃分中有條目,這些訓練器之一的執行就從驗證取主得分。Runs 表 Held-out score 列的提示文字會寫明每個數字背後的劃分和指標。有標籤而沒有預測的條目算作錯誤。訓練器無法通過跳過難條目來抬高得分,<split>_coverage 會報告得到預測的條目所佔的比例。
被更正和被固定的條目
有兩類條目會進入之後每次執行的 train 劃分,無論雜湊把它們分到了哪個劃分。第一類是稽核者在模型稽核中更正過的條目,第二類是有人在目錄頁面上某個切片旁用 Train on these 固定的條目。更正來自模型表現最差的那些條目,如果這些更正留在驗證或 test 中,就等於用模型自己犯錯的樣本給模型評分。把留出條目移入訓練的執行會記錄一條帶數量的警告,此後該次執行的留出得分,就無法與更早一次執行的得分直接比較。如果一次執行在某個更正過的條目上訓練,而該條目在更早的執行中是被留出的,那麼這次執行也會記錄一條警告,因為此時在更早那次執行的驗證或 test 條目上的得分,或者在由這些條目儲存的資料集上的得分,就包含了新模型訓練過的條目。更正和被固定的條目始終參與訓練給出了相關規則。
記錄每個模型訓練過什麼
比較兩次執行,需要知道每次執行在哪些條目上訓練和評分。每次 Potato 執行都會在 <output_annotation_dir>/training/runs/<run_id>/bundle/ 下寫出一個數據包,包含 train.jsonl、val.jsonl、test.jsonl、labels.json 和 manifest.json。清單記錄劃分種子、聚合方法、每個劃分中的條目數、被強制放入訓練的條目數,以及劃分檔案的 SHA-256 摘要。資料包中沒有任何內容回指 Potato,Potato 之外的指令碼可以把資料包當作合併後標籤與劃分的自包含副本來讀取。
項目資料庫 project.sqlite 儲存一份賬本,每次執行一行。每一行記錄訓練器、參數、劃分大小、劃分種子、留出指標和資料包摘要。第二張表記錄每個條目在每次執行中所處的劃分。回寫讀取這張表,絕不會為賬本中仍有的任何一次執行訓練過的條目生成預標籤(retain_runs 預設保留五次已完成的執行)。模型在它訓練過的條目上有把握,其原因與新資料毫無關係。
要在完全相同的條目上比較之後的模型,請在執行頁面上使用 Keep this split as a dataset,它會把該次執行的驗證、test 或 train 條目,連同一致認可的人工標籤,儲存為資料集的一個版本。儲存的版本此後不再改變。每個儲存的版本只包含一個劃分,並且從零開始,而不是在上一個版本上累加。否則,第 2 次執行的驗證條目儲存在第 1 次執行的之上,就會包含第 2 次執行訓練過的條目。對儲存版本的評估無法讀到模型的答案,因為儲存的輸入略去了預標籤欄位。儲存需要 datasets.enabled: true。當模型或資料集離開項目時,為資料集和模型編寫文件介紹了資料表和模型卡。
第一個模型需要多少資料
每個 Potato 訓練器在 train 劃分中的條目少於 min_instances 個時都拒絕擬合。下面的預設值,就是一次執行得以開始時的條目數:
| 訓練器 | min_instances 預設值 | 說明 |
|---|---|---|
setfit | 8 | 為項目的最初幾天而設計,每個標籤約八個條目起步 |
sklearn-text | 10 | 只在訓練條目達到 50 個以上時才校準置信度 |
hf-audio-tagger | 10 | |
hf-text-classification, hf-token-classification, hf-image-classification | 20 | |
llm-sft, llm-dpo | 20 |
下限只統計 train 劃分。在預設的 70/15/15 劃分下,當約 15 個條目有標籤時,sklearn-text 執行就能開始。Potato 倉庫中的模型訓練示例給出了一個實測點。在示例的 160 條合成商品評論中,每條標註一次的 120 條上,一次 sklearn-text 執行在驗證上得到 0.84 的 macro-F1,併發布了 80 個預標籤。這個數字來自一個合成的二標籤任務,對你自己的任務,應當看你自己執行的留出得分。
從 sklearn-text 開始。該訓練器除普通安裝外別無所需,也不需要 GPU。隨著標籤到來重新訓練,並在 split_seed 不變的前提下,逐次執行地觀察留出得分。預標籤會錨定標註者。在留出得分足以支援展示模型的答案之前,請讓 writeback.schemas 保持為空。模型輔助標註討論標註者看到預標籤之後會發生什麼變化,如何區分認真稽核與不加思考的接受則討論如何檢查標註者是否仍在認真閱讀條目。
設定每項決定的配置
下面的配置在一個二標籤情感方案上訓練。model_training 下的每個鍵設定上述決定之一:
annotation_task_name: "Review sentiment"
task_dir: "."
data_files:
- "data/reviews.json"
item_properties:
id_key: "id"
text_key: "text"
output_annotation_dir: "annotation_output"
annotation_schemes:
- annotation_type: "radio"
name: "sentiment"
description: "Is this review positive or negative?"
labels: ["positive", "negative"]
model_training:
enabled: true
aggregation: consensus
split_seed: 0
splits: {train: 0.7, val: 0.15, test: 0.15}
trainer_params:
hf-text-classification:
soft_targets: trueaggregation: consensus 用 Dawid-Skene 合併有重疊的標籤。split_seed 和 splits 按預設值寫了出來,因為這兩項設定在研究的整個生命週期內都不應改變。soft_targets: true 讓項目上的每次 hf-text-classification 執行都在投票分佈上訓練。該訓練器需要 pip install "potato-annotation[train-text]",而 sklearn-text 在同一配置上執行,無需額外安裝。沒有 writeback 塊時,標註者看不到預標籤。用這份配置重啟伺服器,開啟 /admin/training,選擇訓練器和 sentiment 方案,然後點選 Train now。模型訓練配置參考列出了每個鍵,迴圈中的模型教程則加入了回寫和自動重新訓練。
延伸閱讀
- 模型訓練概覽
- 訓練你的第一個模型
- 模型輔助標註
- 匯出標註用於機器學習
- 聚合眾包標籤
- 標註者間一致性
- GitHub 上的模型訓練參考,包含每種方案類型的留出指標
參考文獻
- Dawid, A. P., and Skene, A. M. (1979). Maximum Likelihood Estimation of Observer Error-Rates Using the EM Algorithm. Applied Statistics, 28(1), 20. doi.org/10.2307/2346806
- Uma, A. N., Fornaciari, T., Hovy, D., Paun, S., Plank, B., and Poesio, M. (2021). Learning from Disagreement: A Survey. Journal of Artificial Intelligence Research, 72, 1385–1470. doi.org/10.1613/jair.1.12752