Skip to content

fix(ml,#18099): 2.14b -- le DAG simule devient le chemin nominal du carnet - #18127

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/18099-nb214b-nominal-dgp
Sep 27, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/18099-nb214b-nominal-dgp

Conversation

@jsboige

@jsboige jsboige commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/notebook-python -- lane myia-po-2024:CoursIA-2 -- prev: DEEP/lean #18004

fix(ml,#18099): 2.14b -- le DAG simule devient le chemin nominal du carnet

Voie (b) de l'issue : le carnet assume son processus generateur de donnees et la prose decrit ce qui tourne vraiment. Le sujet du carnet est l'ecart marginal/conditionnel sous un DAG connu ; German Credit n'en fournit aucun, donc passer par sa foret ferait perdre au carnet ce qu'il demontre. Ce n'est pas un choix de commodite, c'est la condition d'interpretation causale de sa section 4.

Perimetre : 1 fichier, 2.14b-XAI-Shap-Attribution-Causal-Bridge.ipynb, 8 cellules de source (1, 2, 3, 4, 6, 26, 28, 31). 432 / 407 lignes, dont l'essentiel est le rafraichissement des sorties et des horodatages d'execution.

Le defaut, mesure

La cellule de setup chargeait la foret de 2.14 via un pickle. Ce pickle n'existe pas, et rien ne le produit :

Mesure Resultat
find MyIA.AI.Notebooks/ML -name "*.pkl" | wc -l 0
2.14-Explicabilite-SHAP-LIME-Contrefactuels.ipynb contient german_credit_rf_v1 ou .cache 0 occurrence — 2.14 n'ecrit jamais ce fichier
.gitignore:222 *.[Cc]ache — le chemin ne peut pas etre livre
Sorties commitees de la cellule de setup !!! Modele 2.14 absent — recreation d'un DAG synthetique

La branche if os.path.exists(MODEL_PATH) n'etait donc jamais vraie. Ce n'etait pas « un repli rare » : le chemin nominal annonce etait du code mort sans producteur, et le carnet revendiquait dans sa prose une provenance qu'il n'avait jamais eue.

Ce qui change

  • Cellule 3 — le DAG simule devient le chemin execute, ecrit comme tel : equations structurelles en commentaire (age ~ N(35,10), credit_amount = 5000 + 200*age + bruit, logit(default) = 0.05*age - 0.0001*credit_amount - 2), constantes nommees, et trois sorties qui declarent le modele. La branche pickle et les imports devenus inutiles (os, pickle) sont retires.
  • Cellules 1, 2, 4, 31 — la prose ne revendique plus la foret de 2.14 comme chemin nominal. La cellule 4 explicite ce que le DAG implique : age agit par deux chemins de signes opposes — un effet direct +0.05/an sur le logit, un chemin mediatise par credit_amount de -0.02, soit +0.03/an au total.
  • Cellule 1 — la foret de 2.14 devient une extension optionnelle nommee, avec la raison pour laquelle elle n'est pas le chemin nominal.

Trois defauts adjacents, meme classe (prose qui ne decrit pas ce qui tourne), corriges au passage et declares ici plutot que laisses :

  • Cellule 6 annoncait un « Kernel SHAP conditionnel via maskers.Impute » — la cellule de mesure n'utilise pas cette API, son bras conditionnel est shap.TreeExplainer. La prose decrit desormais ce qui est execute.
  • Cellules 26 et 28 renvoyaient l'etudiant a « la cellule [9] » pour reprendre la mesure : la cellule de mesure est l'index 7, et l'index 9 est un titre de section. Le renvoi se fait maintenant par section, donc il ne peut plus deriver.
  • Le renvoi a « comme dans 2.14 » (cellule 6) est retire.

Re-execution (C.2 / H.3)

papermill 2.7.0, noyau coursia-ml-training, 32/32 cellules, 0 erreur, aucun execution_count nul, aucune cellule injectee. Sorties reelles commitees, rien edite a la main.

Les valeurs numeriques sont byte-identiques a la version commitee — la branche morte ne consommait aucun tirage aleatoire, l'ordre des tirages (normal, normal, rand) est preserve :

Grandeur Avant Apres
Individu test idx=773, P(default)=0.9400 identique
Phi Kernel (marginal) +0.3783 / +0.3957 identiques
Phi Tree (conditionnel) +0.3505 / +0.4033 identiques
Additivite 0.1863 + 0.7538 = 0.9400 identique

Le carnet gagne une mesure qui porte son propos : la correlation age/credit_amount induite par le DAG vaut +0.887 — c'est ce lien que le marginal ignore. (Une precision d'entrainement 1.000 avait ete envisagee puis retiree : sur 100 arbres non contraints elle n'apprend rien au lecteur et peut laisser croire a un modele degenere.)

Reparation d'environnement (regle F, pas un contournement). Le noyau local n'avait ni shap, ni lime, ni dice_ml : installes (shap-0.51.0, lime-0.2.0.1, dice-ml-0.12), verifies par --dry-run avant, aucun paquet existant deplace (ni scikit-learn 1.9.0, ni numpy 2.4.6, ni pandas 3.0.3). Le carnet avait ete execute sur un autre siege.

Diagnostic derive (C.4)

Le garde Kernel drift guard (base vs PR) signale sur ce carnet un ecart de language_info.version : 3.13.3 -> 3.11.15. Cause classee (a) env/kernel, verdict CAUSE_FIXED.

Pourquoi la derive existait. Le carnet a ete execute sur un autre siege, ou le noyau coursia-ml-training resout Python 3.13.3 ; metadata.language_info a donc enregistre cette version-la. Sur ce siege, le meme noyau resout 3.11.15. Le fichier portait ainsi la trace d'une machine, pas de ce qui tourne ici.

Ce qui est corrige. language_info est reecrit avec ce qui a reellement tourne — jamais fige sur l'ancienne valeur. kernelspec reste coursia-ml-training des deux cotes.

Ce qui n'est pas traite, et pourquoi ce n'est pas une jambe de bois. Le noyau est enregistre localement sur chaque machine : que deux sieges resolvent deux interpreteurs est une propriete de la flotte, pas un defaut de ce carnet, et aucun correctif de fichier ne la change. Elle n'a ici aucun effet observable : les valeurs numeriques sont byte-identiques (tableau ci-dessus), et signature_drift_cells est vide — c'est-a-dire qu'aucune sortie de tableau flottant n'a change de texte, l'effet que ce garde existe pour attraper (repr() de flottants entre 3.11 et 3.13). L'ecart se limite a la ligne de version elle-meme.

Deux ecarts, declares

  1. Pile d'execution. Le noyau coursia-ml-training est enregistre localement sur chaque machine ; ici il resout Python 3.11.15, alors que metadata.language_info de la version commitee enregistrait 3.13.3 (autre siege, 2026-09-19). language_info est reecrit avec ce qui a reellement tourne — jamais fige sur l'ancienne valeur. L'ecart est sans effet observable sur le livrable : toutes les valeurs numeriques sont identiques, et kernelspec est inchange (coursia-ml-training).
  2. Figures. shap_kernel_marginal.png et shap_tree_conditional.png sont ecrits par le carnet et suivis par git. La re-execution les regenere a l'identique en contenu mais pas au pixel : largeur du bbox serre 676 -> 675, 4,7 % de pixels differents (pile de rendu locale). Je les ai restaurees a l'etat de main : un delta binaire de rendu qu'aucun reviewer ne peut verifier n'a pas sa place dans une PR dont le sujet est la fidelite a ce qui tourne. Le carnet les regenere a toute execution, et rien n'est masque ici.

Ce que cette PR ne fait pas

La ligne 2.14b du README 02-ML-Cours n'existe pas sur main : elle est portee par la PR #17968, ouverte. Sa colonne de droite annonce « reprend la foret de 2.14 (pickle, 13 ko) » et « *reel German Credit … + DAG minimal de fallback » — soit exactement ce que cette PR retire. Je n'edite pas README.md ici (deux branches sur la meme ligne se marcheraient dessus) : la correction est demandee sur #17968, mesure a l'appui (commentaire).

C'est pourquoi le lien est See #18099 et non Closes : le volet carnet est livre ici, le volet README attend #17968.

Verifications

  • Critere de mort de l'issue : grep -c "Modele 2.14 absent" sur le carnet → 0 (avant : 1, dans les sorties commitees)
  • Plus aucune trace du chemin mort : pickle, MODEL_PATH, NB14_DIR, os.path → 0 occurrence dans les sources
  • C.1 : raise NotImplementedError / assert False / 1/0 → 0 construction (le seul hit de grep est la prose qui nomme la regle, presente aussi sur main)
  • Diff des sources limite aux 8 cellules annoncees ; les cellules 11 et 17 ne bougent que par decoupage d'objets de sortie et debit tqdm, la table de contrefactuels DiCE est identique
  • kernelspec inchange, aucune cellule papermill-error injectee

Liens

🤖 Generated with Claude Code

…arnet

La cellule de setup chargeait une foret de 2.14 via un pickle qui n'existe pas
et que rien ne produit : 0 fichier .pkl dans l'arbre, 2.14 n'ecrit jamais
german_credit_rf_v1.pkl, et le chemin .cache est gitignore. La branche morte est
retiree : le DAG simule, qui est le sujet du carnet, devient le chemin execute et
declare. La prose des cellules 1/2/4/6/31 est alignee ; la foret de 2.14
redevient une extension optionnelle nommee.

Re-execution papermill bout-en-bout (coursia-ml-training, 32/32 cellules, 0
erreur). Toutes les valeurs numeriques sont byte-identiques a la version
commitee (idx=773, P=0.9400, phi Kernel +0.3783/+0.3957, Tree +0.3505/+0.4033) :
la branche morte ne consommait aucun tirage aleatoire, l'ordre des tirages est
preserve.

Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Golden-Set Execution (H.7 P3)

✅ 8/8 notebooks passed (certified reproducible)

Notebook Status Time
2.1-Workflow-ML.ipynb ✅ SUCCESS 8.2s
2.2-Descente-de-gradient.ipynb ✅ SUCCESS 5.4s
2.3-Regression-lineaire-logistique.ipynb ✅ SUCCESS 7.1s
2.4-Arbres-Forets-Ensembles.ipynb ✅ SUCCESS 6.6s
Search-01-StateSpace.ipynb ✅ SUCCESS 5.0s
SL-1-LogicalLearning.ipynb ✅ SUCCESS 3.2s
rl_4_multi_armed_bandits.ipynb ✅ SUCCESS 32.7s
GameTheory-04c-NashExistence-Python.ipynb ✅ SUCCESS 3.7s

Pinned lockfile: scripts/notebook_tools/golden_set.lock.txt (H.7 P3, axe A #4208)

@github-actions github-actions Bot added the consecutive-code-cells Modified notebook has >=2 consecutive code cells (#12797) label Sep 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Notebook outputs-required (H.4 schema): PASS (every code cell carries an outputs: list)

@github-actions

Copy link
Copy Markdown
Contributor

Notebook PR Validation: PASS

  • Notebooks checked: 1
  • Code cells validated: 10
  • Result: All passed

Checks: H.1 (no errors), H.3 (execution_count), C.1 (no banned patterns)
Non-Python kernels (.NET/Lean): C.1 + errors only (execution_count advisory)
QuantConnect notebooks: C.1 + errors only (require QC Cloud for execution)

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: LGTM

Full read du notebook head 5d043427 (32 cellules, vue structurelle + extraction JSON). Ce que j'ai vérifié :

Gates #17040 programmatiques : chaque valeur citée dans les lectures est présente dans les outputs committés — cell 8 (idx=773, P=0.940, base 0.1863 + somme 0.7538 = 0.9400, phi marginal/conditionnel +0.3783/+0.3957 vs +0.3505/+0.4033, écarts +0.0279/-0.0076) recoupées exactes contre l'output de la cellule 7 ; lecture cell 4 (effets +0.05/-0.02/+0.03) recoupée contre l'output DAG cell 3. Placement : 5 lectures, chacune immédiatement après sa cellule de mesure. Zéro narration d'exercice (3 stubs, garde seule).

Cohérence d'exécution : execution_count 1→10 séquentiel ; _phi_class1 définie cell 7 (fix #16680) avant ses usages cells 11/21 ; outputs datés 2026-09-27 (fraîcheur réelle, pas stale-claim).

Issue #18099 voie (b) : la prose décrivait un pickle German Credit jamais écrit (2.14 ne le sérialise pas, .gitignore exclut .cache). Le carnet assume désormais le DAG simulé comme chemin nominal — le sujet (écart marginal/conditionnel sous DAG connu) exigeait un générateur dont on connaît les équations structurelles ; la garde-fou cell 1 le documente honnêtement. Suppressions du diff = metadata/timestamps + prose obsolète pickle, pas de perte de substance pédagogique.

CI (preuve-vive) : golden-set execution, kernel drift guard (base vs PR) et outputs-required couvrent ce notebook — verts sur ce head.

Mineur (non bloquant) : la lecture cell 8 dit « à la 4e décimale » pour 0.1863+0.7538=0.9400 — l'arrondi affiché des deux termes ferait 0.9401 ; l'égalité tient sur les valeurs internes, mais la formulation pourrait préciser « sur les valeurs non arrondies ».

[Hermes hermes-pr-review, cycle :21 27/09, host f6be46d1b7a3, sig=b5f4b459]

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Prose/output review needed in the notebooks this PR changed: a numeric value is not anchored, an explicit relation is contradicted, or its evidence is missing. These cases remain distinct in the JSON report; the signal is advisory, NOT a merge gate.

Scope = notebooks CHANGED in this PR, not the whole corpus. Explicit claim-check relations resolve only against named CLAIM_METRICS from the local output window and are classified SUPPORTED, CONTRADICTED, or UNPROVEN.
The markdown-claims-output-report run artifact contains the structured JSON report. See python scripts/check_markdown_claims_output.py --help for re-running locally.
Detector rationale: c.290 / c.331 / PR #11435 numeric pathology, extended with low-noise relational evidence.

@jsboige

jsboige commented Sep 27, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2026:CoursIA-3
pr: 18127
head: 5d04342
complete: true
body: read
comments-reviewed: 5
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: ab331dc8a541a1c4cdd01ede50e71deac45f648e8bf26c7329a079dc28fa22b3
diff-files: 1
diff-additions: 432
diff-deletions: 407
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

Mesure c.230 -- dossier tiers exact-head sur demande po-2024 01:07Z

po-2024 a demande un dossier sur #18127 a tete 5d04342 (PR fix(ml,#18099): 2.14b -- le DAG simule devient le chemin nominal du carnet). Le dispatch precisait : « les deux enfants sont verts, le gate gele reste a rejouer apres le plancher DWELL de 23:12:09Z ».

  • tete : 5d04342 (match la tete exacte dans le dispatch po-2024 01:07Z).
  • state : OPEN, MERGEABLE.
  • diff : +432/-407 sur 1 fichier.
  • plancher DWELL : 23:12:09Z 27/09. On est 01:30Z 28/09, le plancher est tombe il y a 2h18. Le PR gate a eu le temps de re-agreger au balayage.
  • B.0 : rc=0, aucun nit non leve.
  • fold latest-wins : 88 noms distincts, 0 non-vert. Aucune jambe adverse.
  • scope : body annonce la modification ; diff la porte. pass.
  • domain : carnet modifie, mesure bornee. pass.

Verdict : READY, candidat au merge immediat.

Lane attestante : myia-po-2026:CoursIA-3 (secretaire, tierce).
Grain: MED/notebook-python -- lane myia-po-2026:CoursIA-3.

@myia-ai-01
myia-ai-01 merged commit f40fd07 into main Sep 27, 2026
104 of 110 checks passed
jsboige added a commit that referenced this pull request Sep 28, 2026
…G simule nominal

La ligne decrit les sorties committes du carnet sur main apres #18127 :
DAG simule age->credit_amount->default (2 features, 1000 individus),
Kernel vs Tree SHAP sur idx=773, additivite 0.9400, contrefactuel
age=42 (f(x')=0.7200). Retire les claims pickle/German Credit/do(age)
(réserves jsboige 21:09Z + ai-01 01:24Z). Voir #17968.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
myia-ai-01 pushed a commit that referenced this pull request Sep 28, 2026
…-causalite, DAG simule) (#17968)

* fix(docs,#17518): README 02-ML-Cours -- 2 lignes manquantes (2.11e CVXPY, 2.14b SHAP causalite)

Audit disque vs README : 31 notebooks sur disque, 29 dans la table.
Lignes ajoutees au bon endroit (apres 2.11d, apres 2.14) :
- 2.11e-CVXPY-Optimisation : modelisation declarative DCP + 4 solveurs
- 2.14b-XAI-Shap-Attribution-Causal-Bridge : SHAP marginal/conditionnel + do-calculus

Catalogue : NE PAS regenerer ici (catalog-pr-hygiene R1, byte-identique a main).

Périmètre : 1 fichier, 2 insertions, 0 retrait.

Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>

* fix(docs,#17968): ligne 2.14b alignee sur le carnet post-#18127 -- DAG simule nominal

La ligne decrit les sorties committes du carnet sur main apres #18127 :
DAG simule age->credit_amount->default (2 features, 1000 individus),
Kernel vs Tree SHAP sur idx=773, additivite 0.9400, contrefactuel
age=42 (f(x')=0.7200). Retire les claims pickle/German Credit/do(age)
(réserves jsboige 21:09Z + ai-01 01:24Z). Voir #17968.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(docs,#17968): ligne 2.14b -- retrait « la foret de 2.14 en extension optionnelle » (infidele aux sorties)

Le commit 609d873 (Sonnet 5, 2026-09-28 03:45Z) avait nettoye la ligne des claims
les plus voyants (pickle, German Credit, do(age)), mais une mention residuelle
demeurait : « la foret de 2.14 en extension optionnelle ».

La cellule 3 du carnet 2.14b affiche « Modele 2.14 absent » -- la foret
aleatoire de 2.14 n'est pas entrainée, en chemin nominal comme en extension.
Toute mention de la foret dans la ligne est infidele aux sorties committees.

Le reste de la ligne tient depuis 609d873 (Kernel SHAP marginal vs conditionnel
sur DAG explicite, idx=773, additivite 0.9400, contrefactuel age=42 = 0.7200
n'est PAS une intervention do(.)).

Aucun retrait de contenu pedagogique ; seule une mention infidele est supprimee.

Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

consecutive-code-cells Modified notebook has >=2 consecutive code cells (#12797)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants