diff --git a/MyIA.AI.Notebooks/Probas/PyMC/PyMC-04-Bayesian-Networks.ipynb b/MyIA.AI.Notebooks/Probas/PyMC/PyMC-04-Bayesian-Networks.ipynb index 4a730de5ec..be4e3223cb 100644 --- a/MyIA.AI.Notebooks/Probas/PyMC/PyMC-04-Bayesian-Networks.ipynb +++ b/MyIA.AI.Notebooks/Probas/PyMC/PyMC-04-Bayesian-Networks.ipynb @@ -784,58 +784,7 @@ "metadata": {}, "source": [ "On observe que l'herbe est mouillee (WetGrass = True). Quelle est la probabilite que l'arroseur soit actif ? Qu'il ait plu ?\n", - "\n", - "### Sortie verbatim code[5]\n", - "\n", - "- Multiprocess sampling (4 chains in 4 jobs)\n", - "- BinaryGibbsMetropolis: [cloudy, sprinkler, rain]\n", - "- Sampling 4 chains for 1_000 tune and 10_000 draw iterations (4_000 + 40_000 draws total) took 26 seconds.\n", - "- Posterior (WetGrass = True observe) :\n", - " - `P(Sprinkler=1 | WetGrass=1) = 0.429 (theorie: ~0.43)`\n", - " - `P(Rain=1 | WetGrass=1) = 0.707 (theorie: ~0.71)`\n", - " - `P(Cloudy=1 | WetGrass=1) = 0.575`\n", - "\n", - "### Lecture\n", - "\n", - "- **P(S=1 | W=1) = 0.43** : sachant que l'herbe est mouillee, on a 43% de chances que l'arroseur ait fonctionne (vs 30% marginal). L'augmentation est modeste car Sprinkler est un « mauvais » predicteur de W (peut etre inactif même si W=1).\n", - "- **P(R=1 | W=1) = 0.71** : la pluie est un meilleur predicteur de W (forte probabilite conditionnelle).\n", - "- **P(C=1 | W=1) = 0.58** : probabilite accrue de nuageux (passe de 0.50 a 0.58), via les chaines causales S et R.\n", - "\n", - "### Implementation technique\n", - "\n", - "L'observation est faite via le paramètre `observed=1` de `pm.Bernoulli` :\n", - "```python\n", - "with pm.Model() as wet_grass_obs:\n", - " ...\n", - " p_w = pt.switch(\n", - " pt.eq(sprinkler, 1),\n", - " pt.switch(pt.eq(rain, 1), 0.99, 0.90),\n", - " pt.switch(pt.eq(rain, 1), 0.90, 0.00),\n", - " )\n", - " wetgrass = pm.Bernoulli('wetgrass', p=p_w, observed=1)\n", - "\n", - " trace_obs = pm.sample(10000, random_seed=42, return_inferencedata=True)\n", - "```\n", - "\n", - "`pm.Potential` est une variante possible (vraisemblance ajoutée manuellement, utile pour des observations bruitées), mais `observed=1` est la forme canonique utilisée dans ce notebook.\n", - "\n", - "### Pourquoi pas un posterior exact ?\n", - "\n", - "Avec 4 variables booleennes, on pourrait calculer **P(S | W=1)** par enumeration exacte :\n", - "```python\n", - "# P(S=1, W=1) = sum_{C, R} P(C) P(S=1|C) P(R|C) P(W=1|S=1, R)\n", - "# = 0.5 * 0.1 * (0.8 * 0.99 + 0.2 * 0.9) + 0.5 * 0.5 * (0.8 * 0.9 + 0.2 * 0)\n", - "# = 0.5 * 0.1 * 0.972 + 0.5 * 0.5 * 0.72\n", - "# = 0.0486 + 0.18 = 0.2286\n", - "# P(W=1) = 0.643 (marginal calculee)\n", - "# P(S=1 | W=1) = 0.2286 / 0.643 = 0.356\n", - "```\n", - "\n", - "Hmm, ca ne correspond pas exactement aux 0.43 obtenu par MCMC. La difference vient du bruit MCMC (4 chains * 10000 draws = 40000 échantillons, erreur ~1/sqrt(40000) = 0.005). Acceptable pour un notebook pedagogique.\n", - "\n", - "### A retenir\n", - "\n", - "Pour des réseaux de taille raisonnable (< 20 variables), l'enumeration exacte est preferable (calcul exact en O(2^N)). Au-dela, on passe au MCMC (échantillonnage approximate) ou au belief propagation (si le graphe est un arbre ou un poly-arbre)." + "\n" ] }, { @@ -945,6 +894,64 @@ "print(f\"P(Cloudy=1 | WetGrass=1) = {c_obs.mean():.3f}\")" ] }, + { + "cell_type": "markdown", + "id": "pymc04-lecture-cond-wetgrass", + "metadata": {}, + "source": [ + "### Sortie verbatim code[5]\n", + "\n", + "- Multiprocess sampling (4 chains in 4 jobs)\n", + "- BinaryGibbsMetropolis: [cloudy, sprinkler, rain]\n", + "- Sampling 4 chains for 1_000 tune and 10_000 draw iterations (4_000 + 40_000 draws total) took 26 seconds.\n", + "- Posterior (WetGrass = True observe) :\n", + " - `P(Sprinkler=1 | WetGrass=1) = 0.429 (theorie: ~0.43)`\n", + " - `P(Rain=1 | WetGrass=1) = 0.707 (theorie: ~0.71)`\n", + " - `P(Cloudy=1 | WetGrass=1) = 0.575`\n", + "\n", + "### Lecture\n", + "\n", + "- **P(S=1 | W=1) = 0.43** : sachant que l'herbe est mouillee, on a 43% de chances que l'arroseur ait fonctionne (vs 30% marginal). L'augmentation est modeste car Sprinkler est un « mauvais » predicteur de W (peut etre inactif même si W=1).\n", + "- **P(R=1 | W=1) = 0.71** : la pluie est un meilleur predicteur de W (forte probabilite conditionnelle).\n", + "- **P(C=1 | W=1) = 0.58** : probabilite accrue de nuageux (passe de 0.50 a 0.58), via les chaines causales S et R.\n", + "\n", + "### Implementation technique\n", + "\n", + "L'observation est faite via le paramètre `observed=1` de `pm.Bernoulli` :\n", + "```python\n", + "with pm.Model() as wet_grass_obs:\n", + " ...\n", + " p_w = pt.switch(\n", + " pt.eq(sprinkler, 1),\n", + " pt.switch(pt.eq(rain, 1), 0.99, 0.90),\n", + " pt.switch(pt.eq(rain, 1), 0.90, 0.00),\n", + " )\n", + " wetgrass = pm.Bernoulli('wetgrass', p=p_w, observed=1)\n", + "\n", + " trace_obs = pm.sample(10000, random_seed=42, return_inferencedata=True)\n", + "```\n", + "\n", + "`pm.Potential` est une variante possible (vraisemblance ajoutée manuellement, utile pour des observations bruitées), mais `observed=1` est la forme canonique utilisée dans ce notebook.\n", + "\n", + "### Pourquoi pas un posterior exact ?\n", + "\n", + "Avec 4 variables booleennes, on pourrait calculer **P(S | W=1)** par enumeration exacte :\n", + "```python\n", + "# P(S=1, W=1) = sum_{C, R} P(C) P(S=1|C) P(R|C) P(W=1|S=1, R)\n", + "# = 0.5 * 0.1 * (0.8 * 0.99 + 0.2 * 0.9) + 0.5 * 0.5 * (0.8 * 0.9 + 0.2 * 0)\n", + "# = 0.5 * 0.1 * 0.972 + 0.5 * 0.5 * 0.72\n", + "# = 0.0486 + 0.18 = 0.2286\n", + "# P(W=1) = 0.643 (marginal calculee)\n", + "# P(S=1 | W=1) = 0.2286 / 0.643 = 0.356\n", + "```\n", + "\n", + "Hmm, ca ne correspond pas exactement aux 0.43 obtenu par MCMC. La difference vient du bruit MCMC (4 chains * 10000 draws = 40000 échantillons, erreur ~1/sqrt(40000) = 0.005). Acceptable pour un notebook pedagogique.\n", + "\n", + "### A retenir\n", + "\n", + "Pour des réseaux de taille raisonnable (< 20 variables), l'enumeration exacte est preferable (calcul exact en O(2^N)). Au-dela, on passe au MCMC (échantillonnage approximate) ou au belief propagation (si le graphe est un arbre ou un poly-arbre)." + ] + }, { "cell_type": "markdown", "id": "a16f54de", diff --git a/MyIA.AI.Notebooks/Probas/PyMC/PyMC-11-Topic-Models.ipynb b/MyIA.AI.Notebooks/Probas/PyMC/PyMC-11-Topic-Models.ipynb index b7fb3b27db..a241352b18 100644 --- a/MyIA.AI.Notebooks/Probas/PyMC/PyMC-11-Topic-Models.ipynb +++ b/MyIA.AI.Notebooks/Probas/PyMC/PyMC-11-Topic-Models.ipynb @@ -180,7 +180,7 @@ "\n", "### Verbatim code[0] : setup PyMC\n", "\n", - "La cellule suivante charge PyMC 5.28.5 et filtre les warnings de deprecation arviz et pytensor qui leakent des chemins absolus du site-packages. On capture la version pour la tracer dans le notebook." + "La cellule code[0] ci-dessus charge PyMC 5.28.5 et filtre les warnings de deprecation arviz et pytensor qui leakent des chemins absolus du site-packages. On capture la version pour la tracer dans le notebook." ] }, { @@ -407,18 +407,6 @@ }, "tags": [] }, - "source": [ - "### Representation bag-of-words\n", - "\n", - "Les 5 documents generes illustrent bien la structure thematique : le document 0 contient surtout des mots de Science (atome, expérience, théorie), le document 1 des mots de Sport (équipe, ballon), et le document 2 des mots de Cuisine (recette, ingredient). Les documents 3 et 4 sont des melanges plus equilibrés.\n", - "\n", - "La cellule suivante construit la matrice bag-of-words (comptes absolus par document et par mot), qui sera l'observation directe du modèle LDA. Cette representation ignore l'ordre des mots et ne conserve que leurs frequences." - ] - }, - { - "cell_type": "markdown", - "id": "fuse-4", - "metadata": {}, "source": [ "Les 5 documents générés illustrent bien la structure thématique :\n", "\n", @@ -436,7 +424,9 @@ "- **TF-IDF** : normalise par la fréquence documentaire inverse (idf). Donne plus de poids aux mots rares.\n", "- **Word embeddings** (Word2Vec, GloVe) : représentation dense, capture la sémantique. Incompatible avec LDA classique (qui veut des comptes).\n", "\n", - "Pour LDA, le BoW ou TF-IDF est obligatoire : on échantillonne des indices dans un vocabulaire fini." + "Pour LDA, le BoW ou TF-IDF est obligatoire : on échantillonne des indices dans un vocabulaire fini.\n", + "\n", + "La cellule suivante construit la matrice bag-of-words (comptes absolus par document et par mot), qui sera l'observation directe du modèle LDA. Cette representation ignore l'ordre des mots et ne conserve que leurs frequences." ] }, { @@ -675,40 +665,8 @@ "source": [ "### Interpretation de l'echantillonnage avec priors symetriques\n", "\n", - "L'echantillonnage NUTS a converge avec des priors uniformes (Dirichlet(1,...,1)) sur phi et theta. En sortie, les trois sujets presentent des distributions de mots quasi-identiques, avec les mêmes mots dominants (atome, recette, four) dans des proportions similaires (~0.11-0.15). Les proportions theta sont également uniformes (~0.33 par sujet pour chaque document).\n", - "\n", - "Ce résultat est le **problème de symetrie** attendu : sans information a priori pour differencier les sujets, l'echantillonneur ne peut pas les distinguer et converge vers une solution ou tous les sujets sont identiques. La cellule suivante affiche les distributions estimees et confirme cette non-differenciation." - ] - }, - { - "cell_type": "markdown", - "id": "fuse-6", - "metadata": {}, - "source": [ - "**Sortie verbatim code[4]** :\n", - "\n", - "```\n", - "Resultats LDA avec priors symetriques :\n", - "(Attendu : distributions dégénérées / uniformes)\n", - "\n", - " Sujet 0 : recette (0.151), atome (0.146), four (0.125), ingredient (0.113)\n", - " Sujet 1 : atome (0.148), recette (0.146), four (0.126), ingredient (0.110)\n", - " Sujet 2 : recette (0.148), atome (0.146), four (0.124), ingredient (0.111)\n", - "```\n", - "\n", - "**Diagnostic** : les 3 sujets ont des distributions de mots quasi-identiques. Aucun n'a spécialisé un mot-canon (`atome` ne se retrouve pas dans un seul sujet). Les proportions theta sont uniformes (~ 1/3 partout).\n", - "\n", - "### Pourquoi ?\n", - "\n", - "Le **posterior symétrique** est invariant sous permutation des indices de sujets. Si le prior est Dirichlet(1) (uniforme), la posterior reste symétrique. Pour briser la symétrie, il faut :\n", - "\n", - "1. **Asymétriser le prior** (section 4) : beta_jk >> 1 pour le mot-canon de chaque sujet.\n", - "2. **Asymétriser le posterior** par post-traitement (Hungarian matching sur la matrice de confusion phi x phi_target).\n", - "3. **Asymétriser l'initialisation** de l'optimiseur NUTS (seed asymétrique), mais cela ne suffit pas seul.\n", - "\n", - "### Métrique de diagnostic\n", - "\n", - "Pour quantifier la degenerescence : calculer la **Jensen-Shannon Divergence (JSD)** moyenne entre paires de sujets. Si JSD_moy ~ 0, les sujets sont indistinguables. Si JSD_moy > 0.3 bits, ils sont bien séparés." + "L'echantillonnage NUTS **signale un probleme de convergence** sous priors symetriques : le journal affiche `The rhat statistic is larger than 1.01 for some parameters` -- les 4 chaines ne convergent pas vers la meme posterior. C'est **attendu** sous prior symetrique : la cellule markdown au-dessus l'explique, les labels de sujet sont interchangeables et les chaines trouvent des posterior symetriques mais distincts. La sortie ci-dessous le confirme (sujets interchangeables, theta proche de 1/3). Le remede (prior informatif ou initialisation asymetrique) est le sujet de la section suivante.\n", + "" ] }, { @@ -783,9 +741,30 @@ "id": "fuse-7", "metadata": {}, "source": [ - "### Lecture du piegé de la symétrie (code[4])\n", + "**Sortie verbatim code[4]** :\n", + "\n", + "```\n", + "Resultats LDA avec priors symetriques :\n", + "(Attendu : distributions dégénérées / uniformes)\n", + "\n", + " Sujet 0 : recette (0.151), atome (0.146), four (0.125), ingredient (0.113)\n", + " Sujet 1 : atome (0.148), recette (0.146), four (0.126), ingredient (0.110)\n", + " Sujet 2 : recette (0.148), atome (0.146), four (0.124), ingredient (0.111)\n", + "```\n", + "\n", + "**Diagnostic** : les 3 sujets ont des distributions de mots quasi-identiques. Aucun n'a spécialisé un mot-canon (`atome` ne se retrouve pas dans un seul sujet). Les proportions theta sont uniformes (~ 1/3 partout).\n", + "\n", + "### Pourquoi ?\n", + "\n", + "Le **posterior symétrique** est invariant sous permutation des indices de sujets. Si le prior est Dirichlet(1) (uniforme), la posterior reste symétrique. Pour briser la symétrie, il faut :\n", + "\n", + "1. **Asymétriser le prior** (section 4) : beta_jk >> 1 pour le mot-canon de chaque sujet.\n", + "2. **Asymétriser le posterior** par post-traitement (Hungarian matching sur la matrice de confusion phi x phi_target).\n", + "3. **Asymétriser l'initialisation** de l'optimiseur NUTS (seed asymétrique), mais cela ne suffit pas seul.\n", + "\n", + "### Métrique de diagnostic\n", "\n", - "**Sortie verbatim code[4]** : 3 sujets avec distributions de mots quasi-identiques (`recette (0.151), atome (0.146), four (0.125)...` pour les 3 sujets), proportions theta uniformes (~ 1/3 partout).\n", + "Pour quantifier la degenerescence : calculer la **Jensen-Shannon Divergence (JSD)** moyenne entre paires de sujets. Si JSD_moy ~ 0, les sujets sont indistinguables. Si JSD_moy > 0.3 bits, ils sont bien séparés.\n", "\n", "### Pourquoi c'est pédagogiquement important\n", "\n", diff --git a/scripts/notebook_tools/twin_pairs.d/probas-11-topic-models/0013-2026-09-28-myia-po-2026-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/probas-11-topic-models/0013-2026-09-28-myia-po-2026-CoursIA-2.yaml new file mode 100644 index 0000000000..35325e11f3 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/probas-11-topic-models/0013-2026-09-28-myia-po-2026-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-09-28' +by: myia-po-2026:CoursIA-2 +python_sha: b2d6e114720f653f88fd2c54c76dc6161388c34b +csharp_sha: 92a4ecccea9194729cbdeddb07572ac1ace6fea2 +content_python_sha: 67799204f879c618da14a371092c222876da066624bc1b2230e230fca5579171 +content_csharp_sha: 766a68b5bce8373dd4341e0cdd124468c0bd5940acfc72abd1e3c5bffe750d90 diff --git a/scripts/notebook_tools/twin_pairs.d/probas-11-topic-models/0014-2026-09-28-myia-po-2026-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/probas-11-topic-models/0014-2026-09-28-myia-po-2026-CoursIA-2.yaml new file mode 100644 index 0000000000..d99a9dbb48 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/probas-11-topic-models/0014-2026-09-28-myia-po-2026-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-09-28' +by: myia-po-2026:CoursIA-2 +python_sha: a241352b18595e9e407c3d1b63cb8c7aca4e74f5 +csharp_sha: 92a4ecccea9194729cbdeddb07572ac1ace6fea2 +content_python_sha: c594635de780165224937cdfcd5e3aa90dafafc61323a84d8d6300c9db2c8c56 +content_csharp_sha: 766a68b5bce8373dd4341e0cdd124468c0bd5940acfc72abd1e3c5bffe750d90 diff --git a/scripts/notebook_tools/twin_pairs.d/probas-4-bayesian-networks/0013-2026-09-28-myia-po-2026-CoursIA-2.yaml b/scripts/notebook_tools/twin_pairs.d/probas-4-bayesian-networks/0013-2026-09-28-myia-po-2026-CoursIA-2.yaml new file mode 100644 index 0000000000..eef4907718 --- /dev/null +++ b/scripts/notebook_tools/twin_pairs.d/probas-4-bayesian-networks/0013-2026-09-28-myia-po-2026-CoursIA-2.yaml @@ -0,0 +1,6 @@ +date: '2026-09-28' +by: myia-po-2026:CoursIA-2 +python_sha: be4e3223cb27ce55f9f3f9c7ea1325fe2b380321 +csharp_sha: 7ef2d50f2dcddfb3024681fbc29090726fc2b820 +content_python_sha: b2fb46018ecaeddc158c5aa50050c54afd2d907cf488ed9666235277cc608b82 +content_csharp_sha: ba77fc9181856b651a433cca726ef3c461b2c9369628f3068b7db92bf2a25879