Zum Inhalt springen

Dein erstes Modell auf den eigenen Annotationen trainieren

Starte Potatos Beispielstudie mit Rezensionen auf einem Laptop ohne GPU, labele 120 Rezensionen mit dem Simulator, trainiere sklearn-text und sieh dir die Vorlabels des Modells an.

Neu in v2.14.0

Dieses Tutorial trainiert einen Sentiment-Klassifikator auf den Labels einer Beispielstudie und zeigt die Antworten des Klassifikators dem nächsten Annotator als Vorlabels. Das Tutorial richtet sich an Studienverantwortliche, die das Modelltraining von Potato zum ersten Mal ausprobieren, und jeder Schritt läuft auf einem Laptop ohne GPU und ohne weitere Installation außer Potato selbst. Du startest Potatos Beispielprojekt mit Rezensionen, lässt den Nutzersimulator 120 der 160 Rezensionen des Projekts labeln, trainierst sklearn-text auf der Admin-Seite Training, liest den Holdout-Score des Laufs und meldest dich als neuer Annotator an, um die Antworten des Modells zu sehen. Was die einzelnen Teile des Kreislaufs allgemein leisten, steht in der Übersicht zum Modelltraining.

Potato und das Beispielprojekt installieren

Das Tutorial verwendet sklearn-text, einen Trainer, der jede Rezension in TF-IDF-Features umwandelt und einen logistischen Regressionsklassifikator anpasst. sklearn-text braucht keine zusätzliche Installation, weil scikit-learn zu den Kernabhängigkeiten von Potato gehört. Das Beispielprojekt liegt im GitHub-Repository von Potato und nicht im pip-Paket. Installiere deshalb Potato und klone das Repository:

bash
pip install --upgrade potato-annotation
git clone https://github.com/davidjurgens/potato.git
cd potato

Alle folgenden Befehle laufen im Hauptverzeichnis des Repositorys. Der Projektordner examples/ai-assisted/model-training/ enthält drei Dateien:

  • config.yaml ist die Studienkonfiguration, deren Kommentare die Befehle dieses Tutorials enthalten.
  • data/reviews.json enthält 160 synthetische Produktrezensionen, je ein JSON-Objekt pro Zeile mit id und text.
  • data/gold.json nennt für jede Rezension das richtige Label. Der Simulator antwortet aus dieser Datei.

Die Beispielkonfiguration

Die Konfiguration definiert ein radio-Schema namens sentiment mit den Labels positive und negative und schaltet das Modelltraining ein. Der folgende Block ist die ausgelieferte Datei ohne Kommentare, und die Datei besteht python -m potato.validate_cli --strict unverändert:

yaml
annotation_task_name: "Review Sentiment (model training demo)"
 
data_files:
  - "data/reviews.json"
 
item_properties:
  id_key: "id"
  text_key: "text"
 
task_dir: "."
output_annotation_dir: "annotation_output"
 
require_password: false
admin_api_key: "demo-admin-key"
 
num_annotators_per_item: 1
 
annotation_schemes:
  - annotation_type: "radio"
    name: "sentiment"
    description: "Is this review positive or negative?"
    labels:
      - "positive"
      - "negative"
    sequential_key_binding: true
 
model_training:
  enabled: true
  writeback:
    schemas: ["sentiment"]
    include_unlabeled: true
    min_confidence: 0.6

Vier Einstellungen bestimmen den Ablauf des Tutorials:

  • num_annotators_per_item: 1 gibt jeder Rezension ein Label. Drei simulierte Annotatoren mit je 40 Rezensionen decken dann 120 verschiedene Rezensionen ab und lassen 40 für das Modell ungelabelt.
  • require_password: false erlaubt einem neuen Annotator die Anmeldung allein mit einem Benutzernamen. Der letzte Schritt meldet sich auf diese Weise an.
  • admin_api_key: "demo-admin-key" öffnet die Admin-Seiten. Ersetze den Schlüssel auf jedem Server, den andere Personen erreichen können.
  • model_training registriert die Routen unter /admin/training. Der Block writeback zeigt den Annotatoren die Vorhersagen für das Schema sentiment, und der Abschnitt zum Zurückschreiben unten erklärt jeden Schlüssel.

Den Server auf Port 8000 starten

Starte Potato mit der Beispielkonfiguration:

bash
potato start examples/ai-assisted/model-training/config.yaml -p 8000

Der Server lädt die 160 Rezensionen und stellt die Annotationsseite unter http://localhost:8000 bereit. Ist Port 8000 auf deinem Rechner belegt, gib -p einen anderen Port und verwende diesen Port in allen URLs unten.

120 Rezensionen mit dem Simulator labeln

Das Modell braucht menschliche Labels, aus denen es lernt. Der Nutzersimulator ersetzt drei Annotatoren. Jeder simulierte Annotator antwortet aus der Gold-Datei und trifft die meisten Antworten richtig. Starte den Simulator in einem zweiten Terminal im Hauptverzeichnis des Repositorys:

bash
python -m potato.simulator --server http://localhost:8000 --users 3 \
  --strategy gold_standard --competence good=1.0 --max-annotations 40 \
  --gold-file examples/ai-assisted/model-training/data/gold.json \
  --sequential --fast-mode --no-export

--strategy gold_standard lässt jeden simulierten Annotator aus gold.json antworten, und --competence good=1.0 gibt allen drei Annotatoren das Profil good des Simulators. Ein Annotator mit dem Profil good zieht eine Genauigkeit zwischen 0,80 und 0,90 und beantwortet jede Rezension mit dieser Wahrscheinlichkeit richtig. Die Labels enthalten deshalb Fehler, wie die Labels eines echten Teams. --sequential lässt die drei Annotatoren nacheinander laufen, --fast-mode streicht die Pausen zwischen den Antworten, und --no-export verzichtet auf die eigenen Ergebnisdateien des Simulators. Der Simulator ist nach etwa zwei Sekunden fertig und endet mit einer Zusammenfassung. Prüfe, dass die Zusammenfassung Total annotations: 120 meldet, bevor du weitermachst. Du kannst Rezensionen auch von Hand unter http://localhost:8000 labeln. sklearn-text verweigert das Anpassen mit weniger als 10 gelabelten Items im Train-Split.

Die Training-Seite mit dem Admin-Schlüssel öffnen

Die Training-Seite braucht eine Admin-Sitzung. Öffne http://localhost:8000/admin, gib demo-admin-key ein, wenn die Seite nach dem API-Schlüssel fragt, und öffne danach http://localhost:8000/admin/training.

Die Potato-Training-Seite mit ausgewähltem sklearn-text, dem Schema sentiment und dem Backend local, über einer Runs-Tabelle mit zwei abgeschlossenen Läufen und Holdout-Scores von 0,847 und 0,840Die Training-Seite nach zwei sklearn-text-Läufen auf dem Beispielprojekt

Das Panel Start a run oben enthält das gesamte Setup. Schema listet das einzige Schema des Projekts, sentiment (radio). Trainer listet alle 38 Trainer, und ein Trainer, den das Projekt nicht ausführen kann, trägt den Grund neben seinem Namen, etwa „not installed“. Die Seite wählt sklearn-text aus, sobald sklearn-text zum Schema passt. Runs on zeigt das einzige Backend des Projekts, local (this machine).

sklearn-text trainieren

Lass Parameters leer, um die Standardwerte des Trainers zu verwenden, und klicke auf Train now. Der Lauf löst die Annotationen zu einem Label pro Rezension auf, teilt die 120 gelabelten Rezensionen in Train-, Val- und Test-Items auf und passt das Modell in einem eigenen Prozess an. Unser Lauf dauerte 1,5 Sekunden, und das Panel zeigte „Run finished.“, als der Lauf beendet war.

sklearn-text verwendet standardmäßig den TfidfVectorizer von scikit-learn für die Features und LogisticRegression als Klassifikator. Bei 50 oder mehr Items im Train-Split kalibriert sklearn-text außerdem die Konfidenzen des Klassifikators. Die Kalibrierung verwendet Platt-Skalierung unter 1.000 Trainings-Items und isotone Regression ab 1.000 Items. Das kalibrierte Modell bleibt nur erhalten, wenn die Kalibrierung höchstens 0,05 Trainingsgenauigkeit kostet. Die Kalibrierung ist hier wichtig, weil das Zurückschreiben jede Konfidenz mit min_confidence vergleicht.

Um denselben Lauf aus einem Skript zu starten, sende den Admin-Schlüssel im Header X-API-Key:

bash
curl -X POST -H "X-API-Key: demo-admin-key" -H "Content-Type: application/json" \
  http://localhost:8000/admin/training/api/runs \
  -d '{"trainer": "sklearn-text", "schemas": ["sentiment"]}'

Die Antwort enthält die neue run_id und "started": true.

Die Lauf-Seite und der Holdout-Score

Der abgeschlossene Lauf erscheint in der Runs-Tabelle mit den Größen von Train und Val und seinem Held-out score. Klicke auf die Run-ID, um die Lauf-Seite unter /admin/training/runs/<run_id> zu öffnen. Die Lauf-Seite zeigt Status, Trainer, Backend, Split-Größen, Split-Seed, Holdout-Score und Parameter des Laufs, danach eine Tabelle mit jeder Metrik und das Log des Laufs.

Ein Lauf hält standardmäßig 15 % der gelabelten Items für Val und 15 % für Test zurück, und split_seed entscheidet, welche Items wohin kommen. Der Split bleibt von Lauf zu Lauf gleich, solange split_seed seinen Wert behält, sodass zwei Läufe auf denselben Labels an denselben Items bewertet werden. Der Holdout-Score eines sklearn-text-Laufs ist der Macro-F1 auf Val. Der Macro-F1 mittelt den F1-Score jedes Labels, hier positive und negative. Der Lauf zeichnet außerdem Genauigkeit und Macro-F1 auf Test auf. Die Genauigkeit auf dem Train-Split wird als train_accuracy aufgezeichnet und nie als Score verwendet. In unserem Lauf lautete das Log:

text
[info] Read 76 labelled rows from the train split
[info] Applied sigmoid calibration over 5 folds
[info] Held-out val macro_f1: 0.725

Potatos eigene Dokumentation berichtet einen Lauf auf demselben Projekt, und die Tabelle stellt diesen Lauf neben unseren:

Dokumentation von PotatoUnser Lauf
Gelabelte Rezensionen120120
Items in Train, Val und Testnicht angegeben76, 19 und 25
Holdout-Score (Val-Macro-F1)0,840,725
Test-Macro-F1nicht angegeben0,826
Veröffentlichte Vorlabels8073
Vorhersagen unter min_confidence411

Deine Zahlen weichen von beiden Spalten ab, weil jeder simulierte Annotator eine Genauigkeit zufällig zieht und andere Fehler macht. In unserem Lauf stimmten die simulierten Labels bei 97 der 120 Rezensionen und bei 15 der 19 Val-Rezensionen mit gold.json überein. Der Holdout-Score misst die Übereinstimmung mit den Labels deiner Annotatoren und nicht mit einem Lösungsschlüssel, sodass Annotatorenfehler in Val den Score senken. Jedes der 73 Vorlabels, die unser Lauf veröffentlichte, stimmte mit gold.json überein. Lies bei einer echten Studie ohne Gold-Datei einen niedrigen Holdout-Score als Anlass, die Übereinstimmung der Annotatoren zu prüfen, bevor du dem Modell die Schuld gibst.

Das Zurückschreiben für das Schema einschalten

Die Vorhersagen eines Laufs erreichen Annotatoren nur über das Zurückschreiben. Die Beispielkonfiguration schaltet das Zurückschreiben für das Schema sentiment bereits ein. Füge für dein eigenes Projekt diesen Block unter model_training in die Konfiguration ein und starte den Server neu:

yaml
model_training:
  enabled: true
  writeback:
    schemas: ["sentiment"]
    include_unlabeled: true
    min_confidence: 0.6

writeback.schemas nennt die Schemas, deren Vorhersagen Annotatoren sehen. Die Liste ist standardmäßig leer, sodass das Einschalten des Trainings auf der Annotationsseite nichts ändert, bis du ein Schema nennst. include_unlabeled: true lässt jeden Lauf auch für die Rezensionen vorhersagen, die niemand gelabelt hat, und nicht nur für die Val- und Test-Rezensionen. Ohne include_unlabeled sagt ein Lauf nur für die Val- und Test-Rezensionen voraus, und diese Rezensionen haben bereits ein menschliches Label. min_confidence: 0.6 hält eine Vorhersage von der Annotationsseite fern, wenn die Konfidenz des Modells unter 0,6 liegt. Potato speichert die Vorhersage trotzdem.

Das Zurückschreiben läuft nach jedem erfolgreichen Lauf und überspringt jedes Item im Train-Split des Laufs. In unserem Lauf sagte das Modell für 84 Rezensionen voraus (19 Val, 25 Test und die 40 ungelabelten), 11 Vorhersagen lagen unter 0,6, und der Lauf veröffentlichte die übrigen 73. Das Feld writeback von GET /admin/training/api/status nennt dieselben Zahlen mit der Zusammenfassung „Published 73 prediction(s) as prelabels.“. Gespeicherte Vorhersagen werden beim Start des Servers erneut zurückgeschrieben, sodass Vorlabels einen Neustart überstehen. Um die Vorlabels eines Laufs von den Items zu entfernen, sende DELETE /admin/training/api/runs/<run_id>/predictions.

Ein Vorlabel aus Sicht eines neuen Annotators

Öffne http://localhost:8000 in einem privaten Browserfenster und melde dich mit einem Benutzernamen an, den noch niemand verwendet hat, etwa newannotator. Jede gelabelte Rezension hat bereits ihr eines Label, sodass dem neuen Annotator die 40 ungelabelten Rezensionen zugewiesen werden, und der Fortschrittszähler in unserem Lauf zeigte 0/40. Unsere erste Rezension lautete „The toaster: Disappointed, it stopped working within a week. Much smaller than the photos suggest.“, mit bereits ausgewähltem Negative bei einer Konfidenz von 0,68.

Eine Potato-Annotationsseite für eine Toaster-Rezension, auf der das Modell die Option Positive bereits ausgewählt hat und das Item weiterhin als Not labeled markiert istEine Rezension, die sich mit der ausgewählten Antwort des Modells öffnet, bevor der Annotator etwas gespeichert hat

Das Vorlabel wird nicht gespeichert, solange der Annotator die Rezension nur ansieht, und der Statuschip zeigt „Not labeled“, bis der Annotator eine Antwort speichert. Die Antwort des Modells wird zur Antwort des Annotators, wenn der Annotator die Auswahl ändert oder auf Next klickt. In unserem Lauf öffneten sich die 5 ungelabelten Rezensionen, deren Vorhersage unter min_confidence lag, ohne Auswahl. Ein Annotator, der mit ai_support.holdout von maschineller Hilfe ausgenommen ist, sieht überhaupt keine Vorlabels. Vorlabels ziehen Annotatoren zur Antwort des Modells, schalte das Zurückschreiben deshalb erst ein, wenn der Holdout-Score hoch genug ist, um ihm zu vertrauen, und achte mit den Prüfungen aus Durchgewinkte Vorlabels erkennen auf Annotatoren, die jedes Vorlabel annehmen.

Nächste Schritte

Dasselbe Projekt trägt noch einige weitere Experimente, bevor du zu deinen eigenen Daten wechselst:

  • Einen Parameter ändern. Gib {"vectorizer_kwargs": {"ngram_range": [1, 2]}} in Parameters ein und trainiere erneut, um den Features Wortpaare hinzuzufügen. Unser zweiter Lauf mit Wortpaaren erreichte auf demselben Split 0,774 Val-Macro-F1 und veröffentlichte 74 Vorlabels. Ein Parametername, den sklearn-text nicht kennt, wird mit der Liste der Namen abgelehnt, die der Trainer kennt.
  • Einen Transformer ausprobieren. hf-text-classification (pip install "potato-annotation[train-text]") und setfit (pip install "potato-annotation[embeddings]") lernen dasselbe Schema, und die Trainer-Seite nennt die Parameter jedes Trainers.
  • Den Kreislauf schließen. Modell im Kreislauf ergänzt die Prüfwarteschlange, das erneute Trainieren bei neu eintreffenden Annotationen mit auto_retrain und das Speichern des Splits eines Laufs als Datensatzversion.
  • Das Training auf eine GPU verlagern. Auf einem GPU-Server, SLURM-Cluster oder Rechner hinter NAT trainieren schickt dieselben Läufe an einen anderen Rechner.
  • Andere Arten von Modellen trainieren. Die Tutorials zu LLM-Fine-Tuning, Bildmodellen, Audiomodellen und Wissenschaftsmodellen folgen denselben Schritten mit anderen Trainern und Schemas.

Jeder hier verwendete Schlüssel steht in der Referenz zur Konfiguration des Modelltrainings. Starte den ersten Lauf deines eigenen Projekts, indem du den obigen Block model_training in deine Konfiguration kopierst und dein Schema unter writeback.schemas nennst.