Zum Inhalt springen

Auf einem GPU-Server, SLURM-Cluster oder Rechner hinter NAT trainieren

Schicke Potato-Trainingsläufe an einen ssh-GPU-Server, einen SLURM-Rechenknoten oder einen pollenden Agent, mit der Konfiguration für jeden, dem Check-Befehl und häufigen Fehlern.

Neu in v2.14.0

Dieses Tutorial verlagert das Modelltraining von Potato vom Annotationsserver auf einen Rechner mit GPU. Das Tutorial richtet sich an Studienadmins, deren Annotationsserver eine kleine Cloud-VM oder ein Laptop ist und deren GPUs in einem Lab-Server, einem Universitätscluster oder auf einer Workstation stehen, zu der sich der Server nicht verbinden kann. Für jedes der drei Remote-Backends behandelt die Seite, wann das Backend die richtige Wahl ist, was auf dem Remote-Rechner installiert sein muss, die Konfiguration, den Check-Befehl, was während eines Laufs geschieht, wie man einen Lauf abbricht und welche Fehler am wahrscheinlichsten auftreten. Das Tutorial setzt ein Projekt voraus, das bereits auf dem Annotationsserver trainiert, etwa das Projekt mit Rezensionen aus Dein erstes Modell trainieren.

Vier Orte, an denen ein Lauf ausgeführt werden kann

Ein Backend ist der Ort, an dem ein Trainingslauf ausgeführt wird. Potato hat immer das Backend local, einen Subprozess auf dem Annotationsserver. Die anderen Backends nennst du unter model_training.backends:

TypWo der Trainer läuftWer die Remote-Seite startetWo die Modelldateien landen
localDer Annotationsserver, in einem SubprozessPotatoDas Verzeichnis artifacts/ des Laufs
sshEin Rechner, den Potato über ssh erreicht, etwa ein GPU-Server im LabPotato, über sshZurückkopiert nach artifacts/
slurmEin Rechenknoten eines Clusters, als Batch-JobPotato, über ssh zum Login-Knoten, dann sbatchZurückkopiert nach artifacts/
agentEin Rechner, den Potato nicht erreicht, etwa eine Workstation hinter NATDu, mit potato training agentAuf dem Trainingsrechner

Wähle ssh, wenn sich der Annotationsserver mit einem ssh-Schlüssel auf dem GPU-Rechner anmelden kann. Wähle slurm, wenn die GPUs hinter dem Scheduler SLURM stehen und der Rechner, auf dem du dich anmelden kannst, ein Login-Knoten ist. Wähle agent, wenn sich vom Server aus keine Verbindung zum GPU-Rechner öffnen lässt, weil der Agent jede Verbindung selbst öffnet. Eine Workstation hinter einem Heimrouter oder einer Campus-Firewall ist der übliche Fall für einen Agent. Die Vorhersagen und das Ergebnis des Laufs erreichen den Server von jedem Backend aus, sodass das Zurückschreiben und der Holdout-Score überall gleich funktionieren, wo der Trainer lief. Jeder Trainer außer decision-calibrate läuft auf jedem Backend.

Die Projektkonfiguration

Die folgende Konfiguration ist das Projekt mit Rezensionen aus dem ersten Tutorial, ergänzt um alle drei Remote-Backends. Ein echtes Projekt braucht nur die Backends, die du verwendest, und jedes Backend bekommt unten einen eigenen Abschnitt. max_wall_seconds: 3600 stoppt jeden Lauf, der nach einer Stunde nicht beendet ist. Bei einem ssh- oder Agent-Backend prüft der Server das Limit jede Sekunde, sodass ein Lauf, der auf einem Remote-Rechner hängt, die Lauf-Warteschlange nicht länger als das Limit blockiert:

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"
admin_api_key: "change-me"
 
annotation_schemes:
  - annotation_type: "radio"
    name: "sentiment"
    description: "Is this review positive or negative?"
    labels: ["positive", "negative"]
 
model_training:
  enabled: true
  backend: gpu-server        # the default for runs; leave out to keep runs local
  max_wall_seconds: 3600
  writeback:
    schemas: ["sentiment"]
    include_unlabeled: true
    min_confidence: 0.6
  backends:
    gpu-server:
      type: ssh
      host: gpu.example.org
      python: /opt/conda/bin/python3
      gpus: auto
      min_free_gpu_mb: 4000
    cluster:
      type: slurm
      host: login.cluster.example.org
      python: /opt/conda/bin/python3
      job_python: /shared/envs/train/bin/python
      remote_dir: /shared/projects/me/potato-training
      gres: gpu:1
      time: "04:00:00"
      prelude: ["module load cuda/12.4"]
    lab-workstation:
      type: agent
      queue_timeout_s: 3600

Validiere die Konfiguration, bevor du den Server startest:

bash
potato validate config.yaml --strict

Der Validator meldet einen Schlüssel, den der Backend-Typ nicht kennt, ein ssh- oder slurm-Backend ohne host, ein SLURM-remote_dir unter /tmp und ein model_training.backend, das kein Backend benennt. Der Server startet bei denselben Fehlern nicht, sodass ein falsch geschriebenes pyhton den Server beim Start anhält, statt Läufe an das Standard-python3 zu schicken.

Das Menü Runs on und die API

Die Training-Seite unter /admin/training hat ein Menü Runs on, das jedes Backend mit Typ und Host auflistet, z. B. gpu-server (ssh to gpu.example.org). model_training.backend legt den Eintrag fest, den das Menü zuerst auswählt, und die Runs-Tabelle hält in der Spalte Ran on fest, wo jeder Lauf ausgeführt wurde. Ein Lauf, der über die API gestartet wird, nennt sein Backend im Feld backend des Request-Bodys:

bash
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  http://localhost:8000/admin/training/api/runs \
  -d '{"trainer": "hf-text-classification", "schemas": ["sentiment"], "backend": "cluster"}'

Ein Backend-Name, der nicht in der Konfiguration steht, wird mit 409 abgelehnt. Das automatische Neutrainieren verwendet model_training.backend, solange auto_retrain.backend kein anderes Backend nennt, und Modell im Kreislauf behandelt auto_retrain vollständig. Unabhängig vom Backend läuft immer ein Lauf zur Zeit, und ein Lauf, der gestartet wird, während ein anderer läuft, wartet in der Warteschlange.

Auf diesem Rechner trainieren

Prüfe, welches Gerät ein lokaler Lauf bekommt, bevor du Läufe woandershin verlagerst. Mit dem Standard device: auto nimmt ein lokaler Lauf zuerst CUDA, dann Apples Metal (mps) und dann die CPU, und device: cuda:1 benennt eine einzelne GPU. Der Check-Befehl gibt das Gerät aus, das ein lokaler Lauf verwenden würde:

bash
potato training check local config.yaml

Auf einem Mac mit Apple Silicon gibt der Befehl local: this machine, Apple Metal (mps) aus. Ein angefordertes Gerät, das nicht vorhanden ist, fällt mit einer Warnung im Log des Laufs auf die CPU oder einen anderen Beschleuniger zurück. Lautet die Antwort CPU und fine-tunt der Trainer einen Transformer, verlagere den Lauf auf eines der Remote-Backends unten. Konfiguration listet device, num_threads und max_ram_mb für lokale Läufe auf.

Ein GPU-Server über ssh

Ein ssh-Backend führt den Trainer auf einem Rechner aus, den der Annotationsserver über ssh erreicht, meist ein GPU-Server im Lab. Potato startet alles auf der Remote-Seite selbst, sodass dort außer Python und den Paketen des Trainers nichts von Hand installiert oder gestartet wird. Auf dem GPU-Host muss Potato nicht installiert sein, weil Potato beim ersten Lauf seinen eigenen Python-Quellcode auf den Host kopiert und die Kopie wiederverwendet, bis sich der Quellcode ändert.

Voraussetzungen für ein ssh-Backend

Der Account, unter dem der Annotationsserver läuft, braucht einen ssh-Schlüssel, der sich ohne Eingabeaufforderung auf dem GPU-Host anmeldet. Potato führt ssh mit BatchMode=yes aus, sodass eine Passwortabfrage den Lauf sofort scheitern lässt, statt ihn hängen zu lassen. ssh gpu.example.org true muss unter diesem Account gelingen, und ein Schlüssel mit Passphrase funktioniert, wenn ssh-agent den Schlüssel hält. Der Wert host ist ein beliebiger Name, den ssh akzeptiert, und ein Alias aus ~/.ssh/config funktioniert. Die Schlüssel user, port und identity_file werden als -l, -p und -i an ssh übergeben.

Der GPU-Host braucht Python 3.8 oder neuer und die Pakete des Trainers, den du ausführst. Für hf-text-classification sind das torch, transformers und peft, der Inhalt des Extras potato-annotation[train-text]. Die Seite Trainer nennt die Installation für jeden Trainer. Fehlt dem Interpreter des Hosts ein Paket, richte python auf einen Interpreter, der das Paket hat, oder führe das Paket unter packages auf. Ist packages gesetzt, legt Potato unter remote_dir eine virtuelle Umgebung mit --system-site-packages an und installiert die aufgeführten Pakete einmal in die Umgebung. Der CUDA-Build von torch des Hosts bleibt in der Umgebung sichtbar:

yaml
model_training:
  enabled: true
  backends:
    gpu-server:
      type: ssh
      host: gpu.example.org
      python: /opt/conda/bin/python3
      packages: ["transformers>=4.46.0", "peft>=0.13.0"]
      gpus: auto
      min_free_gpu_mb: 4000
      num_threads: 8

Mit gpus: auto nimmt jeder Lauf die GPU mit dem meisten freien Speicher und startet nicht, wenn keine GPU min_free_gpu_mb frei hat (Standard 2000). Potato vergleicht den freien Speicher statt der Auslastung, weil eine Karte mit niedriger Auslastung auf einem geteilten Server dennoch wenig freien Speicher haben kann. Setze min_free_gpu_mb nahe an den Speicher, den dein Trainer braucht. gpus: "1" legt GPU 1 fest, "0,1" legt zwei GPUs fest, und gpus: none trainiert auf der CPU. Ein Host ganz ohne GPU trainiert unter auto ebenfalls auf der CPU. num_threads setzt OMP_NUM_THREADS, MKL_NUM_THREADS und OPENBLAS_NUM_THREADS für den Lauf. Manche geteilten Server setzen OMP_NUM_THREADS=1 in Login-Shells, und num_threads überschreibt den Wert der Login-Shell.

Der Check-Befehl für ein ssh-Backend

Führe den Check auf dem Annotationsserver aus, unter dem Account, unter dem der Server läuft:

bash
potato training check gpu-server config.yaml

Der Befehl verbindet sich und meldet die Python-Version des Remote-Rechners, jede GPU mit freiem Speicher und Auslastung, die GPU, die ein Lauf bekäme, und die Trainingspakete, die dem Remote-Interpreter fehlen. Eine GPU, für die das installierte torch keine Kernel hat, wird mit (torch there has no kernels for it) markiert, und gpus: auto überspringt eine solche GPU. --json gibt denselben Bericht als JSON aus. Der Befehl endet mit 0, wenn ein Lauf starten könnte, und sonst mit 1. Die Schaltfläche Check neben dem Menü Runs on führt denselben Check von der Training-Seite aus.

Schritte eines ssh-Laufs

Für jeden Lauf führt Potato diese Schritte aus:

  1. Verbindet sich mit ssh und öffnet eine Reverse-Weiterleitung von einem Unix-Socket im Remote-/tmp zurück zum Annotationsserver.
  2. Prüft den Interpreter, liest nvidia-smi und wählt die GPU.
  3. Kopiert den Quellcode von Potato nach remote_dir/code/<hash>, wenn dem Host diese Version fehlt, und baut die virtuelle Umgebung, wenn packages gesetzt ist und die Umgebung fehlt. remote_dir ist standardmäßig ~/.cache/potato-training.
  4. Startet python -m potato.training.agent für den Lauf. Das Token des Laufs erreicht den Agent über stdin und erscheint nie in einer Befehlszeile, weil Befehlszeilen auf einem geteilten Server für jeden Account sichtbar sind.
  5. Der Agent lädt das Bundle des Laufs mit Items, Labels und Medien herunter. Der Agent führt denselben Training-Worker aus, den das lokale Backend ausführt, und sendet Fortschritt, Vorhersagen und das Ergebnis über den Socket zurück.
  6. Ist der Lauf erfolgreich, kopiert Potato das Artefaktverzeichnis in das artifacts/ des Laufs zurück, löscht das Remote-Job-Verzeichnis und schließt die Verbindung.

Die Schrittzeile auf der Training-Seite folgt diesen Phasen, z. B. copying Potato's code to gpu.example.org und waiting for the agent on gpu.example.org. Das Log des Laufs nennt das Python des Hosts und die GPU, die der Lauf bekam.

Ein vollständiges Fine-Tuning kopiert das ganze Modell zurück, und über eine langsame Verbindung braucht ein Modell von 330 MB Minuten. Die Schrittzeile zeigt, wie viel vom Modell angekommen ist. Dateien, die größer als max_artifact_mb sind (Standard 2048), bleiben auf dem GPU-Host und werden im Log des Laufs genannt. fetch_artifacts: false lässt jede Modelldatei auf dem GPU-Host, und keep_remote: true behält das Remote-Job-Verzeichnis zur Inspektion. Der Push auf den Hugging Face Hub von der Lauf-Seite aus braucht die Modelldateien auf dem Annotationsserver, sodass ein Modell, das auf dem GPU-Host bleibt, nicht von der Lauf-Seite aus gepusht wird.

Der Unix-Socket wird mit dem Modus 0600 angelegt, sodass sich nur der Account, mit dem Potato angemeldet ist, über den Socket verbinden kann. Anfragen über den Socket erreichen den Annotationsserver als Loopback-Anfragen. Ein Server, der mit debug: true gestartet wurde, gewährt Loopback-Anfragen Admin-Zugriff. Jeder, der diesen Account auf dem GPU-Host nutzen kann, hat dann Admin-Zugriff auf einen Debug-Server, solange ein Lauf läuft. Lass debug auf einem Server aus, der über ssh trainiert.

Abbruch und Heartbeat-Timeout

Cancel run auf der Training-Seite erreicht den Agent über den Socket, in der Antwort auf den nächsten Fortschrittsbericht des Agents. Der Agent sendet SIGTERM an den Worker und SIGKILL, wenn der Worker nach model_training.grace_seconds (Standard 20) noch läuft, was der Server mit dem Job mitschickt. Ein Job von einem älteren Potato-Server trägt kein grace_seconds, und der Agent wartet dann 20 Sekunden. Auf dem Server endet der Lauf als abgebrochen, sobald grace_seconds vergangen sind, und der Server schließt die ssh-Sitzung des Agents. Ein Lauf, dessen Agent heartbeat_timeout_s lang (Standard 120) nichts sendet, schlägt fehl, und agent.log im Lauf-Verzeichnis enthält die letzte Ausgabe des Agents.

Ein SLURM-Cluster

Ein slurm-Backend ist für einen Cluster gedacht, dessen GPUs hinter dem Scheduler SLURM stehen. Auf einem solchen Cluster ist der Rechner, den Potato über ssh erreicht, ein Login-Knoten ohne GPUs, und die Rechenknoten erreichen Potato gar nicht. Potato startet den Agent deshalb auf dem Login-Knoten, wie bei einem ssh-Backend, und der Agent übergibt nur den Training-Worker mit sbatch an einen Rechenknoten. Der Fortschritt kommt über eine Datei auf Speicher zurück, den der Login-Knoten und die Rechenknoten teilen.

Voraussetzungen für ein SLURM-Backend

Der Login-Knoten braucht einen ssh-Schlüssel ohne Eingabeaufforderung und für den Agent Python 3.8 oder neuer, wie der Host eines ssh-Backends. Der Login-Knoten braucht außerdem sbatch, squeue und scancel im PATH. Der Agent ruft zusätzlich scontrol auf, wo der Cluster den Befehl hat. Potato ruft nie srun oder sacct auf, sodass ein Cluster mit abgeschaltetem srun und ohne Accounting-Datenbank funktioniert. remote_dir ist erforderlich und muss auf Speicher liegen, den die Rechenknoten teilen, weil der Job dort das Bundle liest und das Modell schreibt. Der Validator meldet einen Fehler für ein remote_dir unter /tmp oder /var/tmp, weil diese Verzeichnisse lokal zu jedem Knoten gehören.

Die Rechenknoten brauchen einen Interpreter mit den Paketen des Trainers, benannt durch job_python. packages wird auf einem SLURM-Backend nicht unterstützt, weil eine virtuelle Umgebung, die auf dem Login-Knoten angelegt wurde, auf den Rechenknoten möglicherweise nicht läuft. Richte job_python auf eine Umgebung, die die Rechenknoten haben, und setze Modul-Ladebefehle oder eine Aktivierung der Umgebung in prelude:

yaml
model_training:
  enabled: true
  backends:
    cluster:
      type: slurm
      host: login.cluster.example.org
      python: /opt/conda/bin/python3                    # on the login node, for the agent
      job_python: /shared/envs/train/bin/python         # on the compute nodes, for the worker
      remote_dir: /shared/projects/me/potato-training   # storage the compute nodes share
      partition: gpu
      gres: gpu:1
      time: "04:00:00"
      prelude: ["module load cuda/12.4"]

Jeder ssh-Schlüssel gilt für ein SLURM-Backend, außer gpus und packages. Die GPUs kommen aus gres, und der Scheduler setzt CUDA_VISIBLE_DEVICES für die GPUs, die er zuteilt. Ein Job ohne gres bekommt keine GPU. Die SLURM-Einstellungen entsprechen sbatch-Flags:

SchlüsselStandardBedeutung
job_pythondas python des BackendsDer Interpreter des Workers auf den Rechenknoten.
greskeinersbatch --gres, z. B. gpu:1 oder gpu:A6000:1.
time04:00:00sbatch --time. Über 6 Stunden melden potato validate und der Start des Servers eine Warnung, wie der nächste Absatz beschreibt.
partitiondie Standard-Partition des Clusterssbatch --partition.
nice0sbatch --nice, von 0 bis 2000.
cpus_per_task, memdie Standardwerte des Clusterssbatch --cpus-per-task und --mem.
sbatch_options[]Weitere Flags, z. B. ["--requeue", "--constraint=a100"]. Potato setzt --output, --chdir, --job-name und --parsable selbst, und der Validator meldet für diese Flags hier einen Fehler.
prelude[]Shell-Zeilen, die im Job vor dem Worker laufen.
poll_interval_s30Sekunden zwischen squeue-Aufrufen, mindestens 10.
exit_grace_s180Sekunden, die auf dem Login-Knoten auf den Exit-Code eines beendeten Jobs gewartet wird, mindestens 20.
job_namepotato-trainPräfix des Job-Namens, gefolgt von den ersten 8 Zeichen der Run-ID.

Ein time über 6 Stunden lässt potato validate und den Start des Servers model_training.backends.cluster.time is 12:00:00. A job that holds a GPU for more than 6 hours is long on a shared cluster; check its policy melden, und potato validate --strict schlägt bei der Warnung fehl. Erlaubt die Richtlinie des Clusters den längeren Job, bestätige die Warnung für dieses eine Backend in einem Block validation auf oberster Ebene, den nur potato validate liest:

yaml
validation:
  acknowledge:
    - "model_training.backends.cluster.time is"

Jeder Eintrag wird als Teilstring von mindestens 12 Zeichen unter Beachtung der Groß- und Kleinschreibung mit dem Warnungstext verglichen, und eine passende Warnung wandert in die Liste der bestätigten Warnungen und lässt --strict nicht mehr fehlschlagen. Ein Eintrag, der das Backend nennt, bestätigt die Warnung nur für dieses Backend. Ein Eintrag, der zu kurz ist oder zu keiner Warnung passt, wird zu einer eigenen Warnung.

Der Check-Befehl für ein SLURM-Backend

bash
potato training check cluster config.yaml

Der Check meldet sich am Login-Knoten an und bestätigt, dass sbatch, squeue und scancel im PATH liegen und dass remote_dir nicht unter /tmp liegt. Der Bericht nennt die Python-Version auf dem Login-Knoten und das job_python, das der Job ausführen wird. Der Check kann nicht sehen, welche Pakete die Rechenknoten haben, sodass ein fehlendes Paket auf einem Rechenknoten als fehlgeschlagener Lauf mit dem Importfehler im Log des Laufs erscheint. Führe einen kurzen ersten Job mit einem kleinen time aus, um solche Probleme früh zu finden.

Schritte eines SLURM-Laufs

Potato verbindet sich mit dem Login-Knoten und kopiert seinen Code dorthin, wie bei einem ssh-Backend. Der Agent führt dann diese Schritte aus:

  1. Lädt das Bundle nach remote_dir/jobs/<run>/ herunter.
  2. Schreibt job.sh und übergibt das Skript mit sbatch --parsable. Das Log des Laufs hält Submitted SLURM job mit der Job-ID und den Flags fest.
  3. Im Job-Verzeichnis schreibt der Worker auf dem Rechenknoten seine Ereignisse in events.jsonl, seine Fehler in stderr.log und seinen Exit-Code in exit_code. Die eigene Ausgabe von SLURM geht nach slurm.out.
  4. Der Agent liest events.jsonl, während die Datei wächst, und reicht den Fortschritt an den Server weiter. Der Agent ruft squeue einmal pro poll_interval_s auf, und das Log des Laufs hält jede Änderung des Queue-Status des Jobs fest, z. B. SLURM job 4242: PENDING (Priority) und dann RUNNING on node07.
  5. Endet der Job, lädt der Agent die Vorhersagen hoch und meldet das Ergebnis. Die Artefakte kommen zum Server zurück und das Job-Verzeichnis wird entfernt, wie bei einem ssh-Backend.

Cancel run sendet scancel --full --signal=TERM an den Job und dann ein einfaches scancel, wenn der Worker nicht gestoppt hat. Bricht die ssh-Sitzung zum Login-Knoten ab, bricht der Agent seinen Job ab, und die GPU-Zuteilung wird freigegeben. Beendet der Scheduler einen Job selbst, schlägt der Lauf mit dem Grund des Schedulers fehl, gelesen aus scontrol show job oder slurm.out. Zu den Gründen, die Potato meldet, gehören das Zeitlimit, ein Knotenausfall, Preemption, Speichermangel und ein scancel von außerhalb von Potato.

Die Testsuite von Potato führt die SLURM-Abfolge gegen einen Ersatz für sbatch, squeue und scancel aus und deckt Job-Übergabe, Queue-Status, Fortschrittsweitergabe und Abbruch ab. Partitionslimits und Preemption-Richtlinien unterscheiden sich von Cluster zu Cluster, beobachte deshalb das Log deines ersten Jobs auf einem neuen Cluster.

Ein Agent, der von Hand auf einem Login-Knoten gestartet wird, der den Server erreicht, kann ebenfalls an SLURM übergeben, mit potato training agent --server ... --backend <name> --workdir <shared dir> --slurm-config slurm.json. Die Datei slurm.json enthält die Einstellungen der obigen Tabelle als JSON-Objekt, und --workdir muss auf Speicher liegen, den die Rechenknoten teilen.

Ein Rechner, den Potato nicht erreicht

Ein agent-Backend ist für einen Rechner gedacht, zu dem sich der Annotationsserver nicht verbinden kann, etwa eine Workstation hinter NAT. Jemand startet potato training agent auf diesem Rechner, und der Agent fragt den Server nach Jobs ab. Der Agent braucht keinen eingehenden Port, weil der Agent jede Verbindung selbst öffnet. Ein Abbruch erreicht den Agent in der Antwort des Servers auf den nächsten Fortschrittsbericht des Agents. Die Modelldateien bleiben auf dem Trainingsrechner, und nur die Vorhersagen und das Ergebnis kommen zurück.

Voraussetzungen für ein Agent-Backend

Der Trainingsrechner braucht ein installiertes Potato, die Pakete des Trainers, den du ausführst, und eine Netzwerkroute zur URL des Annotationsservers. Für hf-text-classification deckt eine Installation Potato und die Pakete des Trainers ab:

bash
pip install "potato-annotation[train-text]"

Der Server braucht nur den Backend-Eintrag. Ein Agent-Backend kennt type, description, heartbeat_timeout_s (Standard 120) und queue_timeout_s, aber keinen anderen Schlüssel:

yaml
model_training:
  enabled: true
  backends:
    lab-workstation:
      type: agent
      queue_timeout_s: 3600

Den Agent registrieren und starten

Stelle auf dem Annotationsserver ein Token für das Backend aus:

bash
potato training register lab-workstation config.yaml

Der Befehl gibt das Token einmal aus, mit den Befehlen, die auf dem Trainingsrechner auszuführen sind:

text
Token for backend 'lab-workstation' (shown once; registering again replaces it):
 
  <token>
 
On the training machine:
 
  export POTATO_TRAINING_TOKEN=<token>
  potato training agent --server http://<this-server>:8000 --backend lab-workstation

Starte den Agent auf dem Trainingsrechner mit der echten URL des Servers:

bash
export POTATO_TRAINING_TOKEN=<the token>
potato training agent --server https://annotate.example.org --backend lab-workstation

Der Agent führt Jobs für sein Backend aus, bis du den Agent stoppst. --token-file liest das Token aus einer Datei statt aus POTATO_TRAINING_TOKEN, und --python benennt den Interpreter, in dem der Training-Worker läuft, der Standard ist der eigene Interpreter des Agents. --once beendet sich nach einem Job, --workdir verlegt die Dateien des Agents aus ~/.cache/potato-training, und --keep behält das Bundle jedes Jobs. Wird der Name erneut registriert, stellt das ein neues Token aus und entwertet das alte Token.

potato training check lab-workstation config.yaml gibt den Token-Eintrag des Backends aus, wobei last_seen gesetzt ist, sobald sich ein Agent verbunden hat. Vor der Registrierung gibt der Befehl no token issued yet und den auszuführenden Register-Befehl aus.

Schritte eines Agent-Laufs

Ein Lauf für ein Agent-Backend wartet im Zustand queued, bis ein Agent nach Arbeit fragt. Mit queue_timeout_s: 3600 schlägt der Lauf nach einer Stunde ohne Agent fehl, und ohne queue_timeout_s wartet der Lauf, bis du den Lauf abbrichst. Der Agent lädt das Bundle als tar.gz-Datei herunter und setzt einen abgebrochenen Download dort fort, wo er stoppte, mit bis zu fünf Versuchen. Der Agent führt dann den Worker aus, sendet den Fortschritt, lädt predictions.jsonl hoch und meldet den Exit-Code. Der Server antwortet mit 413 auf eine Vorhersagedatei, die größer als max_predictions_mb ist (Standard 512).

Die Modelldateien bleiben unter --workdir auf dem Trainingsrechner, und der artifact_uri des Lauf-Eintrags nennt den Host und das Verzeichnis. Erreicht der Agent den Server während eines Laufs 300 Sekunden lang nicht, bricht der Agent den Lauf selbst ab. Ein Lauf, dessen Agent heartbeat_timeout_s lang nichts sendet, schlägt auf dem Server mit No word from the agent on lab-workstation for 120 seconds fehl.

Häufige Fehler

Jeder Eintrag nennt die Meldung im Log des Laufs oder im Check-Bericht und dann die Lösung. Die vollständige Liste für jedes Backend und jeden Trainer steht im Abschnitt zur Fehlersuche der Upstream-Dokumentation.

  • ssh to gpu.example.org failed: Permission denied. Potato braucht einen Schlüssel, der ohne Eingabeaufforderung funktioniert. ssh gpu.example.org true muss unter dem Account des Servers gelingen.
  • /opt/conda/bin/python3 was not found on gpu.example.org. Setze python im Backend auf einen Interpreter, der auf dem Host existiert.
  • No GPU has 4000 MB free. Jede GPU auf dem Host ist stärker ausgelastet, als min_free_gpu_mb erlaubt. potato training check gpu-server config.yaml listet die GPUs auf. Warte, senke die Schwelle oder lege mit gpus: "1" eine GPU fest.
  • Trainer 'hf-text-classification' could not be imported. Dem Remote-Interpreter fehlt ein Paket, das der Trainer braucht. Richte python auf einen Interpreter, der das Paket hat, oder führe das Paket unter packages auf. Behebe auf einem SLURM-Backend die Umgebung, die job_python benennt.
  • This host's torch has no kernels for any of its GPUs. Das Remote-torch wurde für neuere GPUs gebaut, als der Host hat. Installiere einen torch-Build für diese GPUs oder verwende einen anderen Host.
  • No word from the agent on gpu-server for 120 seconds. Der Remote-Rechner oder das Netzwerk ist ausgefallen. Auf einem ssh-Backend enthält agent.log im Lauf-Verzeichnis die letzte Ausgabe des Agents.
  • The copy from gpu.example.org sent nothing for 180 s. Das Netzwerk zum Host ist beim Zurückkopieren des Modells ausgefallen. Die Vorhersagen des Laufs sind bereits gespeichert, und nur die Modelldateien fehlen in artifacts/.
  • login.cluster.example.org has no sbatch on PATH, so it cannot submit jobs. Der host ist nicht der Login-Knoten des Clusters, oder die Befehle liegen in einem PATH, den nur eine Login-Shell setzt. Setze PATH unter env des Backends.
  • SLURM job 4242 ended before the worker finished: it reached its time limit. Erhöhe time im Backend oder trainiere auf weniger Items. Setze keep_remote: true, um slurm.out nach anderen Scheduler-Fehlern zum Lesen zu behalten.
  • Ein Lauf auf einem Agent-Backend bleibt in der Warteschlange. Kein Agent mit diesem Backend-Namen fragt ab. Starte einen Agent mit potato training agent --backend lab-workstation und prüfe das Token mit Check auf der Training-Seite.
  • nvrtc: error: failed to open libnvrtc-builtins.so.13.0. Das torch des Hosts und sein Paket nvidia-cuda-nvrtc gehören zu verschiedenen CUDA-Versionen. Installiere das nvidia-cuda-nvrtc, das zum torch-Build passt, oder richte python auf einen anderen Interpreter.
  • Die Übersicht zum Modelltraining behandelt die Training-Seite, den Trainingskreislauf und die Veröffentlichung eines Modells auf dem Hugging Face Hub.
  • Konfiguration listet jeden Schlüssel von model_training, die Holdout-Scores und den Speicherort der Läufe auf.
  • LLMs fine-tunen behandelt die Trainer, die am häufigsten eine Remote-GPU brauchen, mit LoRA und 4-Bit-Basisgewichten.
  • Die Upstream-Referenz dazu, wo Läufe ausgeführt werden, enthält die vollständige Schlüsseltabelle für jedes Backend, und der Abschnitt zum Agent-Protokoll dokumentiert die Routen für alle, die einen eigenen Agent schreiben.