nemo-rl-e2e-testing

Par nvidia · skills

Workflow de validation de bout en bout NeMo-RL externe pour les modifications de modèle/provider Megatron-Bridge, incluant les vérifications de compatibilité en aval, le comportement du cycle de vie RL externe, la configuration de la politique Megatron, l'import/export HF, le checkpoint/resume, le refit vLLM non colocalisé, le transfert de delta weight, les variantes LoRA/génération optionnelles, ainsi que des questions telles que « ce modèle fonctionne-t-il dans NeMo-RL », « exécuter NeMo-RL e2e » ou « validation de la boucle RL externe ». Couvre l'exécution des jobs de politique Megatron NeMo-RL depuis un checkout Bridge, le choix des variantes GRPO/SFT/checkpoint/refit non colocalisé, la configuration du PYTHONPATH pour que NeMo-RL importe l'arbre Bridge local, et le compte-rendu des résultats pass/fail.

npx skills add https://github.com/nvidia/skills --skill nemo-rl-e2e-testing

Tests e2e NeMo-RL

Validez un modèle Megatron-Bridge ou une modification d'API d'entraînement via le backend Megatron de NeMo-RL. Cela identifie les problèmes d'intégration que les tests Bridge-only manquent : l'ordonnancement de rollout détenu par NeMo-RL, la gestion des récompenses, la configuration policy/référence, l'import/export HF via Bridge, la configuration de l'optimiseur, la propriété des checkpoints et le transfert de poids policy-to-generation.

Utilisez ceci comme test de compatibilité externe après que les tests Bridge focalisés pour la modification du modèle/provider réussissent.

Ce n'est pas un remplacement pour les tests de parité Bridge model. Un run NeMo-RL GRPO ou SFT prouve que Bridge peut survivre à une boucle d'entraînement RL externe ; la correction de l'architecture vient toujours des tests d'import/export, logits, roundtrip et inférence spécifique au modèle de Bridge.

Périmètre

Pensez en niveaux de couverture. Commencez par Level 0 et ajoutez uniquement les niveaux justifiés par la modification.

Niveau Requis quand Ce qu'il prouve
0: Smoke GRPO policy Megatron Tout nouveau provider ou changement de config provider qui revendique la compatibilité NeMo-RL NeMo-RL peut importer le provider Bridge local, construire une policy Megatron, initialiser l'état de l'optimiseur/scheduler, exécuter le câblage rollout/ref/logprob, et terminer un court job GRPO
1: Variante LoRA/checkpoint La sauvegarde des checkpoints, l'export HF, l'état de l'optimiseur, le comportement de reprise, ou un chemin PEFT supporté par NeMo-RL ont changé NeMo-RL peut sauvegarder selon son calendrier de checkpoint, reprendre sans perdre l'état d'entraînement, et, quand PEFT est activé dans ce checkout NeMo-RL, appliquer les hooks LoRA Bridge
2: Refit vLLM non-colocalisé L'export HF, le mapping de poids, le refit policy-to-generation, la compression delta, le transfert compressé, ou le comportement de mise à jour vLLM ont changé Les poids exportés par Bridge peuvent être transférés du worker policy Megatron vers des workers de génération vLLM séparés
3: Backend de génération Megatron optionnel Uniquement quand le checkout NeMo-RL supporte toujours policy.generation.backend=megatron et la modification cible explicitement ce chemin NeMo-RL peut utiliser Megatron à la fois pour policy et génération plutôt que uniquement la génération vLLM
4: Stress de parallélisme TP/PP/CP/EP, sequence parallel, dispatch MoE, layout de stage pipeline, ou comportement de l'optimiseur distribué ont changé Les paramètres du provider restent corrects sous un état Megatron parallèle non-trivial
5: E2e spécifique à l'architecture VLM, audio, MoE, modèles MTP/draft, FP8/QAT/ModelOpt, poids quantifiés, ou couches personnalisées sont impliqués Le chemin d'exécution spécifique à l'architecture est exercé, pas juste un smoke GRPO dense text-only
6: Signal d'apprentissage L'optimiseur, scheduler, loss, récompense, trainabilité PEFT, flux des gradients, ou stabilité d'entraînement ont changé Les métriques bougent dans la direction attendue sur un court run et ne produisent pas silencieusement des mises à jour zero/NaN/instables

La cible Level 0 par défaut est la fonctionnelle GRPO Megatron maintenue par NeMo-RL :

uv run bash tests/functional/grpo_megatron.sh

C'est intentionnellement petit. Cela exerce la boucle RL externe de NeMo-RL sans que Megatron-Bridge ne possède l'ordonnancement de rollout, les récompenses, la cadence des checkpoints, ou l'état du trainer.

Level 0 n'est pas un test de convergence. Cela prouve seulement que le job peut compléter un petit nombre de mises à jour. Utilisez Level 6 quand la question est si le modèle apprend vraiment sous NeMo-RL.

Dépôts

Utilisez des variables de dépôt explicites. Ne vous appuyez pas sur une wheel megatron-bridge installée ; le but est de tester le checkout Bridge actuel.

Utilisez le dépôt upstream NeMo-RL comme source par défaut :

https://github.com/NVIDIA-NeMo/RL

Si un checkout n'est pas déjà disponible, clonez-le à côté du checkout Bridge ou dans l'espace de travail standard du site :

git clone https://github.com/NVIDIA-NeMo/RL.git /path/to/nemo-rl
export BRIDGE_REPO=${BRIDGE_REPO:-/path/to/Megatron-Bridge}
export NEMO_RL_REPO=${NEMO_RL_REPO:-/path/to/nemo-rl}
export PYTHONPATH="${BRIDGE_REPO}/src:${BRIDGE_REPO}/3rdparty/Megatron-LM:${NEMO_RL_REPO}:${PYTHONPATH:-}"

Les checkouts NeMo-RL contiennent souvent aussi un arbre Bridge vendorisé sous :

3rdparty/Megatron-Bridge-workspace/Megatron-Bridge

Quand vous testez une modification locale de Bridge, soit mettez le checkout Bridge local en avant de tout dans PYTHONPATH, soit synchronisez les exactes modifications locales de Bridge dans ce checkout vendorisé. Ne supposez pas que l'arbre vendorisé correspond à la PR Bridge en test.

Avant de lancer, enregistrez les deux états :

git -C "$BRIDGE_REPO" status --short
git -C "$NEMO_RL_REPO" status --short
git -C "$BRIDGE_REPO" rev-parse --short HEAD
git -C "$NEMO_RL_REPO" rev-parse --short HEAD

Si vous testez sur une machine GPU distante, synchronisez d'abord les modifications exactes locales. Ne réinitialisez pas ou ne remplacez pas les modifications non-liées dans aucun arbre.

Vérifiez que Python importe le checkout en test :

python - <<'PY'
import megatron.bridge
print(megatron.bridge.__file__)
PY

Le chemin imprimé doit se trouver sous $BRIDGE_REPO/src, ou sous le checkout Bridge vendorisé NeMo-RL uniquement si ce checkout vendorisé a été intentionnellement synchronisé avec la modification Bridge. S'il pointe vers site-packages ou un chemin 3rdparty inattendu, corrigez PYTHONPATH avant de faire confiance à un résultat.

Vérifications Bridge d'abord

Exécutez des tests Bridge focalisés avant l'e2e NeMo-RL externe. Incluez tout test spécifique au modèle ajouté par la modification.

cd "$BRIDGE_REPO"
uv run python -m pytest -q \
  tests/unit_tests/models/test_model_provider_mixin.py \
  tests/unit_tests/models/test_param_mapping.py \
  tests/unit_tests/training/test_integration.py \
  <model-specific-test-paths>

Pour une nouvelle famille de modèles, lancez aussi le test de conversion ou roundtrip pertinent de la PR du modèle. Voir @skills/adding-model-support/tests-and-examples.md pour les patterns de test de modèle.

Preuves minimales du côté Bridge pour un nouveau modèle/provider :

  • tests unitaires provider/config
  • tests de mapping des paramètres
  • import HF vers Megatron ou roundtrip sur un petit modèle
  • comparaison de génération ou logits spécifique au modèle quand disponible
  • ce smoke e2e NeMo-RL après que les précédents réussissent

Vérifications unitaires NeMo-RL

Lancez les vérifications unitaires NeMo-RL qui correspondent à la surface exercée. Gardez-les focalisées ; l'e2e est le signal coûteux.

cd "$NEMO_RL_REPO"
uv run pytest -q \
  tests/unit/models/megatron/test_megatron_setup.py \
  tests/unit/models/policy/test_megatron_worker.py \
  tests/unit/utils/test_weight_transfer.py

Pour les changements de checkpoint, ajoutez :

uv run pytest -q \
  tests/unit/utils/test_checkpoint.py \
  tests/unit/utils/test_native_checkpoint.py

Pour les changements de refit vLLM ou de worker de génération, ajoutez les tests unitaires vLLM pertinents :

uv run pytest -q \
  tests/unit/models/generation/test_vllm_generation.py \
  tests/unit/models/generation/test_vllm_utils.py

Choix du modèle

Préférez le plus petit checkpoint public HF qui utilise la famille de provider modifiée. La fonctionnelle GRPO Megatron maintenue utilise Qwen/Qwen2.5-0.5B car il est suffisamment petit pour un smoke 2-GPU et est supporté par le chemin Megatron de NeMo-RL.

S'il n'y a pas de petit checkpoint public pour la nouvelle architecture, utilisez la plus proche recette NeMo-RL qui construit le modèle avec une config minimale ou un petit checkpoint local, et rapportez que le run valide les mécaniques de construction/entraînement plutôt que la compatibilité des poids prétrain.

Pour les modèles VLM ou audio, un smoke GRPO text-only ne suffit pas. Associez le smoke policy Level 0 avec la fonctionnelle NeMo-RL VLM/audio pertinente, par exemple :

uv run bash tests/functional/vlm_grpo.sh
uv run bash tests/functional/audio_grpo_megatron.sh

Pour les modèles MoE, Level 0 avec un parallélisme expert trivial capture beaucoup de problèmes de provider, mais ne stresse pas le routage expert. Ajoutez un run Level 4 avec parallélisme expert quand la modification touche le layout expert, la config du dispatcher, le comportement du router, ou le parallélisme tensor expert.

Pour les modèles MTP/draft, utilisez une fonctionnelle Eagle/MTP-spécifique :

uv run bash tests/functional/grpo_megatron_eagle3_online.sh

Pour le support FP8/QAT/ModelOpt ou checkpoint quantifié, utilisez la recette ou fonctionnelle la plus proche qui active explicitement la feature. Ne revendiquez pas que le smoke GRPO générique a validé la quantization sauf si la config l'active.

Configuration d'environnement

Utilisez l'environnement de développement NeMo-RL ou le container NeMo-RL approuvé par le site. Rendez les caches explicites sur les clusters partagés :

export HF_HOME=${HF_HOME:-/scratch/$USER/nemo_rl_hf}
export HF_HUB_CACHE=$HF_HOME/hub
export NEMO_RL_HOME=${NEMO_RL_HOME:-$NEMO_RL_REPO}
export PYTHONPATH="${BRIDGE_REPO}/src:${BRIDGE_REPO}/3rdparty/Megatron-LM:${NEMO_RL_REPO}:${PYTHONPATH:-}"

Si le container a une incompatibilité d'empreinte digitale des dépendances, notez-la dans le rapport. Préférez reconstruire le container ou virtualenv quand possible ; utilisez les overrides d'environnement uniquement comme preuves d'environnement de test, pas modifications de dépôt.

Si les téléchargements de modèles échouent avec No space left on device, déplacez HF_HOME, HF_HUB_CACHE, et tout MODEL_PATH local vers un chemin partagé ou node-local plus grand.

Si les appels API Hugging Face échouent avec des limites de taux après que le modèle soit déjà en cache, pointez à la fois le modèle et le tokenizer vers le snapshot local et exécutez offline :

export MODEL_PATH=/scratch/$USER/hf/hub/models--<org>--<model>/snapshots/<snapshot-sha>
export HF_HOME=/scratch/$USER/hf
export HF_HUB_CACHE=$HF_HOME/hub
export HF_HUB_OFFLINE=1
export TRANSFORMERS_OFFLINE=1

Puis passez les deux overrides à NeMo-RL :

policy.model_name="$MODEL_PATH" \
policy.tokenizer.name="$MODEL_PATH"

Avant de faire confiance au snapshot, vérifiez qu'il se charge localement :

uv run python - <<'PY'
from transformers import AutoConfig, AutoTokenizer

path = "<local-snapshot-path>"
config = AutoConfig.from_pretrained(path, trust_remote_code=True, local_files_only=True)
tokenizer = AutoTokenizer.from_pretrained(path, trust_remote_code=True, local_files_only=True)
print(type(config).__name__, getattr(config, "model_type", None), type(tokenizer).__name__, tokenizer.vocab_size)
PY

Run NeMo-RL minimal

Utilisez le wrapper fonctionnel maintenu par NeMo-RL pour le smoke par défaut :

cd "$NEMO_RL_REPO"
ray stop --force || true

export PYTHONPATH="${BRIDGE_REPO}/src:${BRIDGE_REPO}/3rdparty/Megatron-LM:${NEMO_RL_REPO}:${PYTHONPATH:-}"

uv run bash tests/functional/grpo_megatron.sh

Le wrapper écrit :

tests/functional/grpo_megatron/run.log
tests/functional/grpo_megatron/metrics.json

Capturez la commande exacte et conservez le chemin du log. Préférez un log sauvegardé plutôt qu'un extrait de terminal collé dans les descriptions de PR.

Si le test a besoin d'un provider ou modèle différent, passez les overrides Hydra via le wrapper :

uv run bash tests/functional/grpo_megatron.sh \
  policy.model_name=<small-compatible-hf-model> \
  policy.megatron_cfg.converter_type=<BridgeConverterType>

Gardez le premier smoke petit. Augmentez la taille du modèle ou le parallélisme uniquement après qu'un petit run prouve que le chemin basique fonctionne.

Couverture LoRA et Checkpoint

Utilisez Level 1 quand la modification touche la sauvegarde/chargement des checkpoints, l'export HF, l'état de l'optimiseur, le comportement de reprise, ou un chemin PEFT NeMo-RL connu pour fonctionner dans le checkout en test.

Le support PEFT NeMo-RL dépend du backend et de la révision. Ne bloquez pas un smoke compatibilité provider-only uniquement sur un chemin PEFT NeMo-RL cassé ou non-supporté. Dans ce cas, enregistrez Level 1 PEFT comme non-applicable ou bloqué par NeMo-RL, gardez le smoke GRPO Level 0 comme le signal downstream requis, et couvrez le comportement PEFT Bridge avec des tests Bridge focalisés.

Smoke LoRA + checkpoint save, quand le checkout NeMo-RL supporte ce chemin :

uv run bash tests/functional/grpo_megatron_lora.sh

Parité SFT resume entre les chemins policy dtensor et Megatron :

uv run bash tests/functional/sft_resume_diamond.sh

La fonctionnelle LoRA sauvegarde intentionnellement les checkpoints. Supprimez les sorties de checkpoint obsolètes entre les expériences non-liées, mais gardez-les en validant le comportement de reprise.

Ne revendiquez pas la couverture PEFT de grpo_megatron.sh ; utilisez la fonctionnelle LoRA ou un override Hydra équivalent avec policy.megatron_cfg.peft.enabled=true.

Refit vLLM non-colocalisé

Utilisez Level 2 quand la modification touche l'export HF Bridge, le mapping des paramètres, le refit de poids NeMo-RL, le transfert de tenseur compressé, le chargement vLLM, la compression delta, ou la synchronisation du worker policy/génération.

Smoke non-colocalisé petit 2-GPU avec le backend policy Megatron :

cd "$NEMO_RL_REPO"
uv run coverage run -a --data-file=tests/.coverage --source=nemo_rl \
  examples/run_grpo.py \
  --config examples/configs/grpo_math_1B_megatron.yaml \
  policy.model_name=Qwen/Qwen2.5-0.5B \
  grpo.num_prompts_per_step=2 \
  grpo.num_generations_per_prompt=4 \
  policy.train_global_batch_size=4 \
  policy.train_micro_batch_size=1 \
  policy.logprob_batch_size=4 \
  policy.generation.colocated.enabled=false \
  policy.generation.colocated.resources.gpus_per_node=1 \
  policy.generation.vllm_cfg.async_engine=true \
  cluster.gpus_per_node=2 \
  grpo.max_num_steps=2 \
  logger.tensorboard_enabled=true \
  logger.log_dir=tests/functional/grpo_megatron_non_colocated/logs \
  logger.wandb_enabled=false \
  checkpointing.enabled=false

Après le run, videz les métriques :

uv run tests/json_dump_tb_logs.py \
  tests/functional/grpo_megatron_non_colocated/logs \
  --output_path tests/functional/grpo_megatron_non_colocated/metrics.json

Les helpers d'assertion de métriques diffèrent selon les révisions NeMo-RL. Inspectez tests/check_metrics.py ou le wrapper fonctionnel maintenu avant d'assumer une interface. Certains checkouts s'attendent à des expressions positionnelles :

uv run tests/check_metrics.py tests/functional/grpo_megatron_non_colocated/metrics.json \
  'max(data["train/token_mult_prob_error"]) < 1.05' \
  'min(data["train/probs_ratio_clamped_min"]) > 0.79' \
  'max(data["train/probs_ratio_clamped_max"]) < 1.21'

Pour tester la compression delta, ajoutez ces overrides :

policy.generation.delta_compression.enabled=true \
policy.generation.delta_compression.dtype=bfloat16 \
policy.generation.delta_compression.transport=sparse_indices \
policy.generation.delta_compression.full_sync_interval=20 \
policy.generation.delta_compression.sparse_bucket_size_bytes=5368709120 \
policy.generation.delta_compression.delta_load_batch_size_bytes=536870912

Rapportez les métriques de timing du transfert de poids quand disponibles, notamment :

  • timing/train/prepare_for_generation/total
  • timing/train/prepare_for_generation/transfer_and_update_weights
  • timing/train/prepare_for_generation/weight_transfer/producer/collect_tensors
  • timing/train/prepare_for_generation/weight_transfer/producer/sparse_encode
  • timing/train/prepare_for_generation/weight_transfer/producer/sparse_nonzero
  • timing/train/prepare_for_generation/weight_transfer/consumer/decode_sparse
  • timing/train/prepare_for_generation/weight_transfer/consumer/load_delta

Si le temps de broadcast du payload est minuscule mais sparse encode/decode domine, rapportez cette limite clairement. C'est un goulot d'étranglement de préparation de poids, non un goulot d'étranglement de broadcast NCCL.

Backend de génération Megatron

Utilisez Level 3 uniquement quand le checkout NeMo-RL en test supporte le backend de génération Megatron et la modification Bridge cible explicitement ce chemin downstream. Ne demandez pas cela pour la compatibilité provider normale, l'import/export HF, la génération sauvegardée vLLM, ou les tests d'inférence Bridge génériques.

uv run bash tests/functional/grpo_megatron_generation.sh

Ceci exerce policy.generation.backend=megatron, validant donc plus directement la construction et le comportement d'exécution de la génération Megatron de NeMo-RL que la fonctionnelle GRPO sauvegardée vLLM par défaut.

Certaines révisions NeMo-RL déclarent les extras mcore et vllm comme mutuellement incompatibles. Dans cet environnement, un run Level 0 sauvegardé vLLM peut être bloqué même si le chemin policy Megatron est testable. Utilisez policy.generation.backend=megatron pour un smoke Megatron-only, enregistrez vLLM comme ignoré ou bloqué, et ne revendiquez pas la couverture de refit vLLM non-colocalisé.

Stress de parallélisme

Utilisez Level 4 quand la finalisation du provider, les paramètres model-parallel, sequence parallel, context parallel, dispatch MoE, layout du pipeline, ou comportement de l'optimiseur distribué ont changé.

Démarrez depuis une recette maintenue qui correspond déjà au nombre GPU prévu. Par exemple, utilisez une des configs de recette sous :

examples/configs/recipes/llm/*megatron*.yaml
examples/configs/recipes/llm/performance/*megatron*.yaml
examples/configs/recipes/vlm/*megatron*.yaml

Pour une petite variante stress manuelle, overridez explicitement les tailles Megatron :

uv run bash tests/functional/grpo_megatron.sh \
  policy.megatron_cfg.tensor_model_parallel_size=2 \
  policy.megatron_cfg.pipeline_model_parallel_size=1 \
  policy.megatron_cfg.context_parallel_size=1 \
  policy.megatron_cfg.sequence_parallel=false \
  cluster.gpus_per_node=2

Pour MoE, utilisez une recette MoE et définissez le parallélisme expert uniquement quand le modèle et le nombre GPU le supportent :

policy.megatron_cfg.expert_model_parallel_size=2 \
policy.megatron_cfg.expert_tensor_parallel_size=1

Gardez ceux-ci comme runs de suivi. Ne les faites pas la surface de débogage initiale pour un nouveau provider.

Signal d'apprentissage

Utilisez Level 6 uniquement quand la modification affecte la trainabilité ou quand la validation downstream demande explicitement le comportement d'apprentissage. Ne le demandez pas pour chaque PR provider-only ; l'apprentissage RL est plus lent, plus bruyant, et plus dépendant de l'environnement que les tests de smoke de compatibilité.

L'objectif est un run court de signal d'apprentissage, non un benchmark. Préférez un petit modèle, données fixes, seed fixée quand disponible, et suffisamment d'étapes pour observer un mouvement métrique non-aléatoire :

uv run bash tests/functional/grpo_megatron_lora.sh \
  grpo.max_num_steps=20 \
  data.shuffle=false \
  checkpointing.enabled=false

Les preuves acceptables de signal d'apprentissage dépendent de la tâche, mais le rapport devrait inclure au moins :

  • aucun NaN ou inf dans loss, récompense, KL, entropie, grad norm, ou métriques logprob
  • nombre de paramètres trainables non-zéro quand PEFT est activé
  • losses d'actor et métriques liées à la récompense enregistrées pour plusieurs étapes
  • validation ou trend de récompense comparée au point de départ ou une baseline connue-bonne
  • aucun gradient zéro répété, adaptateurs LoRA gelés, ou logprobs constants sauf si attendu

N'appelez pas un run 20-step "convergé" au sens benchmark. Appelez-le "signal d'apprentissage réussi" sauf s'il atteint un seuil métrique pré-convenu.

Runs Slurm ou Container

Utilisez le container NeMo-RL standard du cluster et montez les deux checkouts dans le container. Gardez la configuration et le run actuel dans la même étape container quand vous utilisez des chemins node-local tels que /tmp ; le cache model node-local et les installs ad-hoc disparaissent quand une nouvelle étape container commence.

Si le filesystem home est plein ou que Megatron-Core essaie de construire des extensions helper dans un checkout read-only/plein, copiez le sous-module MCore vers le stockage node-local et mettez cette copie sur PYTHONPATH plutôt que d'éditer 3rdparty/Megatron-LM/ :

export MCORE_REPO=${MCORE_REPO:-/tmp/$USER/Megatron-LM}
if [[ ! -d "$MCORE_REPO/.git" ]]; then
  cp -a "$BRIDGE_REPO/3rdparty/Megatron-LM" "$MCORE_REPO"
fi

EXT_SUFFIX=$(uv run python - <<'PY'
import sysconfig

print(sysconfig.get_config_var("EXT_SUFFIX") or ".so")
PY
)
make -C "$MCORE_REPO/megatron/core/datasets" LIBEXT="$EXT_SUFFIX"
export PYTHONPATH="${BRIDGE_REPO}/src:${MCORE_REPO}:${NEMO_RL_REPO}:${PYTHONPATH:-}"

Overrider LIBEXT évite un binaire helpers_cpp sans suffixe sur les containers où python3-config est absent de PATH. Vérifiez que le fichier construit est nommé comme helpers_cpp.cpython-<ver>-<platform>.so avant de lancer un long run.

Pour les jobs NeMo-RL multi-nœud, préférez le launcher NeMo-RL ray.sub quand il est disponible. Il démarre les nœuds Ray head et worker sous Slurm, monte le container/les filesystems demandés, et exécute COMMAND depuis la racine NeMo-RL. Lancez-le depuis $NEMO_RL_REPO, non depuis le checkout Bridge :

cd "$NEMO_RL_REPO"

COMMAND="uv run ./examples/run_grpo.py \
  --config examples/configs/grpo_math_1B_megatron.yaml \
  cluster.num_nodes=2 \
  cluster.gpus_per_node=8 \
  logger.log_dir=results/grpo_megatron_2n \
  logger.wandb_enabled=false" \
CONTAINER="$NEMO_RL_IMAGE" \
MOUNTS="$BRIDGE_REPO:$BRIDGE_REPO,$NEMO_RL_REPO:$NEMO_RL_REPO,$HF_HOME:$HF_HOME" \
sbatch \
  --nodes=2 \
  --account=<account> \
  --partition=<partition> \
  --job-name=nemo-rl-bridge-e2e \
  --time=4:00:00 \
  --gres=gpu:8 \
  ray.sub

Incluez le checkout Bridge local dans MOUNTS et dans PYTHONPATH dans COMMAND quand le container ne voit pas déjà le même chemin. Si vous utilisez un Bridge vendorisé sous 3rdparty/Megatron-Bridge-workspace/Megatron-Bridge, synchronisez les exactes modifications Bridge là plutôt et rapportez ce chemin.

Utilisez un srun direct uniquement quand ray.sub n'est pas disponible, obsolète pour le cluster cible, ou quand vous déboguez la couche container/Slurm elle-même. Gardez les chemins génériques dans les scripts commités à Megatron-Bridge :

srun <site-specific-slurm-options> \
  --container-image="${NEMO_RL_IMAGE}" \
  --container-mounts="${BRIDGE_REPO}:/workspace/Megatron-Bridge,${NEMO_RL_REPO}:/workspace/nemo-rl,<data-root>:<data-root>" \
  --container-workdir=/workspace/nemo-rl \
  bash -lc '
    export BRIDGE_REPO=/workspace/Megatron-Bridge
    export NEMO_RL_REPO=/workspace/nemo-rl
    export PYTHONPATH=$BRIDGE_REPO/src:$BRIDGE_REPO/3rdparty/Megatron-LM:$NEMO_RL_REPO
    ray stop --force || true
    uv run bash tests/functional/grpo_megatron.sh
  '

Si un helper attach entre un container qui ne voit plus les checkouts attendus ou le log directory, traitez ce helper comme obsolète. Commencez une étape srun fraîche sur l'allocation existante avec explicite --container-image, --container-mounts, et --container-workdir.

Les helpers attach qui utilisent --no-container-mount-home peuvent entrer dans un /home/$USER minimal lors des étapes de suivi même quand le run original a vu le vrai checkout. Gardez le dumping de métriques et les assertions dans la même étape container que le run quand possible. Si une étape de suivi doit inspecter les artefacts compute-local, utilisez les chemins sous le répertoire run node-local et ne supposez pas que $NEMO_RL_REPO est visible.

Pour les patterns de débogage Slurm général et multi-nœud, lisez @skills/multi-node-slurm/SKILL.md.

Critères de passage

Un passage utile a tous les suivants :

  • Les tests Bridge focalisés réussissent pour le comportement provider/config/mapping.
  • NeMo-RL importe le checkout Bridge prévu, vérifié par megatron.bridge.__file__.
  • La config NeMo-RL a policy.megatron_cfg.enabled=true pour la validation policy Megatron.
  • Le run atteint le nombre d'étapes demandé et écrit metrics.json.
  • tests/check_metrics.py réussit quand la fonctionnelle maintenue inclut des assertions de métriques.
  • Aucune exception ne se produit durant la configuration du provider Bridge, l'import/export HF, le wrapping PEFT/LoRA activé, l'initialisation Megatron, la configuration de l'optimiseur, la configuration du checkpoint manager, le transfert de poids, ou l'étape d'entraînement.

Les avertissements Ray shutdown, les avertissements de resource-tracker Python, ou les avertissements post-complétion de process-group peuvent être acceptables si l'étape d'entraînement a été complétée, les métriques ont été écrites, et le processus s'est terminé avec succès. Mentionnez-les comme bruit de log résiduel.

Ne revendiquez pas l'e2e modèle complet si le run a utilisé une config factice, des données text-only pour un modèle VLM/audio, un parallélisme expert trivial pour un changement expert-parallel, ou a désactivé save/resume pour un changement de checkpointing. Appelez-le le niveau exact qui a réussi.

Ne revendiquez pas la convergence de Level 0. Revendiquez le signal d'apprentissage uniquement de Level 6, et distinguez le "signal d'apprentissage" de la convergence benchmark dans le rapport.

Triage d'échecs

Si la construction du modèle échoue, vérifiez que NeMo-RL importe le checkout Bridge en test et que policy.megatron_cfg.converter_type correspond au provider.

Si la config utilise silencieusement dtensor au lieu de Megatron, définissez policy.dtensor_cfg.enabled=false et policy.megatron_cfg.enabled=true, ou utilisez grpo_megatron.sh.

Si LoRA échoue, vérifiez les noms de config PEFT NeMo-RL et les noms des modules cible Bridge. Reproduisez avec grpo_megatron_lora.sh avant d'ajouter les changements de parallélisme ou modèle plus grand.

Si la sauvegarde/chargement des checkpoints échoue, d'abord relancez avec checkpointing.enabled=false pour séparer la construction du modèle du comportement des checkpoints, puis utilisez sft_resume_diamond.sh pour la parité de reprise.

Si le refit non-colocalisé échoue, séparez la limite :

  • export du producer et préparation des métadonnées sur le worker policy
  • compressage/broadcast du payload
  • décodage du consumer et chargement du modèle sur le worker de génération
  • comportement du loader de poids spécifique à vLLM

Si NeMo-RL rejette TP >= 4 avec la garde d'exactitude variante batch, préférez TP 1 ou 2 pour le smoke, ou définissez policy.train_micro_batch_size et policy.logprob_batch_size égaux. Ne contournez pas avec NRL_IGNORE_TP_ACCURACY_CHECK=1 pour les preuves pass/fail sauf si l'utilisateur veut explicitement un run diagnostic non-supporté.

Si la génération Megatron échoue durant le cuda graph warmup avec CUDA error: an illegal memory access was encountered, relancez la même config avec :

policy.generation.mcore_generation_config.num_cuda_graphs=null \
policy.generation.mcore_generation_config.use_cuda_graphs_for_non_decode_steps=false

Si le run sans-graphe réussit, rapportez le résultat original comme une échec de CUDA-graph de génération Megatron et le run sans-graphe comme un passage optimisation-réduit. Gardez les deux logs.

Si le run atteint le nombre d'étapes demandé mais tests/check_metrics.py échoue sur train/token_mult_prob_error, traitez-le comme un vrai échec de métrique, non un échec de harness. NeMo-RL calcule cette métrique à partir de exp(abs(generation_logprobs - prev_logprobs)) ; les énormes valeurs signifient que les logprobs du backend de génération désaccordent avec les logprobs policy recalculés pour l'entraînement. Isolez en retestant avec un parallélisme ou noyaux plus simples tels que policy.megatron_cfg.sequence_parallel=false, policy.megatron_cfg.apply_rope_fusion=false, longueurs de séquence plus courtes, ou génération vLLM quand disponible. Ne relâchez pas le seuil de métrique ou utilisez le masquage de séquence pour revendiquer un passage ; lancez les tests de parité Bridge logits/import/export pour localiser si le désaccord vient de la conversion Bridge, de la collection logprob de génération Megatron, ou de la recalculation NeMo-RL.

Si le téléchargement du modèle échoue, déplacez les caches HF vers un chemin plus grand et relancez avec les paramètres de cache explicites.

Si Hugging Face retourne 429 Too Many Requests durant la configuration du tokenizer/config, d'abord vérifiez si le snapshot existe déjà sous $HF_HUB_CACHE. S'il le fait, basculez policy.model_name et policy.tokenizer.name vers le chemin du snapshot local et activez le mode offline. C'est une échec d'environnement sauf si le snapshot local ne peut pas se charger avec local_files_only=True.

Si helpers_cpp échoue de lier avec No space left on device, ou si les logs montrent make: python3-config: No such file or directory, reconstruisez le helper dans une copie node-local de Megatron-LM avec LIBEXT défini à partir de sysconfig.get_config_var("EXT_SUFFIX"). Ne patchez pas les fichiers sous 3rdparty/Megatron-LM/ dans le checkout Bridge.

Si une baseline échoue avant la construction du modèle à cause de données, Ray, vLLM, configuration de package, ou incompatibilité container, corrigez l'environnement d'abord et ne le rapportez pas comme une échec de provider Bridge.

Format de résumé

Terminez chaque run avec un court résumé orienté utilisateur qui répond "Les livrables demandés ont-ils réussi ?" avant d'ajouter les détails. Utilisez Pass, Fail, Skipped, ou Blocked pour chaque livrable, et ne rapportez un overall Pass que si les critères de passage pour le niveau de couverture demandé ont été atteints.

Result: <Pass/Fail/Blocked> - <une phrase énonçant ce qui a été validé>
Requested coverage: <Level 0/1/2/3/4/5/6 et variantes demandées>
Model: <policy.model_name ou chemin du modèle local>

Deliverables:
- Bridge-side checks: <Pass/Fail/Skipped> - <commande de test ou raison ignorée>
- Local Bridge import in NeMo-RL: <Pass/Fail> - <chemin megatron.bridge.__file__>
- NeMo-RL Megatron policy run: <Pass/Fail/Skipped> - <GRPO Megatron ou variante demandée>
- Requested variants: <Pass/Fail/Skipped/Not requested> - <LoRA/checkpoint, non-colocalisé vLLM refit, Megatron generation, parallelism stress, architecture-specific, ou learning-signal>
- Metrics/log capture: <Pass/Fail> - <chemin log, chemin métriques, et statut d'assertion de métriques>

Evidence:
- Bridge repo: <commit> plus fichiers dirty
- NeMo-RL repo: <commit> plus fichiers dirty
- Command: <commande exacte ou chemin du script>
- Key lines: <policy.megatron_cfg.enabled=true, completion d'étape, création metrics.json, résultat tests/check_metrics.py, ou première erreur pertinente>

Limitations:
- <modèle factice, save/resume ignoré, VLM/audio smoke text-only, EP trivial, pas de revendication learning-signal, avertissements shutdown connus, etc.>

Follow-ups:
- <rerun nécessaire, fix d'environnement, fix de provider, problème NeMo-RL, ou "aucun">

Si le job est bloqué avant la construction du modèle/provider Bridge par des données, Ray, vLLM, dépendance, disque, container, ou configuration de cluster, marquez le résultat global comme Blocked, non Fail, et énoncez que ce n'est pas une preuves contre le provider Bridge.

Si un livrable demandé n'a pas été lancé, marquez-le Skipped ou Not requested avec la raison. Ne le laissez pas implicite dans les limitations.

Skills similaires