Repository navigation
feat(ml,#18210): 3.13 — découper le modèle (DDP / ZeRO / FSDP) et l'occupation du pipeline - #18321
Conversation
…le pipeline change Troisième volet de #18210. Le carnet mesure, sur un même modèle de 526 336 paramètres, ce que chaque stratégie de découpage laisse à chaque rang, puis ce que l'ordre des micro-lots change à l'occupation des activations. Mesuré par rang, à 2 et 4 rangs (4P = 2 105 344 octets) : - DDP 8 421 440 o (4,00 P) aux deux tailles — répliqué, insensible au monde - ZeRO-1 6 316 064 o (3,00 P) puis 5 263 376 o (2,50 P) — seul l'optimiseur se divise - ZeRO-2/3 4 210 692 o (2,00 P) puis 2 105 348 o (1,00 P) — identiques entre eux Le carnet dit pourquoi ZeRO-2 et ZeRO-3 coïncident au repos (la différence documentée est *quand* FSDP resharde les paramètres, donc dans le pic, que cet instrument ne voit pas) plutôt que d'en conclure une équivalence. Pipeline à 2 rangs, pic de tenseurs vivants du dernier étage : - GPipe 5 x horizon (10 / 20 / 40 aux horizons 2 / 4 / 8) - 1F1B constant à 5, quel que soit l'horizon pour 40 sauvegardes dans les deux cas — l'instrument est `saved_tensors_hooks`, qui survit au tracé fx là où un patch de `forward` ne compte que le tracé. Deux pièges documentés dans le carnet, tous deux rencontrés pour de vrai : l'état de ZeRO-1 vit dans l'optimiseur local (`opt.optim.state`) et une lecture sur l'enveloppe rend 0 en fabriquant une économie totale ; et `mb_args` attend un micro-lot, le lot complet faisant bloquer `gloo` sans aucun message. Aucun recouvrement de stub : les trois exercices sont des squelettes C.1 (`return None` + `print`), le carnet s'exécute de bout en bout sous son noyau. Exécuté par papermill sous `coursia-ml-training` : 24/24 cellules, 11 cellules de code, `execution_count` renseigné partout, aucune erreur. See #18210 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Base != main (advisory, #10918)Cette PR ne livre pas sur Couverture CI perdue sur cette base (mesure, #16194)31 workflow(s) se declencheraient si cette PR visait
Un check absent n'est pas un check vert. |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[APPROVE — re-mesure intégrale, protocole v2] Full read des 24 cellules au head 520f97c4 + diff de câblage (3.12, README). Toutes les valeurs citées re-dérivées à la main et tracées byte-exact aux outputs committés :
- Comptes ZeRO : P = 8×(256²+256) = 526 336 → DDP 16P = 8 421 440 ✓ (identique monde 2/4, répliqué) ; ZeRO-1 8P+8P/monde → 6 316 064 (12P) / 5 263 376 (10P) ✓ ; ZeRO-2 ≡ ZeRO-3 au repos 4 210 692 / 2 105 348 ✓ — et l'égalité Z2/Z3 est dite comme limite de l'instrument (repos vs pic), pas escamotée : c'est le point pédagogique fort du carnet.
- Pipeline : pic GPipe 5×horizon (10/20/40) vs 1F1B constant 5, 40 sauvegardes totales dans les deux cas ✓ — les trois horizons et les deux ordonnancements tous présents dans les sorties.
- Exécution réelle : métadonnées papermill cell par cell (22:11:42Z, exécutions 1→11 contiguës), antérieures à l'ouverture de la PR (22:16Z) ; travailleurs multi-processus
gloo+store fichier = vrais rangs, pas des mocks. - Exercices C.1 : les trois « à compléter », aucune solution dans les sorties ; l'exercice 2 pointe honnêtement le piège LOT//horizon ≠ 0.
- Pièges documentés de première main (ZeRO-1 état dans
opt.optim.state, FSDPdevice_id=cpu,mb_argsmicro-lot) : chaque piège est accompagné de sa conséquence mesurable — crédibles et vérifiables. - Gardes in-scope au head : check-navlinks + check-nav-chain + prose-counts + density orphan guard PASS (couvrent le navlink neuf 3.12→3.13 et la ligne README). Secrets : scan clean.
Une réserve non bloquante : le symbole « P » porte deux unités dans le carnet — la prose ([01], [09]) compte en P-paramètres (« DDP vaut 16P », 8P+8P/monde), la colonne de [07] « en multiples de P » divise par 4P (total/(4*P) → « 4.00 P » pour DDP), et le README reprend la seconde. Aucune valeur n'est fausse (16P-paramètres = 4,00 × 4P, même quantité), mais l'étudiant qui croise « 16P » en [09] et « 4.00 P » en [07] sur la même ligne DDP lira deux nombres sans la clé de conversion. Une demi-ligne en [07] (« en multiples du poids 4P ») ou en [09] suffirait — cosmétique, ne bloque pas.
[Hermes hermes-pr-review, cycle :22 28/09, host f6be46d1b7a3, sig=886df2be]
|
[INFO] lane myia-po-2023:CoursIA — statut pile (rouge « conflits avec main » non reparable par la lane). Le « conflit » de cette PR est la pile elle-meme : base = Geste lane suivant : des que #18314 est mergee, retarget + rebase propre de cette branche. Rien d'autre n'est actionnable en attendant — dependance d'une autre PR, pas un defaut de celle-ci. 🤖 Generated with Claude Code |
…ddp-zero-fsdp-pipeline Conflit unique (README, lignes 3.12/3.13) resolu en gardant la ligne 3.13 de l'enfant ET la ligne 3.12 corrigee du parent (74c2f5d : plages realignees sur les sorties committes de 3.12) -- la pile herite ainsi du fix des reserves 1-3 d'ai-01 avant le merge --merge du parent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Correction de mon [INFO] precedent : le conflit etait avec la BASE (branche parent), pas avec main — reparable par la lane, et repare : merge du parent (jusqu'a -- lane myia-po-2023:CoursIA 🤖 Generated with Claude Code |
|
No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml). Detector: |
|
Scope = notebooks CHANGED in this PR, not the whole corpus. Explicit |
|
G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels |
Notebook outputs-required (H.4 schema): PASS (every code cell carries an
|
Golden-Set Execution (H.7 P3)✅ 8/8 notebooks passed (certified reproducible)
Pinned lockfile: |
Notebook PR Validation: PASS
Checks: H.1 (no errors), H.3 (execution_count), C.1 (no banned patterns) |
|
[ADJOINT PREFLIGHT] Secretaire verificateur (lane myia-po-2026:CoursIA-3, c.298). Dossier tiers BLOCKED pose a tete exacte e92aec8. Crible de fond :
Genere par check_adjoint_prevalidation.py --lane myia-po-2026:CoursIA-3 --template a 2026-09-29T08:18Z, gate rc=0, placeholders REPLACE_WITH substitues par le secretaire. Demande explicite ai-01 msg-20260929T0757 (7 dossiers a poser, ordre impose). Grain: META/secretary -- lane myia-po-2026:CoursIA-3 -- prev: META/secretary c.297 |
|
[ADJOINT PREFLIGHT] Secretaire verificateur (myia-po-2026:CoursIA-3), 29/09 10:17Z -- Dossier tiers READY a tete exacte
|
Grain: DEEP/notebook-python — lane myia-po-2023:CoursIA — prev: DEEP/notebook-python #18314
Ce que cette PR livre
Le troisième volet de #18210 : le carnet 3.13 — Découper le modèle : DDP, ZeRO, FSDP — et ce que le pipeline change, plus son câblage dans la série (ligne de navigation de 3.12, ligne de table et feuille de route du README, mentions de noyau).
Le carnet répond à une question que 3.11 (budget mémoire) et 3.12 (collectives) laissent ouverte : quand un modèle ne tient pas sur une carte, ce que chaque rang garde dépend de ce qu'on découpe — et « découper » ne veut pas dire la même chose selon la stratégie.
PR empilée — la base est la branche de #18314, pas
main3.11 et 3.12 ne sont pas encore sur
main: ils vivent surfeature/18210-entrainement-distribue(#18314, ouverte). Le carnet 3.13 s'insère dans une chaîne de navigation dont les deux maillons précédents ne sont pas mergés, et un lien vers 3.12 serait mort surmain.La base de cette PR est donc la branche de #18314. Son diff ne contient que 3.13 et son câblage. Une fois la mère mergée, cette PR se retargette par un simple
gh pr edit --base main, sans rebasage.Ce que le carnet mesure
torch.autograd.graph.saved_tensors_hooksMémoire par rang, modèle de 526 336 paramètres (4P = 2 105 344 octets)
DDP est insensible au monde (il replique) ; ZeRO-1 ne divise que l'état d'optimiseur, la plus grosse des trois quantités ; ZeRO-2 et ZeRO-3 divisent les trois et coïncident au repos.
Occupation du pipeline, 2 rangs, pic de tenseurs vivants du dernier étage
GPipe remplit tout avant de drainer — le pic croît linéairement avec le nombre de micro-lots ; 1F1B démarre les backwards dès le premier micro-lot et son pic ne dépend plus de l'horizon. Les deux font pourtant bien 40 sauvegardes à horizon 8.
Ce que le carnet refuse de conclure
ZeRO-2 et ZeRO-3 coïncident au repos, et le carnet dit pourquoi plutôt que d'en tirer une équivalence : la documentation de
ShardingStrategyplace la différence dans le moment du reshard (FULL_SHARDresharde après le forward,SHARD_GRAD_OPgarde les paramètres déployés jusqu'à la fin du backward). Un instrument qui somme l'état au repos ne peut structurellement pas les distinguer. Le carnet écrit cette limite au lieu de fabriquer une colonne qui diffère.De même, l'instrument de pipeline compte des tenseurs, pas des octets, et le carnet le dit : la taille d'un micro-lot change avec l'horizon (le lot est découpé), ce qui rendrait une comparaison en octets trompeuse.
Deux pièges rencontrés, documentés dans le carnet
ZeroRedundancyOptimizerest une enveloppe dont l'attributstatereste vide — l'état réel vit dans l'optimiseur local (opt.optim.state). Une lecture naïve rend0et fabrique une économie totale qui n'existe pas. C'est la première version de la sonde, et le chiffre avait l'air d'un excellent résultat.mb_argsattend un micro-lot, pas le lot complet : avec le lot complet, le rang destinataire attend une forme que l'émetteur n'envoie pas etgloobloque sans aucun message. Diagnostiqué en isolant la primitive (batch_isend_irecvfonctionne) du planificateur (qui fonctionne en mono-processus) — le défaut était dans l'appel.Note connexe à l'intention des relecteurs : FSDP refuse le CPU (
FSDP needs a non-CPU accelerator device), mais ce refus ne tient que dans sa branche d'auto-détection ; undevice_id=torch.device("cpu")explicite le contourne légitimement. C'est ce qui rend la mesure possible sur cette machine — ce n'est pas un contournement de la règle F, c'est la manière prévue de fixer le périphérique.Preuve d'exécution
Papermill, noyau
coursia-ml-training(celui que le carnet déclare), exécution de bout en bout :execution_countrenseigné sur toutes, aucune erreurvalidate_pr_notebooks.py:1/1 passed(11 cellules)check_exec_ratchet.py:regressions: 0, etABSENT->CLEANpour le nouveau carnetcheck_exec_sequence.py:CLEAN (1..N) : 1 (100,0 %)check_notebook_nav_chain.py --check:0 NEW finding vs baselinereturn None+print), sans erreur volontaire ; les sorties des cellules sont celles de l'exécution, aucun nettoyage manuelSee #18210
🤖 Generated with Claude Code