Infer-10-Model-Sélection : Sélection et Comparaison de Modèles

Série : Programmation Probabiliste avec Infer.NET (10/19)
Duree estimee : 45 minutes
Prerequis : Infer-9-Classification


Objectifs

  • Comprendre le problème du surapprentissage
  • Calculer l’evidence du modèle (marginal likelihood)
  • Utiliser le facteur de Bayes pour comparer des modèles
  • Implementer l’Automatic Relevance Determination (ARD)

Sources et références canoniques

Ce notebook est distillé des sources fondatrices suivantes (audit fidélité, voir #8081) :

  • Evidence / marginal likelihood (Occam factor) — Bishop, C. M. (2006). Pattern Recognition and Machine Learning. Springer, §3.4 (Bayesian model comparison) et §3.5 (The evidence approximation). MacKay, D. J. C. (1992). Bayesian Interpolation, Neural Computation 4(3):415–447 — cadre fondateur de l’evidence framework.
  • Facteur de Bayes et échelle d’interprétation — Kass, R. E. & Raftery, A. E. (1995). Bayes Factors. Journal of the American Statistical Association, 90(430):773–795 (DOI 10.1080/01621459.1995.10476572). L’échelle de comparaison (substantielle / forte / décisive) est l’échelle de Jeffreys (1961), Theory of Probability, telle que rapportée et normalisée par Kass & Raftery.
  • Automatic Relevance Determination (ARD) — Tipping, M. E. (2001). Sparse Bayesian Learning and the Relevance Vector Machine. Journal of Machine Learning Research, 1:211–244. Également Bishop PRML §6.4.4 (ARD) et §7.2 (Relevance Vector Machines).

1. Configuration

Nous preparons l’environnement pour explorer la sélection de modèles bayesienne. Cette approche permet de comparer objectivement différents modèles en calculant leur evidence marginale, implementant ainsi le rasoir d’Occam de maniere mathematique.

#r "nuget: Microsoft.ML.Probabilistic"
#r "nuget: Microsoft.ML.Probabilistic.Compiler"

using Microsoft.ML.Probabilistic;
using Microsoft.ML.Probabilistic.Distributions;
using Microsoft.ML.Probabilistic.Utilities;
using Microsoft.ML.Probabilistic.Math;
using Microsoft.ML.Probabilistic.Models;
using Microsoft.ML.Probabilistic.Algorithms;
using Microsoft.ML.Probabilistic.Compiler;

Console.WriteLine("Infer.NET pret !");
Installed Packages
  • Microsoft.ML.Probabilistic, 0.4.2504.701
  • Microsoft.ML.Probabilistic.Compiler, 0.4.2504.701
Infer.NET pret !

Chargement du helper de visualisation des graphes de facteurs.

// Chargement du helper pour visualisation des graphes de facteurs
#load "FactorGraphHelper.cs"

Console.WriteLine($"FactorGraphHelper charge. Graphviz disponible : {FactorGraphHelper.IsGraphvizAvailable()}");
FactorGraphHelper charge. Graphviz disponible : True

Visualisation des graphes de facteurs

Ce notebook utilise FactorGraphHelper.cs pour visualiser les graphes de facteurs generes par Infer.NET. Ces graphes montrent la structure probabiliste des modèles : les noeuds representent les variables aleatoires et les observations, les facteurs (carres) representent les distributions conditionnelles.

Pour activer la visualisation, on configure ShowFactorGraph = true sur le moteur d’inference.

Note technique : Calcul de l’evidence dans Infer.NET

Infer.NET calcule l’evidence du modèle via une astuce elegante :

  1. On introduit une variable indicatrice evidence = Bernoulli(0.5)
  2. Le modèle est conditionne par Variable.If(evidence)
  3. Après inference, evidence.LogOdds donne le log de l’evidence

Pourquoi ca fonctionne ? Par le théorème de Bayes : \[P(\text{evidence}=\text{true}|D) \propto P(D|\text{evidence}=\text{true}) \times P(\text{evidence}=\text{true})\]

Comme \(P(\text{evidence}=\text{true}) = 0.5\), le log-odds posterieur est directement le log de l’evidence (a une constante pres).

Cette méthode est spécifique a Infer.NET et permet d’obtenir l’evidence sans calcul integral explicite.

2. Le Problème du Surapprentissage

Observation

Un modèle complexe peut parfaitement ajuster les données d’entrainement mais mal generaliser.

Exemple

Ajuster un polynome de degré n-1 a n points : ajustement parfait mais prediction catastrophique.

Solution bayesienne

  • Les priors penalisent les modèles complexes
  • L’evidence du modèle equilibre ajustement et complexite
  • C’est le rasoir d’Occam bayesien

3. Evidence du Modèle (Marginal Likelihood)

Définition

\[P(D|M) = \int P(D|\theta, M) P(\theta|M) d\theta\]

L’evidence est la probabilité des données sous le modèle, marginalisee sur les paramètres.

Interpretation

  • Un modèle simple fait des predictions moins precises mais moins dispersees
  • Un modèle complexe fait des predictions plus precises mais plus dispersees
  • L’evidence favorise le bon equilibre

Fidélité à la source (Bishop 2006, §3.4 ; MacKay 1992). L’evidence réalise un arbitrage automatique entre ajustement et complexité via le facteur d’Occam : un modèle complexe répartit sa masse de probabilité sur un espace d’hypothèses plus large, donc dilue \(P(D|M)\) dès que les données tombent hors d’une région étroite. Le modèle qui maximise l’evidence n’est ni le plus simple ni le mieux ajusté, mais celui dont la « portée » (volume de prédictions plausibles) épouse le mieux les données — c’est la formalisation bayésienne du rasoir d’Ockham que Bishop §3.4 développe en détail et que l’intégrale ci-dessus encode implicitement.

// Calcul de l'evidence avec Infer.NET

// Données
double[] observations = { 13, 15, 17, 14, 16, 15, 18 };
int n = observations.Length;

// MODELE 1 : Une seule gaussienne
Variable<bool> evidence1 = Variable.Bernoulli(0.5).Named("evidence1");

using (Variable.If(evidence1))
{
    Variable<double> moyenne1 = Variable.GaussianFromMeanAndPrecision(15, 0.01).Named("moyenne");
    Variable<double> precision1 = Variable.GammaFromShapeAndScale(2, 0.5).Named("precision");
    
    for (int i = 0; i < n; i++)
    {
        Variable<double> obs1 = Variable.GaussianFromMeanAndPrecision(moyenne1, precision1).Named($"obs_{i}");
        obs1.ObservedValue = observations[i];
    }
}

InferenceEngine moteur1 = new InferenceEngine();
moteur1.Compiler.CompilerChoice = CompilerChoice.Roslyn;
moteur1.ShowFactorGraph = true;  // Activation de la visualisation

double logEvidence1 = moteur1.Infer<Bernoulli>(evidence1).LogOdds;

Console.WriteLine("=== Evidence du Modele ===");
Console.WriteLine($"\nModele 1 (1 gaussienne) : log evidence = {logEvidence1:F2}");
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
=== Evidence du Modele ===

Modele 1 (1 gaussienne) : log evidence = -16,98

Lecture du résultat

Log evidence = -16.98 pour le modèle a une gaussienne.

Cette valeur negative est normale : c’est un logarithme de probabilité, donc toujours negatif (ou nul). Plus la valeur est proche de 0, meilleure est l’evidence.

En termes absolus, \(e^{-16.98} \approx 4.2 \times 10^{-8}\) semble très petit, mais c’est la comparaison relative entre modèles qui importe, pas la valeur absolue.

// Visualisation du graphe de facteurs - Modèle 1 gaussienne
display(HTML(FactorGraphHelper.GetLatestFactorGraphHtml()));
Model_06_22_26_21_16_50_24.svg
Model node0 Bernoulli(0,5) node1 Random node0->node1 dist node2 evidence1 node1->node2 node3 15 node4 Gaussian node3->node4 mean node6 moyenne node4->node6 node5 0,01 node5->node4 precision node11 Gaussian node6->node11 mean node13 Gaussian node6->node13 mean node15 Gaussian node6->node15 mean node17 Gaussian node6->node17 mean node19 Gaussian node6->node19 mean node21 Gaussian node6->node21 mean node23 Gaussian node6->node23 mean node7 2 node8 Sample node7->node8 shape node10 precision node8->node10 node9 0,5 node9->node8 scale node10->node11 precision node10->node13 precision node10->node15 precision node10->node17 precision node10->node19 precision node10->node21 precision node10->node23 precision node12 13 node11->node12 node14 15 node13->node14 node16 17 node15->node16 node18 14 node17->node18 node20 16 node19->node20 node22 15 node21->node22 node24 18 node23->node24

Lecture du graphe de facteurs - Modèle 1 gaussienne

Le graphe montre la structure du modèle a une gaussienne :

  • Noeuds ovales : variables aleatoires (moyenne, precision, evidence1)
  • Noeuds carres : facteurs (distributions conditionnelles)
  • Noeuds gris : observations (obs_0 a obs_6)

La variable evidence1 (Bernoulli) englobe tout le modèle via Variable.If(). Les 7 observations partagent la même moyenne et precision, ce qui represente l’hypothese i.i.d. (independantes et identiquement distribuees).

Implementation : Modèle 2 - Melange de deux gaussiennes

Le modèle de melange (mixture model) suppose que chaque observation provient de l’une ou l’autre de deux gaussiennes, avec une probabilité \(\pi\) pour la première et \(1-\pi\) pour la seconde.

Paramètres du modèle : - \(\mu_1, \mu_2\) : moyennes des deux composantes - \(\tau\) : precision commune (simplification) - \(\pi\) : proportion du melange (poids de la première composante)

Code : Pour chaque observation, on tire d’abord composante ~ Bernoulli(pi), puis on observe depuis la gaussienne correspondante.

Note algorithmique : Nous utilisons VariationalMessagePassing car les melanges de gaussiennes sont plus stables avec VMP qu’avec EP pour le calcul d’evidence.

// MODELE 2 : Melange de deux gaussiennes
Variable<bool> evidence2 = Variable.Bernoulli(0.5).Named("evidence2");

using (Variable.If(evidence2))
{
    Variable<double> moyenne2a = Variable.GaussianFromMeanAndPrecision(10, 0.01).Named("moyenne_a");
    Variable<double> moyenne2b = Variable.GaussianFromMeanAndPrecision(20, 0.01).Named("moyenne_b");
    Variable<double> precision2 = Variable.GammaFromShapeAndScale(2, 0.5).Named("precision");
    Variable<double> poidsMixte = Variable.Beta(1, 1).Named("poids_mixte");
    
    for (int i = 0; i < n; i++)
    {
        Variable<bool> composante = Variable.Bernoulli(poidsMixte).Named($"comp_{i}");
        Variable<double> obs2 = Variable.New<double>().Named($"obs2_{i}");
        using (Variable.If(composante))
        {
            obs2.SetTo(Variable.GaussianFromMeanAndPrecision(moyenne2a, precision2));
        }
        using (Variable.IfNot(composante))
        {
            obs2.SetTo(Variable.GaussianFromMeanAndPrecision(moyenne2b, precision2));
        }
        obs2.ObservedValue = observations[i];
    }
}

InferenceEngine moteur2 = new InferenceEngine(new VariationalMessagePassing());
moteur2.Compiler.CompilerChoice = CompilerChoice.Roslyn;
moteur2.ShowFactorGraph = true;  // Activation de la visualisation

double logEvidence2 = moteur2.Infer<Bernoulli>(evidence2).LogOdds;

Console.WriteLine($"Modele 2 (melange 2 gaussiennes) : log evidence = {logEvidence2:F2}");
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Modele 2 (melange 2 gaussiennes) : log evidence = -20,12

Visualisation du graphe de facteurs du modèle de melange de gaussiennes.

// Visualisation du graphe de facteurs - Modèle melange
display(HTML(FactorGraphHelper.GetLatestFactorGraphHtml()));
Model_06_22_26_21_16_52_60.svg
Model node0 Bernoulli(0,5) node1 Random node0->node1 dist node2 evidence2 node1->node2 node3 10 node4 Gaussian node3->node4 mean node6 moyenne_a node4->node6 node5 0,01 node5->node4 precision node20 Gaussian node6->node20 mean node25 Gaussian node6->node25 mean node30 Gaussian node6->node30 mean node35 Gaussian node6->node35 mean node40 Gaussian node6->node40 mean node45 Gaussian node6->node45 mean node50 Gaussian node6->node50 mean node7 20 node8 Gaussian node7->node8 mean node10 moyenne_b node8->node10 node9 0,01 node9->node8 precision node22 Gaussian node10->node22 mean node27 Gaussian node10->node27 mean node32 Gaussian node10->node32 mean node37 Gaussian node10->node37 mean node42 Gaussian node10->node42 mean node47 Gaussian node10->node47 mean node52 Gaussian node10->node52 mean node11 2 node12 Sample node11->node12 shape node14 precision node12->node14 node13 0,5 node13->node12 scale node14->node20 precision node14->node22 precision node14->node25 precision node14->node27 precision node14->node30 precision node14->node32 precision node14->node35 precision node14->node37 precision node14->node40 precision node14->node42 precision node14->node45 precision node14->node47 precision node14->node50 precision node14->node52 precision node15 Beta(1,1)[mean=0,5] node16 Random node15->node16 dist node17 poids_mixte node16->node17 node18 Bernoulli node17->node18 probTrue node23 Bernoulli node17->node23 probTrue node28 Bernoulli node17->node28 probTrue node33 Bernoulli node17->node33 probTrue node38 Bernoulli node17->node38 probTrue node43 Bernoulli node17->node43 probTrue node48 Bernoulli node17->node48 probTrue node19 comp_0 node18->node19 node21 13 node19->node21 condition node20->node21 node22->node21 node24 comp_1 node23->node24 node26 15 node24->node26 condition node25->node26 node27->node26 node29 comp_2 node28->node29 node31 17 node29->node31 condition node30->node31 node32->node31 node34 comp_3 node33->node34 node36 14 node34->node36 condition node35->node36 node37->node36 node39 comp_4 node38->node39 node41 16 node39->node41 condition node40->node41 node42->node41 node44 comp_5 node43->node44 node46 15 node44->node46 condition node45->node46 node47->node46 node49 comp_6 node48->node49 node51 18 node49->node51 condition node50->node51 node52->node51

Lecture du graphe de facteurs - Modèle melange

Le graphe du modèle de melange est plus complexe :

  • moyenne_a, moyenne_b : les deux centres des composantes gaussiennes
  • poids_mixte : paramètre Beta controlant la proportion du melange
  • comp_i : variable latente discrete (quelle composante genere l’observation i ?)
  • obs2_i : observations, chacune connectee aux deux moyennes via sa variable de composante

La structure en “gateway” (Variable.If/IfNot) créé des branchements conditionnels visibles dans le graphe. Chaque observation peut provenir de l’une ou l’autre gaussienne selon comp_i.

4. Facteur de Bayes

Définition

\[BF_{12} = \frac{P(D|M_1)}{P(D|M_2)} = \exp(\log E_1 - \log E_2)\]

Interpretation (echelle de Jeffreys)

log(BF) BF Evidence pour M1
0-1 1-3 Negligeable
1-2 3-10 Substantielle
2-3 10-30 Forte
3-5 30-150 Très forte
>5 >150 Decisive

Référence. Kass & Raftery (1995), Bayes Factors, JASA 90(430):773–795. Le tableau ci-dessus est l’échelle de Jeffreys (1961, Theory of Probability) telle que consolidée par Kass & Raftery. À noter : les seuils originels de Jeffreys (1–3 / 3–10 / 10–30 / 30–150 / >150 en \(\log\)) diffèrent légèrement des seuils alternatifs (3 / 20 / 150) utilisés ailleurs dans la littérature — le notebook suit la convention de Jeffreys, ce qui est un choix légitime à documenter explicitement.

// Facteur de Bayes
double logBF = logEvidence1 - logEvidence2;
double BF = Math.Exp(logBF);

Console.WriteLine("=== Facteur de Bayes ===");
Console.WriteLine($"\nlog(BF) = {logBF:F2}");
Console.WriteLine($"BF = {BF:F2}");

string interpretation;
if (Math.Abs(logBF) < 1) interpretation = "Evidence negligeable";
else if (Math.Abs(logBF) < 2) interpretation = "Evidence substantielle";
else if (Math.Abs(logBF) < 3) interpretation = "Evidence forte";
else interpretation = "Evidence tres forte/decisive";

string favori = logBF > 0 ? "Modele 1 (1 gaussienne)" : "Modele 2 (melange)";
Console.WriteLine($"\n{interpretation} en faveur de : {favori}");
=== Facteur de Bayes ===

log(BF) = 3,14
BF = 23,03

Evidence tres forte/decisive en faveur de : Modele 1 (1 gaussienne)

Interprétation du facteur de Bayes

Résultat : log(BF) = 3.14, BF ≈ 23

Selon l’échelle de Jeffreys, un BF de 23 représente une evidence forte (entre 10 et 30) en faveur du modèle 1.

Pourquoi le modèle simple gagne-t-il ?

Les données {13, 15, 17, 14, 16, 15, 18} sont unimodales avec moyenne ~15.3. Le modèle à 2 gaussiennes : 1. Introduit des paramètres inutiles (2 moyennes, poids du mélange) 2. Ces paramètres doivent être “expliqués” par le prior 3. Le prior “dilue” la vraisemblance sur un espace plus grand

C’est le rasoir d’Occam bayésien en action : à ajustement égal, le modèle simple est préféré car il fait des prédictions plus “concentrées”.

Formule intuitive : Evidence ≈ (vraisemblance) × (volume du prior utilisé) / (volume total du prior)

5. Sélection du Nombre de Composantes

Application

Determiner le nombre optimal de composantes dans un modèle de melange.

Données bimodales : quand le modèle complexe gagne

Les données précédentes etaient unimodales (autour de 15). Testons maintenant avec des données clairement bimodales : deux groupes bien separes autour de 6 et 15.

Question : Le modèle a 2 composantes va-t-il maintenant etre prefere ?

L’algorithme compare systematiquement 1 vs 2 composantes en calculant l’evidence de chaque modèle.

// Données bimodales
double[] dataBimodal = { 5, 6, 7, 5.5, 6.5, 15, 16, 17, 14, 15.5, 16.5, 6, 15 };
int nBi = dataBimodal.Length;

Console.WriteLine("=== Selection du nombre de composantes ===");
Console.WriteLine($"Donnees : {string.Join(", ", dataBimodal)}\n");

// Test avec 1, 2, 3 composantes
double[] logEvidences = new double[3];

// 1 composante
{
    Variable<bool> ev = Variable.Bernoulli(0.5);
    using (Variable.If(ev))
    {
        Variable<double> m = Variable.GaussianFromMeanAndPrecision(10, 0.01);
        Variable<double> p = Variable.GammaFromShapeAndScale(2, 0.5);
        foreach (var d in dataBimodal)
        {
            Variable<double> o = Variable.GaussianFromMeanAndPrecision(m, p);
            o.ObservedValue = d;
        }
    }
    var eng = new InferenceEngine();
    eng.Compiler.CompilerChoice = CompilerChoice.Roslyn;
    logEvidences[0] = eng.Infer<Bernoulli>(ev).LogOdds;
}

Console.WriteLine($"1 composante : log evidence = {logEvidences[0]:F2}");

// 2 composantes - simplifie
{
    Variable<bool> ev = Variable.Bernoulli(0.5);
    using (Variable.If(ev))
    {
        Variable<double> m1 = Variable.GaussianFromMeanAndPrecision(6, 0.1);
        Variable<double> m2 = Variable.GaussianFromMeanAndPrecision(15, 0.1);
        Variable<double> p = Variable.GammaFromShapeAndScale(2, 1);
        Variable<double> w = Variable.Beta(1, 1);
        
        foreach (var d in dataBimodal)
        {
            Variable<bool> c = Variable.Bernoulli(w);
            Variable<double> o = Variable.New<double>();
            using (Variable.If(c)) { o.SetTo(Variable.GaussianFromMeanAndPrecision(m1, p)); }
            using (Variable.IfNot(c)) { o.SetTo(Variable.GaussianFromMeanAndPrecision(m2, p)); }
            o.ObservedValue = d;
        }
    }
    var eng = new InferenceEngine(new VariationalMessagePassing());
    eng.Compiler.CompilerChoice = CompilerChoice.Roslyn;
    logEvidences[1] = eng.Infer<Bernoulli>(ev).LogOdds;
}

Console.WriteLine($"2 composantes : log evidence = {logEvidences[1]:F2}");

// Meilleur modèle
int meilleur = logEvidences[0] > logEvidences[1] ? 1 : 2;
Console.WriteLine($"\n=> Le modele a {meilleur} composante(s) est prefere");
=== Selection du nombre de composantes ===
Donnees : 5, 6, 7, 5,5, 6,5, 15, 16, 17, 14, 15,5, 16,5, 6, 15

Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
1 composante : log evidence = -45,89
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
2 composantes : log evidence = -31,35

=> Le modele a 2 composante(s) est prefere

Analyse des résultats : données bimodales

Données : deux groupes distincts autour de 6 et 15

Modèle Log evidence Interpretation
1 composante -45.89 Mal adapte (moyenne ~10.5 ne represente aucun groupe)
2 composantes -31.35 Bien adapte (capture les deux modes)

Différence : log(BF) = -31.35 - (-45.89) = 14.54

Un facteur de Bayes \(e^{14.54} \approx 2 \times 10^6\) en faveur du modèle a 2 composantes constitue une evidence decisive.

Lecon cle : Le facteur de Bayes detecte automatiquement la structure des données. Il prefere le modèle simple quand les données sont simples (section 3-4) et le modèle complexe quand les données l’exigent (ici).

6. Automatic Relevance Determination (ARD)

Principe

ARD utilise des priors hiérarchiques pour determiner automatiquement quelles features sont pertinentes.

Modèle

\[\alpha_f \sim \text{Gamma}(a, b)\] \[w_f \sim \mathcal{N}(0, \alpha_f^{-1})\]

Si \(\alpha_f\) devient grand, le poids \(w_f\) est contraint pres de 0 -> feature non pertinente.

Fidélité à la source (Tipping 2001 ; Bishop PRML §6.4.4 et §7.2). Le mécanisme d’ARD est le cœur du Sparse Bayesian Learning de Tipping : le prior hiérarchique \(\alpha_f \sim \text{Gamma}\) agit comme une « précision » apprise par inférence. Pour une feature non pertinente, les données ne contraignent pas \(w_f\), le posterior de \(\alpha_f\) croît vers de grandes valeurs, et le prior \(w_f \sim \mathcal{N}(0, \alpha_f^{-1})\) rétrécit le poids vers zéro — la feature est ainsi automatiquement désactivée par le modèle lui-même, sans seuillage manuel. C’est exactement le principe exploité par le Relevance Vector Machine (RVM), qui n’en retient qu’un petit sous-ensemble de « relevance vectors ».

Transition : de la comparaison de modèles a la sélection de features

Jusqu’ici, nous avons compare des modèles entiers (1 vs 2 gaussiennes, lineaire vs quadratique). Mais en pratique, on veut souvent repondre a une question plus fine :

Quelles features sont vraiment utiles dans mon modèle ?

C’est le problème de la sélection de variables. L’approche bayesienne offre une solution elegante : l’Automatic Relevance Determination (ARD).

Generation des données synthetiques

Nous creons un problème de regression ou : - Feature 1 : coefficient reel = 2.0 (pertinente) - Feature 2 : coefficient reel = 0.0 (non pertinente) - Feature 3 : coefficient reel = 3.0 (pertinente)

Le modèle ARD devra “decouvrir” automatiquement que la feature 2 n’apporte aucune information predictive.

// ARD pour regression

// Données : y = 2*x1 + 0*x2 + 3*x3 + bruit
// x2 est une feature non pertinente
int nSamples = 20;
int nFeatures = 3;
Random rng = new Random(42);

double[,] X = new double[nSamples, nFeatures];
double[] y = new double[nSamples];
double[] vraisPoids = { 2.0, 0.0, 3.0 };  // x2 a poids 0

for (int i = 0; i < nSamples; i++)
{
    for (int f = 0; f < nFeatures; f++)
    {
        X[i, f] = rng.NextDouble() * 2 - 1;  // [-1, 1]
    }
    y[i] = vraisPoids[0] * X[i, 0] + vraisPoids[1] * X[i, 1] + vraisPoids[2] * X[i, 2]
           + rng.NextDouble() * 0.5 - 0.25;  // Bruit
}

Console.WriteLine("=== ARD : Automatic Relevance Determination ===");
Console.WriteLine($"\nVrais poids : w1={vraisPoids[0]}, w2={vraisPoids[1]} (non pertinent), w3={vraisPoids[2]}");
=== ARD : Automatic Relevance Determination ===

Vrais poids : w1=2, w2=0 (non pertinent), w3=3

Construction du modèle ARD hiérarchique

Le modèle ARD introduit un hyperparametre de precision \(\alpha_f\) pour chaque feature \(f\) :

\[w_f \sim \mathcal{N}(0, \alpha_f^{-1})\]

Interpretation : - Si \(\alpha_f\) est petit (ex: 0.3), la variance \(1/\alpha_f\) est grande, donc \(w_f\) peut prendre des valeurs significatives - Si \(\alpha_f\) devient grand (ex: 10), la variance est petite, \(w_f\) est “pousse” vers 0

Les \(\alpha_f\) sont eux-mêmes des variables aleatoires avec prior Gamma(1, 1). L’inference determine simultanement les poids et leur pertinence.

// Modèle ARD
Range sampleRange = new Range(nSamples).Named("sample");
Range featureRange = new Range(nFeatures).Named("feature");

// Precisions par feature (ARD)
VariableArray<double> alpha = Variable.Array<double>(featureRange).Named("alpha");
alpha[featureRange] = Variable.GammaFromShapeAndScale(1, 1).ForEach(featureRange);

// Poids avec prior dependant de alpha
VariableArray<double> poids = Variable.Array<double>(featureRange).Named("poids");
using (Variable.ForEach(featureRange))
{
    poids[featureRange] = Variable.GaussianFromMeanAndPrecision(0, alpha[featureRange]);
}

// Bruit de l'observation
Variable<double> noisePrecision = Variable.GammaFromShapeAndScale(2, 1).Named("noise");

// Données
VariableArray2D<double> xVar = Variable.Array<double>(sampleRange, featureRange).Named("x");
VariableArray<double> yVar = Variable.Array<double>(sampleRange).Named("y");

using (Variable.ForEach(sampleRange))
{
    Variable<double> prediction = Variable.Constant(0.0);
    for (int f = 0; f < nFeatures; f++)
    {
        prediction = prediction + poids[f] * xVar[sampleRange, f];
    }
    yVar[sampleRange] = Variable.GaussianFromMeanAndPrecision(prediction, noisePrecision);
}

xVar.ObservedValue = X;
yVar.ObservedValue = y;

InferenceEngine moteurARD = new InferenceEngine(new ExpectationPropagation());
moteurARD.Compiler.CompilerChoice = CompilerChoice.Roslyn;
moteurARD.ShowFactorGraph = true;  // Activation de la visualisation

Gaussian[] poidsPost = moteurARD.Infer<Gaussian[]>(poids);
Gamma[] alphaPost = moteurARD.Infer<Gamma[]>(alpha);

Console.WriteLine("\nResultats ARD :");
for (int f = 0; f < nFeatures; f++)
{
    double wMean = poidsPost[f].GetMean();
    double wStd = Math.Sqrt(poidsPost[f].GetVariance());
    double alphaMean = alphaPost[f].GetMean();
    string relevance = alphaMean > 5 ? "faible" : alphaMean > 1 ? "moyenne" : "haute";
    Console.WriteLine($"  Feature {f+1} : poids = {wMean:F2} +/- {wStd:F2}, alpha = {alphaMean:F2} (pertinence {relevance})");
}

Console.WriteLine("\n=> Les features avec alpha eleve sont considerees non pertinentes");
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50

Resultats ARD :
  Feature 1 : poids = 2,04 +/- 0,12, alpha = 0,49 (pertinence haute)
  Feature 2 : poids = 0,02 +/- 0,11, alpha = 1,49 (pertinence moyenne)
  Feature 3 : poids = 2,97 +/- 0,15, alpha = 0,28 (pertinence haute)

=> Les features avec alpha eleve sont considerees non pertinentes

Visualisation du graphe de facteurs du modèle ARD.

// Visualisation du graphe de facteurs - Modèle ARD
display(HTML(FactorGraphHelper.GetLatestFactorGraphHtml()));
Model_06_22_26_21_17_01_25.svg
Model node0 poids[vint4][sample] node1 Multiply node0->node1 a node3 vdouble130[sample] node1->node3 node2 x[sample,vint5] node2->node1 b node18 Plus node3->node18 b node4 poids[vint6][sample] node5 Multiply node4->node5 a node7 vdouble134[sample] node5->node7 node6 x[sample,vint7] node6->node5 b node16 Plus node7->node16 b node8 poids[vint8][sample] node9 Multiply node8->node9 a node11 vdouble138[sample] node9->node11 node10 x[sample,vint9] node10->node9 b node13 Plus node11->node13 b node12 vdouble135[sample] node12->node13 a node14 vdouble139[sample] node13->node14 node19 Gaussian node14->node19 mean node15 vdouble131[sample] node15->node16 a node16->node12 node17 0 node17->node18 a node18->node15 node21 y[sample] node19->node21 node20 noise node20->node19 precision node22 2 node23 Sample node22->node23 shape node23->node20 node24 1 node24->node23 scale node25 0 node26 Gaussian node25->node26 mean node28 poids[feature] node26->node28 node27 alpha[feature] node27->node26 precision node28->node0 node28->node4 node28->node8 node29 1 node30 Sample node29->node30 shape node30->node27 node31 1 node31->node30 scale

Lecture du graphe de facteurs - Modèle ARD hiérarchique

Le graphe ARD illustre la structure hiérarchique a deux niveaux :

Niveau hyperparametres : - alpha[feature] : precision par feature (hyperparametre Gamma) - Le prior sur alpha contrôle la “force” de la regularisation

Niveau paramètres : - poids[feature] : poids de regression, chacun avec une precision alpha[f] différente - Les poids sont couples : poids[f] ~ N(0, 1/alpha[f])

Niveau données : - x[sample, feature] : matrice des features (observee) - y[sample] : cible (observee) - noise : precision du bruit (infere)

La structure “plate notation” avec ForEach créé des repetitions sur les ranges sample et feature, representees par des boites dans le graphe.

Analyse des résultats ARD

Comparaison vrais poids vs estimations :

Feature Vrai poids Estimé α estimé Pertinence
1 2.0 2.04 0.49 Haute ✓
2 0.0 0.02 1.49 Moyenne
3 3.0 2.97 0.28 Haute ✓

Interprétation des hyperparamètres α : - α petit (< 1) → le prior sur w est large → w peut prendre des valeurs significatives → feature pertinente - α grand (> 1) → le prior sur w est concentré autour de 0 → w contraint à ~0 → feature non pertinente

Pourquoi Feature 2 n’a pas α très élevé ?

Avec seulement 20 échantillons, le modèle reste incertain. α = 1.49 indique une pertinence “moyenne” plutôt que clairement nulle. Plus de données augmenteraient α pour cette feature.

Application pratique : ARD est utilisé en machine learning pour la sélection automatique de features sans validation croisée explicite.

Exercice : ARD avec 5 features – quelles features sont pertinentes ?

L’exemple précédent montrait l’ARD avec 3 features (dont 1 non pertinente). Dans cet exercice, vous allez appliquer l’ARD a un problème plus realiste avec 5 features, dont seulement 2 sont reellement informatives.

Enonce

On genere des données synthetiques selon :

\[y = 1.5 \cdot x_1 + 0 \cdot x_2 + 0 \cdot x_3 + 2.5 \cdot x_4 + 0 \cdot x_5 + \epsilon\]

Seules les features 1 et 4 contribuent a la prediction. Les features 2, 3 et 5 sont du bruit.

Travail demande : 1. Generez les données avec nSamples = 30 et nFeatures = 5 (seed 42) 2. Construisez le modèle ARD hiérarchique (reutilisez la structure de la section 6) 3. Lancez l’inference et affichez les poids posterieurs et les valeurs alpha pour chaque feature 4. Identifiez quelles features sont selectionnees (alpha faible = pertinente) 5. Comparez les poids estimes avec les vrais poids : {1.5, 0.0, 0.0, 2.5, 0.0}

Indice : Avec plus de features (5 vs 3) et plus de données (30 vs 20), les alpha des features non pertinentes devraient etre plus eleves qu’avec 3 features, car le modèle a plus d’information pour distinguer le signal du bruit. Utilisez le même prior Gamma(1, 1) sur les alpha et ExpectationPropagation pour l’inference.

// Exercice : ARD avec 5 features

// TODO: Étape 1 - Generer les données synthetiques
int nSamplesARD = 30;
int nFeaturesARD = 5;
double[] vraisPoidsARD = { 1.5, 0.0, 0.0, 2.5, 0.0 };
double[,] XARD = new double[nSamplesARD, nFeaturesARD];  // TODO: remplir avec Random(42)
double[] yARD = new double[nSamplesARD];                  // TODO: calculer y = sum(w_f * x_f) + bruit

// TODO: Étape 2 - Construire le modèle ARD hierarchique
// Range sampleRangeARD = new Range(nSamplesARD);
// Range featureRangeARD = new Range(nFeaturesARD);
// VariableArray<double> alphaARD = ...  (Gamma prior par feature)
// VariableArray<double> poidsARD = ... (Gaussian avec precision alphaARD)
// Variable<double> noiseARD = ...      (Gamma prior sur bruit)
// Relation: y = sum(poids[f] * x[f])

// TODO: Étape 3 - Inference avec ExpectationPropagation

// TODO: Étape 4 - Afficher les résultats
// Console.WriteLine("=== Résultats ARD (5 features) ===");
// Pour chaque feature : afficher poids moyen, ecart-type, alpha, pertinence

// TODO: Étape 5 - Comparer avec les vrais poids et conclure
// Quelles features ont ete correctement identifiees comme pertinentes/non pertinentes ?

Console.WriteLine("Exercice a completer");
Exercice a completer

7. Validation Croisee Bayesienne

Principe

Au lieu de diviser les données, utiliser la predictive posterieure pour evaluer le modèle.

Leave-One-Out (LOO)

\[\text{LOO-CV} = \sum_{i=1}^n \log P(y_i | y_{-i}, M)\]

Algorithme Leave-One-Out bayesien

Pour chaque point \(i\) : 1. Entrainer le modèle sur tous les points sauf \(i\) 2. Calculer la distribution predictive posterieure 3. Evaluer la log-probabilité du point \(i\) sous cette predictive

La variance predictive combine deux sources d’incertitude : - L’incertitude sur la moyenne (\(\text{Var}(\mu)\)) - Le bruit inherent des observations (\(1/\tau\))

\[\sigma^2_{\text{pred}} = \text{Var}(\mu) + \frac{1}{\mathbb{E}[\tau]}\]

// Validation LOO simplifiee

double[] dataLOO = { 10, 12, 11, 13, 12, 11, 14, 10, 12, 11 };
int nLOO = dataLOO.Length;

double totalLogPred = 0;

for (int i = 0; i < nLOO; i++)
{
    // Entrainer sur toutes les données sauf i
    Variable<double> mu = Variable.GaussianFromMeanAndPrecision(10, 0.01);
    Variable<double> prec = Variable.GammaFromShapeAndScale(2, 0.5);
    
    for (int j = 0; j < nLOO; j++)
    {
        if (j != i)
        {
            Variable<double> obs = Variable.GaussianFromMeanAndPrecision(mu, prec);
            obs.ObservedValue = dataLOO[j];
        }
    }
    
    InferenceEngine eng = new InferenceEngine();
    eng.Compiler.CompilerChoice = CompilerChoice.Roslyn;
    
    Gaussian muPost = eng.Infer<Gaussian>(mu);
    Gamma precPost = eng.Infer<Gamma>(prec);
    
    // Probabilité predictive pour le point i
    double predMean = muPost.GetMean();
    double predVar = muPost.GetVariance() + 1.0 / precPost.GetMean();
    
    double logProb = Gaussian.FromMeanAndVariance(predMean, predVar).GetLogProb(dataLOO[i]);
    totalLogPred += logProb;
}

Console.WriteLine("=== Validation Leave-One-Out ===");
Console.WriteLine($"\nLog predictive totale : {totalLogPred:F2}");
Console.WriteLine($"Log predictive moyenne : {totalLogPred / nLOO:F2}");
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
=== Validation Leave-One-Out ===

Log predictive totale : -18,13
Log predictive moyenne : -1,81

Interpretation de la validation LOO

Log predictive moyenne = -1.81

Cette metrique mesure la capacite du modèle a predire des observations non vues. Comparons avec des références :

Log predictive moyenne Qualite du modèle
> -1.0 Excellente
-1.0 a -2.0 Bonne
-2.0 a -3.0 Acceptable
< -3.0 Mauvaise

Notre valeur de -1.81 indique une bonne capacite predictive.

Avantage du LOO bayesien : Contrairement au LOO classique, cette méthode : - Utilise l’incertitude complete (pas juste une estimation ponctuelle) - Tient compte de l’incertitude sur les paramètres via la variance predictive - Ne necessite pas de reentrainer completement le modèle (en théorie, via des approximations)

Exercice : Sélection de modèle par validation croisee LOO

Dans cette section, vous avez vu la validation Leave-One-Out pour un modèle gaussien simple. L’objectif de cet exercice est d’etendre cette approche pour comparer deux modèles sur les mêmes données, et de verifier si le résultat LOO est coherent avec le facteur de Bayes.

Enonce

On considere les données bimodales de la section 5 :

double[] dataEx = { 5, 6, 7, 5.5, 6.5, 15, 16, 17, 14, 15.5, 16.5, 6, 15 };

Modèle A : Une seule gaussienne \(y \sim \mathcal{N}(\mu, \tau^{-1})\) avec priors : - \(\mu \sim \mathcal{N}(10, 100)\) (moyenne vague) - \(\tau \sim \text{Gamma}(2, 0.5)\)

Modèle B : Melange de deux gaussiennes (même structure que la section 5).

Travail demandé : 1. Implementez la validation LOO pour le modèle A (une gaussienne) 2. Implementez la validation LOO pour le modèle B (melange de deux gaussiennes) - utilisez VariationalMessagePassing 3. Comparez les scores LOO totaux : quel modèle est prefere ? 4. Comparez avec le résultat du facteur de Bayes de la section 5 : les deux méthodes donnent-elles le même gagnant ?

Indice : Pour le modèle B dans la boucle LOO, vous devez recreer le modèle de melange complet a chaque itération (en retirant le point i). La distribution predictive posterieure d’un melange n’est pas gaussienne – utilisez GetMean() et GetVariance() sur le résultat Gaussian inferé pour chaque point laisse de cote.

// Exercice : Sélection de modèle par validation croisee LOO

double[] dataEx = { 5, 6, 7, 5.5, 6.5, 15, 16, 17, 14, 15.5, 16.5, 6, 15 };
int nEx = dataEx.Length;

// TODO: Étape 1 - Implementer LOO pour le Modèle A (1 gaussienne)
// Pour chaque point i, entrainer sur dataEx sans le point i, calculer log P(dataEx[i])
double totalLogPredA = 0;

// TODO: Boucle LOO Modèle A

Console.WriteLine($"Modele A - LOO total : {totalLogPredA:F2}");

// TODO: Étape 2 - Implementer LOO pour le Modèle B (melange 2 gaussiennes)
// Utilisez VariationalMessagePassing pour la stabilite
double totalLogPredB = 0;

// TODO: Boucle LOO Modèle B
// Indice : pour chaque iteration, recreer le melange complet sans le point i
// puis inferer la posteriorie et evaluer la log-probabilité du point laisse de cote

Console.WriteLine($"Modele B - LOO total : {totalLogPredB:F2}");

// TODO: Étape 3 - Comparer les résultats
Console.WriteLine("\n=== Comparaison LOO ===");
// Quel modèle est prefere par LOO ?
// Est-ce coherent avec le facteur de Bayes de la section 5 (2 composantes preferees) ?

Console.WriteLine("Exercice a completer");
Modele A - LOO total : 0,00
Modele B - LOO total : 0,00

=== Comparaison LOO ===
Exercice a completer

Exercice : Comparer les critères BIC et evidence approximee

Dans les sections précédentes, nous avons utilise l’evidence exacte (marginal likelihood) calculee par Infer.NET pour comparer des modèles. En pratique, l’evidence exacte est souvent incalculable et on utilise des approximations comme le BIC (Bayesian Information Criterion).

Enonce

Le BIC est défini par :

\[\text{BIC} = -2 \ln(\hat{L}) + k \ln(n)\]

ou \(\hat{L}\) est la vraisemblance maximale, \(k\) le nombre de paramètres et \(n\) le nombre d’observations. Un BIC plus faible indique un meilleur modèle.

On reprend les données bimodales de la section 5 :

double[] dataBIC = { 5, 6, 7, 5.5, 6.5, 15, 16, 17, 14, 15.5, 16.5, 6, 15 };

Travail demande : 1. Pour le modèle a 1 gaussienne, calculez le BIC en estimant mu et tau par maximum de vraisemblance (moyenne empirique et variance inverse) 2. Pour le modèle a 2 gaussiennes, utilisez les posteriors Infer.NET de la section 5 comme approximation du MLE, puis calculez le BIC (k = 5 paramètres : mu1, mu2, tau, poids, + 1 bruit) 3. Comparez les classements BIC vs facteur de Bayes : les deux méthodes selectionnent-elles le même modèle ? 4. Affichez un tableau comparatif : | Critere | Modèle 1 | Modèle 2 | Gagnant |

Indice : Pour le BIC du modèle a 1 gaussienne, \(k=2\) (mu + tau). La log-vraisemblance se calcule en sommant Gaussian.FromMeanAndPrecision(mu_hat, tau_hat).GetLogProb(dataBIC[i]) pour chaque point. Pour le modèle a 2 gaussiennes, \(k=5\) (mu1, mu2, tau, poids + variance commune). Le BIC penalise davantage les modèles complexes que le facteur de Bayes – observez si la penalite change le gagnant.

// Exercice : Comparer les criteres BIC et evidence approximee

double[] dataBIC = { 5, 6, 7, 5.5, 6.5, 15, 16, 17, 14, 15.5, 16.5, 6, 15 };
int nBIC = dataBIC.Length;

// TODO: Étape 1 - Calculer le BIC pour le modèle a 1 gaussienne (k=2)
// Estimer mu_hat = moyenne empirique, tau_hat = 1 / variance empirique
// Puis BIC = -2 * sum(log P(x_i | mu_hat, tau_hat)) + k * ln(n)
double bicModele1 = 0;

// Indice : double muHat = dataBIC.Average();
// Indice : double varHat = dataBIC.Select(x => (x - muHat) * (x - muHat)).Sum() / nBIC;
// Indice : double tauHat = 1.0 / varHat;
// Indice : double logLik = dataBIC.Sum(x => Gaussian.FromMeanAndPrecision(muHat, tauHat).GetLogProb(x));
// Indice : bicModele1 = -2 * logLik + 2 * Math.Log(nBIC);

Console.WriteLine($"Modele 1 (1 gaussienne) - BIC : {bicModele1:F2}");

// TODO: Étape 2 - Calculer le BIC pour le modèle a 2 gaussiennes (k=5)
// Utilisez les posteriors de la section 5 ou estimez par MLE
double bicModele2 = 0;

// Indice : k=5 parametres (mu1, mu2, tau, poids, variance)
// Indice : Pour chaque point, la vraisemblance est P(x_i) = w * N(x_i|mu1,tau) + (1-w) * N(x_i|mu2,tau)
// Indice : log P(x_i) = log(w * exp(logN1) + (1-w) * exp(logN2))

Console.WriteLine($"Modele 2 (2 gaussiennes) - BIC : {bicModele2:F2}");

// TODO: Étape 3 - Comparer BIC vs facteur de Bayes
Console.WriteLine("\n=== Comparaison BIC vs Facteur de Bayes ===");
// Indice : Le facteur de Bayes de la section 5 favorisait le modèle a 2 composantes (log BF ~ 14.5)
// Indice : Le BIC favorise-t-il le meme modèle ? Si oui, les deux méthodes sont coherentes.
// Indice : Si non, expliquez pourquoi (taille d'echantillon, approximation BIC, etc.)

// TODO: Étape 4 - Afficher le tableau comparatif
// | Critere              | Modèle 1 | Modèle 2 | Gagnant    |
// |----------------------|----------|----------|------------|
// | BIC (plus petit=mieux)| ...     | ...      | ...        |
// | log Evidence          | -45.89  | -31.35   | Modèle 2   |

Console.WriteLine("Exercice a completer");
Modele 1 (1 gaussienne) - BIC : 0,00
Modele 2 (2 gaussiennes) - BIC : 0,00

=== Comparaison BIC vs Facteur de Bayes ===
Exercice a completer

8. Exemple guide : Comparer Polynomes

Enonce

Comparez trois modèles de regression : - Lineaire : y = ax + b - Quadratique : y = ax^2 + bx + c - Cubique : y = ax^3 + bx^2 + cx + d

Sur des données lineaires avec bruit.

Mise en pratique : comparaison lineaire vs quadratique

Les données sont generees selon \(y = 2x + 1 + \epsilon\) (relation lineaire).

Modèles a comparer : - Lineaire : \(y = ax + b\) (2 paramètres) - Quadratique : \(y = ax^2 + bx + c\) (3 paramètres)

Le modèle quadratique peut representer la relation lineaire (avec \(a \approx 0\)), mais paie un “cout de complexite” pour ce paramètre inutile.

Hint : Pour ajouter un modèle cubique, il suffirait d’ajouter un terme \(d \times x^3\). Le même raisonnement s’applique : plus de paramètres = plus de penalite si ils ne sont pas necessaires.

// Exemple guide : Comparaison de modèles polynomiaux

// Données lineaires : y = 2*x + 1 + bruit
double[] xPoly = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
double[] yPoly = { 1.2, 3.1, 4.8, 7.2, 8.9, 11.1, 13.0, 14.8, 17.2, 19.1 };
int nPoly = xPoly.Length;

Console.WriteLine("=== Comparaison de Modeles Polynomiaux ===");
Console.WriteLine("Vraie relation : y = 2*x + 1\n");

// Modèle lineaire
Variable<bool> evLin = Variable.Bernoulli(0.5).Named("evidence_lin");
using (Variable.If(evLin))
{
    Variable<double> a = Variable.GaussianFromMeanAndVariance(0, 10).Named("a_lin");
    Variable<double> b = Variable.GaussianFromMeanAndVariance(0, 10).Named("b_lin");
    Variable<double> noise = Variable.GammaFromShapeAndScale(2, 0.5).Named("noise_lin");
    
    for (int i = 0; i < nPoly; i++)
    {
        Variable<double> pred = (a * xPoly[i] + b).Named($"pred_lin_{i}");
        Variable<double> obs = Variable.GaussianFromMeanAndPrecision(pred, noise).Named($"obs_lin_{i}");
        obs.ObservedValue = yPoly[i];
    }
}
var engLin = new InferenceEngine();
engLin.Compiler.CompilerChoice = CompilerChoice.Roslyn;
engLin.ShowFactorGraph = true;  // Activation de la visualisation
double logEvLin = engLin.Infer<Bernoulli>(evLin).LogOdds;
Console.WriteLine($"Modele lineaire : log evidence = {logEvLin:F2}");

// Modèle quadratique
Variable<bool> evQuad = Variable.Bernoulli(0.5).Named("evidence_quad");
using (Variable.If(evQuad))
{
    Variable<double> a = Variable.GaussianFromMeanAndVariance(0, 10).Named("a_quad");
    Variable<double> b = Variable.GaussianFromMeanAndVariance(0, 10).Named("b_quad");
    Variable<double> c = Variable.GaussianFromMeanAndVariance(0, 10).Named("c_quad");
    Variable<double> noise = Variable.GammaFromShapeAndScale(2, 0.5).Named("noise_quad");
    
    for (int i = 0; i < nPoly; i++)
    {
        Variable<double> pred = (a * xPoly[i] * xPoly[i] + b * xPoly[i] + c).Named($"pred_quad_{i}");
        Variable<double> obs = Variable.GaussianFromMeanAndPrecision(pred, noise).Named($"obs_quad_{i}");
        obs.ObservedValue = yPoly[i];
    }
}
var engQuad = new InferenceEngine();
engQuad.Compiler.CompilerChoice = CompilerChoice.Roslyn;
engQuad.ShowFactorGraph = true;  // Activation de la visualisation
double logEvQuad = engQuad.Infer<Bernoulli>(evQuad).LogOdds;
Console.WriteLine($"Modele quadratique : log evidence = {logEvQuad:F2}");

// Meilleur modèle
string meilleurMod = logEvLin > logEvQuad ? "Lineaire" : "Quadratique";
Console.WriteLine($"\n=> Le modele {meilleurMod} est prefere (rasoir d'Occam)");
=== Comparaison de Modeles Polynomiaux ===
Vraie relation : y = 2*x + 1

Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Modele lineaire : log evidence = -14,03
Compiling model...done.
Iterating: 
.........|.........|.........|.........|.........| 50
Modele quadratique : log evidence = -20,28

=> Le modele Lineaire est prefere (rasoir d'Occam)

Visualisation du graphe de facteurs du modèle polynomial.

// Visualisation du graphe de facteurs - Modèle quadratique (dernier compile)
display(HTML(FactorGraphHelper.GetLatestFactorGraphHtml()));
Model_06_22_26_21_17_07_14.svg
Model node0 Bernoulli(0,5) node1 Random node0->node1 dist node2 evidence_quad node1->node2 node3 0 node4 GaussianFromMeanAndVariance node3->node4 mean node6 a_quad node4->node6 node5 10 node5->node4 variance node19 Multiply node6->node19 a node34 Multiply node6->node34 a node49 Multiply node6->node49 a node64 Multiply node6->node64 a node79 Multiply node6->node79 a node94 Multiply node6->node94 a node109 Multiply node6->node109 a node124 Multiply node6->node124 a node139 Multiply node6->node139 a node154 Multiply node6->node154 a node7 0 node8 GaussianFromMeanAndVariance node7->node8 mean node10 b_quad node8->node10 node9 10 node9->node8 variance node25 Multiply node10->node25 a node40 Multiply node10->node40 a node55 Multiply node10->node55 a node70 Multiply node10->node70 a node85 Multiply node10->node85 a node100 Multiply node10->node100 a node115 Multiply node10->node115 a node130 Multiply node10->node130 a node145 Multiply node10->node145 a node160 Multiply node10->node160 a node11 0 node12 GaussianFromMeanAndVariance node11->node12 mean node14 c_quad node12->node14 node13 10 node13->node12 variance node30 Plus node14->node30 b node45 Plus node14->node45 b node60 Plus node14->node60 b node75 Plus node14->node75 b node90 Plus node14->node90 b node105 Plus node14->node105 b node120 Plus node14->node120 b node135 Plus node14->node135 b node150 Plus node14->node150 b node165 Plus node14->node165 b node15 2 node16 Sample node15->node16 shape node18 noise_quad node16->node18 node17 0,5 node17->node16 scale node32 Gaussian node18->node32 precision node47 Gaussian node18->node47 precision node62 Gaussian node18->node62 precision node77 Gaussian node18->node77 precision node92 Gaussian node18->node92 precision node107 Gaussian node18->node107 precision node122 Gaussian node18->node122 precision node137 Gaussian node18->node137 precision node152 Gaussian node18->node152 precision node167 Gaussian node18->node167 precision node21 vdouble354 node19->node21 node20 0 node20->node19 b node22 Multiply node21->node22 a node24 vdouble356 node22->node24 node23 0 node23->node22 b node28 Plus node24->node28 a node27 vdouble358 node25->node27 node26 0 node26->node25 b node27->node28 b node29 vdouble359 node28->node29 node29->node30 a node31 pred_quad_0 node30->node31 node31->node32 mean node33 1,2 node32->node33 node36 vdouble363 node34->node36 node35 1 node35->node34 b node37 Multiply node36->node37 a node39 vdouble365 node37->node39 node38 1 node38->node37 b node43 Plus node39->node43 a node42 vdouble367 node40->node42 node41 1 node41->node40 b node42->node43 b node44 vdouble368 node43->node44 node44->node45 a node46 pred_quad_1 node45->node46 node46->node47 mean node48 3,1 node47->node48 node51 vdouble372 node49->node51 node50 2 node50->node49 b node52 Multiply node51->node52 a node54 vdouble374 node52->node54 node53 2 node53->node52 b node58 Plus node54->node58 a node57 vdouble376 node55->node57 node56 2 node56->node55 b node57->node58 b node59 vdouble377 node58->node59 node59->node60 a node61 pred_quad_2 node60->node61 node61->node62 mean node63 4,8 node62->node63 node66 vdouble381 node64->node66 node65 3 node65->node64 b node67 Multiply node66->node67 a node69 vdouble383 node67->node69 node68 3 node68->node67 b node73 Plus node69->node73 a node72 vdouble385 node70->node72 node71 3 node71->node70 b node72->node73 b node74 vdouble386 node73->node74 node74->node75 a node76 pred_quad_3 node75->node76 node76->node77 mean node78 7,2 node77->node78 node81 vdouble390 node79->node81 node80 4 node80->node79 b node82 Multiply node81->node82 a node84 vdouble392 node82->node84 node83 4 node83->node82 b node88 Plus node84->node88 a node87 vdouble394 node85->node87 node86 4 node86->node85 b node87->node88 b node89 vdouble395 node88->node89 node89->node90 a node91 pred_quad_4 node90->node91 node91->node92 mean node93 8,9 node92->node93 node96 vdouble399 node94->node96 node95 5 node95->node94 b node97 Multiply node96->node97 a node99 vdouble401 node97->node99 node98 5 node98->node97 b node103 Plus node99->node103 a node102 vdouble403 node100->node102 node101 5 node101->node100 b node102->node103 b node104 vdouble404 node103->node104 node104->node105 a node106 pred_quad_5 node105->node106 node106->node107 mean node108 11,1 node107->node108 node111 vdouble408 node109->node111 node110 6 node110->node109 b node112 Multiply node111->node112 a node114 vdouble410 node112->node114 node113 6 node113->node112 b node118 Plus node114->node118 a node117 vdouble412 node115->node117 node116 6 node116->node115 b node117->node118 b node119 vdouble413 node118->node119 node119->node120 a node121 pred_quad_6 node120->node121 node121->node122 mean node123 13 node122->node123 node126 vdouble417 node124->node126 node125 7 node125->node124 b node127 Multiply node126->node127 a node129 vdouble419 node127->node129 node128 7 node128->node127 b node133 Plus node129->node133 a node132 vdouble421 node130->node132 node131 7 node131->node130 b node132->node133 b node134 vdouble422 node133->node134 node134->node135 a node136 pred_quad_7 node135->node136 node136->node137 mean node138 14,8 node137->node138 node141 vdouble426 node139->node141 node140 8 node140->node139 b node142 Multiply node141->node142 a node144 vdouble428 node142->node144 node143 8 node143->node142 b node148 Plus node144->node148 a node147 vdouble430 node145->node147 node146 8 node146->node145 b node147->node148 b node149 vdouble431 node148->node149 node149->node150 a node151 pred_quad_8 node150->node151 node151->node152 mean node153 17,2 node152->node153 node156 vdouble435 node154->node156 node155 9 node155->node154 b node157 Multiply node156->node157 a node159 vdouble437 node157->node159 node158 9 node158->node157 b node163 Plus node159->node163 a node162 vdouble439 node160->node162 node161 9 node161->node160 b node162->node163 b node164 vdouble440 node163->node164 node164->node165 a node166 pred_quad_9 node165->node166 node166->node167 mean node168 19,1 node167->node168

Lecture du graphe de facteurs - Modèle quadratique

Le graphe montre la structure du modèle quadratique \(y = ax^2 + bx + c\) :

  • a_quad, b_quad, c_quad : les trois coefficients du polynome (priors Gaussiens)
  • noise_quad : precision du bruit d’observation (prior Gamma)
  • evidence_quad : variable indicatrice pour le calcul d’evidence
  • pred_quad_i : predictions intermediaires (combinaison des coefficients)
  • obs_quad_i : observations (valeurs fixees)

Comparativement au modèle lineaire, ce graphe contient un paramètre supplementaire (c_quad), ce qui augmente la complexite du modèle et la “surface” du prior - d’ou la penalisation par le rasoir d’Occam bayesien.

Analyse de l’exercice polynomes

Résultats :

Modèle Paramètres Log evidence
Lineaire a, b (2) -14.03
Quadratique a, b, c (3) -20.28

Facteur de Bayes : \(\exp(-14.03 - (-20.28)) = \exp(6.25) \approx 518\)

Le modèle lineaire est decisement prefere (BF > 150).

Pourquoi le modèle quadratique perd-il ?

  1. Données generees lineairement : y = 2x + 1 + bruit
  2. Coefficient quadratique inutile : le paramètre \(a\) (coefficient de \(x^2\)) n’apporte rien
  3. Penalite de complexite : le prior sur \(a\) “dilue” la vraisemblance

Exercice supplementaire : Que se passerait-il si les données etaient generees par y = 0.1x^2 + 2x + 1 ? Le terme quadratique est present mais faible. Le modèle lineaire pourrait encore gagner si le signal quadratique est noye dans le bruit - c’est la balance ajustement vs complexite en action.

9. Resume

Concept Description
Evidence P(D|M) - vraisemblance marginale
Facteur de Bayes Ratio d’evidences pour comparer modèles
Rasoir d’Occam Préférence automatique pour modèles simples
ARD Sélection automatique de features
LOO-CV Validation sans diviser les données

Prochaine étape

Dans Infer-11-Topic-Models, nous explorerons :

  • Latent Dirichlet Allocation (LDA)
  • Modelisation de topics dans les documents
  • Inference sur structures hiérarchiques complexes

Annexe : Distributions et concepts

Distributions utilisees dans ce notebook

Distribution Rôle Paramètres typiques
Bernoulli(0.5) Variable indicatrice pour calcul d’evidence p=0.5 (prior non informatif)
GaussianFromMeanAndPrecision Modèle d’observation mean~15, precision~1
GammaFromShapeAndScale Prior sur precision shape=2, scale=0.5
Beta(1,1) Prior sur proportion de melange Prior uniforme sur [0,1]

Concepts probabilistes illustres

Concept Section Application
Evidence marginale \(P(D\|M)\) 3, 5 Comparer modèles sans validation croisee
Facteur de Bayes 4 Quantifier la préférence pour un modèle
Rasoir d’Occam bayesien 3-5 Penalisation automatique de la complexite
Priors hiérarchiques 6 ARD pour sélection de features
Distribution predictive 7 LOO-CV bayesien

Applications pratiques

  • Sélection du nombre de composantes : Clustering avec nombre de clusters inconnu
  • Sélection de features : Regression avec beaucoup de covariables
  • Choix d’architecture : Reseaux bayesiens avec structure variable
  • Comparaison de familles : Lineaire vs non-lineaire, parametrique vs non-parametrique

Points cles a retenir

1. Le rasoir d’Occam est automatique

La sélection de modèles bayesienne penalise naturellement la complexite. Pas besoin de critères ad hoc comme l’AIC ou le BIC - l’evidence marginale fait le travail.

2. L’echelle compte

Méthode Quand l’utiliser
Facteur de Bayes Comparer 2-3 modèles distincts
ARD Sélectionner parmi de nombreuses features
LOO-CV Evaluer la capacite predictive

3. Les priors sont importants

Les priors vagues (\(\sigma^2 = 10\) sur les poids) penalisent moins que des priors informatifs. Un mauvais choix de prior peut fausser la comparaison.

Conseil pratique : Pour une comparaison equitable, utilisez des priors de même “force” (même variance) sur les paramètres comparables entre modèles.

10. Exercice : Trouver le Meilleur Modèle pour des Données Quadratiques

Enonce

Vous disposez de données generees par y = 2*x^2 - 3*x + 1 + bruit :

x = {-2, -1, 0, 1, 2, 3}
y = {14.8, 5.9, 1.1, -0.2, 3.8, 10.1}

Comparez 3 modèles de regression polynomiale : 1. Lineaire : y = a*x + b (2 paramètres) 2. Quadratique : y = a*x^2 + b*x + c (3 paramètres) 3. Cubique : y = a*x^3 + b*x^2 + c*x + d (4 paramètres)

Quel modèle a le meilleur log evidence ? Le cubique surpasse-t-il le quadratique ?

// Exercice : Sélection de modèle polynomial sur données quadratiques
Console.WriteLine("Exercice a completer : selection de modele polynomial");

// Données quadratiques : y = 2*x^2 - 3*x + 1 + bruit
double[] xData = { -2, -1, 0, 1, 2, 3 };
double[] yData = { 14.8, 5.9, 1.1, -0.2, 3.8, 10.1 };

// TODO: Construire les matrices de features polynomiales
// Lineaire  : X[i] = [1, x_i]
// Quadratique: X[i] = [1, x_i, x_i^2]
// Cubique   : X[i] = [1, x_i, x_i^2, x_i^3]
// using Microsoft.ML.Probabilistic.Math;

// TODO: Creer une fonction CalculLogEvidence(Vector[] features, double[] y)
// (Reutilisez la structure de la section 8 de l'exemple guide)

// TODO: Calculer le log evidence pour chaque modèle

// TODO: Afficher et comparer
// Quel modèle gagne ? Expliquez pourquoi le cubique ne bat pas forcement le quadratique.
Exercice a completer : selection de modele polynomial

Conclusion

Ce notebook a presente la sélection de modèles bayesienne : evidence, facteur de Bayes, ARD et validation croisee LOO.

Méthode Principe Quand l’utiliser
Evidence (marginal likelihood) P(D|M) integre sur les paramètres Comparer 2-3 modèles
Facteur de Bayes Ratio des evidences, echelle de Jeffreys Quantifier la préférence
ARD Priors hiérarchiques Gamma -> precision par feature Sélection automatique de features
LOO-CV Log-probabilité predictive leave-one-out Evaluer la capacite predictive
Distribution Rôle
Bernoulli(0.5) Variable indicatrice pour le calcul d’evidence
Gaussian Priors sur les poids et coefficients
Gamma Priors sur les precisions (bruit, ARD)
Beta Prior sur les proportions de melange

Rasoir d’Occam bayesien : L’evidence penalise automatiquement la complexite. Un modèle plus simple avec un bon ajustement bat toujours un modèle complexe dont les paramètres supplementaires n’apportent rien. Cela rend la comparaison objective, sans critères ad hoc.

Retour au sommet