Ce que vous allez exécuter
Le mini-projet Kernodeck contient un petit jeu de données synthétiques, un réseau avec dropout, une boucle d’entraînement et un vérificateur. Le protocole force le CPU pour isoler la logique de sauvegarde et de reprise. Il ne constitue pas une qualification CUDA, ROCm, multicarte ou une mesure de performance d’un GPU loué.
Le vérificateur ouvre des processus neufs pour le parcours continu, la coupure, la reprise complète et un cas négatif qui ne restaure pas les générateurs aléatoires. L’intérêt de ce dernier est de vérifier que le contrôle sait détecter une reprise incomplète, même si les poids et le numéro d’étape paraissent corrects.
Faites défiler le tableau pour lire toutes les colonnes.| Parcours | Exécution | Question vérifiée |
|---|---|---|
| Continu | 10 mises à jour depuis l’état initial. | Quel état atteint-on sans interruption ? |
| Coupure | 5 mises à jour, puis sauvegarde et arrêt. | Le point intermédiaire contient-il les états attendus ? |
| Reprise complète | Nouveau processus, chargement du point 5, puis 5 mises à jour. | Obtient-on la même suite d’entrées, de taux et de paramètres dans la tolérance choisie ? |
| Reprise sans RNG | Nouveau processus, même point de reprise mais restauration de l’aléatoire omise. | Le test détecte-t-il une dérive qu’un simple chargement des poids laisserait passer ? |
Prérequis et lancement du protocole
Téléchargez l’archive, extrayez-la dans un dossier de travail, puis placez-vous dans le dossier contenant train.py et verify_resume.py. Utilisez un environnement Python disposant de PyTorch et NumPy. L’archive contient le code et les données synthétiques ; elle ne télécharge aucun modèle et n’exige pas de compte Kernodeck pour exécuter l’exercice.
La preuve fournie a été exécutée avec Python 3.14.6, PyTorch 2.11.0+cu128 et NumPy 2.4.4. Le programme force le CPU, la précision float64 et un thread PyTorch. Le suffixe du paquet ne signifie donc pas que la reprise a utilisé CUDA. Sur un autre environnement, exécutez votre propre vérification.
Choisissez un répertoire de sortie qui n’existe pas encore. Chaque parcours produit checkpoint.pt, son empreinte checkpoint.pt.sha256 et summary.json. Le vérificateur rassemble la comparaison dans verification.json. L’option --steps compte des étapes supplémentaires : après la coupure à 5, la commande de reprise en exécute 5 pour arriver à 10. L’option Python -B évite les caches de bytecode dans le dossier de l’exercice.
python -B verify_resume.py --output runs/preuve-cpupython -B train.py --steps 10 --output runs/continu
python -B train.py --steps 5 --output runs/coupure
python -B train.py --steps 5 --resume runs/coupure/checkpoint.pt --output runs/repriseExport de poids et checkpoint de reprise n’ont pas le même rôle
Commencez par choisir ce que vous voulez retrouver. Un export pour l’inférence sert à produire des prédictions avec un modèle entraîné. Une reprise d’entraînement doit retrouver aussi l’état qui détermine les prochaines mises à jour. Un traitement d’inférence par fichiers demande, lui, une liste fiable des éléments déjà terminés. Ces trois besoins produisent des sauvegardes différentes.
Ne confondez pas cette sauvegarde persistante avec l’activation checkpointing. Cette technique réduit certaines activations gardées en mémoire en les recalculant pendant la rétropropagation ; elle ne crée pas, à elle seule, un fichier permettant de reprendre après un arrêt. Précisez donc dans votre projet si le mot checkpoint désigne une optimisation de mémoire ou un point de reprise.
Les états à garder ensemble
Le state_dict du modèle contient les paramètres et les buffers enregistrés ; l’optimiseur a son propre état. Ici, Adam, StepLR, le dropout et trois générateurs aléatoires influencent les prochaines mises à jour. Le checkpoint doit représenter le même instant pour tous ces éléments.
Documentez aussi la version du code, les paramètres de l’expérience et l’identité des données. Au milieu d’une époque, connaître seulement son numéro ne suffit pas : il faut pouvoir retrouver l’ordre des exemples et le prochain groupe à consommer. Une erreur à cet endroit peut sauter des entrées ou les traiter deux fois.
Le jeu de 24 lignes décrit une relation synthétique entre deux variables et une cible. Le réseau compte 33 paramètres, avec une couche de huit neurones et un dropout de 0,25. Le batch contient quatre lignes. Après cinq mises à jour, le curseur vaut 20 sur 24 : la coupure se situe au milieu d’une époque. Les dix mises à jour consomment 40 observations, ce qui oblige le contrôle à traverser une nouvelle permutation des données.
Faites défiler le tableau pour lire toutes les colonnes.| État | Rôle | Contrôle à effectuer |
|---|---|---|
| Modèle | Conserver poids et buffers. | Comparer les paramètres finaux et une sortie d’évaluation. |
| Optimiseur | Conserver les états utilisés par la prochaine mise à jour. | Vérifier son rechargement, pas seulement ses hyperparamètres. |
| Scheduler | Continuer la séquence des taux d’apprentissage. | Comparer le prochain taux appliqué puis les taux suivants. |
| RNG Python, NumPy et PyTorch | Continuer les tirages effectivement utilisés. | Vérifier que l’exercice négatif sans restauration diverge. |
| Données | Reprendre la permutation et le curseur. | Comparer les identifiants d’entrées après la coupure. |
| Progression | Interpréter les étapes et les époques. | Arriver à 10 mises à jour au total, sans en refaire ou en omettre. |
| Configuration | Reconstruire la même expérience. | Conserver dimensions, précision, réglages et versions. |
Restaurer dans le bon ordre
Reconstruisez le modèle, l’optimiseur et le scheduler avant de charger leurs états. Le scheduler doit être créé avant optimizer.load_state_dict() : sa construction peut autrement écraser les taux d’apprentissage restaurés. Rechargez aussi son propre état, puis vérifiez le taux réellement utilisé à l’étape suivante.
Restaurez les générateurs aléatoires après la construction des objets qui consomment des tirages, juste avant de continuer le travail. Remettre simplement la graine initiale ferait repartir la séquence au début ; ce n’est pas retrouver l’état atteint après la cinquième mise à jour. Dans votre projet, repérez tous les générateurs utilisés, y compris ceux des transformations et du chargement des données.
Dans cet exercice, Python règle un léger gain sur les entrées, un générateur NumPy PCG64 produit du bruit et les permutations, et PyTorch produit le dropout. Le checkpoint conserve leurs états atteints à la coupure. Le vérificateur observe aussi leurs prochains tirages, en restaurant immédiatement l’état pour ne pas perturber la suite du calcul.
optimizer = torch.optim.Adam(model.parameters(), lr=0.03)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=3, gamma=0.5)
# Dans le parcours de reprise, après la construction des objets :
state = load_checkpoint(resume)
model.load_state_dict(state["model"])
scheduler.load_state_dict(state["scheduler"])
optimizer.load_state_dict(state["optimizer"])
progress = state["progress"]
history = state["history"]
restore_rng(state["rng"], generator)
model.train()Choisir une frontière de sauvegarde cohérente
Fixez une frontière explicite, par exemple après une mise à jour complète de l’optimiseur. Si vous accumulez plusieurs microbatchs avant cette mise à jour, sauvegarder au milieu impose de gérer aussi l’état intermédiaire. Une première implémentation est plus facile à vérifier lorsqu’elle sauvegarde à une frontière où les gradients accumulés ont déjà été consommés.
Conservez plusieurs générations de sauvegarde. Écrivez le nouveau fichier sous un nom distinct, attendez la fin de l’écriture, vérifiez qu’il est lisible, puis marquez-le comme utilisable. Ne remplacez pas votre unique checkpoint valide avant ce contrôle. La fréquence dépend du travail que vous acceptez de refaire et du temps d’écriture observé ; elle ne se déduit pas seulement de la durée de location.
Le mini-projet sauvegarde après une itération terminée, puis exporte le fichier et son empreinte. Il utilise un nouveau dossier pour chaque parcours et ne remplace pas une preuve précédente. Si votre entraînement emploie la précision mixte avec un GradScaler, son état fait également partie de la reprise. Cette variante n’est pas couverte par l’exercice CPU.
Lire la comparaison et sa tolérance
Le protocole compare la continuation après le point 5 : données consommées, taux d’apprentissage, pertes et paramètres atteints. Une concordance du seul numéro d’étape ne suffit pas. Un optimiseur réinitialisé peut poursuivre la boucle tout en produisant des mises à jour différentes.
La tolérance choisie pour cet exercice est absolue : 1e-12, avec une tolérance relative de 0. Ce seuil fait partie du protocole CPU fourni ; il ne constitue pas une règle universelle pour vos modèles. La comparaison doit signaler des valeurs non finies et les différences de structure, au lieu d’accepter silencieusement une sortie inexploitable.
PyTorch ne garantit pas une identité des résultats entre versions, plateformes, CPU et GPU. Si vous portez l’exercice, refaites la preuve sur la cible et expliquez la tolérance retenue. N’élargissez pas le seuil simplement pour faire disparaître un échec dont vous n’avez pas compris l’origine.
Dans la preuve fournie, tous les écarts du parcours complet valent zéro : paramètres, état de l’optimiseur, pertes, taux et MSE. L’ordre des lignes, la progression, l’état du scheduler et les prochains tirages coïncident également. Le prochain taux d’apprentissage après l’étape 10 vaut 0,00375 dans les deux parcours. Le résultat ne dépend donc pas uniquement d’une métrique finale qui pourrait masquer des différences intermédiaires.
Faites défiler le tableau pour lire toutes les colonnes.| Comparaison | Reprise complète | Reprise sans restauration RNG |
|---|---|---|
| Écart maximal des poids | 0 | 0,011669328447718508 |
| MSE finale | 0,09538858591775097 | 0,0936034144665111 |
| Écart de MSE par rapport au parcours continu | 0 | 0,001785171451239867 |
| Verdict du sous-test de concordance | Concordant dans la tolérance de 1e-12 | Divergence détectée |
Pourquoi conserver le cas négatif sans aléatoire restauré
Un contrôle est plus utile lorsque vous savez quelle erreur il détecte. La variante négative recharge les mêmes poids, états d’optimiseur, scheduler et progression, mais omet volontairement la restauration RNG. Le processus peut terminer sans exception Python tout en poursuivant une autre trajectoire.
Dans la preuve fournie, cette omission produit un écart maximal des poids supérieur à 0,011 et une différence de MSE supérieure à 0,0017. La MSE négative est ici plus basse que celle du parcours continu : cela ne rend pas la reprise correcte. Le but consiste à retrouver la même expérience, pas à classer deux modèles par leur erreur finale.
Le vérificateur réussit seulement lorsque le parcours complet concorde et que le cas négatif diverge. Il affiche alors all_checks_passed: true, positive: true et negative_divergence_detected: true. Son code de sortie vaut 0 en cas de réussite du protocole, 1 si la comparaison échoue et 2 si la vérification n’a pas pu être terminée.
python -B train.py --steps 5 --resume runs/coupure/checkpoint.pt --omit-rng-restore --output runs/reprise-incompleteCharger le fichier de l’exercice sans assouplir les protections
Le projet charge uniquement le checkpoint que vous avez créé avec cet exercice et conservé sous votre contrôle. Il utilise explicitement torch.load(..., map_location="cpu", weights_only=True). L’état Python contient des primitives, celui du générateur NumPy PCG64 des entiers et des chaînes, et celui de PyTorch CPU un tenseur d’octets. Aucun tableau NumPy arbitraire n’est placé dans l’état RNG sauvegardé.
Le chargeur vérifie l’empreinte associée, la taille, le schéma, la progression, les versions ainsi que l’identité du code et des données. Il refuse un état incohérent au lieu de réinitialiser silencieusement un élément manquant. L’empreinte détecte une modification ; elle n’authentifie pas l’expéditeur d’un fichier.
N’ajoutez pas weights_only=False simplement pour faire taire une erreur de chargement. Le format enregistré et sa reconstruction doivent être cohérents. Le chargement restreint réduit les possibilités de désérialisation, mais ne rend pas un fichier inconnu digne de confiance.
Ce qui change pour un entraînement distribué
Avec plusieurs processus ou des états répartis entre GPU, vérifiez qui écrit quoi. Un fichier produit par un seul processus n’est pas nécessairement une sauvegarde complète du travail distribué. Utilisez la procédure de sauvegarde prévue par votre stratégie et attendez son achèvement sur les participants concernés. Identifiez clairement les fragments qui appartiennent au même point de reprise.
Un changement de nombre de GPU peut nécessiter une redistribution des états et modifier la répartition des données. Les mécanismes de checkpoint distribué peuvent gérer certains changements, mais cette possibilité doit être vérifiée pour votre format et votre configuration. Faites un essai de chargement sur la cible prévue. Ajouter des lots à la commande ne convertit pas automatiquement une sauvegarde monocarte en programme distribué.
Terminer par un export réellement récupérable
Avant l’échéance, exportez les checkpoints utiles avec leur configuration, les métriques, les instructions de chargement et les identifiants des données. Vérifiez la taille et une empreinte des fichiers copiés, puis chargez au moins une sauvegarde depuis sa destination. Une empreinte identique contrôle la copie ; le rechargement vérifie que le contenu suffit réellement à reconstruire le travail.
Chargez uniquement des fichiers dont vous connaissez la provenance et choisissez un format ainsi que des options de désérialisation adaptés. Gardez le dernier point de reprise validé tant que le nouveau n’a pas passé vos contrôles. La sortie attendue est un dossier récupérable et une courte preuve de reprise : commande exécutée, étape retrouvée, contrôle réussi et résultat exporté. Prévoyez ce temps dans vos 3, 7 ou 30 jours.
Périmètre de la preuve et choix de la location
La preuve du 24 septembre 2026 compare quatre processus neufs sur CPU, avec une tolérance absolue de 1e-12 et aucune tolérance relative. Elle ne couvre ni CUDA, ni ROCm, ni AMP, ni entraînement distribué, ni workers de chargement des données. Elle valide la logique de reprise de la version fournie, dans l’environnement décrit, et ne mesure pas les capacités d’un GPU loué.
Après ce petit exercice, transposez le même protocole à votre modèle, vos données et votre backend. Une carte de 80 Go ou une carte de 192 Go ne corrige pas un checkpoint incomplet : choisissez d’abord la chaîne compatible, puis dimensionnez la mémoire d’une étape réelle. Les offres liées ci-dessous ne sont pas présentées comme du matériel testé pour cette preuve.
Prévoyez dans votre période de 3, 7 ou 30 jours un premier cycle sauvegarde–arrêt–reprise et le temps d’export final. La sortie utile est un dossier dont vous pouvez expliquer les versions, le point de reprise, le contrôle comparatif et les limites ; l’existence seule d’un fichier .pt ne donne pas cette assurance.