complexa-sweep

Par nvidia · skills

Runbook agent pour les balayages de paramètres Proteina-Complexa via le CLI et le générateur de configuration first-party installés séparément. À utiliser pour les scans d'hyperparamètres en produit cartésien, la rédaction de YAML pour le sweeper, les comparaisons de configurations, les ablations, le tuning, le classement par taux de succès ou les recherches de Pareto sur la qualité et le coût en temps réel. Ne pas utiliser pour le lancement d'un job existant unique ou un template de soumission SLURM. SKILL.md assure l'orchestration ; les exécutables fournis se contentent de vérifier la disponibilité locale et d'écrire un manifeste d'exécution.

npx skills add https://github.com/nvidia/skills --skill complexa-sweep

complexa-sweep

Exécutez des sweeps de paramètres de produit cartésien sur les pipelines de conception Proteina-Complexa. Choisissez ou écrivez un sweeper YAML dans configs/sweeps/, développez-le en N configs d'inférence avec script_utils/generate_inference_configs.py, bouclez complexa design sur ces configs, puis agrégez les métriques de succès par config dans un CSV classé plus un manifeste.

Important : La CLI complexa design N'accepte PAS --sweeper directement. Les sweeps sont pilotés par script_utils/generate_inference_configs.py, qui écrit un configs/inference_configs/inf_{idx}_{run_name}.yaml par combinaison de sweep. Vous bouclez ensuite complexa design sur ces configs générés.

Instructions

La création de sweepers, l'énumération cartésienne, les estimations de coût et l'analyse des CSVs fournis ne nécessitent que les configs et données pertinentes. Complétez ces artefacts sans configurer l'inférence. Lisez la section d'axe pertinente dans sweep_axes.md, puis vérifiez les clés correspondantes dans la config source sélectionnée pour les valeurs par défaut actuelles. Les CSVs récapitulatives avec les comptages et colonnes d'objectif fournis ne nécessitent pas le guide complet d'inférence ou de métriques. Pour un instantané partiel, énumérez les combinaisons localement et fournissez la commande de générateur futur ; exécuter cette commande nécessite le projet complet et ses dépendances.

Pour un lancement demandé, vérifiez la préparation et le budget ci-dessous. Un job existant unique ou un template SLURM ne nécessite pas un sweep de paramètres.

Étape 1 : Pré-vol

Avant l'exécution GPU, ou quand la demande conditionne son workflow sur le matériel, définissez SKILL_DIR au répertoire contenant ce manifeste et exécutez preflight une fois. Utilisez une affectation shell séparée ; une affectation d'environnement inline ne peut pas définir l'expansion de $SKILL_DIR dans la même commande. Réutilisez une probe existante de la même demande si l'environnement est inchangé :

bash "$SKILL_DIR"/scripts/preflight.sh

Lisez ./complexa_setup/preflight.json. Un sweep multiplie le temps GPU par le nombre de configs et cibles. Calculez le budget avant le lancement et obtenez une confirmation si l'utilisateur n'a pas déjà autorisé cette portée et ce coût :

« Ce sweep produit N configs × ~M minutes par config ≈ TOTAL GPU-heures. OK pour continuer ? (y / réduire / annuler) »

Si gpu.available=false, arrêtez-vous avant l'exécution GPU. La création de sweepers, l'énumération de produit cartésien, les estimations de coût et l'analyse des CSVs fournis peuvent s'exécuter sur CPU. Pour ces demandes, terminez les artefacts demandés et enregistrez les prérequis de lancement. Étiquetez les données d'entrée synthétiques comme synthétiques et gardez le temps GPU estimé séparé du runtime mesuré.

Pour une demande conditionnelle au matériel, vérifiez le matériel alloué avant de sélectionner la solution de secours CPU. Les poids manquants, les dépendances ou la VRAM insuffisante pour un GPU alloué sont des blocages de lancement, pas la preuve d'un environnement CPU uniquement. Signalez les défaillances de probe ou d'exécution sans reclassifier la branche sélectionnée. Le gpu.available=false du preflight partagé couvre aussi l'nvidia-smi défaillant ou manquant ; vérifiez les preuves de device/allocation avant de le traiter comme une absence GPU. Dans les conteneurs, /proc/driver/nvidia/gpus et les modules du noyau chargés peuvent décrire l'hôte, pas l'allocation de cette tâche. Vérifiez l'exposition du device du conteneur et toute information d'allocation du planificateur disponible ensemble. Une allocation CPU peut partager un hôte GPU ; un GPU alloué avec des devices inaccessibles est bloqué. Si l'allocation reste peu claire, signalez-la comme indéterminée.

Étape 2 : Choisir le pipeline + cible

Utilisez le pipeline, les cibles et le nom de run fournis par l'utilisateur. Les runs de protéine, ligand et AME utilisent respectivement search_binder_local_pipeline, search_ligand_binder_local_pipeline et search_ame_local_pipeline. Demandez uniquement les valeurs manquantes :

  • pipeline_config_name — par ex. search_binder_local_pipeline (par défaut), search_ligand_binder_local_pipeline, search_ame_local_pipeline.
  • task_name — par ex. 02_PDL1, 22_DerF21, 39_7V11_LIGAND. Passé comme --override generation.task_name=<task>.
  • run_name — tag court pour le nommage du répertoire de sortie.

Exemples

Étape 3 : Choisir ou écrire le sweeper YAML

Les YAMLs sweeper se trouvent dans configs/sweeps/. Chaque clé est un chemin Hydra en notation pointée ; chaque valeur est une liste. Le produit cartésien devient N configs.

Sweepers prêts à l'emploi

Fichier Axe Valeurs Configs
configs/sweeps/beam_width.yaml generation.search.beam_search.beam_width 1, 2, 4, 8 4
configs/sweeps/bb_ca_temperature.yaml generation.model.bb_ca.simulation_step_params.sc_scale_noise 0.1, 0.4 2
configs/sweeps/search_replicas.yaml generation.search.best_of_n.replicas 1, 4, 16, 64 4
configs/sweeps/example.yaml beam_width × nsteps (2,4) × (200,400) 4

Utilisez un sweeper correspondant, puis vérifiez que ses axes affectent l'algorithme sélectionné. La config binder utilise par défaut best-of-n : un sweep de beam-width doit aussi épingler generation.search.algorithm: [beam-search]. Un sweep de replicas épingle generation.search.algorithm: [best-of-n]. Pour AME, la recherche guidée par récompense nécessite aussi un modèle de récompense configuré ; sa valeur par défaut est null.

Écrire un nouveau sweeper

Exemple multi-axe minimal (sauvegardé dans configs/sweeps/my_sweep.yaml) :

# 3 beam widths × 2 nsteps = 6 configs
generation.search.algorithm: [beam-search]

generation.search.beam_search.beam_width:
  - 2
  - 4
  - 8

generation.args.nsteps:
  - 200
  - 400

Règles (de script_utils/generate_inference_configs.py:load_sweeper_file) :

  • Mapping de haut niveau uniquement. Les clés sont des chemins Hydra en notation pointée.
  • Gardez les budgets, l'état de lancement et autres métadonnées de planification dans le plan de lancement, en dehors du sweeper. Chaque entrée de haut niveau devient un axe d'override ; une liste targets séparée multiplierait à nouveau la grille.
  • Les valeurs doivent être des listes. Un scalaire est auto-enrobé dans une liste à un seul élément (qui épingle une valeur sans ajouter une dimension).
  • Pour un paramètre avec valeur de liste, imbriquez chaque liste candidate : metric.sequence_types: [[self, mpnn]] épingle une liste. La forme plate balaie deux strings ; --override analyse les scalaires uniquement.
  • Produit cartésien : configs totales = produit des longueurs de liste. Multipliez par le nombre de cibles sauf si les noms de cibles sont déjà l'un des axes ; ne les comptez pas deux fois.
  • Si une clé apparaît à la fois dans le fichier sweeper et dans un --override, l'override gagne et cet axe s'effondre.
  • Rejetez les axes vides avant le lancement : un axe de [] produit zéro configuration.

Voir references/sweep_axes.md pour le catalogue complet des clés balayées (plages typiques, multiplicateurs de coût, ce qui améliore/régresse).

Aperçu de test avant la génération

Avec le projet complet disponible, confirmez d'abord le nombre de configs :

python script_utils/generate_inference_configs.py \
    --config_name search_binder_local_pipeline \
    --sweeper configs/sweeps/my_sweep.yaml \
    --override generation.task_name=22_DerF21 \
    --run_name my_sweep \
    --dryrun

La sortie liste chaque axe + liste de valeurs et affiche DRY RUN — auraient généré N paire(s) de config. Ceci prévisualise l'énumération uniquement ; elle retourne avant la composition Hydra et ne valide pas le pipeline, les types de paramètres ou les prérequis de lancement.

Quand le projet complet est disponible, inspectez les configs d'inférence matérialisés avant de lancer. Vérifiez la cible résolue, l'algorithme de recherche sélectionné et les valeurs de paramètres demandées dans la grille générée. Le générateur permet les clés inconnues lors de la fusion, donc une écriture réussie seule n'établit pas qu'un axe mal orthographié ou mal placé change le paramètre prévu. Avec seulement un instantané partiel, vérifiez chaque point-chemin par rapport à sa config source et signalez que la matérialisation reste non vérifiée.

Étape 4 : Générer les configs + boucler complexa design

Une fois que le test à sec semble bon, supprimez --dryrun pour matérialiser les paires inf_{idx}_{run_name}.yaml + eval_{idx}_{run_name}.yaml sous configs/inference_configs/ et configs/eval_configs/. Puis bouclez complexa design sur les configs d'inférence.

Pour plusieurs cibles, mettez generation.task_name dans le sweeper comme un axe, ou donnez à chaque invocation de générateur de cible un --run_name distinct. Les indices redémarrent à zéro à chaque invocation et les noms de fichiers omettent la cible ; réutiliser le même run name et les mêmes répertoires de sortie écrase les configs antérieurs et réutilise les chemins de résultat.

# 1. Générer un inf_*.yaml + un eval_*.yaml par combinaison.
python script_utils/generate_inference_configs.py \
    --config_name search_binder_local_pipeline \
    --sweeper configs/sweeps/my_sweep.yaml \
    --override generation.task_name=22_DerF21 \
    --run_name my_sweep

# 2. Boucler complexa design sur chaque config d'inférence générée.
for cfg in configs/inference_configs/inf_*_my_sweep.yaml; do
    complexa design "$cfg" || echo "FAILED: $cfg"
done

Cela sérialise le sweep sur un seul GPU — soyez honnête avec l'utilisateur que le temps écoulé = N × par-run.

Hôte multi-GPU (accélération optionnelle)

Sur un hôte avec K GPUs, shardez la liste de configs K voies et lancez une boucle par GPU en parallèle. Chaque appel complexa design utilise exactement un GPU aux valeurs par défaut gen_njobs=1 / eval_njobs=1, donc l'épinglage via CUDA_VISIBLE_DEVICES les empêche de collisionner :

CONFIGS=(configs/inference_configs/inf_*_my_sweep.yaml)
N=${#CONFIGS[@]}; K=4   # 4 GPUs
for gpu in $(seq 0 $((K-1))); do
    (
        for i in $(seq $gpu $K $((N-1))); do
            CUDA_VISIBLE_DEVICES=$gpu complexa design "${CONFIGS[$i]}" \
                || echo "FAILED on GPU $gpu: ${CONFIGS[$i]}"
        done
    ) &
done
wait

Déposez les overrides gen_njobs / eval_njobs dans la boucle uniquement si vous voulez intentionnellement que chaque invocation complexa design consomme plusieurs GPUs (et vous avez un moyen de les garder en dehors de la portée les uns des autres).

Étape 5 : Collecter les résultats

Chaque config balayée écrit dans son propre répertoire ./inference/inf_{idx}_{run_name}/ ; l'étape d'analyse écrit ./evaluation_results/eval_{idx}_{run_name}/results_*.csv. Après la fin du sweep :

ls -d ./inference/inf_*_my_sweep/
ls ./evaluation_results/eval_*_my_sweep/results_*.csv

Inspectez le schéma CSV fourni avant d'agréger. S'il contient déjà une ligne par configuration avec n_passed et n_designs, calculez success_rate = n_passed / n_designs ; signalez les dénominateurs zéro et les comptages invalides. Ne traitez pas ces lignes récapitulatives comme des designs individuels. Pour les lignes par design, utilisez les flags de passage existants, en analysant explicitement les booléens de string. Si les flags sont absents, utilisez les seuils d'analyse du run, result_type, les noms de colonnes et les unités de EVALUATION_METRICS.md. PAE peut être normalisé par 31 et pLDDT peut utiliser des échelles différentes ; ne substituez pas les seuils génériques.

Étape 6 : Classer les configs

Émettez sweep_summary.csv vers le répertoire de run. Une ligne par config :

Colonne Comment calculer
config_id Le {idx} de inf_{idx}_{run_name}
<axis_1>, <axis_2>, ... La valeur balayée à cette combinaison (lue depuis le inf_*.yaml par config)
n_samples n_designs pour un résumé de config fourni, sinon par le nombre de lignes par design
success_rate n_passed / n_designs pour un résumé de config, sinon moyenne des flags de passage analysés par design
mean_i_pae Préservez la moyenne de config fournie, ou moyennes des valeurs par design en unités cohérentes (inférieur = mieux)
mean_i_plddt i_plddt.mean() (supérieur = mieux)
diversity_score Nombre de séquences uniques / n_samples (ou utilisez le clustering TM-score si disponible)
wall_clock_min Depuis les horodatages de log par config

Remplissez uniquement les métriques présentes dans les entrées ou calculables à partir de celles-ci. Les données de diversité ou de timing manquantes restent indisponibles.

Signalez ensuite :

  • Meilleure config = argmax de success_rate. Tie-break sur mean_i_pae (inférieur).
  • Frontière de Pareto : choisissez les objectifs et directions demandés. Pour le temps par rapport au succès, minimisez le temps et maximisez le succès ; pour le temps par rapport à iPAE, minimisez les deux. Un point est dominé quand un autre n'est pas pire sur chaque objectif et strictement mieux sur au moins un. Conservez les IDs de config distincts aux coordonnées non-dominées égales ; signalez les mesures invalides/manquantes séparément.

Sauvegardez le tableau complet vers sweep_summary.csv, puis rouvrez les résultats sauvegardés et imprimez un résumé compact : nombre de lignes, meilleure config et valeurs de métriques, et IDs frontière avec leurs valeurs d'objectif. Signalez les chemins CSV et gardez la probe matérielle et les vidages de configuration séparés de ce résumé de résultats.

Étape 7 : Émettre le manifeste

Capturez l'invocation résolue + sorties pour la rediffusion. L'helper partagé prend un --output-dir unique (il marche pour les CSVs et tire la config Hydra du .hydra/ du run), donc appelez-le par rapport au répertoire d'évaluation de la meilleure config et passez la commande complexa design parent pour ce run :

BEST_ID=4   # de la classification Étape 6
python3 "$SKILL_DIR"/scripts/write_manifest.py \
    --output-dir ./evaluation_results/eval_${BEST_ID}_my_sweep \
    --command "python script_utils/generate_inference_configs.py --config_name search_binder_local_pipeline --sweeper configs/sweeps/my_sweep.yaml --override generation.task_name=22_DerF21 --run_name my_sweep && for cfg in configs/inference_configs/inf_*_my_sweep.yaml; do complexa design \"\$cfg\"; done" \
    --skill complexa-sweep \
    --out ./sweep_runs/my_sweep/sweep_manifest.json

Aux côtés du manifeste, sauvegardez le sweep_summary.csv classé de l'Étape 6 vers ./sweep_runs/my_sweep/sweep_summary.csv et surfacez les deux chemins vers l'utilisateur.

Recettes de sweep recommandées

Symptôme Balayez ceci Pourquoi
Qualité pas assez bonne beam_width × nsteps (utilisez example.yaml comme point de départ) Les deux augmentent le calcul → qualité ; trouvez la combinaison la moins chère qui atterrit.
Trop lent / désirer une accélération nsteps vers le bas (par ex. [100, 200, 400]) avec beam_width=4 fixe Trouvez le plus petit nsteps qui retient le taux de succès.
Effondrement de mode / faible diversité generation.model.bb_ca.simulation_step_params.sc_scale_noise (utilisez bb_ca_temperature.yaml) Bruit plus élevé → épines dorsales plus diverses.
Surapprentissage de récompense (récompense élevée, mauvaises métriques) Ratio generation.reward_model.reward_models.af2folding.reward_weights.{i_pae, plddt} Rééquilibrez la récompense composite.
Élargir le pool de candidats best-of-N search_replicas.yaml (best_of_n.replicas) Plus de candidats par recherche ; utilisez des seeds/runs séparé(e)s pour mesurer la répétabilité.
Comparaison d'algorithme generation.search.algorithm sur [single-pass, best-of-n, beam-search, fk-steering] Comparez les régimes de recherche ; épinglez tout le reste.

Matériel

Temps GPU total pour un sweep = N_configs × per_run_GPU_time. Un seul run search_binder_local_pipeline sur un A100 est environ 30–90 min (dépendant de la longueur du binder + nsteps). Un sweep 4-axe × 4-valeur = 256 configs × ~60 min = ~256 GPU-heures — à cette échelle, planifiez un hôte multi-GPU avec le pattern de sharding Étape 4.

Reportez-vous à references/hardware.md pour la baseline par run + minima VRAM.

Dépannage

Symptôme Cause Correctif
Sweeper file not found de generate_inference_configs.py Chemin résolu depuis le mauvais CWD Utilisez un chemin relatif à la racine du repo ; ou passez un chemin absolu.
Sweeper YAML must be a mapping Le YAML de haut niveau est une liste ou un scalaire Réécrivez comme un mapping key: [v1, v2].
Le test à sec rapporte zéro paire de config L'une des listes de valeurs est vide [] Fournissez au moins une valeur avant la génération ou le lancement ; le générateur ne rejette pas un produit vide.
complexa design rejette --sweeper Confusion entre les points d'entrée La CLI n'accepte pas --sweeper. Utilisez generate_inference_configs.py d'abord, puis bouclez complexa design sur les configs générés.
Override s'effondre silencieusement un axe de sweep --override key=v a occulté une clé de sweep Déposez soit l'override SOIT la clé correspondante du fichier sweeper.
Une config dans la boucle échoue, le sweep continue Le \|\| echo "FAILED…" à l'Étape 4 avale l'erreur Exécutez à nouveau le inf_*.yaml échoué seul ; vérifiez le log par config sous ./logs/. Ignorez l'ID de config échoué lors du classement.

Pour une référence par axe (plages typiques, coût, ce qui s'améliore/régresse), voir references/sweep_axes.md.

Pour l'aperçu système de sweep face à l'utilisateur (génération de config, disposition de la sortie), voir references/SWEEP.md.

Skills similaires