


Modifier du code distribué d’entraînement et d’inférence en apprentissage automatique sans le casser
Pour modifier du code qui entraîne ou exécute des modèles sur de nombreux processus ou accélérateurs. Consulte avant les changements risqués, aligne les versions de poids et l’ordre des opérations collectives sur chaque rang, garde la configuration compatible et signale les tests ignorés.
Pour utiliser ces règles d'IA
## Lire le code d’abord et demander avant de changer la configuration partagée ou les API
Avant toute modification, lisez l’implémentation concernée, les schémas employés dans les modules voisins, les contrats de configuration et les tests. Utilisez le gestionnaire d’environnement, l’outil de formatage, l’analyseur statique et la chaîne d’outils pre-commit du projet ; ne contournez pas les hooks.
N’inscrivez jamais en dur des identifiants d’accès, des chemins propres aux machines, des points de terminaison de services ou la topologie du cluster. Ne devinez pas les réglages de l’ordonnanceur et ne reconstruisez pas les pilotes ni les piles d’exécution des accélérateurs comme raccourci de dépannage.
Obtenez une décision avant de :
- modifier des structures de configuration partagées ;
- ajouter des dépendances ;
- modifier le comportement du lanceur ou de l’ordonnanceur ;
- supprimer ou renommer des API publiques, ou les modifier de manière incompatible.
Si le matériel requis ou l’accès au cluster n’est pas disponible, indiquez quelles vérifications d’intégration ont été omises et pourquoi. Ne transformez pas en code une hypothèse non vérifiée sur le système distribué.
Orientez le travail selon le sous-système : moteur d’entraînement, moteur d’inférence, algorithme, lanceur, ordonnanceur, jeu de données, récompense, flux de travail ou débogage distribué. Utilisez le guide d’implémentation spécialisé ou le processus de revue du domaine prévu par le projet, lorsqu’il existe.
## Séparer chaque sous-système et marquer les données avec leur version de poids
Maintenez comme responsabilités distinctes l’orchestration, la génération de rollouts, l’entraînement, l’inférence, l’infrastructure, l’adaptation des modèles, les récompenses, les jeux de données et les utilitaires transversaux.
Le composant d’entraînement coordonne la boucle, le chargement des données et les flux de travail. Les flux de travail de rollout définissent la génération asynchrone d’épisodes. Les moteurs d’inférence génèrent des sorties et reçoivent des mises à jour des poids ; les moteurs d’entraînement consomment des tenseurs de rollout, calculent des mises à jour et publient de nouvelles versions des poids.
Dans les systèmes asynchrones, associez des métadonnées explicites de version des poids aux données générées et aux mises à jour. N’entraînez ni n’évaluez jamais avec des versions du modèle qui ne correspondent pas entre elles sans que cela soit signalé.
Émettez les métriques par l’intermédiaire de l’outil de suivi standard, conservez durablement les artefacts sous la racine de sortie configurée et utilisez le chemin canonique d’enregistrement et de récupération des points de contrôle. L’observabilité et la récupération font partie du contrat d’exécution.
Préférez la composition et la délégation à une hiérarchie d’héritage profonde. Maintenez des limites d’extension suffisamment réduites pour permettre de tester indépendamment les moteurs, les flux de travail et les adaptateurs de modèles.
## Écrire du code rapide pour accélérateurs sans synchronisation entre périphérique et hôte
Respectez les conventions existantes de nommage, de typage et de journalisation dans le module responsable. Utilisez des annotations de type et des imports explicites ; n’utilisez jamais d’imports avec caractère générique. Limitez les dépendances facultatives lourdes aux fonctions ou aux chemins de code qui en ont besoin.
Utilisez le système de journalisation du projet au lieu d’imprimer directement. Incluez dans les entrées de journal le contexte du composant et du rang distribué afin que l’origine des sorties simultanées reste identifiable.
Dans les chemins critiques de l’accélérateur :
- évitez la synchronisation entre le périphérique et l’hôte, par exemple l’extraction de valeurs scalaires ou de listes à des fins de journalisation ;
- regroupez les opérations sur les tenseurs au lieu de parcourir les éléments un par un en Python ;
- définissez explicitement le périphérique et le type de données ;
- vérifiez par des assertions les formes attendues des tenseurs aux limites.
Maintenez les flux de travail de rollout non bloquants. Attendez la fin des appels asynchrones aux moteurs et des opérations sur les fichiers ; n’introduisez pas d’E/S synchrone dans un chemin d’épisode asynchrone.
Pour une nouvelle fonctionnalité, suivez le modèle du module opérationnel le plus proche, ajoutez des tests ciblés et évitez toute refactorisation sans rapport avec celle-ci.
## Changer les champs de configuration et les API publiques sans casser leurs utilisateurs
Ordonnez les champs de configuration en plaçant d’abord les champs obligatoires, puis les champs facultatifs courants, les champs facultatifs rares et enfin les champs internes. Validez-les lors de l’initialisation avec une exception claire qui nomme la valeur non valide ou la contrainte enfreinte.
Ajoutez les champs publics avec des valeurs par défaut sûres. Déclarez-les obsolètes avant de les supprimer et évitez de modifier les types de champs établis. Les classes de configuration publiques doivent documenter les contraintes et les valeurs acceptées.
Représentez les choix finis de la ligne de commande par des types contraints plutôt que par des chaînes de forme libre. Réutilisez les classes de données de configuration canoniques au lieu de créer des structures parallèles.
Traitez la configuration partagée, les lanceurs, les ordonnanceurs et les noms d’API publiques comme des zones à fort impact. Rendez explicite l’effet sur la compatibilité dans la description de la modification et obtenez une approbation avant toute modification destructive ou incompatible.
Lorsque le comportement correct ne peut pas être déterminé à partir des contrats actuels, laissez un marqueur de suivi au périmètre clairement défini et signalez la contrainte non résolue au lieu d’inventer une valeur par défaut.
## Garder groupes de processus et opérations collectives cohérents sur tous les rangs
Ne créez jamais de groupe de processus global au moment de l’importation. Transmettez explicitement le groupe de processus prévu et interrogez le rang par rapport à ce groupe lorsque l’appartenance au groupe importe.
Maintenez les dimensions du maillage de périphériques alignées sur le modèle de parallélisme déclaré, y compris, selon le cas, les axes de partitionnement des données, de tenseurs, de contexte, d’experts et de tenseurs d’experts.
Les opérations collectives sont des contrats globaux :
- chaque rang participant doit appeler la même opération all-reduce dans le même ordre ;
- choisissez délibérément l’opération de réduction, par exemple entre somme et moyenne ;
- les opérations de broadcast doivent nommer explicitement un rang source ;
- les barrières sont des outils de diagnostic, et non une stratégie courante de synchronisation.
Diagnostiquez les blocages en recherchant des séquences d’opérations collectives qui ne correspondent pas. Diagnostiquez les résultats incorrects en vérifiant la sémantique de réduction et les versions des poids. Diagnostiquez les erreurs d’épuisement de mémoire en vérifiant le partitionnement, le placement des tenseurs et la propriété des périphériques avant de réduire les fonctionnalités du modèle.
N’utilisez les diagnostics détaillés de l’exécution distribuée, de la bibliothèque de communication et du lancement synchrone que pour un débogage ciblé, puis supprimez-les ou désactivez-les une fois le problème compris.
## Tester le code distribué et lister les tests ignorés dans la pull request
Nommez les tests d’après le comportement, la condition et le résultat attendu, puis structurez-les en préparation, action et vérification. Marquez les tests lents, asynchrones, liés aux accélérateurs et distribués afin que l’intégration continue par défaut puisse sélectionner les suites appropriées.
Ignorez proprement les tests d’accélérateur ou multinœuds indisponibles en indiquant explicitement la raison. Utilisez le groupe de processus simulé du framework pour le comportement distribué au niveau unitaire ; ne simulez pas les mécanismes internes de partitionnement profond ou de tenseurs distribués dont le test doit vérifier la sémantique.
Comparez les tenseurs avec des tolérances relatives et absolues explicites. Préférez les chemins temporaires gérés et l’application de monkeypatches à portée limitée.
Exécutez d’abord la suite de tests unitaires au périmètre restreint, puis la suite distribuée ou liée aux accélérateurs directement concernée lorsque le matériel le permet. Exécutez l’ensemble de la chaîne de formatage et de pre-commit avant la soumission.
Générez la documentation de référence de la ligne de commande à l’aide du générateur canonique. Construisez la documentation de publication à l’aide du wrapper du projet qui effectue la configuration statique et l’empaquetage requis, et non d’une commande de documentation de plus bas niveau qui omet des étapes propres au projet.
Dans la pull request, indiquez le problème, les zones de risque, les commandes de test exactes, les suites omises et leurs raisons, ainsi que toute limitation matérielle. Utilisez des intitulés de commit conventionnels formulés à l’impératif, puis supprimez les commits de travail en cours avant la revue.
