Zum Inhalt springen

Ein Modell auf Annotationsdaten trainieren

Löse die Labels mehrerer Annotatoren zu Trainingszielen auf, halte einen zurückgehaltenen Test-Split zwischen den Runden fest, protokolliere, was jedes Modell gesehen hat, und dimensioniere einen ersten Lauf.

Um ein Modell auf Annotationsdaten zu trainieren, löse die Labels jedes Items zu einem Ziel oder zur Stimmenverteilung der Annotatoren auf, weise Items nach einer Regel, die zwischen den Runden fest bleibt, Trainings-, Validierungs- und Test-Splits zu und berichte den Test-Score, sobald der Validierungs-Split den Checkpoint gewählt hat. Das Modelltraining von Potato führt jeden Schritt auf den eigenen Annotationen einer Studie aus und hält fest, auf welchen Items jeder Lauf trainiert hat.

Neu in v2.14.0

Annotationsdaten kommen selten in der Form an, die ein Trainer liest. Eine Studie mit Überlappung hat mehrere Labels pro Item, und die Labels widersprechen sich oft. Eine Studie, die noch läuft, gewinnt jeden Tag Labels hinzu, und jede Runde des erneuten Trainings sieht mehr Items als die Runde davor. Ein Trainer braucht ein Ziel pro Item und eine feste Menge von Items zur Bewertung, und die folgenden Entscheidungen liefern beides. Jeder Abschnitt unten nennt die Potato-Einstellung, die die Entscheidung umsetzt. Zur Training-Seite selbst siehe die Übersicht zum Modelltraining und das Tutorial, das ein erstes Modell trainiert. Wer im eigenen Code trainieren möchte, findet die Exportformate in Annotationen für maschinelles Lernen exportieren, und dieselben Entscheidungen gelten für die exportierte Datei.

Mehrere Annotatoren zu einem Label auflösen

Aggregation macht aus den Labels mehrerer Annotatoren zu einem Item das eine Label, auf dem ein Modell trainiert. Die einfachste Methode ist der Mehrheitsentscheid. Der Mehrheitsentscheid zählt die Antwort jedes Annotators einmal und behält die häufigste Antwort. Dawid und Skene (1979) schätzen mit Expectation-Maximization eine Konfusionsmatrix für jeden Annotator und gewichten jede Stimme mit der geschätzten Zuverlässigkeit des Annotators. Ein nachlässiger Annotator beeinflusst das Ergebnis dann weniger als ein sorgfältiger. Crowd-Labels aggregieren vergleicht die beiden Methoden und die auf Dawid-Skene aufbauenden Modelle.

Ein Trainingslauf in Potato löst Labels mit model_training.aggregation auf. Der Standard consensus führt Dawid-Skene aus, sobald das Projekt mehr als einen Annotator hat, und fällt auf den Mehrheitsentscheid zurück, wenn die Schätzung fehlschlägt. Der andere Wert, majority, führt nur den Mehrheitsentscheid aus. Beide Methoden behandeln die gesamte Antwort eines Annotators auf ein Schema als eine Stimme. Zwei multiselect-Antworten zählen deshalb nur dann als dieselbe Stimme, wenn beide Antworten dieselbe Menge von Labels ankreuzen.

Die Einstellung consensus des Laufs und der Consensus-Export sind getrennte Funktionen. Der Consensus-Export gibt jedem Annotator eine Stimme, berichtet Anzahl und Anteil jeder Antwort bei jedem Item und markiert jedes Item als retired oder needs_review. Lies den Export vor dem Training, wenn du Item für Item sehen möchtest, wo sich Annotatoren spalten. MACE schätzt aus denselben Stimmen einen Kompetenz-Score für jeden Annotator.

Aus Uneinigkeit lernen

Bei subjektiven Aufgaben wie Beleidigung oder Emotion können Annotatoren uneins sein, weil jeder das Item anders liest, und ein einzelnes per Abstimmung gewonnenes Label verwirft die Spaltung. Uma et al. (2021) geben einen Überblick über Methoden, die auf der Uneinigkeit statt auf einem aggregierten Label trainieren. Eine Familie dieser Methoden trainiert auf Soft Labels. Ein Soft Label ist eine Wahrscheinlichkeitsverteilung über die Labels, gebildet aus dem Anteil der Annotatoren, die jedes Label gewählt haben.

hf-text-classification nimmt den Parameter soft_targets: true. Ist der Parameter gesetzt, trainiert ein Item, das zwei oder mehr Annotatoren gelabelt haben, per Kreuzentropie gegen die Verteilung auf die Spaltung der Annotatoren hin. Haben zwei von drei Annotatoren positive gesagt, ist das Ziel 0,67 positive und 0,33 negative. Bei einem multiselect-Schema trainiert jedes Label auf den Anteil der Annotatoren hin, die das Label angekreuzt haben. Ein Item mit einem Annotator trainiert wie bisher auf das Label dieses Annotators. Das Modell bleibt dann dort unsicher, wo Menschen uneins waren, und jede Vorhersage enthält die probabilities des Modells. Bei zurückgehaltenen Items mit Stimmenspaltung berichtet der Lauf drei weitere Metriken:

MetrikWas die Metrik misst
soft_jsdJensen-Shannon-Divergenz zwischen der Verteilung des Modells und der Spaltung der Annotatoren, in Bit von 0 bis 1
soft_cross_entropyKreuzentropie der Spaltung der Annotatoren unter der Verteilung des Modells
eceErwarteter Kalibrierungsfehler des obersten Labels gegenüber dem per Abstimmung gewonnenen Label, über 10 Konfidenz-Bins

In einem Soft-Label-Schema gibt jeder Annotator mit Schiebereglern eine Verteilung an. hf-text-classification trainiert ein soft_label-Schema immer auf die mittlere Verteilung der Annotatoren hin, und das Vorlabel stellt die Schieberegler auf die vorhergesagte Verteilung. Soft Targets brauchen zwei oder mehr Labels pro Item. Eine Studie, die auf Uneinigkeit trainieren will, sammelt deshalb von Anfang an überlappende Labels, und Wie viele Annotatoren brauchst du? behandelt die Einstellungen zur Überlappung. Uneinigkeit ist Signal, kein Rauschen begründet, warum die Spaltung in den Daten bleiben sollte.

Trainings-, Validierungs- und Test-Splits

Die Trainings-, Validierungs- und Test-Splits erfüllen drei verschiedene Aufgaben. Der Trainings-Split passt die Gewichte des Modells an. Der Validierungs-Split wählt unter Kandidatenmodellen aus, zum Beispiel die Epoche, in der das Training stoppt. Der Test-Split schätzt die Leistung auf ungesehenen Daten und spielt bei keiner der beiden Wahlen eine Rolle. Einen Checkpoint auf Validierung zu wählen, ist eine Form des Anpassens an Validierung. Der Checkpoint, der für den besten Validierungs-Score behalten wird, hat einen nach oben verzerrten Validierungs-Score, und nur der Test-Score stammt von Items, die die Wahl nie berücksichtigt hat.

Ein Lauf in Potato teilt die gelabelten Items standardmäßig 70/15/15 auf (splits). Der Split jedes Items stammt aus einem Hash der Item-ID mit festem Seed (split_seed). Ein Item, das in einem Lauf zurückgehalten wurde, bleibt deshalb auch im nächsten Lauf zurückgehalten, solange split_seed und splits gleich bleiben. Eine Änderung einer der beiden Einstellungen kann zurückgehaltene Items ins Training verschieben, und jeder Score nach der Änderung misst dann teilweise Auswendiglernen. Lege beide einmal fest, zu Beginn der Studie.

Die Fine-Tuning-Trainer, etwa hf-text-classification, behalten den Checkpoint der Epoche, die auf Validierung am besten abschnitt. Der Hauptscore eines solchen Laufs stammt von Test. sklearn-text, setfit, rdkit-property, die Trainer für Entscheidungsmodelle und die Inference-Bridges wählen nichts auf Validierung, und ein Lauf eines dieser Trainer nimmt den Hauptscore von Validierung, sobald Validierung Items hat. Der Tooltip der Spalte Held-out score der Runs-Tabelle nennt den Split und die Metrik hinter jeder Zahl. Ein Item mit einem Label und ohne Vorhersage zählt als falsch. Ein Trainer kann den Score nicht erhöhen, indem er schwierige Items überspringt, und <split>_coverage berichtet den Anteil der Items, die eine Vorhersage bekamen.

Korrigierte und angeheftete Items

Zwei Arten von Items kommen in den Train-Split jedes späteren Laufs, welchen Split der Hash auch zugewiesen hat. Die erste ist ein Item, das ein Reviewer in der Modellprüfung korrigiert hat, die zweite ein Item, das jemand mit Train on these neben einem Slice auf der Katalog-Seite angeheftet hat. Korrekturen kommen von den Items, bei denen das Modell am schlechtesten war, und in Validierung oder Test würden die Korrekturen das Modell an einer Stichprobe seiner eigenen Fehler bewerten. Ein Lauf, der zurückgehaltene Items ins Training verschiebt, schreibt eine Warnung mit der Anzahl ins Log, und der Holdout-Score des Laufs ist dann nicht direkt mit dem Score eines früheren Laufs vergleichbar. Ein Lauf, der auf einem korrigierten Item trainiert, das ein früherer Lauf zurückgehalten hat, schreibt ebenfalls eine Warnung, weil ein Score auf den Validierungs- oder Test-Items des früheren Laufs oder auf einem aus diesen Items gespeicherten Datensatz dann Items enthält, auf denen das neue Modell trainiert hat. Die Konfiguration des Modelltrainings nennt die Regeln im Abschnitt zu Korrekturen und angehefteten Items, die immer mittrainieren.

Festhalten, worauf jedes Modell trainiert hat

Zwei Läufe zu vergleichen setzt voraus, dass man weiß, auf welchen Items jeder Lauf trainiert und bewertet wurde. Jeder Lauf in Potato schreibt ein Bundle unter <output_annotation_dir>/training/runs/<run_id>/bundle/ mit train.jsonl, val.jsonl, test.jsonl, labels.json und manifest.json. Das Manifest hält den Split-Seed, die Aggregationsmethode, die Item-Anzahl in jedem Split, die Anzahl der ins Training erzwungenen Items und einen SHA-256-Digest der Split-Dateien fest. Nichts in einem Bundle verweist auf Potato zurück, und ein Skript außerhalb von Potato kann das Bundle als in sich geschlossene Kopie der aufgelösten Labels und Splits lesen.

Die Projektdatenbank project.sqlite führt ein Ledger mit einer Zeile pro Lauf. Jede Zeile hält Trainer, Parameter, Split-Größen, Split-Seed, Holdout-Metriken und den Bundle-Digest fest. Eine zweite Tabelle hält fest, in welchem Split jedes Item bei jedem Lauf lag. Das Zurückschreiben liest diese Tabelle und vorlabelt nie ein Item, auf dem ein Lauf im Ledger trainiert hat (retain_runs behält standardmäßig fünf abgeschlossene Läufe). Ein Modell ist bei Items, auf denen es trainiert hat, aus Gründen sicher, die nichts über neue Daten aussagen.

Um spätere Modelle an genau denselben Items zu vergleichen, speichert Keep this split as a dataset auf der Lauf-Seite die Validierungs-, Test- oder Train-Items des Laufs mit den vereinbarten menschlichen Labels als Version eines Datensatzes. Eine gespeicherte Version ändert sich danach nicht mehr. Jede gespeicherte Version enthält einen Split und beginnt von vorn, statt zur vorigen Version hinzuzufügen. Die Validierungs-Items von Lauf 2, auf die von Lauf 1 gespeichert, würden sonst Items enthalten, auf denen Lauf 2 trainiert hat. Eine Auswertung auf einer gespeicherten Version kann die Antwort des Modells nicht lesen, weil die gespeicherten Eingaben das Vorlabel-Feld auslassen. Das Speichern braucht datasets.enabled: true. Wenn das Modell oder der Datensatz das Projekt verlässt, behandelt Datensätze und Modelle dokumentieren Datasheets und Modellkarten.

Wie viele Daten ein erstes Modell braucht

Jeder Trainer von Potato verweigert das Anpassen mit weniger als min_instances Items im Train-Split. Die folgenden Standardwerte sind die Anzahlen, ab denen ein Lauf startet:

TrainerStandard von min_instancesHinweis
setfit8Gebaut für die ersten Tage eines Projekts, ab etwa acht Items pro Label
sklearn-text10Kalibriert Konfidenzen erst ab 50 Trainings-Items
hf-audio-tagger10
hf-text-classification, hf-token-classification, hf-image-classification20
llm-sft, llm-dpo20

Die Untergrenze zählt nur den Train-Split. Beim Standard-Split 70/15/15 startet ein sklearn-text-Lauf, sobald etwa 15 Items ein Label haben. Das Modelltraining-Beispiel im Repository von Potato liefert einen gemessenen Punkt. Mit je einem Label für 120 der 160 synthetischen Produktrezensionen des Beispiels erreichte ein sklearn-text-Lauf 0,84 Macro-F1 auf Validierung und veröffentlichte 80 Vorlabels. Die Zahl stammt von einer synthetischen Aufgabe mit zwei Labels, und der Holdout-Score deiner eigenen Läufe ist die Zahl, die du für deine Aufgabe lesen solltest.

Beginne mit sklearn-text. Der Trainer braucht nichts außer einer einfachen Installation und keine GPU. Trainiere neu, wenn Labels eintreffen, und beobachte den Holdout-Score von Lauf zu Lauf mit unverändertem split_seed. Vorlabels verankern Annotatoren. Lass writeback.schemas leer, bis der Holdout-Score das Anzeigen der Antworten des Modells rechtfertigt. Modellgestütztes Labeln behandelt, was sich ändert, sobald Annotatoren Vorlabels sehen, und Prüfen von Durchwinken unterscheiden behandelt, wie sich prüfen lässt, ob Annotatoren die Items noch lesen.

Eine Konfiguration, die jede Entscheidung festlegt

Die folgende Konfiguration trainiert auf einem Sentiment-Schema mit zwei Labels. Jeder Schlüssel unter model_training legt eine der obigen Entscheidungen fest:

yaml
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: true

aggregation: consensus löst überlappende Labels mit Dawid-Skene auf. split_seed und splits stehen mit den Standardwerten da, weil sich keine der beiden Einstellungen während der Laufzeit der Studie ändern sollte. soft_targets: true lässt jeden hf-text-classification-Lauf des Projekts auf Stimmenspaltungen trainieren. Dieser Trainer braucht pip install "potato-annotation[train-text]", und sklearn-text läuft mit derselben Konfiguration ohne zusätzliche Installation. Ohne einen Block writeback sehen Annotatoren keine Vorlabels. Starte den Server mit der Konfiguration neu, öffne /admin/training, wähle einen Trainer und das Schema sentiment und klicke auf Train now. Die Referenz zur Konfiguration des Modelltrainings listet jeden Schlüssel auf, und das Tutorial zum Modell im Kreislauf ergänzt das Zurückschreiben und das automatische Neutrainieren.

Literatur

  • 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