diff --git a/MyIA.AI.Notebooks/Probas/PyMC/PyMC-03-Factor-Graphs.ipynb b/MyIA.AI.Notebooks/Probas/PyMC/PyMC-03-Factor-Graphs.ipynb index 8237ead4a4..2fd719b9ac 100644 --- a/MyIA.AI.Notebooks/Probas/PyMC/PyMC-03-Factor-Graphs.ipynb +++ b/MyIA.AI.Notebooks/Probas/PyMC/PyMC-03-Factor-Graphs.ipynb @@ -126,7 +126,9 @@ "\n", "On decouvre que le **revolver appartient a Colonel Mustard**. Qui est le coupable ?\n", "\n", - "> *Source.* Le « Murder Mystery » (M. Boddy, Miss Scarlet, Colonel Mustard, Mrs. Peacock) est l'exemple introductif phare du **chapitre 1** de Winn & Bishop, *Model-Based Machine Learning* (2019, [mbmlbook.com](https://www.mbmlbook.com)) — conçu pour faire émerger l'inférence bayésienne *via* un récit, sans équation, en révisant itérativement les *a priori* à chaque indice. Le notebook en reprend l'énoncé et le résout en PyMC (`pm.Categorical` + vraisemblance conditionnelle) ; le twin Infer.NET utilise `Variable.Discrete` + `Variable.If/Case` (voir [Infer-3](../Infer/Infer-3-Factor-Graphs.ipynb))." + "> *Source.* Le « Murder Mystery » (M. Boddy, Miss Scarlet, Colonel Mustard, Mrs. Peacock) est l'exemple introductif phare du **chapitre 1** de Winn & Bishop, *Model-Based Machine Learning* (2019, [mbmlbook.com](https://www.mbmlbook.com)) — conçu pour faire émerger l'inférence bayésienne *via* un récit, sans équation, en révisant itérativement les *a priori* à chaque indice. Le notebook en reprend l'énoncé et le résout en PyMC (`pm.Categorical` + vraisemblance conditionnelle) ; le twin Infer.NET utilise `Variable.Discrete` + `Variable.If/Case` (voir [Infer-3](../Infer/Infer-3-Factor-Graphs.ipynb)).\n", + "\n", + "**Le modèle vu comme deux facteurs.** Tout ce que PyMC va échantillonner est déjà contenu dans deux tables locales : le facteur *a priori* `f1(coupable) = (0.6, 0.3, 0.1)` et le facteur de vraisemblance `f2(arme=Mustard | coupable) = 0.9` si Mustard, `0.1` sinon. La distribution jointe est leur produit — c'est littéralement le « graphe de facteurs » du titre : une variable `coupable`, deux facteurs accrochés, une observation `arme_mustard = 1`. L'interprétation de la section 1 montrera que l'on peut faire le calcul exact à la main sur ces deux tables ; MCMC va le redécouvrir tout seul." ] }, { @@ -273,6 +275,16 @@ "print(f\"Diagnostic MCMC (Murder Mystery, CompoundStep) : pire r_hat={diag_murder['r_hat'].max():.3f} (sur {worst_var}) ; ess_bulk min={int(diag_murder['ess_bulk'].min())}\")\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lecture du diagnostic — pourquoi il est si propre\n", + "\n", + "`r_hat = 1.000` et `ess_bulk >= 15 310` pour 20 000 tirages : sur un modèle aussi petit, l'échantillonneur discret (`CategoricalGibbsMetropolis`, pas NUTS — les variables discrètes n'offrent pas de gradient à exploiter) mélange presque parfaitement : chaque état reste accessible depuis chaque autre, il n'y a ni géométrie difficile, ni « funnel » à craindre. Le réflexe diagnostic n'est pas superflu pour autant : il deviendra indispensable sur les modèles plus riches de la série (voir PyMC-06-Debugging)." + ], + "id": "aa05d7e" + }, { "cell_type": "markdown", "id": "bd33d3f1", @@ -301,7 +313,17 @@ "\n", "> **Note technique** : L'echantillonnage par CategoricalGibbsMetropolis est adapte aux variables discretes comme `coupable`. L'utilisation de `pt.switch` (equivalent de `Variable.If` en Infer.NET) permet de conditionner la probabilite de l'observation selon la valeur du coupable.\n", "\n", - "La cellule suivante visualise la distribution posterieure sous forme de diagramme en barres, permettant de comparer visuellement les frequences d'echantillonnage entre les trois suspects." + "La cellule suivante visualise la distribution posterieure sous forme de diagramme en barres, permettant de comparer visuellement les frequences d'echantillonnage entre les trois suspects.\n", + "\n", + "**Le contrôle par calcul exact.** Ces trois nombres se retrouvent à la main en trois lignes — c'est le vrai contenu du graphe de facteurs :\n", + "\n", + "| Suspect | Prior × Vraisemblance | Non normalisé | Exact (÷ 0.34) | Échantillonné |\n", + "|---|---|---|---|---|\n", + "| Scarlet | 0.6 × 0.1 | 0.06 | 0.176 | 0.176 |\n", + "| Mustard | 0.3 × 0.9 | 0.27 | 0.794 | 0.797 |\n", + "| Peacock | 0.1 × 0.1 | 0.01 | 0.029 | 0.028 |\n", + "\n", + "La constante de normalisation est la somme des produits : 0.06 + 0.27 + 0.01 = **0.34** — c'est aussi la probabilité d'observer l'arme de Mustard *avant* de savoir qui a tiré. Les 20 000 tirages MCMC reproduisent le calcul exact au millième près (écart maximal 0.003, pur bruit Monte-Carlo) : l'échantillonneur n'invente rien, il redécouvre numérateur et dénominateur." ] }, { @@ -437,7 +459,9 @@ "\n", "Le phenomene d'**explaining away** : quand on observe l'arme de Mustard, la probabilite que Scarlet soit coupable diminue, car l'observation \"explique\" le crime par Mustard.\n", "\n", - "> *Référence.* Le mécanisme d'« explaining away » est propre aux structures en V (colliders) : deux causes partagent un effet commun, et observer l'effet les rend *compétitives*. Formalisé par Pearl (1988), *Probabilistic Reasoning in Intelligent Systems* (Morgan Kaufmann), §3.3 — c'est l'une des structures élémentaires de la propagation d'information dans un réseau bayésien (chaîne, fourche, collider)." + "> *Référence.* Le mécanisme d'« explaining away » est propre aux structures en V (colliders) : deux causes partagent un effet commun, et observer l'effet les rend *compétitives*. Formalisé par Pearl (1988), *Probabilistic Reasoning in Intelligent Systems* (Morgan Kaufmann), §3.3 — c'est l'une des structures élémentaires de la propagation d'information dans un réseau bayésien (chaîne, fourche, collider).\n", + "\n", + "La lecture chiffrée du tableau de la section 1 rend la compétition visible : l'indice *contre* Scarlet n'a jamais changé — son motif pèse toujours 0.6 *a priori* — et pourtant son posterior tombe de 0.600 à 0.176 (−70.7 %). Ce n'est pas une preuve accumulée contre elle, c'est une **pression concurrentielle** : l'arme de Mustard explique le crime à sa place, et les explications rivales se partagent une masse de probabilité fixée par la vraisemblance de l'observation. Mustard gagne exactement ce que Scarlet et Peacock perdent (+165.7 % contre −70.7 % et −72.0 %)." ] }, { @@ -646,6 +670,18 @@ "print(f\"\\nReponse : il faut CHANGER ! P(gagner si changement) = {(voiture_samples == 2).mean():.3f}\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pourquoi changer gagne — la contrainte de Monty comme information\n", + "\n", + "Là encore, trois produits suffisent : `P(Monty ouvre 1 | voiture=0) = 1/2` (il hésite entre les portes 1 et 2), `P(... | voiture=1) = 0` (il ne montre jamais la voiture), `P(... | voiture=2) = 1` (il n'a plus le choix). Non normalisé : `1/6, 0, 1/3` ; constante de normalisation `1/2` ; exact : **`1/3, 0, 2/3`** — exactement ce que renvoie l'échantillonnage (0.333, 0.000, 0.667).\n", + "\n", + "L'information ne vient pas de la porte ouverte mais de la **règle** de Monty : « jamais la voiture, jamais le choix du joueur ». Si la voiture est en 0, Monty pouvait ouvrir 1 ou 2 — l'ouverture de la 1 n'apprend rien. Si elle est en 2, il était *forcé* d'ouvrir la 1 : cette ouverture est un aveu. La porte 0 ne bouge jamais de 1/3 parce que l'observation restait possible dans tous les mondes où le joueur avait bien choisi ; toute la masse libérée par l'information se concentre sur la porte 2. Changer double la chance de gagner : 0.667 contre 0.333." + ], + "id": "aa0ed7e" + }, { "cell_type": "markdown", "id": "0d7e4f60", @@ -748,6 +784,8 @@ "noyau de Metropolis specialise pour les `Categorical`. Le résultat est une\n", "approximation Monte-Carlo du calcul exact qu'Infer.NET obtient par EP.\n", "\n", + "La ligne « Performance » du tableau se lit maintenant avec les chiffres de ce notebook : Infer.NET (EP) donnerait 0.176 / 0.794 / 0.029 *analytiquement et instantanément* ; PyMC y arrive par 20 000 tirages en 14 secondes, au millième près. Sur deux tables de trois états, l'écart est invisible ; c'est sur les modèles continus non conjugués — là où EP doit approximer chaque message — que la généralité de MCMC devient le bon côté de l'arbitrage.\n", + "\n", "***\n", "\n", "**Retour au sommaire** : [Index Probas](../README.md)" diff --git a/scripts/notebook_tools/twin_pairs.d/probas-3-factor-graphs.yaml b/scripts/notebook_tools/twin_pairs.d/probas-3-factor-graphs.yaml index 976469cdcf..0856ff86b9 100644 --- a/scripts/notebook_tools/twin_pairs.d/probas-3-factor-graphs.yaml +++ b/scripts/notebook_tools/twin_pairs.d/probas-3-factor-graphs.yaml @@ -7,6 +7,7 @@ bridge_verdict: SOTA-OK bridge_verdict_reason: "Modele nominal lib-vs-lib cite par owner #10382 (\"PyMC vs Infer, 2 moteurs qui brillent\") : C# = Microsoft Infer.NET (Microsoft.ML.Probabilistic, NuGet officiel, native .NET, inférence variationnelle EP/VMP) et Python = PyMC (pip pymc, native Python, NUTS/HMC + ADVI). Chaque cote atteint le moteur SOTA de son ecosysteme probabiliste -- ni pont intermediaire ni reimplementation. Aucune asymetrie de machinerie a corriger. Verifie firsthand : C# Microsoft.ML.Probabilistic refs + execution_count, Python pymc imports." known_differences: + - '2026-09-16 (myia-po-2023:CoursIA) #16364 : REBASELINE cote Python apres densification markdown (#13410) : 1227 -> 1915 mots (+2 cellules d''interpretation diagnostic MCMC et Monty Hall, 4 extensions), markdown-only, 9/9 cellules code byte-identiques, ids originaux preserves. content_csharp_sha inchange : le jumeau C# n''est pas touche.' - '2026-08-19 (myia-ai-01) #11685 : REBASELINE cote C# apres reparation. Le merge 9881553 (#11622) avait re-execute Infer-3 sur une machine sans Graphviz -- le helper .NET imprime l''echec au lieu de lever, donc 6 bannieres "Problem with converting DOT to SVG" + chemins machine se sont retrouves dans les sorties, et l''audit precedent a enregistre un csharp_sha (bb769dc0f648) qui n''a JAMAIS ete le blob du fichier (test_twin_registry_integrity rouge sur main depuis ce merge). Repare par re-execution reelle avec dot sur le PATH (Graphviz 14.1.3 present sur ai-01, seulement absent du PATH) puis strip_probe_banner.py, --update en DERNIER (#8957). Volume de rendu verifie contre la base de fusion : blocs SVG 13356 -> 13362 et 28948 -> 28954 B, svg 2 -> 2 -- aucun livrable rendu perdu. content_python_sha inchange : le jumeau Python n''est pas touche.' - 'Socle pedagogique commun : graphes de facteurs et variables aleatoires modelise dans les deux stacks.' - 'Moteurs d''inference distincts : C# Infer.NET = inference deterministe approchee (Expectation Propagation / Variational diff --git a/scripts/notebook_tools/twin_pairs.d/probas-3-factor-graphs/0008-2026-09-16-myia-po-2023-CoursIA.yaml b/scripts/notebook_tools/twin_pairs.d/probas-3-factor-graphs/0008-2026-09-16-myia-po-2023-CoursIA.yaml new file mode 100644 index 0000000000..95dfa97022 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/probas-3-factor-graphs/0008-2026-09-16-myia-po-2023-CoursIA.yaml @@ -0,0 +1,6 @@ +date: '2026-09-16' +by: myia-po-2023:CoursIA +python_sha: 2fd719b9ac10f6756066ae01e31e23c4cd64afbf +csharp_sha: e8381cc8e9ede47d089ce7c12fb8397c7cc1919e +content_python_sha: bdae44e7b6b0b0057a38e4c7093089780e905451a2b4c9207cc239d105f7ce81 +content_csharp_sha: 4516c2c0a108f167aea626ccb6ce18b2a32c4ff8f2b92383fb6b8ab2c516a426