kermt-monitor

Par nvidia · skills

Vérifie la progression d'une exécution KERMT détachée (pretrain, finetune, ou tout appel à `kermt_run_detached`). Lit `run.json`, interroge Docker pour l'état du conteneur, suit le log de pretrain/finetune et analyse les lignes de progression (epoch, step, val loss).

npx skills add https://github.com/nvidia/skills --skill kermt-monitor

kermt-monitor

Skill compagnon pour tout workflow KERMT qui s'exécute en détaché : les trois skills de préentraînement (kermt-continue-pretrain, kermt-pretrain-scratch, kermt-add-cmim-pretrain) plus kermt-finetune. kermt-infer et kermt-embed s'exécutent en mode bloquant par défaut et n'ont pas besoin de ce skill, mais si un utilisateur les lance en détaché intentionnellement, le monitor fonctionne quand même (le workflow-dispatch à l'étape 4 traite les workflows inconnus en lisant le fichier log le plus récent du répertoire de run). Lit le répertoire de run pour run.json, interroge docker sur l'état du conteneur, affiche la progression la plus récente, et soit affiche ou suit le log.

Prérequis matériel

Aucun. Ce skill ne fait que lire le disque et interroger docker ; pas de calcul GPU.

Entrées

L'une ou l'autre :

  • <run-dir> — un argument positionnel pointant sur le répertoire contenant run.json (ex. runs/continue-pretrain_2026-05-17T10-23Z). Préféré.
  • --container <name-or-id> — référence de conteneur directe ; le skill lit toujours run.json du répertoire de run référencé dans la sortie d'inspect du conteneur si disponible, mais fonctionne en mode dégradé sans lui.

Optionnel :

  • --lines N — nombre de lignes de log finales à afficher (défaut 50).
  • --follow — diffuse docker logs -f jusqu'à ^C. Utile pour « regarder la loss ». Sans cela, le skill est ponctuel et se termine.
  • --json — émet un rapport d'état structuré au lieu de texte lisible par l'humain. Utile quand l'agent parent veut agir en aval.

Workflow

Soit RUN_DIR=$1 (ou quel que soit le chemin fourni par l'utilisateur).

  1. Localiser le manifest.

    MANIFEST=$RUN_DIR/run.json

    Refuser de continuer s'il n'existe pas ; afficher un message utile pointant l'utilisateur vers la convention de run-dir (runs/<workflow>_<ts>/).

  2. Parser le manifest (helper Python) :

    workflow=$(jq -r .workflow $MANIFEST)
    container_name=...   # pas directement dans run.json aujourd'hui ; le skill qui
                         # l'a lancé l'a stocké dans run.json sous
                         # container.name au lancement (voir note ci-dessous).
    logs_dir=$(jq -r .logs_dir $MANIFEST)
    image_tag=$(jq -r .container.image_tag $MANIFEST)
    started_at=$(jq -r .started_at $MANIFEST)
  3. Interroger docker pour l'état du conteneur.

    docker ps --filter "name=$container_name" --format \
        '{{.ID}}\t{{.Status}}\t{{.CreatedAt}}'

    S'il est absent, revenir à docker inspect $container_name --format '{{.State.Status}} (exit {{.State.ExitCode}})' pour voir si le conteneur s'est arrêté (ok ou erreur) ou a été supprimé (--rm après arrêt).

  4. Trouver le fichier log en direct.

    case "$workflow" in
      continue-pretrain|pretrain-scratch)  LOG=$logs_dir/pretrain_ddp.log ;;
      finetune)                            LOG=$logs_dir/finetune.log ;;
      *)                                   LOG=$(ls -1t $logs_dir/*.log 2>/dev/null | head -n 1) ;;
    esac

    Le champ workflow du manifest désambiguïse préentraînement (pretrain_ddp.log) et finetune (finetune.log). Les autres workflows reviennent au .log le plus récemment modifié dans $logs_dir.

  5. Afficher la progression la plus récente.

    • tail -n $LINES $LOG pour la sortie brute récente.
    • Parser les dernières lignes de progression et afficher un résumé convivial. Le format diffère par workflow :
      • Préentraînement : epoch / step / val_loss
        Current epoch: 12/100  step: 4523/9000  val_loss: 0.832 (best 0.821 @ step 4100)
      • Finetune : fold / epoch / val_<metric> (ex. val_mae pour régression, val_auc pour classification — lire args_applied.metric depuis run.json)
        Fold 0  epoch 12/30  val_mae 0.187 (best 0.182 @ epoch 9)
        Wall-clock: 1h 23m since started_at; ETA ~6h remaining.
  6. Bloc de métriques test finales (finetune, à la fin). Si workflow est finetune ET le conteneur s'est arrêté proprement (State.Status=exited, ExitCode=0) ET $RUN_DIR/ckpt/fold_*/test_result.csv existe, le parser et émettre un tableau de métriques par tâche :

    Final test metrics (per task):
      Target              MAE
      HLM_clearance       0.187
      RLM_clearance       0.213
      MDR1-MDCK_efflux    0.241
      solubility_pH6.8    0.156

    La colonne métrique correspond à args_applied.metric (mae pour régression, auc pour classification, etc.). Pour runs multi-fold ou ensemble, faire la moyenne sur les folds/modèles et noter ± std si std > 0. Ignorer silencieusement si aucun test_result.csv n'existe (run incomplet ou pas de test split émis).

  7. Si --follow, diffuser les logs en direct.

    docker logs -f $container_name

    Boucle jusqu'à ^C.

  8. Conseils pour arrêter / nettoyer (affichés à la fin du mode ponctuel) :

    To stop:        docker stop $container_name
    To remove:     docker rm $container_name
    To re-run:    `$(jq -r .cmd_replay $MANIFEST)`

Règles strictes

  • Lecture seule sur les données de l'utilisateur. Ne jamais modifier run.json, ne jamais toucher au répertoire de checkpoint du conteneur. Le monitor n'inspecte que.
  • Ne pas tuer le conteneur sans instruction explicite de l'utilisateur. Si l'utilisateur demande d'arrêter, exécuter docker stop ; s'il demande d'abandonner, le laisser tourner et juste quitter.
  • Ne pas pull ni modifier l'image kermt. Le monitor ne fait que lire.
  • Le mode sortie JSON est non-interactif. Sauter les prompts « appuyez sur ^C pour quitter » et émettre un seul document JSON pour que l'agent parent puisse le piper.

Note sur le plumbing container_name

Le schéma run.json tel qu'actuellement écrit n'inclut pas encore le nom du conteneur lancé — kermt_run_detached l'affiche sur stdout mais le script de runner ne le capture pas dans run.json. Le monitor se rabat sur une recherche basée sur le système de fichiers : lister les répertoires runs/<workflow>_*/ et correspondre par mtime ; ou accepter --container <name> explicitement. Suivi : faire en sorte que le skill de lancement enregistre le nom du conteneur dans run.json avant de quitter.

Sortie (mode texte, défaut)

KERMT continue-pretrain · runs/continue-pretrain_2026-05-17T10-23Z
  Container : kermt-continue-pretrain-…  (Up 1 hour, status: running)
  Image     : kermt:latest@sha256:…
  Repo      : 2fe00f9 (clean)
  Started   : 2026-05-17T10:23:14Z (1h 23m ago)
  Workflow  : continue-pretrain, pretrain_mode=hybrid, world_size=2

  Latest log (last 50 lines from $LOG):
    [Epoch 12/100] step 4523/9000 loss 0.832 lr 1.2e-4
    [val] step 4100 val_loss 0.821 (new best)
    ...

  Progress: epoch 12/100, ~12% done. ETA ~6h.
  TensorBoard: tensorboard --logdir $RUN_DIR/logs/tb
  Replay command: $(jq -r .cmd_replay $RUN_DIR/run.json)

Skills similaires