Serie : Programmation Probabiliste avec Infer.NET Duree estimee : 2h30 Prerequis : C# et .NET Interactive, notions de probabilités, loi normale, inférence bayésienne
Objectifs d’apprentissage
Comprendre le concept de variable aléatoire en programmation probabiliste
Modeliser un problème d’incertitude avec des variables Variable<T> et Infer.NET
Entrainer un modèle bayesien simple (gaussien) par inférence postérieure
Refactorer un modèle en classes C# orientees objet reutilisables
Implementer l’apprentissage en ligne par mise a jour des a priori
Comparer des modèles (simple vs mélange) avec la preuve bayésienne (log evidence)
Introduction à la programmation probabiliste avec Infer.Net
Avant-propos
Les ordinateurs sont rigoureusement logiques, mais le monde réel ne l’est pas. Par exemple, supposons que vous deviez représenter ce qu’un utilisateur griffonne sur un écran tactile sous forme de mot. Les gens ne sont généralement pas très appliqués dans leur écriture, donc ce gribouillis peut correspondre à plusieurs mots possibles comme “hill”, “bull” ou “hello”. L’utilisateur sait ce qu’il a écrit, mais pour l’application, la valeur correcte est incertaine. Cependant, certaines valeurs sont plus probables que d’autres.
Comment représentez-vous une telle incertitude dans un programme ? Des variables conventionnelles telles que bool ou int doivent avoir des valeurs bien définies. Une solution est d’utiliser des variables aléatoires.
Variables aléatoires
La programmation probabiliste est conçue pour gérer une telle incertitude en utilisant des variables aléatoires. Une variable aléatoire représente un ensemble ou une plage de valeurs possibles, chacune associée à une probabilité.
// Exemple de création d'une variable aléatoireVariable<bool> isHeads = Variable.Bernoulli(0.5);
Modèles probabilistes
Un modèle probabiliste définit comment les utilisateurs transforment les mots en gribouillis. Ce modèle reconnaît que le même mot peut conduire à différents gribouillis et que des mots différents peuvent conduire à des gribouillis similaires.
Inférence probabiliste
L’inférence probabiliste utilisé une méthodologie statistique connue sous le nom d’inférence bayésienne pour raisonner rétrospectivement d’une observation jusqu’à son origine.
Apprentissage probabiliste
Un modèle a généralement un ensemble de paramètres ajustables qui régissent son comportement. Pour adapter les paramètres au style d’écriture d’un utilisateur, un programme probabiliste peut traiter les paramètres du modèle eux-mêmes comme des variables aléatoires et apprendre les valeurs réelles des paramètres en fonction des entrées de l’utilisateur.
Présentation d’Infer.Net
Qu’est-ce que Infer.Net
Infer.NET est un framework permettant d’exécuter l’inférence bayésienne dans des modèles graphiques. Il fournit les algorithmes de passe-messages et les routines statistiques nécessaires à la réalisation d’inférences pour une grande variété d’applications.
Les principales caractéristiques d’Infer.NET sont :
Langage de modélisation : Supporte les variables univariées et multivariées, continues et discrètes.
Algorithmes d’inférence : Inclut la propagation d’espérance (EP), la propagation des convictions, le passage de messages variationnels et l’échantillonnage de Gibbs.
Conçu pour l’inférence à grande échelle : Compile les modèles dans du code source dédié.
Extensible par l’utilisateur : Permet d’ajouter des distributions de probabilité, des facteurs, des opérations de message et des algorithmes d’inférence.
Comment fonctionne Infer.NET
Infer.NET fonctionne en compilant une définition de modèle dans le code source nécessaire pour calculer un ensemble de requêtes d’inférence sur le modèle.
Création de la définition de modèle : Utilisation de l’API de modélisation.
Compilation du modèle : Le compilateur crée le code source nécessaire à l’exécution des requêtes d’inférence.
Compilation du code source : Pour créer un algorithme compilé.
Exécution de l’inférence : Utilisation du moteur d’inférence pour produire les distributions marginales demandées.
Installation des Packages Nuget et Usings
Pour utiliser Infer.NET dans votre projet .NET Interactive, vous devez installer le package Nuget Microsoft.ML.Probabilistic et inclure les usings nécessaires.
The below script needs to be able to find the current output cell; this is an easy method to get it.
Installed Packages
Microsoft.ML.Probabilistic, 0.4.2504.701
Microsoft.ML.Probabilistic.Compiler, 0.4.2504.701
Packages NuGet Microsoft.ML.Probabilistic charges
1a. Ce que l’installation etablit — et pourquoi le nom du paquet compte
La sortie Packages NuGet Microsoft.ML.Probabilistic charges est plus informative qu’elle n’en a l’air : Infer.NET n’est plus un paquet autonome. Il vit désormais a l’interieur de Microsoft.ML.Probabilistic, la bibliothèque probabiliste de la galaxie ML.NET. Deux consequences pratiques pour tout le reste du notebook.
D’abord, la rumeur tenace selon laquelle « Infer.NET est un projet abandonne » se lit ici pour ce qu’elle est : le projet a change d’adresse, pas disparu. Le moteur qui compilé les modèles et l’API Variable.* sont ceux d’Infer.NET, sous un autre nom de paquet.
Ensuite, l’installation est un geste unique et suffisant : tout ce que ce notebook utilisé — modèles, moteur d’inférence, distributions a posteriori — vient de ce seul paquet. Il n’y a pas de dependance native a installer, pas de compilateur externe a cabler. C’est ce qui rend le notebook executable de bout en bout sur une machine nue, et c’est cette propriete qui permet de committer des sorties réelles plutot qu’un mode degrade.
(Infer fait désormais parti de la bibliothèque ML.Net)
Import des espaces de noms essentiels
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("Espaces de noms Microsoft.ML.Probabilistic importes");
Espaces de noms Microsoft.ML.Probabilistic importes
1b. Ce que deux espaces de noms separent
Espaces de noms Microsoft.ML.Probabilistic importes : l’import tient en deux lignes, et la separation n’est pas cosmetique.
Le premier espace porte les variables aléatoires et les operateurs — Variable.Bernoulli, Variable.GaussianFromMeanAndPrecision, Variable.If. C’est le vocabulaire avec lequel on écrit un modèle. Le second porte les algorithmes et le moteur — InferenceEngine, CompilerChoice, Algorithms. C’est l’outillage qui execute le modèle.
Retenez la frontiere, elle structuré tout ce qui suit : un modèle Infer.NET se lit comme une declaration (des variables et des liens de dependance), jamais comme une suite d’instructions. La cellule suivante va le montrer sur trois lignes — et c’est cette separation qui explique que l’on puisse changer d’algorithme d’inférence sans reecrire une seule ligne du modèle.
Un exemple simple
Voici un exemple d’utilisation d’Infer.NET pour déterminer la probabilité d’obtenir deux faces lors du lancement de deux pièces non biaisées.
Compiling model...done.
Probabilité d’avoir deux faces: Bernoulli(0,25)
1c. Bernoulli(0,25) : la première verification arithmetique du notebook
La sortie Probabilite d'avoir deux faces: Bernoulli(0,25) est le premier résultat verifiable du notebook, et il faut le verifier tout de suite : c’est lui qui etablit que la chaine complete (modèle -> moteur -> requête) fonctionne reellement.
Deux pièces independantes donnent 0,25. Chacune vaut 0,5, et les deux lancers sont independants dans le modèle. Le produit 0,5 x 0,5 = 0,25 est donc exactement ce que le moteur rend. Un modèle mal cable — pièces correlees, mauvaise distribution, requête sur la mauvaise variable — rendrait un autre nombre, et le desaccord serait visible immediatement.
C’est cette propriete qu’il faut conserver comme contrôle positif pour tout le reste du notebook : a chaque fois qu’une sortie sera plus difficile a lire (jusqu’au facteur de Bayes de la section 7), on pourra revenir ici se rappeler que le moteur ne se contente pas d’imprimer des distributions plausibles — il en calcule.
A noter la forme Bernoulli(0,25) : la notation emploie la virgule decimale. La même convention d’affichage reviendra partout, y compris dans Gaussian(15,33, 1,32), ou elle se combine avec un second piege — plus difficile, celui-la (section 2a).
Ce court exemple contient les trois éléments clés de tout programme Infer.NET :
Définition d’un modèle probabiliste : Les variables aléatoires premierePiece et deuxiemePiece et la variable dépendante deuxFaces.
Création d’un moteur d’inférence : Le moteur d’inférence est créé et configuré.
Exécution d’une requête d’inférence : Le moteur est utilisé pour déduire la distribution marginale de deuxFaces.
Exercice 1 : Lancer de trois pièces et probabilités conditionnelles
Objectif : Etendre l’exemple des deux pièces pour modeliser trois lancers independants et calculer des probabilités conditionnelles.
Contexte : Vous lancez trois pièces non biaisées. Vous observez que la première est tombee sur face. Quelle est la probabilité que les trois soient face ?
Indices : - Indice 1 : Utilisez Variable.Bernoulli(0.5) pour chaque piece - Indice 2 : Combinez les trois avec l’opérateur & - Indice 3 : Pour le conditionnement, utilisez ObservedValue sur la première piece
// Exercice 1 : Lancer de trois pieces// TODO etudiant : Creer trois variables booleennes pour trois pieces// TODO etudiant : Calculer la probabilite que les trois soient face// TODO etudiant : Conditionner sur la premiere piece etant face, puis recalculerConsole.WriteLine("Exercice a completer : lancer de trois pieces");
Exercice a completer : lancer de trois pieces
Mise en œuvre d’Infer.Net dans un exemple détaillé
Contexte
Scénario
Les programmes présentés ici sont basés sur le scénario suivant :
Plusieurs de vos collègues et vous-même rendez-vous à vélo chaque jour au travail.
Le temps de trajet d’un cycliste varie de jour en jour et sa valeur est donc aléatoire.
L’incertitude du temps de trajet est représentée par une distribution de probabilité qui définit le temps de trajet moyen et combien il varie.
L’application apprendra cette distribution à partir de plusieurs temps de trajet observés et utilisera ces connaissances pour faire des prévisions sur les temps de déplacement futurs.
Création du modèle
La première étape consiste à créer les variables aléatoires dureeMoyenne et bruitTrafic avec des distributions initiales.
2a. Le piege fondateur : GaussianFromMeanAndPrecision(15, 0.01) n’est pas un a priori serre
Le modèle est declare par Variable.GaussianFromMeanAndPrecision(15, 0.01) et Variable.GammaFromShapeAndScale(2, 0.5). Lisez ces deux lignes avant de regarder la suite, parce que le nom de la fonction est le seul endroit ou le second argument se declare comme une précision :
Ligne de code
Second argument
Sa lecture correcte
Variance equivalente
GaussianFromMeanAndPrecision(15, 0.01)
précision 0,01
1 / 0,01
100
GammaFromShapeAndScale(2, 0.5)
forme et échelle
moyenne = 2 x 0,5 = 1,0
précision 1,0 -> variance 1,0
Le reflexe naturel — lire 0.01 comme une variance — donnerait un écart type de 0,1 minute : un a priori extraordinairement serre, qui ecraserait les observations et forcerait la moyenne a rester collee a 15. Ce n’est pas ce que fait ce modèle. La précision 0,01 equivaut a une variance de 100, soit un écart type de 10 minutes : un a priori volontairement vague, presque sans opinion.
La différence n’est pas theorique, elle est lisible dans les résultats. La section 2b montre que la moyenne a posteriori vaut 15,33 après trois observations dont la moyenne arithmetique est exactement 15,33 : le posterior est entierement détermine par les données, ce qui n’est possible que parce que l’a priori laissait la place. Avec un a priori de variance 0,01, la même experience aurait rendu une moyenne coincee pres de 15.
Le vrai enseignement est methodologique : dans Infer.NET, le parametrage est porte par le nom de la fabrique, et une même distribution s’écrit de plusieurs facons selon la fabrique choisie. La section 6a montrera que ce notebook emploie, quelques cellules plus loin, l’autre notation pour exactement le même a priori.
Ensuite, nous définissons les variables pour les temps de trajet observés (dureeLundi, dureeMardi, dureeMercredi).
// Définir les temps de trajetVariable<double> dureeLundi = Variable.GaussianFromMeanAndPrecision(dureeMoyenne, bruitTrafic);Variable<double> dureeMardi = Variable.GaussianFromMeanAndPrecision(dureeMoyenne, bruitTrafic);Variable<double> dureeMercredi = Variable.GaussianFromMeanAndPrecision(dureeMoyenne, bruitTrafic);Console.WriteLine("Variables de trajet definies : dureeLundi, dureeMardi, dureeMercredi");
Variables de trajet definies : dureeLundi, dureeMardi, dureeMercredi
Entraînement du modèle
Nous allons maintenant observer les temps de trajet pour trois jours et entraîner le modèle.
// Observations des temps de trajetdureeLundi.ObservedValue=13;dureeMardi.ObservedValue=17;dureeMercredi.ObservedValue=16;Console.WriteLine("Observations definies : lundi=13, mardi=17, mercredi=16");
Pour calculer les distributions postérieures pour dureeMoyenne et bruitTrafic, nous utilisons le moteur d’inférence.
// Entraînement du modèle et calcul des postérieursInferenceEngine engine =newInferenceEngine();engine.Compiler.CompilerChoice= CompilerChoice.Roslyn;Gaussian moyennePosterieure = engine.Infer<Gaussian>(dureeMoyenne);Gamma bruitPosterieur = engine.Infer<Gamma>(bruitTrafic);Console.WriteLine($"Moyenne a posteriori: {moyennePosterieure}");Console.WriteLine($"Bruit traffic a posteriori: {bruitPosterieur}");
Compiling model...done.
Iterating:
.........|.........|.........|.........|.........| 50
Moyenne a posteriori: Gaussian(15,33, 1,32)
Bruit traffic a posteriori: Gamma(2,242, 0,2445)[mean=0,5482]
2b. Lire une sortie d’Infer.NET : ce que Gaussian(15,33, 1,32) et Gamma(2,242, 0,2445)[mean=0,5482] disent exactement
Deux lignes de sortie, deux objets de nature differente, et un piege de lecture dans chacune.
Moyenne a posteriori: Gaussian(15,33, 1,32) — le second argument est la variance, pas l’écart type (la section 2c en donne la preuve independante par Math.Sqrt). Donc : moyenne 15,33, écart type 1,15. La moyenne arithmetique des trois observations (13 + 17 + 16) / 3 = 15,33 est retrouvee au centieme — c’est le signe que l’a priori vague de la section 2a a bien laisse les données parler.
Bruit traffic a posteriori: Gamma(2,242, 0,2445)[mean=0,5482] — ici l’arithmetique se verifie directement : 2,242 x 0,2445 = 0,5482, et c’est exactement le [mean=...] imprime. Le moteur affiche donc, en plus de la distribution, la moyenne qu’il en a calculee : c’est un contrôle gratuit que l’on peut refaire de tete a chaque ligne de ce genre dans le notebook.
Reste a savoir ce que ce 0,5482mesure. bruitTrafic est la précision des observations, pas leur variance : une précision plus haute signifie des trajets plus reguliers. Sa valeur postérieure est donc a lire a l’envers de l’intuition — et c’est précisément ce que la section 3b etablit sur neuf observations, ou cette quantite s’effondre alors que l’on aurait pu croire le contraire.
Interpretation : Posterieurs après 3 observations
Avec les observations (13, 17, 16 min), l’inférence bayésienne met a jour les distributions :
Paramètre
A priori
Posterieur
Moyenne (dureeMoyenne)
Gaussian(15, 100)
Gaussian(15.33, 1.32)
Bruit (bruitTrafic)
Gamma(2, 0.5)
Gamma(2.24, 0.24)
L’a priori sur la moyenne etait très peu informatif (variance = 100), donc le postérieur est presque entierement détermine par les 3 observations. La moyenne arithmetique des données est (13+17+16)/3 = 15.33 min — identique au postérieur, ce qui confirme que l’a priori n’a pas “tire” le résultat.
Prédiction du temps de trajet
Nous allons maintenant utiliser le modèle entraîné pour prédire le temps de trajet de demain (dureeDemain).
// Prédiction du temps de trajet de demainVariable<double> dureeDemain = Variable.GaussianFromMeanAndPrecision(dureeMoyenne, bruitTrafic);Gaussian distribDemain = engine.Infer<Gaussian>(dureeDemain);Console.WriteLine($"Prédiction demain: {distribDemain}, écart type: {Math.Sqrt(distribDemain.GetVariance())}");
2c. Compiling model...done. : l’inférence est compilee — et c’est visible dans les sorties
Le debut de cette sortie porte Compiling model...done., et ce n’est pas un ornement de journal : le moteur compilé le modèle en code, il ne l’interprete pas. La cellule c18 a d’ailleurs fixe explicitement le compilateur (engine.Compiler.CompilerChoice = CompilerChoice.Roslyn), ce qui rend la chose visible : le modèle probabiliste devient du C# compilé, puis execute.
Cette mecanique explique un detail de lecture qui, sinon, passe pour un caprice : certaines cellules impriment Compiling model...done. et d’autres pas du tout. Comparez la sortie de cette cellule avec celle de c40 (apprentissage en ligne) : la première compilé, la seconde non. La raison n’est pas l’importance du calcul, mais ceci : c40 reutilise un objet monEntrainement dont le modèle a déjà ete compilé et dont la structuré n’a pas change — seules les valeurs observées diffèrent. La compilation est mise en cache tant que la structuré du modèle est identique.
Retenez donc la regle de lecture, elle vaut pour tout Infer.NET : Compiling model...done. signale un modèle dont la structuré change entre deux requêtes. Changer une valeur observee, ou interroger une nouvelle variable derivee du même modèle (ce que fait cette cellule avec dureeDemain), peut declencher une recompilation ou non, et la sortie le dit.
Enfin, Iterating: ........| 50 est le compte de rendu de Expectation Propagation, l’algorithme par defaut. Ce compteur reviendra identique dans presque toutes les cellules suivantes : il ne mesure pas la qualité du résultat, il mesure l’effort du moteur. Un 50 partout n’est pas une coincidence, c’est le plafond d’iterations par defaut.
Interpretation : Distribution predictive
La prédiction du trajet de demain a une variance plus large que le postérieur de la moyenne. Infer.NET affiche Gaussian(moyenne, variance) : le second paramètre est la variance (verifiable via GetVariance() dans la cellule précédente, sqrt(4.613) ~ 2.15), et non la précision. La variance predictive se decompose donc en deux termes qui s’ajoutent pour atteindre le total observé :
Source
Variance
Incertitude sur la moyenne (Gaussian(15.33, 1.32))
1.32 min^2
Bruit du trajet (E[1/bruit], bruit etant la précision Gamma(2.24, 0.24))
~ 3.29 min^2
Variance totale predictive
1.32 + 3.29 ~ 4.61 min^2 -> écart type 2.15 min
L’incertitude totale combine l’incertitude sur les paramètres ET le bruit inherent du trajet. Même si on connaissait exactement la moyenne réelle, les trajets varieraient toujours autour d’elle.
Calculer des probabilités basées sur les prédictions
Nous pouvons également calculer la probabilité que le trajet de demain prenne moins de 18 minutes.
// Calcul de la probabilitédouble probMoinsDe18Mn = engine.Infer<Bernoulli>(dureeDemain <18.0).GetProbTrue();Console.WriteLine($"Probabilité que le trajet prenne moins de 18mn: {probMoinsDe18Mn:F2}");
Compiling model...done.
Iterating:
.........|.........|.........|.........|.........| 50
Probabilité que le trajet prenne moins de 18mn: 0,89
2d. Verifier la probabilité imprimee : le contrôle qui valide toute la lecture
Probabilite que le trajet prenne moins de 18mn: 0,89. Une probabilité a deux decimales est facile a imprimer et impossible a falsifier du regard : il faut la recalculer. C’est faisable, parce que la cellule précédente a donne les deux paramètres de la distribution predictive.
Moyenne 15,33 et variance 4,613, donc écart type 2,148. On cherche la masse sous 18 minutes :
écart reduit : z = (18 − 15,33) / 2,148 = 1,243 ;
probabilité cumulee : la fonction de repartition de la loi normale en 1,243 vaut 0,893.
Le 0,89 imprime est exactement cet arrondi. Ce n’est pas une coincidence : la même verification reussit sur les deux autres probabilités du notebook (section 3c et section 4b). Cette concordance etablit trois choses d’un coup :
la distribution predictive est bien une gaussienne de moyenne 15,33 ;
son second paramètre est bien une variance et non un écart type, sans quoi le calcul ci-dessus aurait donne un tout autre nombre ;
la requête engine.Infer<Bernoulli>(dureeDemain < 18.0) calcule une vraie probabilité de depassement, et non une heuristique.
C’est le genre de contrôle qui coute trente secondes et qui separe une sortie lue d’une sortie recopiee. Un notebook d’inférence qui n’en pose aucun laisse son lecteur croire sur parole.
Résumé
En résumé, nous avons défini un modèle probabiliste pour les temps de trajet d’un cycliste, observé les données pour entraîner le modèle, et utilisé ce modèle pour faire des prédictions sur les temps de trajet futurs. Le code est structuré de manière à tirer parti des capacités interactives du notebook .NET Interactive, permettant ainsi une approche progressive et claire.
Restructuration de notre application
Introduction
L’application DureeCycliste1 a présenté les basés de l’apprentissage des paramètres, mais elle n’est pas facilement extensible pour des scénarios plus sophistiqués. Nous allons restructurer l’application pour encapsuler le code de modélisation dans des classes séparées et introduire l’utilisation de tableaux de variables aléatoires pour les variables observées.
Encapsulation dans des classes séparées
Nous allons créer une basé commune pour les modèles d’entraînement et de prédiction en utilisant une classe de basé CyclisteBase, puis créer des classes spécifiques pour l’entraînement (EntrainementCycliste) et la prédiction (PredictionCycliste).
Classe de basé
La classe CyclisteBase contient les éléments communs aux modèles d’entraînement et de prédiction.
3a. Ce que la refactorisation OO change — et ce qu’elle ne change pas
Classes definies : CyclisteBase, ModeleCycliste : le modèle probabiliste vient de passer d’une suite de variables locales a une hierarchie de classes, avec une classe de basé portant la structuré et deux sous-classes, l’une pour l’entraînement et l’autre pour la prédiction.
Ce qu’elle ne change pas, d’abord — et c’est le point a ne pas manquer. Le modèle mathematique est identique : mêmes a priori, mêmes liens de dependance, même moteur. La section 3c le montrera chiffre en main, en comparant les sorties des deux chemins sur les mêmes données. Une refactorisation qui deplacerait les nombres serait un bug, pas une amelioration.
Ce qu’elle change, ensuite, et qui justifie le detour :
Le modèle devient une valeur reutilisable. Un objet d’entraînement peut être instancie plusieurs fois, pour plusieurs cyclistes, sans recopier la définition du modèle.
Entrainement et prédiction sont separes. C’est cette separation qui rend possible la cellule c40, ou l’on reutilise un objet déjà entraîné en lui fournissant de nouvelles données — donc l’apprentissage en ligne de la section 4.
Les distributions deviennent des paramètres.DefinirDistributions recoit les a priori (et plus tard les postérieurs) en argument. C’est ce qui permet a la section 4a de passer les postérieurs d’une semaine comme a priori de la suivante : sans cette entree, l’apprentissage en ligne demanderait de reecrire le modèle a chaque periode.
Autrement dit, la refactorisation ne rend pas le calcul meilleur — elle rend le modèle manipulable. C’est la condition technique des trois sections suivantes.
Classe d’entraînement
La classe EntrainementCycliste hérite de CyclisteBase et implémente le modèle d’entraînement.
Classe PredictionCycliste definie (prediction par modele simple)
Utilisation du modèle
Nous allons utiliser ces classes pour entraîner le modèle et prédire le temps de déplacement de demain.
Entraînement
double[] donneesTrajets =new[]{13,17,20,25,16,11,16,14,12.5};DonneesCycliste mesDistributions =newDonneesCycliste( Gaussian.FromMeanAndPrecision(1,0.01), Gamma.FromShapeAndScale(2,0.5));EntrainementCycliste monEntrainement =newEntrainementCycliste();monEntrainement.CreationModeleBayesien();monEntrainement.DefinirDistributions(mesDistributions);DonneesCycliste monPosterieur = monEntrainement.CalculePosterieurs(donneesTrajets);Console.WriteLine($"Moyenne a posteriori: {monPosterieur.DistribMoyenne}");Console.WriteLine($"Bruit traffic a posteriori: {monPosterieur.DistribBruitTraffic}");
Compiling model...done.
Iterating:
.........|.........|.........|.........|.........| 50
Moyenne a posteriori: Gaussian(15,85, 1,762)
Bruit traffic a posteriori: Gamma(5,158, 0,01568)[mean=0,08087]
3b. Neuf observations : ce que la précision du bruit mesure vraiment
Les deux postrerieurs de cette cellule sont Gaussian(15,85, 1,762) et Gamma(5,158, 0,01568)[mean=0,08087] — et le second est celui qu’il faut regarder de pres, parce qu’il contredit une lecture spontanee.
Verifions d’abord l’arithmetique, comme en 2b : 5,158 x 0,01568 = 0,0809, soit exactement le [mean=...] imprime. La encore, le moteur publie sa propre moyenne, et elle se recalcule.
Maintenant la comparaison des deux experiences du notebook :
La précision du bruit a baisse d’un facteur 6,8 en passant de 3 a 9 observations, et la variance du bruit a augmente d’autant. On aurait pu attendre l’inverse de la part d’un modèle « mieux informe » : c’est la lecture qu’un tableau hâtif suggere plus haut dans le notebook.
La raison est que cette précision ne mesure pas la quantite de données, elle mesure leur dispersion. Le premier echantillon (13, 17, 16) est serre : trois trajets a deux minutes d’écart au plus. Le second va de 11 a 25 minutes — une amplitude de 14 minutes. Un modèle qui explique ces neuf valeurs doit admettre beaucoup plus de bruit que celui qui expliquait les trois premieres, et le posterior le dit sans qu’on le lui demande.
Retenez la distinction, elle est le coeur de cette section : plus de données ne veut pas dire un modèle plus confiant, cela veut dire un modèle mieux calibre. Confiance et calibrage sont deux choses differentes, et ici elles evoluent en sens contraires. C’est ce que la section 3c met a l’epreuve sur les prédictions.
Interpretation : Posterieurs avec 9 observations
Avec 9 observations (vs 3 dans l’exemple précédent), le modèle est plus précis :
Paramètre
A priori
Posterieur (3 obs)
Posterieur (9 obs)
Moyenne
Gaussian(1, 0.01)
Gaussian(15.33, 1.32)
Gaussian(15.85, 1.76)
Precision bruit
Gamma(2, 0.5)
Gamma(2.24, 0.24)
Gamma(5.16, 0.016)
Plus de données → postérieurs plus concentres (précision plus élevée) → prédictions plus fiables.
Prédiction
PredictionCycliste maPrediction =newPredictionCycliste();maPrediction.CreationModeleBayesien();maPrediction.DefinirDistributions(monPosterieur);Gaussian distribDemain = maPrediction.EstimerTempsDemain();Console.WriteLine($"Prédiction demain: {distribDemain}, écart type: {Math.Sqrt(distribDemain.GetVariance())}");double probMoinsDe18Mn = maPrediction.EstimerTempsDemainInferieurA(18).GetProbTrue();Console.WriteLine($"Probabilité que le trajet prenne moins de 18mn: {probMoinsDe18Mn:F2}");
Compiling model...done.
Prédiction demain: Gaussian(15,85, 17,1), écart type: 4,135447159938724
Compiling model...done.
Probabilité que le trajet prenne moins de 18mn: 0,70
3c. Le contrôle de coherence a travers les deux chemins de code
Cette prédiction vient du chemin OO (classes EntrainementCycliste / PredictionCycliste), après 9 observations. La section 2 avait obtenu une prédiction par le chemin « plat », après 3 observations. Comparons ce qui doit l’être, et verifions les nombres au passage.
Chemin plat, 3 obs (section 2)
Chemin OO, 9 obs (ici)
Prediction
Gaussian(15,33, 4,613)
Gaussian(15,85, 17,1)
Ecart type imprime
2,14776700894404
4,135447159938724
P(trajet < 18 min)
0,89
0,70
Trois verifications, toutes reussies :
L’écart type est bien la racine de la variance.racine(4,613) = 2,1478 et racine(17,1) = 4,1352 — les deux valeurs imprimees par Math.Sqrt(distribDemain.GetVariance()) concordent avec le second argument de la distribution, a l’arrondi d’affichage pres (le moteur imprime la variance a trois decimales, puis sa racine a seize). Cette concordance, refaite ici sur deux jeux de données différents, est la preuve que Gaussian(moyenne, variance) se lit avec une variance.
La probabilité est coherente avec ses paramètres.z = (18 − 15,85) / 4,135 = 0,520 et la fonction de repartition vaut 0,698 : le 0,70 imprime suit. Meme contrôle qu’en 2d, sur un autre jeu.
Les deux chemins de code calculent le même modèle. La prédiction a change (15,33 -> 15,85) parce que les données ont change, pas parce que l’architecture a change. Si la refactorisation OO avait modifie le modèle, l’écart serait apparu ici.
Et l’effet de domaine, qui est le vrai enseignement de cette section : la prédiction est devenue bien plus incertaine en recevant plus de données — écart type 2,15 -> 4,14, probabilité d’arriver en moins de 18 minutes 0,89 -> 0,70. Ce n’est pas un paradoxe, c’est la consequence directe de la section 3b. Comme la précision du bruit a chute (0,5482 -> 0,0809), la variance predictive a augmente. Le modèle a appris que cette cycliste est imprevisible, et il le dit. Une baisse de la probabilité imprimee n’est donc pas un echec du modèle : c’est un résultat.
Interpretation : Predictions du modèle OO
Le modèle OO produit les mêmes résultats que le modèle plat (même algorithme, meilleure architecture) :
Prediction demain : Gaussian(15.85, 17.1) → moyenne 15.85 min, écart type 4.14 min
P(trajet < 18 min) : 0.70 (70% de chances)
La refactorisation OO n’affecte pas les résultats numériques, mais permet de : 1. Reutiliser les classes pour plusieurs cyclistes independants 2. Separer l’entraînement de la prédiction 3. Gerer facilement l’apprentissage en ligne
Avec cette approche, nous avons encapsulé les modèles d’entraînement et de prédiction dans des classes séparées tout en mutualisant les parties communes dans une classe de basé. Cela permet de gérer efficacement plusieurs ensembles d’observations et améliore les performances en évitant la recompilation du modèle.
Apprentissage en ligne avec Infer.NET
L’application DureeCycliste3 implémente l’apprentissage en ligne et la gestion des événements extraordinaires en utilisant un modèle de mélange de Gaussiennes. Cette méthode permet d’apprendre progressivement les paramètres du modèle en fonction des nouvelles données, améliorant ainsi les prévisions.
1. Mise à jour des postérieurs
Dans l’apprentissage en ligne, nous commençons par des a priori initiaux larges, puis nous les mettons à jour avec les postérieurs calculés à partir des nouvelles données. Voici comment implémenter ce processus :
Regardez d’abord ce qui manque a cette sortie : il n’y a aucunCompiling model...done.. Elle commence directement par Iterating:, ce qui la distingue de toutes les cellules de calcul du notebook. La raison a ete etablie en 2c : cette cellule reutilise monEntrainement, dont la structuré de modèle est déjà compilee, et ne fait que lui fournir un nouveau tableau. La compilation est mise en cache tant que la structuré ne bouge pas.
L’arithmetique se verifie encore : 2,747 x 0,01289 = 0,03541, exactement le [mean=...] imprime.
Sur le fond, ce que fait l’apprentissage en ligne est exactement ceci : les postérieurs de la periode précédente deviennent les a priori de la periode suivante. Les cinq nouveaux trajets (18, 25, 30, 14, 11) ne sont donc pas traites comme cinq observations venant s’ajouter a un a priori vague : ils viennent mettre a jour une croyance déjà etablie. D’ou deux consequences lisibles :
la moyenne se deplace de 15,85 a 18,49, tiree vers le haut par les trajets longs de la deuxieme semaine ;
la précision du bruit tombe a 0,03541, la plus basse du notebook — la deuxieme semaine est la plus dispersee (11 a 30 minutes) et le modèle, encore une fois, le declare.
Notez enfin que ce déplacement n’est pas un oubli de la première semaine : le prior de la semaine 2 etant le posterior de la semaine 1 (variance 1,76, donc informatif), les neuf premiers trajets continuent de peser. Online ne signifie pas « amnesique ».
Interpretation : Mise a jour des postérieurs (apprentissage en ligne)
L’apprentissage en ligne consiste a passer les postérieurs de la semaine 1 comme a priori de la semaine 2 :
Paramètre
Après semaine 1
Après semaine 2
Commentaire
Moyenne
Gaussian(15.85, 1.76)
Gaussian(18.49, 9.79)
Augmentation due aux longs trajets
Bruit
Gamma(5.16, 0.016)
Gamma(2.75, 0.013)
Variance plus élevée (semaine instable)
La cle de l’apprentissage en ligne : les postérieurs de la periode t deviennent les a priori de la periode t+1, permettant une mise a jour progressive sans necessiter toutes les données historiques.
2. Nouvelles prédictions
Après avoir mis à jour les postérieurs avec les nouvelles données, nous utilisons ces postérieurs pour faire de nouvelles prédictions.
Code de prédiction
maPrediction.DefinirDistributions(posterieurSemaineSuivante);Gaussian distribDemain = maPrediction.EstimerTempsDemain();Console.WriteLine($"Prédiction demain: {distribDemain}");Console.WriteLine($"Ecart type: {Math.Sqrt(distribDemain.GetVariance())}");double probMoinsDe18Mn = maPrediction.EstimerTempsDemainInferieurA(18).GetProbTrue();Console.WriteLine($"Probabilité que le trajet prenne moins de 18mn: {probMoinsDe18Mn:F2}");
Prédiction demain: Gaussian(18,49, 54,19)
Ecart type: 7,361051425330401
Compiling model...done.
Probabilité que le trajet prenne moins de 18mn: 0,47
4b. Une prevision qui traverse sa propre moyenne
Prédiction demain: Gaussian(18,49, 54,19) puis Ecart type: 7,361051425330401, et Probabilité que le trajet prenne moins de 18mn: 0,47.
Le detail qui vaut la peine d’être vu est le dernier. La moyenne predictive est de 18,49 minutes et la question posee est « moins de 18 minutes » : la prevision a donc traverse sa propre moyenne. Autrement dit, l’événement demande est désormais marginalement improbable, alors qu’il etait confortablement probable au debut du notebook.
Verifions le nombre, comme partout ailleurs : racine(54,19) = 7,3614 — l’écart type imprime concorde a l’arrondi d’affichage pres. Puis z = (18 − 18,49) / 7,361 = −0,067, et la fonction de repartition vaut 0,4735, soit le 0,47 imprime. Troisieme reussite du même contrôle.
Le trajet de l’incertitude sur l’ensemble du notebook se lit alors en une ligne :
Etape
Moyenne predictive
Ecart type
P(< 18 min)
3 observations
15,33
2,15
0,89
9 observations
15,85
4,14
0,70
après semaine 2
18,49
7,36
0,47
La probabilité est passee de 0,89 a 0,47 sans qu’aucun modèle n’ait change : seules les données ont change. C’est l’illustration la plus nette de ce que ce notebook cherche a montrer — en inférence bayésienne, la reponse a une question n’est pas une propriete du modèle seul, c’est une propriete du couple (modèle, données), et elle bouge avec les données.
Interpretation : Predictions après la deuxieme semaine
Après avoir observé 5 nouveaux trajets (18, 25, 30, 14, 11), le modèle a recalibré ses prédictions :
Metrique
Après semaine 1
Après semaine 2
Evolution
Moyenne predictive
15.85 min
18.49 min
+2.64 min
Ecart type
4.14 min
7.36 min
Plus incertain
P(trajet < 18 min)
0.70
0.47
Baisse (-0.23)
L’augmentation de l’écart type reflete que la deuxieme semaine avait une forte variabilité (de 11 a 30 min). L’apprentissage en ligne a correctement integre ces nouvelles informations sans oublier la semaine précédente.
Exercice 2 : Apprentissage en ligne avec vos propres données
Objectif : Appliquer l’apprentissage en ligne avec un nouveau jeu de données et interpréter l’evolution des postérieurs.
Contexte : Vous avez collecte les temps de trajet suivants sur une nouvelle semaine : [10, 12, 11, 14, 10]. Utilisez les postérieurs déjà calculés comme a priori pour cette nouvelle semaine.
Indices : - Indice 1 : Utilisez monEntrainement.CalculePosterieurs() avec les nouvelles données - Indice 2 : Comparez les postérieurs avant et après la mise a jour - Étape 1 : Définir les nouvelles données - Étape 2 : Calculer les nouveaux postérieurs - Étape 3 : Predire et comparer avec les prédictions précédentes
// Exercice 2 : Apprentissage en ligne avec nouvelles donnees// TODO etudiant : Definir les nouvelles observationsdouble[] nouvellesDonnees =newdouble[]{/* Vos observations ici */};// TODO etudiant : Utiliser les posterieurs precedents comme a priori// Indice : maPrediction.DefinirDistributions(...) puis monEntrainement.CalculePosterieurs(...)// TODO etudiant : Afficher les nouveaux posterieurs et comparerConsole.WriteLine("Exercice a completer : apprentissage en ligne");
Exercice a completer : apprentissage en ligne
Modèle mixte
Pour gérer des événements extraordinaires, nous utilisons un modèle de mélange de deux Gaussiennes. Ce modèle permet de mieux capturer la variabilité des temps de trajet.
5a. Lire les avertissements CS0649 presents dans la sortie
La sortie de cette cellule contient des avertissements du compilateur C#, de la forme warning CS0649: Le champ '...' n'est jamais assigne et aura toujours sa valeur par defaut null. Ils meritent deux minutes, parce qu’ils disent quelque chose de la structuré du modèle mixte.
Ce que le compilateur signale est précis : la structuré DonneesCyclisteMixtedeclare des champs (tableaux DistribMoyenne, DistribBruitTraffic, DistribMixe) que la cellule ne remplit pas elle-même. Ce n’est pas un defaut : la structuré sert de conteneur de distributions, et ce sont les classes d’entraînement et de prédiction qui la peuplent, a la manière de DefinirDistributions en section 3a. Le compilateur ne peut pas le savoir — d’ou l’avertissement, qui est une observation sur la portee locale du champ, pas un jugement sur le modèle.
Deux consequences pratiques :
Un avertissement n’est pas une erreur. La cellule poursuit et rend son résultat. Confondre les deux ferait passer ce notebook pour casse alors qu’il fonctionne ; c’est la même distinction qui gouverne le traitement des sorties dans tout notebook pedagogique, ou l’on exige l’absence d’erreur, pas l’absence d’avertissement.
Un avertissement visible est une information, pas un bruit a masquer. Un CS0649 sur un conteneur est le signe normal d’une structuré remplie par sa classe de basé. Le supprimer en initialisant les champs a null explicitement ne changerait rien au calcul et retirerait au lecteur cet indice sur l’architecture.
La bonne lecture d’une sortie de notebook n’est donc pas « tout est vert » : c’est « je sais ce que chaque ligne annonce ».
6a. Deux notations pour le même a priori, dans le même notebook
La cellule vient d’ecrire new Gaussian(15, 100) et new Gaussian(30, 100) pour les deux composantes du mélange. Confrontez cette ligne a celle de la section 2a :
Variable.GaussianFromMeanAndPrecision(15,0.01)// section 2 : fabrique "Precision"newGaussian(15,100)// ici : constructeur de distribution
Deux notations, et le même a priori exactement : 1 / 0,01 = 100. La fabrique nomme la précision, le constructeur prend la variance ; le notebook emploie les deux, a quelques cellules d’écart, sans le signaler. C’est la meilleure demonstration possible du piege de la section 2a — il n’est pas theorique, il traverse tout le fichier.
La regle de lecture qui en decoule : ne jamais déduire le sens du second argument du nombre, le déduire du nom. GaussianFromMeanAndPrecision -> précision. Gaussian.FromMeanAndPrecision -> précision. new Gaussian(m, v) -> variance. Un 100 peut donc valider un a priori serre ou vague selon la ligne qui l’écrit, et 0,01 fait ici l’inverse de ce qu’il suggere.
Sur le résultat lui-même, l’arithmetique se verifie une fois de plus :
Composante
Moyenne postérieure
Precision postérieure
Verification
1 (ordinaire)
15,07
Gamma(5,498, 0,02972) -> 0,1634
5,498 x 0,02972 = 0,1634
2 (extraordinaire)
26,69
Gamma(3,502, 0,08199) -> 0,2871
3,502 x 0,08199 = 0,2871
Et les poids : Dirichlet(7,995, 4,005), dont le total vaut 12 — soit les 10 observations plus les 2 pseudo-comptages de l’a priori Dirichlet(1, 1) declare dans le code. Les poids rendus sont donc 7,995 / 12 = 0,666 et 4,005 / 12 = 0,334. Le prior n’est pas efface par les données : il est compte comme deux observations virtuelles, et il reste visible dans la somme.
Interpretation : Modèle a mélange de gaussiennes
Le modèle identifie deux regimes dans les données :
Composante
Moyenne postérieure
Interpretation
Composante 1
~15 min
Trajet normal (circulation fluide)
Composante 2
~27 min
Événement extraordinaire (accident, pluie…)
Les coefficients du mélange Dirichlet(8, 4) indiquent que ~67% des trajets sont normaux et ~33% sont extraordinaires, ce qui correspond aux données observées (7 valeurs <= 20 min, 3 valeurs >= 25 min dans les 10 observations).
6b. La prevision du modèle mixte, lue sur les mêmes criteres
Prédiction demain: Gaussian(18,48, 33,39) puis Ecart type: 5,778650340614958.
Appliquons la même grille de lecture qu’aux sections précédentes, sans exception — c’est ainsi que l’on verifie qu’un modèle plus riche ne se contente pas d’être plus complique.
racine(33,39) = 5,7784, soit l’écart type imprime, a l’arrondi d’affichage pres. Quatrieme concordance variance / écart type du notebook.
La moyenne predictive (18,48) tombe presque exactement sur celle du modèle a une seule gaussienne en section 4b (18,49), alors que les deux composantes du mélange sont pourtant a 15,07 et 26,69. C’est le comportement attendu d’un mélange : la prevision est une moyenne ponderee des composantes, et les poids 0,666 / 0,334 de la section 6a la ramenent au voisinage du centre de gravite des données.
La variance, elle, ne se résumé pas de la même facon : 33,39 contre 54,19 pour le modèle simple, soit un écart type de 5,78 contre 7,36. Le modèle mixte est moins incertain, parce qu’il explique une partie de la dispersion des trajets par l’existence de deux regimes plutot que par un bruit unique et large.
Ce dernier point est le vrai apport de cette section, et il prepare la section 7 : un modèle qui structuré la variabilité (deux regimes) rend des prévisions plus tranchees qu’un modèle qui se contente de l’absorber dans un bruit unique. Reste a savoir si cette structuré est justifiee, ou si elle fait seulement payer des paramètres supplementaires. C’est exactement la question a laquelle la comparaison par preuve va repondre.
Résultats
Les résultats montrent que le modèle prédit une durée de trajet moyen plus élevée et un écart type plus important en tenant compte des événements extraordinaires, ce qui rend le modèle plus réaliste et adapté aux variations réelles des trajets.
Comparaison de Modèles
Nous disposons maintenant de deux modèles pour représenter le temps de trajet des cyclistes : l’un basé sur une seule gaussienne et l’autre sur un mélange de deux gaussiennes. Pourquoi ne pas envisager un modèle basé sur un mélange de trois gaussiennes, ou vingt ou trente gaussiennes ? Ou bien est-ce qu’une seule gaussienne suffit ? Comment choisir le meilleur modèle ?
En général, un modèle complexe avec plus de paramètres ajustables représente un ensemble de données particulier plus précisément qu’un modèle plus simple avec moins de paramètres. La question plus intéressante est de savoir si le modèle plus complexe offre une meilleure représentation qu’un modèle plus simple. Les modèles trop adaptés à un ensemble de données particulier ne seront pas utiles en pratique car ils ne s’ajusteront pas nécessairement bien aux nouvelles données.
Par exemple, lorsque vous ajustez un polynôme à un ensemble de points de données, vous pouvez toujours obtenir un ajustement exact en ajoutant suffisamment d’éléments au polynôme. Cependant, un modèle qui correspond exactement à chaque point de données fluctue généralement de manière erratique entre les points et ne correspondra donc pas bien aux nouvelles données. Ce phénomène est connu sous le nom de surapprentissage (overfitting).
La meilleure approche consiste à trouver un modèle qui ajuste raisonnablement bien les données sans être trop complexe. Comparer visuellement les modèles avec les données est subjectif et peu pratique pour des scénarios plus complexes. Ce qu’il vous faut est un critère objectif, comme le rasoir d’Occam, qui évalue quantitativement la qualité du modèle et détermine le compromis optimal entre précision et complexité. En inférence bayésienne, il existe un mécanisme robuste pour évaluer la qualité du modèle appelé preuve du modèle (evidence).
Calculer la preuve du modèle avec Infer.NET
Avec Infer.NET, la preuve est représentée par une variable aléatoire booléenne. La procédure de basé est illustrée dans l’exemple suivant.
Variable<bool> Evidence = Variable.Bernoulli(0.5);using(Variable.If(Evidence)){// Implémenter le modèle d'entraînement à évaluer}// Observer les données d'entraînement// Interroger le moteur d'inférence pour les postérieurs du modèle// Interroger le moteur d'inférence pour la distribution de la preuveConsole.WriteLine("Variable Evidence creee (pattern de calcul de preuve bayesienne)");
Variable Evidence creee (pattern de calcul de preuve bayesienne)
Infer.NET définit des modèles à deux branches en utilisant Variable.If et Variable.IfNot, qui sont l’équivalent de if-else en C#. La condition est une variable aléatoire booléenne. La probabilité que la condition soit vraie détermine la proportion de la branche If dans le mélange, et le reste du mélange est la branche IfNot.
Pour évaluer la preuve d’un modèle, utilisez If/IfNot comme illustré dans l’exemple, ce qui crée un mélange de deux modèles :
Le modèle que vous souhaitez évaluer, représenté par la branche If.
Un modèle “vide”, représenté par la branche IfNot manquante.
La variable Preuve est la condition qui contrôle les proportions dans le mélange. Son a priori initial est généralement défini sur Bernoulli(0.5). Pour déterminer la distribution réelle de la preuve, observez les données et calculez le postérieur de la variable Preuve.
Implémentation de
La nouvelle application utilisé la preuve pour évaluer si le modèle EntrainementCycliste ou EntrainementCyclisteMixte représente le mieux les données d’entraînement de EntrainementCyclisteMixte.
Classe CyclisteAvecPreuve
La classe CyclisteAvecPreuve évalue la preuve pour le modèle EntrainementCycliste.
Classe CyclisteMixedAvecPreuve definie (evaluateur de preuve pour modele mixte)
Calcul de la preuve
On calcule la preuve pour les deux modèles et on affiche les résultats.
double[] trainingData =newdouble[]{13,17,16,12,13,12,14,18,16,16,27,32};DonneesCycliste initPriors =newDonneesCycliste( Gaussian.FromMeanAndPrecision(15.0,0.01), Gamma.FromShapeAndScale(2.0,0.5));CyclisteAvecPreuve cyclistWithEvidence =newCyclisteAvecPreuve();cyclistWithEvidence.CreationModeleBayesien();cyclistWithEvidence.DefinirDistributions(initPriors);double logEvidence = cyclistWithEvidence.CalculPreuve(trainingData);// Preuves pour le modèle CyclistMixedWithEvidence (CyclingTime3)DonneesCyclisteMixte initPriorsMixed =new DonneesCyclisteMixte{ DistribMoyenne =new Gaussian[]{newGaussian(15.0,100),newGaussian(30.0,100)}, DistribBruitTraffic =new Gamma[]{newGamma(2.0,0.5),newGamma(2.0,0.5)}, DistribMixe =newDirichlet(1,1)};CyclisteMixedAvecPreuve cyclistMixedWithEvidence =newCyclisteMixedAvecPreuve();cyclistMixedWithEvidence.CreationModeleBayesien();cyclistMixedWithEvidence.DefinirDistributions(initPriorsMixed);double logEvidenceMixed = cyclistMixedWithEvidence.CalculPreuve(trainingData);// Affichage des résultatsConsole.WriteLine($"Preuve logarithmique pour une gaussienne simple : {logEvidence}");Console.WriteLine($"Preuve logarithmique pour un mélange de deux gaussiennes : {logEvidenceMixed}");
Compiling model...done.
Iterating:
.........|.........|.........|.........|.........| 50
Compiling model...done.
Iterating:
.........|.........|.........|.........|.........| 50
Preuve logarithmique pour une gaussienne simple : -45,79730358385471
Preuve logarithmique pour un mélange de deux gaussiennes : -40,98166057283106
7a. Pourquoi LogOdds d’un Bernoulli(0.5)est le facteur de Bayes
Les deux nombres de cette cellule sont -45,79730358385471 et -40,98166057283106. Leur différence vaut 4,8156 nats, et exp(4,8156) = 123,4. Le notebook a déjà écrit ce facteur ; ce qui manque est pourquoi ce calcul est licite, et ce qui le rend valide ici.
Le mécanisme tient en deux lignes du code, et il faut les lire ensemble :
Preuve = Variable.Bernoulli(0.5);// a priori sur l'interrupteur de modeleusing(Variable.If(Preuve)){base.CreationModeleBayesien();}// ...logEvidence = MoteurInference.Infer<Bernoulli>(Preuve).LogOdds;
Preuve est une variable booléenne a priori equilibree : Bernoulli(0.5) donne des chances egales aux deux branches, donc une probabilité a priori de 1/2 pour chacune et des chances a priori de 1. Or LogOdds rend le logarithme du rapport des chances a posteriori. Comme les chances a priori valent 1, leur logarithme est nul, et le résultat imprime est donc directement le logarithme du rapport de vraisemblances marginales entre les deux branches — le facteur de Bayes, sans correction a appliquer.
Trois consequences, qui sont le contenu veritable de cette section :
La comparaison n’a de sens que sur les mêmes données et le même a priori. Les deux classes heritent de la même structuré Variable.If / Bernoulli(0.5), et la section fixe trainingData une seule fois pour les deux appels. C’est ce qui rend la différence interpretable.
Aucune penalite de complexité n’est ajoutee a la main — et c’est le point le plus important. Le mélange mobilise davantage de paramètres libres (deux moyennes, deux precisions, un poids) que la gaussienne simple, et il gagne pourtant de 4,82 nats. La raison est que la vraisemblance marginale integre ces paramètres au lieu de les optimiser : le volume de l’espace qu’ils occupent est déjà compte dans la preuve. Le facteur d’Occam est automatique ; il n’y a rien a corriger.
L’échelle de lecture.4,82 nats = 4,82 / ln(10) = 2,09 unites de log decimal, soit un facteur de 123. Sur les echelles usuelles de comparaison de modèles, un facteur de cet ordre est decisif — et il est obtenu sur les mêmes 12 trajets ou le mélange a du payer ses paramètres supplementaires.
Le résultat de domaine du notebook est donc celui-ci : les données contraignent la structuré, pas seulement les paramètres. Un modèle a un seul regime ne peut pas expliquer les 12 trajets aussi bien qu’un modèle a deux regimes, et la mesure le chiffre a 123 contre 1 plutot que de l’affirmer.
Interpretation : Comparaison par log evidence
Les résultats montrent que le mélange de deux gaussiennes est nettement préférable :
Modèle
Log evidence
Evidence relative
Gaussienne simple
-45.80
1 (reference)
Melange 2 gaussiennes
-40.98
exp(4.82) ≈ 124 fois mieux
La différence de log evidence de 4.82 nats correspond a un facteur de Bayes de ~124 en faveur du modèle mixte. Cela indique que les données contiennent bel et bien deux regimes distincts (trajets normaux ~14 min, événements extraordinaires ~25-32 min).
Le “rasoir d’Occam” bayesien penalise automatiquement la complexité superflue : le modèle mixte gagne ici car la complexité additionnelle (2 gaussiennes) est justifiee par les données.
Exercice : Variables aléatoires et Inférence probabiliste
Objectifs : 1. Créer un modèle simple avec des données d’entraînement 2. Comparer deux modèles (simple vs mixte) avec leurs preuves (logEvidence) 3. Interpréter les résultats
Contexte : Vous disposez de temps de trajet observés et devez déterminer si un modèle simple (une gaussienne) ou un modèle mixte (deux gaussiennes) représente mieux les données.
Questions de réflexion : 1. Quel modèle a la meilleure preuve logarithmique ? Pourquoi ? 2. Comment le modèle mixte capture-t-il les événements extraordinaires ? 3. Que se passerait-il avec un mélange de 3 gaussiennes ?
// Exercice : Comparaison de modèles probabilistesConsole.WriteLine("Exercice a completer");// TODO: Définir les données d'entraînementdouble[] mesDonnees =newdouble[]{/* Vos observations ici */};// TODO: Créer et configurer le modèle simple// var modeleSimple = new ...// modeleSimple.CreationModeleBayesien();// ...// TODO: Créer et configurer le modèle mixte// var modeleMixte = new ...// modeleMixte.CreationModeleBayesien();// ...// TODO: Calculer et comparer les preuves logarithmiques// double preuveSimple = ...// double preuveMixte = ...// Console.WriteLine($"Preuve simple: {preuveSimple}");// Console.WriteLine($"Preuve mixte: {preuveMixte}");// TODO: Interpréter les résultats - quel modèle est préférable ?
Exercice a completer
Resume : Programmation Probabiliste avec Infer.NET
Ce notebook a couvert les grandes étapes de la programmation probabiliste avec Infer.NET :
Points clés a retenir : - Les variables Variable<T> representent des distributions, pas des valeurs fixes - L’inférence postérieure conditionne sur les observations (ObservedValue) - La preuve logarithmique (log evidence) permet de comparer des modèles objectivement - Un log evidence plus eleve (moins negatif) indique un meilleur equilibre fit/complexité
Comment fonctionne Infer.NET
Infer.NET fonctionne en compilant une définition de modèle dans le code source nécessaire pour calculer un ensemble de requêtes d’inférence sur le modèle.