Les namespaces importants pour le debugging sont : - Algorithms : contient ExpectationPropagation, VariationalMessagePassing, GibbsSampling - Compiler : options de compilation et generation de code - Distributions : tous les types de distributions (Gaussian, Gamma, Beta, etc.)
Note technique : Ce notebook est oriente troubleshooting. Il suppose que vous avez déjà explore plusieurs notebooks de la serie et rencontre des comportements inattendus. Les exemples sont volontairement simplifies pour isoler chaque type de problème.
Le debugging en programmation probabiliste differe du debugging classique :
Debugging classique
Debugging probabiliste
Erreur = crash ou mauvaise valeur
Erreur = distribution inattendue ou divergence
Cause souvent déterministe
Cause souvent liee aux priors ou a l’algorithme
Solution : corriger le code
Solution : ajuster le modèle ou l’algorithme
Outil de visualisation
Le FactorGraphHelper est un utilitaire qui permet d’afficher les graphes de facteurs generes par Infer.NET directement dans le notebook. Ces graphes sont essentiels pour :
Verifier la structure du modèle probabiliste
Identifier les connexions manquantes ou incorrectes
Comprendre le flux des messages d’inference
Prerequis : Graphviz doit etre installe sur le système pour generer les visualisations SVG. Si Graphviz n’est pas disponible, le helper retournera False et les graphes ne seront pas affichés.
// Chargement du helper pour afficher les graphes de facteurs inline#load "FactorGraphHelper.cs"Console.WriteLine("FactorGraphHelper charge !");Console.WriteLine($"Graphviz disponible : {FactorGraphHelper.IsGraphvizAvailable()}");Console.WriteLine("Usage: display(HTML(FactorGraphHelper.GetLatestFactorGraphHtml()))");
// Exemple 1 : Erreur "Model has no support"Console.WriteLine("=== Erreur : Model has no support ===");Console.WriteLine();// PROBLEME : Observer une valeur impossible sous le priortry{ Variable<double> x = Variable.GaussianFromMeanAndPrecision(0,1000);// Prior tres concentre autour de 0 x.ObservedValue=100;// Observation tres eloignee InferenceEngine engine =newInferenceEngine(); engine.Compiler.CompilerChoice= CompilerChoice.Roslyn;var result = engine.Infer(x);// Peut echouer ou donner des resultats etranges}catch(Exception e){ Console.WriteLine($"Erreur : {e.Message.Substring(0, Math.Min(100, e.Message.Length))}...");}// SOLUTION : Utiliser un prior plus largeConsole.WriteLine("\nSOLUTION : Elargir le prior");Variable<double> x2 = Variable.GaussianFromMeanAndPrecision(50,0.01);// Prior largex2.ObservedValue=100;InferenceEngine engine2 =newInferenceEngine();engine2.Compiler.CompilerChoice= CompilerChoice.Roslyn;Console.WriteLine($"Resultat avec prior large : {engine2.Infer(x2)}");
=== Erreur : Model has no support ===
Compiling model...done.
SOLUTION : Elargir le prior
Compiling model...done.
Resultat avec prior large : Gaussian.PointMass(100)
Interpretation des résultats :
Le résultat Gaussian.PointMass(100) signifie que le posterieur est une distribution degeneree concentree exactement sur la valeur observee. C’est le comportement attendu quand :
L’observation est déterministe (ObservedValue)
Le prior est suffisamment large pour “accepter” cette valeur
règle pratique : Si votre prior a une precision prec, alors les observations situees a plus de 3/sqrt(prec) ecarts-types du centre auront un support quasi-nul. Avec prec=1000, cela represente environ 0.1 unites autour de la moyenne.
// Visualisation du factor graph pour comprendre le probleme de supportConsole.WriteLine("=== Visualisation : Modele avec prior large ===");Variable<double> xVis = Variable.GaussianFromMeanAndPrecision(50,0.01).Named("x_prior_large");xVis.ObservedValue=100;InferenceEngine engineVis =newInferenceEngine();engineVis.Compiler.CompilerChoice= CompilerChoice.Roslyn;engineVis.ShowFactorGraph=true;engineVis.ShowProgress=false;var resultVis = engineVis.Infer(xVis);Console.WriteLine($"Resultat : {resultVis}");Console.WriteLine();Console.WriteLine("Le factor graph montre la structure simple : prior -> observation");display(HTML(FactorGraphHelper.GetLatestFactorGraphHtml()));FactorGraphHelper.CleanupGeneratedFiles();
=== Visualisation : Modele avec prior large ===
Resultat : Gaussian.PointMass(100)
Le factor graph montre la structure simple : prior -> observation
Model_08_19_26_03_10_41_48.svg
2.2 problème de convergence
Le deuxième type d’erreur courant concerne la convergence vers des modes non désirés. Cela se produit souvent dans les modèles de mélange où les variables ont des rôles symétriques.
Choix de paramètre (transparence) — la cellule suivante illustre la défaillance avec un prior symétrique de précision prec=10. Avec un prior beaucoup plus plat (prec=0.01, à peine informatif), EP diverge numériquement sur ces données bimodales : la magnitude des moyennes postérieures explosait (~1e71 à 1e74) et n’était pas reproductible d’un processus à l’autre (mesuré po-2026 c.743). prec=10 rend le collapse symétrique net et reproductible (3 runs identiques sur 3) : le paramètre est changé pour rendre l’échec démontrable et exploitable pédagogiquement, pas pour le masquer. Le contraste qui suit (prior asymétrique) montre ensuite comment réparer cette convergence.
// Exemple 2 : Probleme de convergence — EP sur un melange gaussien bimodal.// Demo mesurable (mesure po-2026 c.743) : on rend la defaillance reproductible// au lieu de se contenter de la decrire en prose.Console.WriteLine("=== Probleme : Convergence vers mode symetrique ===");Console.WriteLine();// Donnees bimodales : 30 points autour de -5, 30 autour de +5.Rand.Restart(42);// reproductibilite (3 runs identiques, cf mesure c.743)double[] donnees =newdouble[60];for(int i =0; i <30; i++) donnees[i]= Rand.Normal(-5.0,1.0);for(int i =30; i <60; i++) donnees[i]= Rand.Normal(5.0,1.0);Console.WriteLine($"Donnees : 60 points bimodaux, moyenne empirique = {donnees.Average():F3}");Console.WriteLine();// ---- Cas 1 : Prior SYMETRIQUE (prec = 10) ----// Un prior identique sur les deux composantes laisse EP libre d'attribuer// chaque point a l'une ou l'autre : la solution ou les deux moyennes collapses// vers la meme valeur est un attracteur (label switching / mode symetrique).Console.WriteLine("--- Cas 1 : Prior symetrique means[k] ~ Gaussian(0, prec=10) ---");{ Range k =newRange(2); Range n =newRange(donnees.Length); VariableArray<double> x = Variable.Array<double>(n).Named("x_sym"); x.ObservedValue= donnees; VariableArray<double> means = Variable.Array<double>(k).Named("means_sym"); means[k]= Variable.GaussianFromMeanAndPrecision(0.0,10.0).ForEach(k); VariableArray<int> assign = Variable.Array<int>(n).Named("assign_sym");using(Variable.ForEach(n)){ assign[n]= Variable.DiscreteUniform(k);using(Variable.Switch(assign[n])) x[n].SetTo(Variable.GaussianFromMeanAndPrecision(means[assign[n]],1.0));}var engine =newInferenceEngine(newExpectationPropagation()); engine.Compiler.CompilerChoice= CompilerChoice.Roslyn; engine.ShowProgress=false;var post = engine.Infer<Gaussian[]>(means); Console.WriteLine($" means[0] = {post[0].GetMean():F4}"); Console.WriteLine($" means[1] = {post[1].GetMean():F4}"); Console.WriteLine(" -> Collapse symetrique : les deux composantes sont identiques"); Console.WriteLine(" (le modele ne parvient pas a separer les deux modes).");}Console.WriteLine();// ---- Cas 2 : Prior ASYMETRIQUE (la solution) ----// Casser la symetrie du prior (means[0] tire vers -5, means[1] vers +5) leve// l'ambiguite : EP separe proprement les deux modes de la distribution.Console.WriteLine("--- Cas 2 : Prior asymetrique means[0] ~ G(-5,1), means[1] ~ G(+5,1) ---");{ Range k =newRange(2); Range n =newRange(donnees.Length); VariableArray<double> x = Variable.Array<double>(n).Named("x_asym"); x.ObservedValue= donnees; VariableArray<double> means = Variable.Array<double>(k).Named("means_asym"); means[0]= Variable.GaussianFromMeanAndVariance(-5.0,1.0); means[1]= Variable.GaussianFromMeanAndVariance(5.0,1.0); VariableArray<int> assign = Variable.Array<int>(n).Named("assign_asym");using(Variable.ForEach(n)){ assign[n]= Variable.DiscreteUniform(k);using(Variable.Switch(assign[n])) x[n].SetTo(Variable.GaussianFromMeanAndPrecision(means[assign[n]],1.0));}var engine =newInferenceEngine(newExpectationPropagation()); engine.Compiler.CompilerChoice= CompilerChoice.Roslyn; engine.ShowProgress=false;var post = engine.Infer<Gaussian[]>(means); Console.WriteLine($" means[0] = {post[0].GetMean():F4}"); Console.WriteLine($" means[1] = {post[1].GetMean():F4}"); Console.WriteLine(" -> Convergence : les deux modes sont separement identifies.");}
=== Probleme : Convergence vers mode symetrique ===
Donnees : 60 points bimodaux, moyenne empirique = -0,124
--- Cas 1 : Prior symetrique means[k] ~ Gaussian(0, prec=10) ---
means[0] = 5,0737
means[1] = 5,0737
-> Collapse symetrique : les deux composantes sont identiques
(le modele ne parvient pas a separer les deux modes).
--- Cas 2 : Prior asymetrique means[0] ~ G(-5,1), means[1] ~ G(+5,1) ---
means[0] = -5,1493
means[1] = 4,9088
-> Convergence : les deux modes sont separement identifies.
Le problème du “label switching”
Dans les modèles de melange, le problème des modes symetriques est connu sous le nom de label switching. Si les composantes sont echangeables (même prior), l’inference peut :
Converger vers la moyenne : toutes les composantes au même endroit
Osciller entre permutations : les labels des composantes s’echangent entre itérations
Les solutions incluent :
Solution
Avantage
Inconvenient
Priors asymetriques
Simple a implementer
Introduit un biais
Contraintes d’ordre
Mathematiquement propre
Complexifie le modèle
Post-traitement
Pas de biais
Necessite analyse manuelle
3. Comparaison des Algorithmes d’Inference
Quand utiliser quel algorithme ?
Algorithme
Forces
Faiblesses
Usage recommande
EP
Rapide, bon pour melanges continus
Peut diverger, approximatif
modèles Gaussian, Probit
VMP
Stable, bon pour discret
Sous-estime l’incertitude
LDA, melanges categoriques
Gibbs
Exact asymptotiquement
Lent, diagnostics difficiles
Validation, petits modèles
La cellule suivante compare EP et VMP sur un problème simple d’estimation de moyenne avec precision inconnue.
Configuration du test : - 6 observations autour de 2.0 - Prior vague sur la moyenne : Gaussian(0, 0.01) - Prior informatif sur la precision : Gamma(2, 0.5)
Ce type de modèle (données gaussiennes avec paramètres inconnus) est un cas classique ou EP et VMP donnent des résultats comparables mais avec des niveaux d’incertitude différents.
// Comparaison EP vs VMP sur un modele simpleConsole.WriteLine("=== Comparaison EP vs VMP ===");Console.WriteLine();// Modele : estimation de moyenne avec observations bruiteesdouble[] observations ={2.1,1.9,2.3,2.0,1.8,2.2};int nObs = observations.Length;// Fonction pour creer et inferer le modele avec EPGaussian InferAvecEP(){ Variable<double> mean = Variable.GaussianFromMeanAndPrecision(0,0.01); Variable<double> prec = Variable.GammaFromShapeAndScale(2,0.5); Range r =newRange(nObs); VariableArray<double> obs = Variable.Array<double>(r); obs[r]= Variable.GaussianFromMeanAndPrecision(mean, prec).ForEach(r); obs.ObservedValue= observations; InferenceEngine engine =newInferenceEngine(newExpectationPropagation()); engine.Compiler.CompilerChoice= CompilerChoice.Roslyn; engine.ShowProgress=false;return engine.Infer<Gaussian>(mean);}// Fonction pour creer et inferer le modele avec VMPGaussian InferAvecVMP(){ Variable<double> mean = Variable.GaussianFromMeanAndPrecision(0,0.01); Variable<double> prec = Variable.GammaFromShapeAndScale(2,0.5); Range r =newRange(nObs); VariableArray<double> obs = Variable.Array<double>(r); obs[r]= Variable.GaussianFromMeanAndPrecision(mean, prec).ForEach(r); obs.ObservedValue= observations; InferenceEngine engine =newInferenceEngine(newVariationalMessagePassing()); engine.Compiler.CompilerChoice= CompilerChoice.Roslyn; engine.ShowProgress=false;return engine.Infer<Gaussian>(mean);}var resultEP =InferAvecEP();var resultVMP =InferAvecVMP();Console.WriteLine($"Observations : {string.Join(",", observations)}");Console.WriteLine($"Moyenne empirique : {observations.Average():F3}");Console.WriteLine();Console.WriteLine($"EP : {resultEP}");Console.WriteLine($"VMP : {resultVMP}");Console.WriteLine();Console.WriteLine("Note : VMP tend a avoir une variance plus faible (sous-estime l'incertitude)");
=== Comparaison EP vs VMP ===
Observations : 2,1, 1,9, 2,3, 2, 1,8, 2,2
Moyenne empirique : 2,050
EP : Gaussian(2,048, 0,0808)
VMP : Gaussian(2,048, 0,07725)
Note : VMP tend a avoir une variance plus faible (sous-estime l'incertitude)
Interpretation des résultats EP vs VMP :
Les deux algorithmes estiment la moyenne autour de 2.05 (proche de la moyenne empirique 2.05), mais avec des caractéristiques différentes :
Métrique
EP
VMP
Interpretation
Moyenne posterieure
~2.05
~2.05
Accord sur l’estimation ponctuelle
Variance posterieure
Plus large
Plus etroite
VMP sous-estime l’incertitude
Pourquoi VMP sous-estime l’incertitude ?
VMP (Variational Message Passing) approxime le posterieur par une distribution factorisee. Cette hypothese d’indépendance ignore les correlations entre variables, ce qui conduit typiquement a des posterieurs trop “confiants”.
EP (Expectation Propagation) maintient des correlations locales via les messages, produisant des approximations plus realistes de l’incertitude.
Quand cela importe : La sous-estimation de l’incertitude par VMP peut etre problematique pour : - La prise de decision sous incertitude - Les intervalles de prediction - La propagation de l’incertitude dans des modèles hiérarchiques
Quand EP devient-elle vraiment instable ? Le cas non-conjugué
L’exemple conjugué ci-dessus (estimation d’une moyenne gaussienne) est un régime trop favorable pour EP : la vraisemblance est gaussienne, donc le marginal exact est lui-même gaussien et EP le retrouve directement — aucune instabilité n’est possible. La ligne « Peut diverger » du tableau du §3 ne s’y manifeste pas, et c’est ce qui rend la comparaison ci-dessus trompeuse quant à la faiblesse réelle d’EP.
Pour observer le comportement distinctif d’EP, il faut un modèle non-conjugué : une vraisemblance dont le marginal n’a pas de forme fermée gaussienne, forçant EP à approcher chaque message factor→variable. Le cas d’école est la régression logistique bayésienne, dont la vraisemblance BernoulliFromLogOdds(w·x) n’est conjuguée à aucun prior gaussien. C’est exactement le régime que le notebook Infer-4 cite comme motivation pour surveiller la convergence d’EP.
La cellule suivante construit un tel modèle (2 features, 8 observations linéairement séparables) et mesure la moyenne postérieure du vecteur de poids w au fil des itérations, pour EP et VMP. On cherche à voir comment EP se comporte quand elle doit approximer : divergence franche (NaN/Inf) ? oscillation ? convergence monotone ?
// Modèle NON-CONJUGUÉ : régression logistique bayésienne.// Vraisemblance BernoulliFromLogOdds(w.x) : EP doit approcher chaque message,// c'est ici que son instabilité (vs le cas conjugué du §3) devient observable.double[][] X =newdouble[][]{newdouble[]{0.5,0.8},newdouble[]{0.9,0.4},newdouble[]{0.7,0.9},newdouble[]{0.95,0.6},newdouble[]{0.1,0.2},newdouble[]{0.2,0.15},newdouble[]{0.3,0.1},newdouble[]{0.15,0.25},};bool[] Y =newbool[]{true,true,true,true,false,false,false,false};int nFeatLogit = X[0].Length;Range nObsLogit =newRange(X.Length).Named("nObsLogit");Variable<Vector> wLogit = Variable.VectorGaussianFromMeanAndVariance( Vector.Zero(nFeatLogit), PositiveDefiniteMatrix.IdentityScaledBy(nFeatLogit,10.0)).Named("wLogit");VariableArray<Vector> Xv = Variable.Array<Vector>(nObsLogit).Named("Xv");Xv.ObservedValue= X.Select(v => Vector.FromArray(v)).ToArray();VariableArray<bool> yv = Variable.Array<bool>(nObsLogit).Named("yv");yv.ObservedValue= Y;using(Variable.ForEach(nObsLogit)){ yv[nObsLogit]= Variable.BernoulliFromLogOdds(Variable.InnerProduct(wLogit, Xv[nObsLogit]));}// Renvoie la moyenne postérieure de wLogit selon l'algorithme et le nombre d'itérations.Vector RunLogit(string algo,int nIters,outbool nan){ nan =false; InferenceEngine engLogit = algo=="EP"?newInferenceEngine(newExpectationPropagation()):newInferenceEngine(newVariationalMessagePassing()); engLogit.NumberOfIterations= nIters; engLogit.ShowProgress=false; engLogit.Compiler.CompilerChoice= CompilerChoice.Roslyn;var postLogit = engLogit.Infer<VectorGaussian>(wLogit);var meanVec = postLogit.GetMean();if(double.IsNaN(meanVec[0])||double.IsInfinity(meanVec[0])) nan =true;return meanVec;}Console.WriteLine("=== EP vs VMP sur régression logistique (non-conjugué) ===");Console.WriteLine();Console.WriteLine("algo iters mean[0] mean[1] flag");Console.WriteLine(newstring('-',44));foreach(var algo innew[]{"EP","VMP"})foreach(var it innew[]{1,2,5,10,50,100}){bool nan;var meanVec =RunLogit(algo, it,out nan);string flag = nan ?"NaN/Inf":"ok"; Console.WriteLine(algo.PadRight(5)+" "+ it.ToString().PadLeft(4)+" "+ meanVec[0].ToString("F3").PadLeft(7)+" "+ meanVec[1].ToString("F3").PadLeft(7)+" "+ flag);}
=== EP vs VMP sur régression logistique (non-conjugué) ===
algo iters mean[0] mean[1] flag
--------------------------------------------
EP 1 30,500 27,000 ok
EP 2 -7,490 -6,986 ok
EP 5 1,507 1,191 ok
EP 10 1,446 1,138 ok
EP 50 1,446 1,138 ok
EP 100 1,446 1,138 ok
VMP 1 0,168 0,640 ok
VMP 2 0,911 1,077 ok
VMP 5 1,312 1,085 ok
VMP 10 1,368 1,075 ok
VMP 50 1,453 1,143 ok
VMP 100 1,453 1,143 ok
Lecture du résultat — ce que « EP peut diverger » signifie concrètement :
Algorithme
Itérations 1→2
Itération ≥ 5
Verdict mesuré
EP
+30,5 puis −7,5 (changement de signe !)
≈ +1,45 (stable)
Oscille violemment, puis converge
VMP
+0,17 → +0,91 (monotone)
≈ +1,45 (stable)
Progression régulière dès le départ
Deux faits honnêtes, mesurés dans la cellule précédente :
EP ne part pas en NaN sur ce modèle. L’implémentation Infer.NET (EP amortie) contient les messages : toutes les itérations renvoient une valeur finie. La « divergence » cataclysmique n’est donc pas la bonne lecture de la ligne du tableau §3 sur ce cas d’école.
EP oscille fortement avant de converger : à l’itération 1, le message sur-corrige (poids à +30,5, soit ~20× la valeur finale) ; à l’itération 2, le poids change de signe (−7,5 : il prédit momentanément la classe opposée). C’est l’instabilité réelle de la propagation de messages non-conjuguée : chaque message approximatif déplace trop la gaussienne, et la correction suivante la rejette de l’autre côté. VMP, qui propage des moments (moyenne/variance) plutôt que des messages factoriels naturels, est monotone dès la première itération.
Leçon de debugging : face à un résultat EP surprenant, augmentez NumberOfIterations et observez la trajectoire plutôt que le seul point final. Une oscillation précoce qui se stabilise (EP ici) se distingue d’une divergence franche (valeurs NaN/Inf, ou croissance monotone non bornée). Le réflexe « EP = instable » est juste mais doit être diagnostiqué, jamais présupposé : sur modèle conjugué EP est impeccable (cf. §3 ci-dessus), sur modèle non-conjugué elle oscille mais converge si le modèle est bien posé. C’est cette nuance que la simple ligne de tableau ne pouvait pas capturer.
// Exercice : Diagnostic d'un modele de melange gaussien// Modele avec problemes (a corriger)double[] dataMelange ={-4.2,-3.8,-5.1,-4.5,-3.9,5.3,4.8,5.1,4.6,5.5};int nData = dataMelange.Length;int nComposantes =2;// TODO 1 : Definir des priors asymetriques pour les moyennes des 2 composantes// Indice : composante 0 centree vers -5, composante 1 centree vers +5// Variable<double> mean0 = ...// Variable<double> mean1 = ...// TODO 2 : Definir un prior raisonnable pour la precision commune// Indice : GammaFromShapeAndScale avec shape >= 1// TODO 3 : Creer le tableau d'observations avec VariableArray// Indice : chaque observation est tiree d'une des deux composantes// TODO 4 : Choisir l'algorithme d'inference adapte (EP ou VMP)// Indice : pour un melange gaussien, EP est generalement recommande// TODO 5 : Executer l'inference et verifier les posterieurs avec DiagnosticGaussian()Console.WriteLine("Exercice a completer : diagnostiquer et corriger le melange gaussien");
Exercice a completer : diagnostiquer et corriger le melange gaussien
Exercice 1 : Diagnostic d’un modèle de melange gaussien
Objectif : Identifiez et corrigez les problemes dans un modèle de melange gaussien a 2 composantes.
Contexte : Un modèle de melange gaussien tente de separer des données issues de deux distributions distinctes, mais l’inference produit des résultats inattendus (moyennes identiques ou divergence).
étapes : 1. Analysez le modèle fourni et identifiez au moins 2 problemes parmi : prior symetrique, algorithme mal adapte, observation hors-support 2. Corrigez chaque problème en vous basant sur les bonnes pratiques vues dans ce notebook 3. Comparez les résultats obtenus avec EP et VMP sur votre modèle corrige
Indices : - Indice 1 : Les composantes d’un melange doivent avoir des priors distincts pour eviter le label switching - Indice 2 : Testez avec engine.ShowProgress = true pour observer la convergence - Indice 3 : Utilisez DiagnosticGaussian() pour verifier la sante des posterieurs
// Visualisation du factor graph du modele EP vs VMP// Le graphe est identique pour les deux algorithmes - seul le calcul des messages differe// TODO etudiant : Implementer la visualisation du factor graph du modele EP vs VMP.// Le graphe doit montrer la structure partagee (hyperparametres mean/precision + observations y).// Indice 1 : definir 6 observations bruitees (cf cellules 13-15 pour le modele canonique)// Indice 2 : creer Variable<double> mean = ... .Named("mean") et Variable<double> prec = ... .Named("precision")// Indice 3 : creer VariableArray<double> obs[r] = Variable.GaussianFromMeanAndPrecision(mean, prec).ForEach(r)// Indice 4 : InferenceEngine engVis = new InferenceEngine(); engVis.ShowFactorGraph = true;// Indice 5 : afficher avec display(HTML(FactorGraphHelper.GetLatestFactorGraphHtml())) et nettoyer via FactorGraphHelper.CleanupGeneratedFiles()Console.WriteLine("Exercice a completer : visualiser le factor graph EP vs VMP");
Exercice a completer : visualiser le factor graph EP vs VMP
4. Outils de Debug Infer.NET
4.1 Options du Moteur
engine.ShowProgress=true;// Affiche les itérationsengine.ShowSchedule=true;// Affiche l'ordre des messagesengine.ShowFactorGraph=true;// Genere le graphe de facteursengine.Compiler.WriteSourceFiles=true;// Sauvegarde le code genereengine.Compiler.ShowWarnings=true;// Affiche les avertissements
// Demonstration des outils de debugConsole.WriteLine("=== Outils de Debug ===");Console.WriteLine();// Modele simple pour demonstrationVariable<double> mu = Variable.GaussianFromMeanAndPrecision(0,1).Named("mu");Variable<double> y = Variable.GaussianFromMeanAndPrecision(mu,1).Named("y");y.ObservedValue=5.0;InferenceEngine debugEngine =newInferenceEngine();debugEngine.Compiler.CompilerChoice= CompilerChoice.Roslyn;// Activer les options de debugdebugEngine.ShowProgress=true;debugEngine.Compiler.ShowWarnings=true;Console.WriteLine("Options de debug activees :");Console.WriteLine(" - ShowProgress : affiche les iterations");Console.WriteLine(" - ShowWarnings : affiche les avertissements du compilateur");Console.WriteLine();var muPost = debugEngine.Infer<Gaussian>(mu);Console.WriteLine($"\nResultat : mu ~ {muPost}");
=== Outils de Debug ===
Options de debug activees :
- ShowProgress : affiche les iterations
- ShowWarnings : affiche les avertissements du compilateur
Compiling model...done.
Resultat : mu ~ Gaussian(2,5, 0,5)
Interpretation du résultat :
Le posterieur Gaussian(2.5, 0.5) resulte de la mise a jour bayesienne :
Ou \(\tau\) represente la precision (inverse de la variance). Le posterieur est exactement a mi-chemin entre le prior (0) et l’observation (5), car les deux ont la même precision.
4.2 Visualisation des Factor Graphs
L’option ShowFactorGraph = true genere des fichiers .gv (DOT) et .svg (si Graphviz est installe). Le helper FactorGraphHelper permet d’afficher ces graphes directement dans le notebook.
// Demonstration de la visualisation du Factor GraphConsole.WriteLine("=== Visualisation du Factor Graph ===");Console.WriteLine();// Modele hierarchique pour une visualisation interessanteVariable<double> hyperMean = Variable.GaussianFromMeanAndPrecision(0,0.1).Named("hyperMean");Variable<double> hyperPrec = Variable.GammaFromShapeAndScale(2,0.5).Named("hyperPrec");Variable<double> obs1 = Variable.GaussianFromMeanAndPrecision(hyperMean, hyperPrec).Named("obs1");Variable<double> obs2 = Variable.GaussianFromMeanAndPrecision(hyperMean, hyperPrec).Named("obs2");obs1.ObservedValue=3.0;obs2.ObservedValue=5.0;InferenceEngine fgEngine =newInferenceEngine();fgEngine.Compiler.CompilerChoice= CompilerChoice.Roslyn;fgEngine.ShowFactorGraph=true;// Generer le graphefgEngine.ShowProgress=false;var hyperMeanPost = fgEngine.Infer<Gaussian>(hyperMean);Console.WriteLine($"Resultat : hyperMean ~ {hyperMeanPost}");// Afficher le factor graph inlinedisplay(HTML(FactorGraphHelper.GetLatestFactorGraphHtml()));// Nettoyer les fichiers generesint cleaned = FactorGraphHelper.CleanupGeneratedFiles();Console.WriteLine($"\nFichiers nettoyes : {cleaned}");
Le graphe de facteurs visualise la structure du modèle probabiliste :
élément
Representation
Signification
Cercles
Variables
Variables aléatoires du modèle
Carres
Facteurs
Distributions ou contraintes
Aretes
Connexions
Dependances entre variables et facteurs
Couleur grise
Observe
Variables avec valeurs fixees
Utilite pour le debugging :
Le factor graph permet de verifier visuellement que : 1. Les variables sont connectees comme prevu 2. Les observations sont bien marquees 3. Il n’y a pas de composantes deconnectees 4. La structure hiérarchique est correcte
Dans le graphe ci-dessus, on voit que hyperMean et hyperPrec sont les hyperparamètres partages par les deux observations obs1 et obs2, formant un modèle hiérarchique classique.
5. Bonnes Pratiques de Modelisation
5.1 Nommage des Variables
// BON : Noms explicites avec .Named()Variable<double> capaciteEtudiant = Variable.GaussianFromMeanAndPrecision(0,1).Named("capacite");// MAUVAIS : Variables anonymesVariable<double> x = Variable.GaussianFromMeanAndPrecision(0,1);
5.2 Priors Informatifs
Situation
Prior recommande
Moyenne inconnue
Gaussian large (precision ~0.01)
Precision inconnue
Gamma(2, 0.5) ou plus concentre
Probabilite
Beta(1, 1) pour uniforme, Beta(2, 2) pour centre
Poids melange
Dirichlet(1, 1, …) pour uniforme
Demonstration de l’impact des priors
Le choix des priors est souvent la source principale de problemes en programmation probabiliste. Un prior mal choisi peut :
Rendre l’inference impossible : si l’observation a probabilite nulle sous le prior
Biaiser les résultats : si le prior “domine” les données
Ralentir la convergence : si le prior est très différent des données
La cellule suivante illustre l’impact de différents priors Beta sur l’estimation d’une probabilite binomiale avec seulement 5 observations.
// Demonstration de l'importance des priorsConsole.WriteLine("=== Impact du choix des Priors ===");Console.WriteLine();// Observations : 3 succes sur 5 essaisint succes =3, echecs =2;// Differents priors pour la probabilitevar priors =new(string nom,double a,double b)[]{("Uniforme Beta(1,1)",1,1),("Centre Beta(2,2)",2,2),("Informatif Beta(5,5)",5,5),("Biaise succes Beta(8,2)",8,2)};Console.WriteLine($"Observations : {succes} succes, {echecs} echecs");Console.WriteLine($"MLE (maximum de vraisemblance) : {(double)succes/(succes+echecs):F2}");Console.WriteLine();foreach(var(nom, a, b)in priors){ Variable<double> p = Variable.Beta(a, b); Variable<int> obs = Variable.Binomial(succes + echecs, p); obs.ObservedValue= succes; InferenceEngine eng =newInferenceEngine(); eng.Compiler.CompilerChoice= CompilerChoice.Roslyn; eng.ShowProgress=false; Beta postP = eng.Infer<Beta>(p); Console.WriteLine($"{nom,-25} -> Posterieur : mean = {postP.GetMean():F3}");}Console.WriteLine();Console.WriteLine("Observation : Le prior influence le posterieur, surtout avec peu de donnees.");
=== Impact du choix des Priors ===
Observations : 3 succes, 2 echecs
MLE (maximum de vraisemblance) : 0,60
Uniforme Beta(1,1) -> Posterieur : mean = 0,571
Centre Beta(2,2) -> Posterieur : mean = 0,556
Informatif Beta(5,5) -> Posterieur : mean = 0,533
Biaise succes Beta(8,2) -> Posterieur : mean = 0,733
Observation : Le prior influence le posterieur, surtout avec peu de donnees.
Le prior uniforme (Beta(1,1)) est le plus “neutre” et donne un résultat proche du MLE
Les priors centres (Beta(2,2) et Beta(5,5)) “tirent” le posterieur vers 0.5
Le prior biaise (Beta(8,2)) domine les observations et maintient une estimation elevee
La force de l’effet du prior depend du ratio entre les pseudo-observations du prior (\(\alpha + \beta\)) et les observations reelles (5 dans cet exemple).
// Exercice : Test de depistage et impact du prior// TODO etudiant : Creer un modele pour un test medical avec sensibilite=0.9, faux_positifs=0.05// TODO etudiant : Observer un resultat positif et calculer P(malade | test+)// Indice : Utilisez Variable.Bernoulli pour la maladie et If/IfNot pour la vraisemblance du testConsole.WriteLine("Exercice a completer : test de depistage medical");
Exercice a completer : test de depistage medical
Exercice 2 : Impact du prior sur un diagnostic medical
Objectif : Modeliser un test de depistage avec des priors différents et observer l’impact sur le diagnostic posterieur.
Contexte : Un test medical a un taux de faux positifs de 5% et un taux de sensibilite de 90%. La prevalence de la maladie est de 1%. Vous observez un test positif. Quelle est la probabilite que le patient soit reellement malade ?
Indices : - Indice 1 : Modelisez la probabilite de maladie avec Variable.Beta(alpha, beta) ou Variable.Bernoulli(prevalence) - Indice 2 : Testez avec Beta(1, 99) (prevalence 1%), puis Beta(10, 90) (prevalence 10%) - Étape 1 : définir le modèle avec la probabilite de maladie comme variable latente - Étape 2 : Ajouter la vraisemblance du test (sensibilite et taux de faux positifs) - Étape 3 : Observer un test positif et calculer le posterieur pour différentes prevalences
6. Checklist de Debugging
Quand votre modèle ne fonctionne pas, verifiez :
étape 1 : Verification du modèle - [ ] Les types des variables sont corrects (double vs int vs bool) - [ ] Les observations sont dans le support du prior - [ ] Les arrays ont les bonnes dimensions - [ ] Les Range sont correctement définis
étape 2 : Verification de l’Inference - [ ] L’algorithme est adapte au modèle (EP/VMP/Gibbs) - [ ] Le nombre d’itérations est suffisant - [ ] Les warnings de compilation sont examines
étape 3 : Verification des résultats - [ ] Les posterieurs ne sont pas degeneres (variance > 0) - [ ] Les moyennes sont dans des plages raisonnables - [ ] Les predictions sur données connues sont correctes
6.1 Fonctions de diagnostic automatisees
Plutot que d’inspecter manuellement chaque posterieur, il est recommande de créer des fonctions de diagnostic reutilisables. Les fonctions ci-dessous verifient automatiquement les conditions de sante des posterieurs pour les trois types de distributions les plus courants : Gaussian, Gamma et Beta.
Ces fonctions peuvent etre integrees dans un pipeline de validation pour detecter automatiquement : - Les distributions degenerees (variance quasi-nulle) - Les inferences non informatives (variance très elevee) - Les valeurs hors plage attendue
// Fonctions utilitaires de diagnostic pour differents types de distributionsvoidDiagnosticGaussian(Gaussian posterior,string nom){ Console.WriteLine($"=== Diagnostic : {nom} ==="); Console.WriteLine($" Distribution : {posterior}"); Console.WriteLine($" Moyenne : {posterior.GetMean():F4}");double variance = posterior.GetVariance(); Console.WriteLine($" Variance : {variance:F6}");if(variance <1e-10) Console.WriteLine(" [ALERTE] Variance tres faible - possible degenerescence");if(variance >1e6) Console.WriteLine(" [ALERTE] Variance tres elevee - inference non informative"); Console.WriteLine();}voidDiagnosticGamma(Gamma posterior,string nom){ Console.WriteLine($"=== Diagnostic : {nom} ==="); Console.WriteLine($" Distribution : {posterior}"); Console.WriteLine($" Moyenne : {posterior.GetMean():F4}");double variance = posterior.GetVariance(); Console.WriteLine($" Variance : {variance:F6}");if(variance <1e-10) Console.WriteLine(" [ALERTE] Variance tres faible - possible degenerescence");if(variance >1e6) Console.WriteLine(" [ALERTE] Variance tres elevee - inference non informative"); Console.WriteLine();}voidDiagnosticBeta(Beta posterior,string nom){ Console.WriteLine($"=== Diagnostic : {nom} ==="); Console.WriteLine($" Distribution : {posterior}"); Console.WriteLine($" Moyenne : {posterior.GetMean():F4}");double variance = posterior.GetVariance(); Console.WriteLine($" Variance : {variance:F6}");if(variance <1e-10) Console.WriteLine(" [ALERTE] Variance tres faible - possible degenerescence"); Console.WriteLine();}// Exemple d'utilisationVariable<double> test = Variable.GaussianFromMeanAndPrecision(0,0.1);Variable<double> yTest = Variable.GaussianFromMeanAndPrecision(test,1);yTest.ObservedValue=3.0;InferenceEngine diagEngine =newInferenceEngine();diagEngine.Compiler.CompilerChoice= CompilerChoice.Roslyn;diagEngine.ShowProgress=false;var testPost = diagEngine.Infer<Gaussian>(test);DiagnosticGaussian(testPost,"test");
=== Diagnostic : test ===
Distribution : Gaussian(2,727, 0,9091)
Moyenne : 2,7273
Variance : 0,909091
Interpretation des diagnostics :
Les fonctions de diagnostic ci-dessus verifient plusieurs conditions de sante du posterieur :
Condition
Seuil
Signification si viole
Variance trop faible
< 10^-10
Distribution degeneree, possible erreur numérique
Variance trop elevee
> 10^6
Inference non informative, données insuffisantes
Pour l’exemple test, le diagnostic montre : - Moyenne ~2.73 : compromise entre le prior (0) et l’observation (3) - Variance ~0.91 : incertitude reduite par l’observation mais non nulle
Bonne pratique : Integrez ces diagnostics dans vos pipelines d’inference pour detecter automatiquement les cas problematiques, surtout dans les modèles complexes avec de nombreuses variables latentes.
Tableau recapitulatif des concepts
Concept
Description
Application au debugging
Support
Ensemble des valeurs possibles sous une distribution
Verifier que les observations sont dans le support du prior
Precision
Inverse de la variance (1/sigma^2)
Plus la precision est elevee, plus la distribution est concentree
Label switching
Permutation des labels dans les modèles de melange
Utiliser des priors asymetriques ou des contraintes d’ordre
EP
Expectation Propagation
Algorithme rapide pour modèles continus, peut diverger
VMP
Variational Message Passing
Stable mais sous-estime l’incertitude
Factor Graph
Representation graphique du modèle
Visualiser la structure pour identifier les erreurs
Distributions utilisees dans ce notebook
Distribution
paramètres
Usage typique
Gaussian
(mean, precision)
Variables continues, estimations de moyennes
Gamma
(shape, scale)
Precisions, variances, taux
Beta
(alpha, beta)
Probabilites binomiales, proportions
Dirichlet
(alpha_1, …, alpha_k)
Proportions multinomiales, poids de melange
7. Exemple guide : Debugger un modèle
Enonce
Le modèle ci-dessous a plusieurs problemes. Identifiez et corrigez-les.
// Visualisation du factor graph du modele corrige// Utile pour verifier que la structure est correcte apres debuggingConsole.WriteLine("=== Visualisation : Modele corrige ===");Variable<double> moyenneVis = Variable.GaussianFromMeanAndPrecision(25,0.01).Named("moyenne");Variable<double> precisionVis = Variable.GammaFromShapeAndScale(2,0.5).Named("precision");Variable<double> observationVis = Variable.GaussianFromMeanAndPrecision(moyenneVis, precisionVis).Named("observation");observationVis.ObservedValue=50;InferenceEngine exEngineVis =newInferenceEngine();exEngineVis.Compiler.CompilerChoice= CompilerChoice.Roslyn;exEngineVis.ShowFactorGraph=true;exEngineVis.ShowProgress=false;var moyPostVis = exEngineVis.Infer<Gaussian>(moyenneVis);Console.WriteLine($"Moyenne posterieure : {moyPostVis}");Console.WriteLine();Console.WriteLine("Le factor graph valide la structure :");Console.WriteLine(" - 'moyenne' avec prior Gaussian large");Console.WriteLine(" - 'precision' avec prior Gamma(2, 0.5)");Console.WriteLine(" - 'observation' conditionnee sur les deux parametres");display(HTML(FactorGraphHelper.GetLatestFactorGraphHtml()));FactorGraphHelper.CleanupGeneratedFiles();
=== Visualisation : Modele corrige ===
Moyenne posterieure : Gaussian(49,48, 2,826)
Le factor graph valide la structure :
- 'moyenne' avec prior Gaussian large
- 'precision' avec prior Gamma(2, 0.5)
- 'observation' conditionnee sur les deux parametres
Model_08_19_26_03_10_50_34.svg
A votre tour : identifiez les problemes dans le modèle suivant.
Étape manquante : faire TOURNER le modèle cassé pour le diagnostiquer
Note (#8081) : la version initiale de cet exemple guidé laissait le modèle cassé en commentaire et passait directement à la version corrigée. Or le geste distinctif d’un notebook de debugging est précisément de faire échouer l’inférence puis de la diagnostiquer — pas seulement de décrire la panne. On exécute ici le modèle cassé (prior trop concentré, Gamma de shape < 1, observation à ~500 écarts-types du centre du prior) et on applique les fonctions DiagnosticGaussian / DiagnosticGamma du §6.1 pour voir le symptôme apparaître dans la sortie, avant d’appliquer les corrections de la cellule suivante.
C’est la boucle exécuter le modèle suspect → diagnostiquer le posterior → corriger qui transforme un catalogue d’erreurs en une vraie démarche de débogueur.
// #8081 — Faire TOURNER le modele casse pour voir le symptome (avant de corriger)// Le modele ci-dessous est celui laisse en commentaire dans la cellule suivante.// On l'execute vraiment pour observer ce que donne une inference mal specifiee,// puis on applique les fonctions de diagnostic du §6.1 (definies plus haut, cellule 35).Console.WriteLine("=== Modele CASSE execute : prior trop concentre + Gamma(shape<1) + obs a 500 ecarts-types ===");Console.WriteLine();Variable<double> m_casse = Variable.GaussianFromMeanAndPrecision(0,100);// prior N(0, var=0.01) — beaucoup trop serreVariable<double> p_casse = Variable.GammaFromShapeAndScale(0.1,0.1);// shape < 1 : densite impropre en 0Variable<double> obs_casse = Variable.GaussianFromMeanAndPrecision(m_casse, p_casse);obs_casse.ObservedValue=50;// observation a ~500 ecarts-types du priorInferenceEngine eng_casse =newInferenceEngine();eng_casse.Compiler.CompilerChoice= CompilerChoice.Roslyn;eng_casse.ShowProgress=false;var mPost_casse = eng_casse.Infer<Gaussian>(m_casse);var pPost_casse = eng_casse.Infer<Gamma>(p_casse);DiagnosticGaussian(mPost_casse,"moyenne (modele casse)");DiagnosticGamma(pPost_casse,"precision (modele casse)");Console.WriteLine(">>> Symptome : la moyenne posterieure (~0) n'a quasi pas bouge malgre l'observation a 50.");Console.WriteLine(" Le prior N(0, var=0.01) etait si concentre que la donnee n'a pas pu le deplacer :");Console.WriteLine(" le diagnostic de variance seul passe (0.01 est 'raisonnable'), MAIS la moyenne est");Console.WriteLine(" a 500 ecarts-types de l'observation - echec de type 'prior ecrase la donnee', invisible");Console.WriteLine(" au seul controle de variance. C'est ce constat qui motive les corrections de la cellule");Console.WriteLine(" suivante (prior precision 0.01 -> la moyenne suit la donnee, comme on le verra : ~49.5).");
=== Modele CASSE execute : prior trop concentre + Gamma(shape<1) + obs a 500 ecarts-types ===
=== Diagnostic : moyenne (modele casse) ===
Distribution : Gaussian(0,0002382, 0,01)
Moyenne : 0,0002
Variance : 0,010000
=== Diagnostic : precision (modele casse) ===
Distribution : Gamma(0,6003, 0,0007935)[mean=0,0004764]
Moyenne : 0,0005
Variance : 0,000000
>>> Symptome : la moyenne posterieure (~0) n'a quasi pas bouge malgre l'observation a 50.
Le prior N(0, var=0.01) etait si concentre que la donnee n'a pas pu le deplacer :
le diagnostic de variance seul passe (0.01 est 'raisonnable'), MAIS la moyenne est
a 500 ecarts-types de l'observation - echec de type 'prior ecrase la donnee', invisible
au seul controle de variance. C'est ce constat qui motive les corrections de la cellule
suivante (prior precision 0.01 -> la moyenne suit la donnee, comme on le verra : ~49.5).
// Exemple guide : Trouvez les problemes dans ce modeleConsole.WriteLine("=== Exercice : Debugger ce modele ===");Console.WriteLine();// Probleme 1 : Prior trop etroit pour les observations// Probleme 2 : Variables non nommees// Probleme 3 : Precision negative (invalide)// Modele original (avec erreurs)/*Variable<double> m = Variable.GaussianFromMeanAndPrecision(0, 100); // Prior trop concentreVariable<double> p = Variable.GammaFromShapeAndScale(0.1, 0.1); // Shape trop petitVariable<double> obs = Variable.GaussianFromMeanAndPrecision(m, p);obs.ObservedValue = 50; // Tres eloigne du prior sur m*/// Version corrigeeVariable<double> moyenne = Variable.GaussianFromMeanAndPrecision(25,0.01).Named("moyenne");// Prior largeVariable<double> precision = Variable.GammaFromShapeAndScale(2,0.5).Named("precision");// Shape >= 1Variable<double> observation = Variable.GaussianFromMeanAndPrecision(moyenne, precision).Named("obs");observation.ObservedValue=50;InferenceEngine exEngine =newInferenceEngine();exEngine.Compiler.CompilerChoice= CompilerChoice.Roslyn;exEngine.ShowProgress=false;var moyPost = exEngine.Infer<Gaussian>(moyenne);var precPost = exEngine.Infer<Gamma>(precision);Console.WriteLine("Corrections appliquees :");Console.WriteLine("1. Prior sur moyenne : precision 0.01 (large) au lieu de 100 (etroit)");Console.WriteLine("2. Prior sur precision : Gamma(2, 0.5) au lieu de Gamma(0.1, 0.1)");Console.WriteLine("3. Variables nommees avec .Named()");Console.WriteLine();Console.WriteLine($"Resultats : moyenne ~ {moyPost}, precision ~ {precPost}");
=== Exercice : Debugger ce modele ===
Corrections appliquees :
1. Prior sur moyenne : precision 0.01 (large) au lieu de 100 (etroit)
2. Prior sur precision : Gamma(2, 0.5) au lieu de Gamma(0.1, 0.1)
3. Variables nommees avec .Named()
Resultats : moyenne ~ Gaussian(49,48, 2,826), precision ~ Gamma(2, 0,4876)[mean=0,9752]
Analyse des corrections :
problème original
Consequence
Correction appliquee
Precision 100 sur le prior
Prior concentre autour de 0 (ecart-type ~0.1)
Precision 0.01 (ecart-type ~10)
Observation a 50
500 ecarts-types du centre du prior
Prior centre a 25 pour couvrir l’observation
Gamma(0.1, 0.1)
Shape < 1 donne une densite infinie en 0
Gamma(2, 0.5) avec shape >= 1
Variables anonymes
Difficulte a interpreter les erreurs
Nommage explicite avec .Named()
Le résultat corrige montre : - Moyenne ~49.5 : proche de l’observation (50) car le prior est large - Precision ~0.98 : estime a partir d’une seule observation (incertitude elevee)
Points clés a retenir
stratégie de debugging en 3 étapes :
Verifier le support : Les observations sont-elles probables sous le prior ?
Verifier l’algorithme : EP pour continu, VMP pour discret, Gibbs pour validation
Verifier les posterieurs : Variance raisonnable ? Moyennes plausibles ?
La plupart des problemes d’inference proviennent de : - Priors mal specifies (trop etroits, mauvais support) - Mauvais choix d’algorithme (EP sur modèle discret, VMP sur correlations fortes) - modèle trop complexe (simplifier d’abord, complexifier ensuite)
Exercice 3 : Deboguer un modèle hiérarchique Casse
Enonce
Le modèle ci-dessous tente d’estimer les moyennes de performance de 3 groupes, mais il contient 3 erreurs intentionnelles. Identifiez et corrigez chaque erreur.
Indices : 1. Une precision de distribution ne peut pas etre negative 2. Une variable observee doit dependre du paramètre correct du groupe, pas d’une variable partagee 3. Un tableau de données doit etre indexe par l’indice de boucle courant
Corrigez le code et verifiez que les posterieurs correspondent aux moyennes des groupes.
// Exercice : Corriger ce modele hierarchique bayesien (3 erreurs)int nGroupes =3;int nObs =4;double[][] donneesGroupes ={newdouble[]{12.1,11.8,12.5,12.3},// Groupe 0 : ~12newdouble[]{15.2,14.9,15.8,15.1},// Groupe 1 : ~15newdouble[]{9.8,10.2,9.5,10.1}// Groupe 2 : ~10};// TODO: Identifier et corriger les 3 erreurs dans ce code :/*InferenceEngine engine = new InferenceEngine();engine.Compiler.CompilerChoice = CompilerChoice.Roslyn;// ERREUR 1 : Shape de Gamma negatif (invalide)Variable<double> precisionGlobale = Variable.GammaFromShapeAndScale(-1, 1);// ERREUR 2 : Precision trop etroite pour la moyenne de populationVariable<double> moyennePopulation = Variable.GaussianFromMeanAndPrecision(10, 10000);// ERREUR 3 : Les moyennes de groupe ne dependent pas de la populationVariable<double>[] moyenneGroupe = new Variable<double>[nGroupes];for (int g = 0; g < nGroupes; g++){ moyenneGroupe[g] = Variable.GaussianFromMeanAndPrecision(0, 1); for (int j = 0; j < nObs; j++) { var obs = Variable.GaussianFromMeanAndPrecision(moyenneGroupe[g], precisionGlobale); obs.ObservedValue = donneesGroupes[g][j]; }}*/// TODO 1 : Corriger le prior Gamma (shape doit etre positif)// Indice : utilisez GammaFromShapeAndScale(2, 0.5) ou similaire// TODO 2 : Corriger le prior de la moyenne de population// Indice : la precision ne doit pas etre trop grande, sinon la moyenne est "figee"// TODO 3 : Lier les moyennes de groupe a la moyenne de population// Indice : moyenneGroupe[g] ~ Gaussian(moyennePopulation, precisionGroupe)// TODO 4 : Inferer et afficher les moyennes de chaque groupe et la moyenne de populationConsole.WriteLine("Exercice a completer");
Exercice a completer
Conclusion
Ce notebook a couvert les techniques essentielles pour diagnostiquer et corriger les modèles probabilistes Infer.NET.
Concept
Point cle
Support du prior
Verifier que les observations sont dans le support avant inference
Choix d’algorithme
EP pour continu, VMP pour discret, Gibbs pour validation
Priors informatifs
Elargir ou ajuster les priors selon le domaine
Factor graphs
Visualiser la structure pour detecter les erreurs de connexion
Diagnostics
Tester variance non-degeneree et moyennes plausibles
Distribution
Usage pour le debug
Gaussian
Verifier precision non-infinie, moyenne dans plage attendue
Gamma
Shape >= 1 pour eviter densite infinie en 0
Beta
Pseudo-observations du prior vs données reelles
Demarche systématique : Support -> Algorithme -> Posterieurs. La plupart des problemes d’inference proviennent de priors mal specifies ou d’un mauvais choix d’algorithme.
Exercice 4 : Debugging d’un modèle de regression bayesienne
Objectif : Identifiez et corrigez les problemes dans un modèle de regression lineaire bayesienne qui produit des posterieurs degeneres.
Contexte : Un chercheur tente d’etablir une relation lineaire entre les heures d’étude (x) et les scores d’examen (y). Le modèle utilise une pente slope, une ordonnee a l’origine intercept et un bruit noise. Malheureusement, les posterieurs sont inutilisables (variance quasi-nulle ou infinie).
Indices : - Indice 1 : Verifiez le prior sur la precision du bruit. Un shape < 1 produit une densite infinie en 0. - Indice 2 : La precision du prior sur la pente est-elle adaptee a l’echelle des données (scores sur ~50-100) ? - Étape 1 : Identifiez les 2 problemes dans le modèle fourni (prior sur le bruit + precision de la pente) - Étape 2 : Corrigez les priors et relancez l’inference - Étape 3 : Utilisez DiagnosticGaussian() pour verifier la sante des posterieurs corriges
// Exercice : Debugging d'un modele de regression bayesienne// Donnees : heures d'etude (x) et scores d'examen (y)double[] xData ={2,4,6,8,10};double[] yData ={55,62,71,78,88};int nPoints = xData.Length;// MODELE A CORRIGER (contient 2 problemes) :/*Variable<double> slope = Variable.GaussianFromMeanAndPrecision(0, 10000); // PROBLEME ?Variable<double> intercept = Variable.GaussianFromMeanAndPrecision(0, 0.01); // OKVariable<double> noise = Variable.GammaFromShapeAndScale(0.1, 0.1); // PROBLEME ?Range r = new Range(nPoints);VariableArray<double> yObs = Variable.Array<double>(r);yObs[r] = Variable.GaussianFromMeanAndPrecision( intercept + slope * xData[r], noise);yObs.ObservedValue = yData;InferenceEngine eng = new InferenceEngine();eng.Compiler.CompilerChoice = CompilerChoice.Roslyn;var slopePost = eng.Infer<Gaussian>(slope);var interceptPost = eng.Infer<Gaussian>(intercept);*/// TODO 1 : Corriger le prior sur la pente (precision trop elevee pour des scores ~50-100)// Indice : avec precision=10000, l'ecart-type est de 0.01, la pente ne peut pas bouger// TODO 2 : Corriger le prior sur le bruit (shape < 1 = densite infinie en 0)// Indice : utilisez GammaFromShapeAndScale(2, 1) ou similaire// TODO 3 : Executer l'inference et verifier avec DiagnosticGaussian()// Resultat attendu : slope ~ Gaussian(~3.3, ~0.05), intercept ~ Gaussian(~42, ~3)Console.WriteLine("Exercice a completer : debugging regression bayesienne");
Exercice a completer : debugging regression bayesienne
Synthese : la demarche du debuggeur probabiliste
Les quatre exercices de fin illustrent une même realite : en programmation probabiliste, l’erreur se manifeste rarement par un crash, mais par un posterieur degenere (variance quasi-nulle ou infinie) ou non informatif. Le reflexe du debuggeur classique – ou est le bug dans le code – doit ceder la place a une demarche en trois temps, dont chaque exercice isole un symptome.
Exercice
Piege decouvert
Ou le diagnostic le repere
Ex 3 (modèle hiérarchique)
Gamma de shape negatif + moyenne de population figee
shape < 0 leve une exception ; une precision de 10000 fige la moyenne
Ex 4 (regression bayesienne)
Prior trop etroit sur la pente + bruit Gamma(0.1, 0.1)
DiagnosticGaussian revele une variance nulle ; le bruit a une densite infinie en 0
Les deux familles de fautifs
Dans toute la serie, les pannes se ramenent a deux familles :
Les priors – trop etroits (GaussianFromMeanAndPrecision(0, 10000) fige la variable), hors-support de l’observation (ObservedValue = 100 sous un prior centre sur 0), ou invalides (Gamma de shape < 1, precision negative). La règle empirique reste : un Gamma doit avoir shape >= 1, et la precision d’un prior vague vaut 0.01, pas 10000.
Le choix d’algorithme – EP pour le continu (rapide mais peut diverger), VMP pour le discret (stable mais sous-estime l’incertitude, comme on l’a mesure : variance posterieure plus etroite), Gibbs pour la validation exacte sur petits modèles. Un melange gaussien brise sous VMP peut converger sous EP.
Le factor graph, juge de paix
Quand un posterieur defie l’intuition, le factor graph tranche : il revele les composantes deconnectees, les observations mal indexees (Ex 3, indice 3), et les dependances manquantes. engine.ShowFactorGraph = true associe au FactorGraphHelper n’est pas une fioriture – c’est l’équivalent du print du debuggeur classique.
Ce quil faut emporter
Le debugging probabiliste est avant tout un changement de regard : un mauvais résultat n’est pas un bug a corriger dans le code, mais un signal que le modèle ou l’algorithme ne correspond pas aux hypotheses implicites des données. La demarche systématique – Support, Algorithme, Posterieurs, validee par les fonctions DiagnosticGaussian / DiagnosticGamma / DiagnosticBeta – est transferable a tous les notebooks suivants de la serie (modèles hiérarchiques, series temporelles, modèles de recommandation). Gardez-la sous la main : les pannes se ressemblent, seules les distributions changent.
Comment lire un Factor Graph ?
Le graphe de facteurs visualise la structure du modèle probabiliste :
Dans le graphe ci-dessus, on voit que
hyperMeanethyperPrecsont les hyperparamètres partages par les deux observationsobs1etobs2, formant un modèle hiérarchique classique.