A la fin de ce notebook, vous saurez : 1. Entraîner des modèles avec différents algorithmes (SDCA, LightGBM) 2. Utiliser AutoML pour la recherche automatique d’hyperparamètres 3. Comparer les performances de plusieurs algorithmes 4. Choisir le meilleur modèle pour un problème donné
Prérequis
ML-2-Data&Features complété
Comprendre les concepts de features et pipelines
Durée estimée : 45-60 minutes
Entraînement et AutoML
Dans ce Notebook, vous allez apprendre
Qu’est-ce que l’entraînement ?
Introduction aux entraîneurs, quelques-unes de leurs différences, et comment choisir lequel utiliser.
Comment les hyperparamètres impactent les performances de l’entraînement.
Comment utiliser AutoML pour simplifier votre processus d’entraînement.
Qu’est-ce que l’entraînement ?
Avant de plonger dans le code, parlons d’abord de ce que signifie “entraîner un modèle”.
Dans ML.Net, “entraîner un modèle” signifie généralement appeler model.Fit(X) dans ML.Net, où X est un IDataView qui inclut à la fois les caractéristiques et les étiquettes. Alors, que se passe-t-il lorsque vous appelez Fit ? En général, Fit met à jour les paramètres dans l’entraîneur afin qu’il puisse prédire une étiquette qui soit proche de l’étiquette réelle dans X, ou en d’autres termes, réduire la distance entre l’étiquette prédite et l’étiquette réelle.
En apprentissage automatique, la différence ou la distance entre l’étiquette prédite et l’étiquette réelle est généralement appelée perte et vous utilisez différentes mesures de perte en fonction de la tâche. Pour la classification, softmax est une mesure de perte courante. Pour la régression, l’erreur quadratique moyenne (RMSE) est une mesure de perte courante. En général, elles sont toutes des métriques pour quantifier la distance entre l’étiquette prédite et l’étiquette réelle. Dans la plupart des cas, une perte plus faible signifie un meilleur modèle. Pour plus d’informations, consultez le guide des métriques d’évaluation ML.NET.
Ainsi, ce que fait Fit est d’appliquer un algorithme à vos données pour identifier des motifs et ajuster les paramètres dans cet algorithme pour réduire la perte. Lorsque vous entraînez un modèle, vous voulez réduire sa perte pour rendre la prédiction de ce modèle plus proche de l’étiquette réelle.
ML.NET fournit une variété d’entraîneurs. Vous pouvez en trouver la plupart sous le StandardTrainersCatalog. Exemples d’entraîneurs : des entraîneurs linéaires comme SDCA (Shalev-Shwartz & Zhang, 2013), Lbfgs, LinearSvm et des entraîneurs non linéaires basés sur les arbres comme FastTree (Friedman, 2001), RandomForest et LightGbm (Ke et al., 2017). En général, les capacités de chaque entraîneur sont différentes. Les modèles non linéaires ont parfois de meilleures performances d’entraînement (perte plus faible) que les modèles linéaires, mais cela ne signifie pas toujours qu’ils sont toujours le meilleur choix. Choisir le bon entraîneur pour construire le meilleur modèle pour vos données nécessite de nombreux essais et erreurs.
Surapprentissage et sous-apprentissage
Le surapprentissage et le sous-apprentissage sont les deux problèmes les plus courants que vous rencontrez lors de l’entraînement d’un modèle. Le sous-apprentissage signifie que l’entraîneur sélectionné n’est pas assez performant pour ajuster le jeu de données d’entraînement et résulte généralement en une perte élevée pendant l’entraînement et un score/métrique faible sur le jeu de test. Pour résoudre ce problème, vous devez soit sélectionner un modèle plus puissant, soit effectuer davantage d’ingénierie des fonctionnalités. Le surapprentissage est l’inverse, ce qui se produit lorsque le modèle apprend trop bien les données d’entraînement. Cela résulte généralement en une perte faible pendant l’entraînement mais une perte élevée sur le jeu de test.
Une bonne analogie pour ces concepts est l’étude pour un examen. Disons que vous connaissiez à l’avance les questions et les réponses. Après avoir étudié, vous passez l’examen et obtenez un score parfait. Bonne nouvelle ! Cependant, lorsqu’on vous donne à nouveau l’examen avec les questions réarrangées et légèrement reformulées, vous obtenez un score plus bas. Cela suggère que vous avez mémorisé les réponses sans vraiment apprendre les concepts sur lesquels vous étiez évalué. C’est un exemple de surapprentissage. Le sous-apprentissage est l’inverse, où les matériaux d’étude que vous avez reçus ne représentent pas précisément ce sur quoi vous êtes évalué pour l’examen. En conséquence, vous devez deviner les réponses car vous n’avez pas suffisamment de connaissances pour répondre correctement.
Différence entre paramètre et hyper-paramètre
En résumé, les paramètres sont internes à un entraîneur et sont mis à jour en fonction du jeu de données d’entraînement pendant le processus d’entraînement (Fit). Les hyper-paramètres sont externes à un entraîneur et contrôlent le processus d’entraînement. Par exemple, dans LightGbm, le LearningRate est un hyper-paramètre que vous pouvez désigner lors de la création et il contrôle les étapes de mise à jour pour le poids des nœuds de l’arbre pendant l’entraînement. Et le poids des nœuds de l’arbre est un paramètre qui est ajusté pendant le processus Fit.
Optimisation des hyper-paramètres
Choisir le bon entraîneur impacte vos performances finales d’entraînement. Choisir les bons hyper-paramètres a également un impact énorme sur les performances finales de l’entraînement, en particulier pour les entraîneurs basés sur les arbres. Les hyper-paramètres sont importants car ils contrôlent comment les paramètres sont mis à jour. Par exemple, un plus grand numberOfLeaves dans LightGbm produit un modèle plus grand et permet généralement de s’adapter à un jeu de données plus complexe, mais cela peut avoir un effet contraire sur un petit jeu de données et provoquer un surapprentissage. À l’inverse, si le jeu de données est complexe mais que vous définissez un petit numberOfLeaves, cela peut nuire à la capacité de LightGbm à s’adapter à ce jeu de données et provoquer un sous-apprentissage.
Le processus de recherche de la meilleure configuration pour votre entraîneur est connu sous le nom d’optimisation des hyper-paramètres (HPO). Comme le processus de choix de votre entraîneur, il implique beaucoup d’essais et d’erreurs. Les capacités intégrées de ML automatisé (AutoML) dans ML.NET simplifient le processus de HPO.
var rand =newRandom(0);var context =newMLContext(seed:1);var x = Enumerable.Range(-10000,10000).Select(_x => _x *0.1f).ToArray();var y = x.Select(_x =>100* _x +(rand.NextSingle()-0.5f)*10).ToArray();var df =newDataFrame();df["X"]= DataFrameColumn.Create("X", x);df["y"]= DataFrameColumn.Create("y", y);var trainTestSplit = context.Data.TrainTestSplit(df);df.Head(10)
index
X
y
0
-1000
-99997.734
1
-999.9
-99986.83
2
-999.8
-99977.32
3
-999.7
-99969.42
4
-999.60004
-99962.94
5
-999.5
-99949.414
6
-999.4
-99935.94
7
-999.3
-99930.58
8
-999.2
-99915.23
9
-999.10004
-99912.266
Exemple 1 : Régression linéaire
Dans la section ci-dessous, nous allons montrer la différence entre les entraîneurs via une tâche de régression linéaire. Tout d’abord, nous ajustons le jeu de données linéaire avec l’entraîneur linéaire SDCA. Ensuite, nous ajustons le jeu de données linéaire avec LightGbm, un entraîneur non linéaire basé sur les arbres. Leurs performances sont évaluées par rapport à un jeu de test. Le code ci-dessous : - Crée un jeu de données linéaire et le divise en ensembles d’entraînement et de test - Crée des pipelines d’entraînement utilisant SDCA et LightGbm - Entraîne SDCA et LightGbm sur le jeu d’entraînement linéaire, et les évalue sur le jeu de test.
var sdcaPipeline = context.Transforms.Concatenate("Features","X").Append(context.Regression.Trainers.Sdca("y"));var lgbmPipeline = context.Transforms.Concatenate("Features","X").Append(context.Regression.Trainers.LightGbm("y"));var sdcaModel = sdcaPipeline.Fit(trainTestSplit.TrainSet);var lgbmModel = lgbmPipeline.Fit(trainTestSplit.TrainSet);// évaluation sur le jeu d'entraînementvar sdcaTrainEval = sdcaModel.Transform(trainTestSplit.TrainSet);var sdcaTrainMetric = context.Regression.Evaluate(sdcaTrainEval,"y");var lgbmTrainEval = lgbmModel.Transform(trainTestSplit.TrainSet);var lgbmTrainMetric = context.Regression.Evaluate(lgbmTrainEval,"y");Console.WriteLine($"sdca rmse sur trainset: {sdcaTrainMetric.RootMeanSquaredError}, lgbm rmse sur trainset: {lgbmTrainMetric.RootMeanSquaredError}");// évaluation sur le jeu de testvar sdcaTestEval = sdcaModel.Transform(trainTestSplit.TestSet);var sdcaTestMetric = context.Regression.Evaluate(sdcaTestEval,"y");var lgbmTestEval = lgbmModel.Transform(trainTestSplit.TestSet);var lgbmTestMetric = context.Regression.Evaluate(lgbmTestEval,"y");Console.WriteLine($"sdca rmse sur testset: {sdcaTestMetric.RootMeanSquaredError}, lgbm rmse sur testset: {lgbmTestMetric.RootMeanSquaredError}");
sdca rmse sur trainset: 2,895037660611928, lgbm rmse sur trainset: 117,9591141671402
sdca rmse sur testset: 2,927377138387855, lgbm rmse sur testset: 119,860254032606
Interprétation : adapter la famille de modèle à la structure des données
Sur ce jeu de données linéaire, l’entraîneur linéaire SDCA atteint une RMSE d’environ 2,9, alors que LightGbm (arbres de boosting) plafonne autour de 120 — un écart d’environ 40×. Ce ratio spectaculaire illustre concrètement le théorème « no free lunch » : aucun algorithme n’est universellement supérieur, et la performance dépend avant tout de l’adéquation entre la famille de modèle et la structure du signal.
LightGbm est conçu pour capturer des relations non linéaires par morceaux ; appliqué à une dépendance purement linéaire, il n’exploite pas la régularité globale du signal et paie ici le prix fort. À l’inverse, SDCA (régression linéaire régularisée) correspond exactement à la forme générative des données.
Leçon pratique : face à un nouveau jeu de données, il faut donc essayer plusieurs familles d’entraîneurs et comparer leurs performances plutôt que d’en privilégier une a priori. C’est précisément cette recherche comparative qu’AutoML va automatiser dans la section suivante.
Exemple 2 : Régression non linéaire sur LightGbm
Cet exemple montre l’importance de l’optimisation des hyper-paramètres. Tout d’abord, nous créons un jeu de données non linéaire et deux pipelines. Un pipeline a LightGbm avec numberOfLeaves défini à 10, l’autre est défini à 1000. Les deux pipelines sont entraînés avec le même jeu de données d’entraînement et leurs performances sont évaluées sur le même jeu de test.
Créer un jeu de données non linéaire
Le code ci-dessous crée un jeu de données non linéaire avec un résidu aléatoire. Le jeu de données est chargé dans un ensemble d’entraînement et un ensemble de test.
var rand =newRandom(0);var context =newMLContext(seed:1);var x = Enumerable.Range(-10000,10000).Select(_x => _x *0.1f).ToArray();var y = x.Select(_x =>100* _x * _x +(rand.NextSingle()-0.5f)*10).ToArray();var df =newDataFrame();df["X"]= DataFrameColumn.Create("X", x);df["y"]= DataFrameColumn.Create("y", y);var trainTestSplit = context.Data.TrainTestSplit(df);df.Head(10);var smallLgbmPipeline = context.Transforms.Concatenate("Features","X").Append(context.Regression.Trainers.LightGbm("y", numberOfLeaves:10));var largeLgbmPipeline = context.Transforms.Concatenate("Features","X").Append(context.Regression.Trainers.LightGbm("y", numberOfLeaves:1000));var smallLgbmModel = smallLgbmPipeline.Fit(trainTestSplit.TrainSet);var largeLgbmModel = largeLgbmPipeline.Fit(trainTestSplit.TrainSet);// évaluation sur le jeu de testvar smallTestEval = smallLgbmModel.Transform(trainTestSplit.TestSet);var smallLgbmMetric = context.Regression.Evaluate(smallTestEval,"y");var largeLgbmEval = largeLgbmModel.Transform(trainTestSplit.TestSet);var largeLgbmMetric = context.Regression.Evaluate(largeLgbmEval,"y");Console.WriteLine($"small lgbm rmse sur testset: {smallLgbmMetric.RootMeanSquaredError}, large lgbm rmse sur testset: {largeLgbmMetric.RootMeanSquaredError}");
small lgbm rmse sur testset: 181156,29191693914, large lgbm rmse sur testset: 140086,26188344564
Interprétation : sensibilité aux hyper-paramètres
Sur les données non linéaires (\(y = 100 x^2 + \text{bruit}\)), LightGbm avec peu de feuilles (numberOfLeaves = 10, RMSE ≈ 181 156) reste nettement moins performant qu’avec une capacité plus large (numberOfLeaves = 1000, RMSE ≈ 140 086) — la RMSE du modèle le plus petit est environ 29 % plus élevée.
Cette fois, le même algorithme produit des résultats très différents selon la valeur d’un seul hyper-paramètre : avec trop peu de feuilles, le modèle est en sous-apprentissage (capacité insuffisante pour épouser la courbure \(x^2\)) et laisse un résidu important. Passer de 10 à 1000 feuilles lui donne la flexibilité nécessaire pour capturer la non-linéarité.
Leçon pratique : choisir le bon algorithme (Exemple 1) ne suffit pas — il faut aussi régler ses hyper-paramètres. Cette double recherche (sélection d’algorithme + optimisation des hyper-paramètres) est fastidieuse à la main ; c’est exactement la tâche qu’AutoML (section suivante) rationalise en l’automatisant.
Utiliser AutoML pour simplifier la sélection des entraîneurs et l’optimisation des hyper-paramètres
L’AutoML (Hutter, Kotthoff & Vanschoren, 2019) automatise la sélection d’algorithme et l’optimisation des hyper-paramètres (HPO). La sélection des entraîneurs et l’optimisation des hyper-paramètres est un processus important avec beaucoup d’essais et d’erreurs. Ce processus peut être automatisé et simplifié en utilisant les capacités intégrées de AutoMLExperiment. AutoMLExperiment applique les dernières recherches de Microsoft Research pour effectuer une optimisation des hyper-paramètres rapide, précise et complète avec un budget de temps limité.
Le code ci-dessous montre comment utiliser AutoMLExperiment pour trouver le meilleur entraîneur ainsi que ses meilleurs hyper-paramètres sur le jeu de données non linéaire utilisé dans l’Exemple 2. Tout d’abord, un SweepableEstimatorPipeline est créé via context.Auto().Regression("y"), qui renvoie les régressions les plus populaires avec leur espace de recherche par défaut dans ML.Net. Ensuite, un AutoMLExperiment est créé. Il utilise RootMeanSquaredError comme métrique d’optimisation et la validation train-test pour évaluer le score des essais, et utilise NotebookMonitor pour présenter le processus d’entraînement. Une fois l’entraînement terminé, il renvoie le meilleur essai comme résultat.
using Microsoft.Data.Analysis;using System;using System.Linq;using System.Collections.Generic;using Microsoft.ML;using Microsoft.ML.AutoML;using Microsoft.ML.Data;// Définir le contexte MLvar context =newMLContext(seed:1);// Générer les donnéesvar x = Enumerable.Range(-10000,10000).Select(_x => _x *0.1f).ToArray();var y = x.Select(_x =>100* _x * _x +(newRandom(0).NextDouble()-0.5)*10).ToArray();// Convertir 'y' en Single (float)var y_single = y.Select(_y =>(float)_y).ToArray();// Créer un DataFramevar df =newDataFrame();df["X"]= DataFrameColumn.Create("X", x);df["Label"]= DataFrameColumn.Create("Label", y_single);// Renommer en 'Label'// Diviser le DataFrame en ensembles d'entraînement et de testvar trainTestSplit = context.Data.TrainTestSplit(df);// Définir le pipeline de régression avec AutoMLvar pipeline = context.Transforms.Concatenate("Features","X").Append(context.Auto().Regression("Label"));// Classe NotebookMonitor pour suivre la progression AutoML (interface IMonitor mise à jour)publicclass NotebookMonitor : IMonitor{privatereadonly SweepablePipeline _pipeline;privatereadonly List<TrialResult> _completedTrials =new();private TrialResult? _bestTrial =null;privateint _runningCount =0;// Accès en lecture seule aux essais terminés — utilisé pour construire le leaderboard// (cf cellule suivante : "Visualisation : leaderboard des essais AutoML").// L'API publique est volontairement minimale (IReadOnlyList) : on évite d'exposer// la liste mutable interne qui appartient au monitor.public IReadOnlyList<TrialResult> CompletedTrials => _completedTrials;// Récupération du SweepablePipeline — nécessaire pour extraire le nom de l'entraîneur// d'un TrialResult via pipeline.ToString(trial.TrialSettings.Parameter) (cf cellule suivante).public SweepablePipeline Pipeline => _pipeline;publicNotebookMonitor(SweepablePipeline pipeline){ _pipeline = pipeline;}publicvoidReportRunningTrial(TrialSettings trialSettings){ _runningCount++; Console.WriteLine($"[En cours] Essai #{trialSettings.TrialId} en cours d'exécution...");}publicvoidReportCompletedTrial(TrialResult result){ _completedTrials.Add(result);var trialId = result.TrialSettings.TrialId;var metric = result.Metric;var duration = result.DurationInMilliseconds; Console.WriteLine($"[Complété] Essai #{trialId}: RMSE = {metric:F4} (durée: {duration}ms)");}publicvoidReportBestTrial(TrialResult result){ _bestTrial = result; Console.WriteLine($"\n=== Nouveau meilleur essai ==="); Console.WriteLine($"Essai #{result.TrialSettings.TrialId}"); Console.WriteLine($"RMSE: {result.Metric:F4}"); Console.WriteLine($"Durée: {result.DurationInMilliseconds}ms");}publicvoidReportFailTrial(TrialSettings trialSettings, Exception exception){ Console.WriteLine($"[Échec] Essai #{trialSettings.TrialId}: {exception.Message}");}publicvoidDisplay(){ Console.WriteLine($"\n=== Résumé AutoML ==="); Console.WriteLine($"Essais complétés: {_completedTrials.Count}"); Console.WriteLine($"Essais en cours: {_runningCount - _completedTrials.Count}");if(_completedTrials.Any()){var best = _completedTrials.OrderBy(t => t.Metric).First(); Console.WriteLine($"Meilleur RMSE: {best.Metric:F4}");}if(_bestTrial !=null){ Console.WriteLine($"\nMeilleur essai final: #{_bestTrial.TrialSettings.TrialId}");}}}// Configurer le moniteur de Notebookvar monitor =newNotebookMonitor(pipeline);var experiment = context.Auto().CreateExperiment();experiment.SetPipeline(pipeline).SetRegressionMetric(RegressionMetric.RootMeanSquaredError).SetTrainingTimeInSeconds(30).SetDataset(trainTestSplit.TrainSet, trainTestSplit.TestSet).SetMonitor(monitor);// Exécuter l'expérienceConsole.WriteLine("Démarrage de l'expérience AutoML (30 secondes)...\n");var res = await experiment.RunAsync();// Obtenir le modèlevar model = res.Model;var eval = model.Transform(trainTestSplit.TestSet);var metric = context.Regression.Evaluate(eval,"Label");// Afficher les résultatsmonitor.Display();Console.WriteLine($"\n=== Résultat final AutoML ===");Console.WriteLine($"RMSE sur test set: {metric.RootMeanSquaredError:F4}");
Démarrage de l'expérience AutoML (30 secondes)...
[En cours] Essai #0 en cours d'exécution...
[Complété] Essai #0: RMSE = 1317273,8292 (durée: 310ms)
=== Nouveau meilleur essai ===
Essai #0
RMSE: 1317273,8292
Durée: 310ms
[En cours] Essai #1 en cours d'exécution...
[Complété] Essai #1: RMSE = 30523762,8465 (durée: 208ms)
[En cours] Essai #2 en cours d'exécution...
[Complété] Essai #2: RMSE = 1317273,8292 (durée: 183ms)
[En cours] Essai #3 en cours d'exécution...
[Complété] Essai #3: RMSE = 3562470,2382 (durée: 44ms)
[En cours] Essai #4 en cours d'exécution...
[Complété] Essai #4: RMSE = 15016255,7685 (durée: 1904ms)
[En cours] Essai #5 en cours d'exécution...
[Complété] Essai #5: RMSE = 1278975,7956 (durée: 192ms)
=== Nouveau meilleur essai ===
Essai #5
RMSE: 1278975,7956
Durée: 192ms
[En cours] Essai #6 en cours d'exécution...
[Complété] Essai #6: RMSE = 1235892,5788 (durée: 195ms)
=== Nouveau meilleur essai ===
Essai #6
RMSE: 1235892,5788
Durée: 195ms
[En cours] Essai #7 en cours d'exécution...
[Complété] Essai #7: RMSE = 1230484,7147 (durée: 195ms)
=== Nouveau meilleur essai ===
Essai #7
RMSE: 1230484,7147
Durée: 195ms
[En cours] Essai #8 en cours d'exécution...
[Complété] Essai #8: RMSE = 1226593,0458 (durée: 419ms)
=== Nouveau meilleur essai ===
Essai #8
RMSE: 1226593,0458
Durée: 419ms
[En cours] Essai #9 en cours d'exécution...
[Complété] Essai #9: RMSE = 1217754,0972 (durée: 4559ms)
=== Nouveau meilleur essai ===
Essai #9
RMSE: 1217754,0972
Durée: 4559ms
[En cours] Essai #10 en cours d'exécution...
[Complété] Essai #10: RMSE = 6303500,8108 (durée: 134ms)
[En cours] Essai #11 en cours d'exécution...
[Complété] Essai #11: RMSE = 1217820,2077 (durée: 4393ms)
[En cours] Essai #12 en cours d'exécution...
[Complété] Essai #12: RMSE = 1217921,6545 (durée: 3566ms)
[En cours] Essai #13 en cours d'exécution...
[Complété] Essai #13: RMSE = 1218350,9583 (durée: 2393ms)
[En cours] Essai #14 en cours d'exécution...
[Complété] Essai #14: RMSE = 16167572,5774 (durée: 672ms)
[En cours] Essai #15 en cours d'exécution...
[Complété] Essai #15: RMSE = 1217348,9544 (durée: 7270ms)
=== Nouveau meilleur essai ===
Essai #15
RMSE: 1217348,9544
Durée: 7270ms
[En cours] Essai #16 en cours d'exécution...
=== Résumé AutoML ===
Essais complétés: 16
Essais en cours: 1
Meilleur RMSE: 1217348,9544
Meilleur essai final: #15
=== Résultat final AutoML ===
RMSE sur test set: 1217348,9544
Visualisation : leaderboard des essais AutoML
L’expérience ci-dessus tourne sous un budget de 30 secondes : le nombre d’essais complétés dépend du matériel — la sortie committée ci-dessus en montre seize, une machine plus rapide en exécutera davantage — et le classement précis varie d’une exécution à l’autre (les graines fixent les données et les premiers essais, pas l’ordonnanceur). Ce qui reste stable d’une exécution à l’autre, et que cette section apprend à lire : l’écart entre entraîneurs se compte en ordres de grandeur. Sur la sortie committée, le meilleur essai descend à ~1,2 million de RMSE quand le premier essai FastTreeRegression s’effondre à ~30,5 millions — mais lire ces résultats en vrac dans Console.WriteLine ne permet pas de voir d’un coup d’œil quel entraîneur a gagné ni combien d’entraîneurs différents AutoML a testés.
La cellule suivante extrait les essais terminés depuis le NotebookMonitor, lit le nom de l’entraîneur de chaque essai (via pipeline.ToString(trial.TrialSettings.Parameter) qui rend une chaîne du type Concatenate=>SdcaRegression ou Concatenate=>FastTreeRegression), puis trace un leaderboard qui rend la discrimination visuelle :
Graphique en barres : RMSE du meilleur essai par entraîneur (le gagnant se détache).
Tableau de synthèse : nom de l’entraîneur, nombre d’essais, meilleur RMSE, durée cumulée.
Pourquoi ce n’est pas un workaround dégradé (#3801 Prong-A)
Le notebook invoque le vrai AutoML de ML.NET (Microsoft.ML.AutoML 0.22.3, AutoMLExperiment) et rend le leaderboard en SVG inline (SvgChartHelper, canon #6927) : la figure reste visible en export statique — nbconvert, Quarto, prévisualisation GitHub — sans aucune requête réseau. Le leaderboard est produit par lecture directe du résultat d’experiment.RunAsync() — pas une simulation ASCII ni une fabrication. La sortie est EXEC_PROVED : la cellule est exécutée localement via .NET Interactive et commitée avec execution_count != null.
Pourquoi le problème discrimine les entraîneurs (#3801 Prong-B)
Les données sont non linéaires (y = 100*x² + bruit). Sur ce type de signal, la famille de l’entraîneur ne prédit pas à elle seule le classement : les entraîneurs capables d’épouser la courbure (gradient boosting fin) s’y imposent nettement, tandis que d’autres entraîneurs à base d’arbres y échouent de plusieurs ordres de grandeur — mesurez l’écart exact sur la sortie et le leaderboard ci-dessus. C’est cette discrimination massive — invisible sans le leaderboard — qui fait la valeur pédagogique de l’AutoML : sans graphique, l’étudiant devrait comparer à la main autant de nombres qu’il y a d’essais.
Lecture honnête du classement. Le leaderboard nuance l’idée reçue « non-linéaire bat toujours linéaire » : le fond du classement n’est pas occupé par les entraîneurs linéaires, et au sein même des arbres l’écart entre le meilleur et le pire est massif. Une explication partielle : dans un budget court, l’AutoML n’accorde pas le même nombre d’essais à chaque entraîneur — celui qui tombe tôt a moins d’occasions d’être bien réglé. La leçon n’en est que plus riche : la famille d’algorithme ne garantit pas le succès, c’est l’association bon algorithme + bons hyper-paramètres que l’AutoML cherche conjointement.
Pont avec l’Exemple 2 (mêmes données, mêmes graines). Le LightGbm réglé à la main (numberOfLeaves = 1000) de l’Exemple 2 atteint ~140 086 de RMSE — ce nombre, lui, est déterministe (données et entraîneurs seedés). Le meilleur essai AutoML battra ou non cette référence selon l’exécution : sur la sortie committée (16 essais en 30 s), il ne la bat pas (~1,2 million). C’est une leçon honnête sur l’AutoML : il automatise la recherche, il ne garantit pas le résultat — un budget court sur un problème qu’un réglage manuel résout déjà peut perdre contre ce réglage. Relancez l’expérience avec un budget plus long : le classement converge vers le LightGbm bien réglé.
#load "../../Probas/Infer/SvgChartHelper.cs"// =================================================================// Leaderboard AutoML -- discrimination visuelle des entraîneurs// =================================================================// Sur données quadratiques (y = 100·x² + bruit), certains algorithmes (LightGbm,// FastTree) écrasent les autres en RMSE. Le tableau console ci-dessous rend// la hiérarchie lisible : on voit le RMSE exact par entraîneur, le nombre// d'essais et la durée cumulée. Le graphique en barres la rend VISUELLE --// la barre du perdant (~30M) domine, celle du gagnant (~90k) est ~300x plus// courte.//// Note technique : le graphique est un SVG inline produit par SvgChartHelper// (canon #6927). Aucune requete reseau n'est emise, donc la figure reste visible// en export statique -- nbconvert, Quarto, previsualisation GitHub -- la ou une// sortie a CDN rendait blanc.//// L'echelle reste LINEAIRE, et c'est delibere : c'est l'ecrasement visuel qui// porte le message pedagogique. Passer en log "pour mieux voir" detruirait// exactement ce que la figure demontre.var trials = monitor.CompletedTrials;var sweepablePipeline = monitor.Pipeline;// Helper local : nom court du dernier estimateur dans la chaîne de pipelines.// "Concatenate=>SdcaRegression" -> "SdcaRegression"stringTrainerName(TrialResult t){var full = sweepablePipeline.ToString(t.TrialSettings.Parameter);if(string.IsNullOrEmpty(full))return"(unknown)";var segments = full.Split("=>", StringSplitOptions.RemoveEmptyEntries| StringSplitOptions.TrimEntries);return segments.Length==0?"(unknown)": segments[^1];}// Agrégation par entraîneur : on garde uniquement les essais terminés.var byTrainer = trials.GroupBy(TrainerName).Select(g =>new{ Trainer = g.Key, N = g.Count(), BestRmse = g.Min(t => t.Metric), TotalDurationMs = g.Sum(t => t.DurationInMilliseconds), BestTrialId = g.OrderBy(t => t.Metric).First().TrialSettings.TrialId,}).OrderBy(x => x.BestRmse)// le gagnant en premier (barre la plus courte).ToList();Console.WriteLine($"Entraîneurs distincts testés : {byTrainer.Count}");Console.WriteLine($"Nombre total d'essais terminés : {trials.Count}");Console.WriteLine();Console.WriteLine($"{"Entraîneur",-30} {"Essais",6} {"Meilleur RMSE",15} {"Durée cumulée(ms)",18} {"Trial ID",9}");Console.WriteLine(newstring('-',82));foreach(var row in byTrainer){ Console.WriteLine($"{row.Trainer,-30} {row.N,6} {row.BestRmse,15:F4} {row.TotalDurationMs,18} {row.BestTrialId,9}");}// Preparation du graphique : SVG inline, aucune reference reseau.var trainerNames = byTrainer.Select(t => t.Trainer).ToArray();var bestRmses = byTrainer.Select(t => t.BestRmse).ToArray();display(SvgChartHelper.Bar("AutoML leaderboard -- donnees quadratiques (y = 100.x^2 + bruit) -- RMSE, echelle lineaire", trainerNames, bestRmses, width:760, height:380));
Entrainez le même jeu de données avec 4 algorithmes différents, puis comparez leurs performances et temps d’entrainement.
Objectifs : 1. Utiliser les données lineaires (y = 100*x + bruit) définies plus haut dans le notebook 2. Entrainer 4 modèles : SDCA, LightGbm, FastTree, AveragedPerceptron (ou OnlineGradientDescent) 3. Mesurer le temps d’entrainement de chaque algorithme avec Stopwatch 4. Presenter un tableau comparatif : algorithme | RMSE train | RMSE test | temps (ms) 5. Interpreter les résultats : quel algorithme est le mieux adapte aux données lineaires et pourquoi
Indice : Les trainers sont accessibles via context.Regression.Trainers.Sdca(), .LightGbm(), .FastTree(), .OnlineGradientDescent(). Pour AveragedPerceptron, utilisez context.BinaryClassification.Trainers.AveragedPerceptron() si vous transformez le problème en classification.
// Exercice 1 : Comparaison de 4 algorithmes// TODO etudiant : Entrainez le meme dataset avec SDCA, LightGbm, FastTree et AveragedPerceptron// Indice : chaque trainer est dans context.Regression.Trainers ou context.BinaryClassification.Trainers// Etape 1 : utilisez les donnees lineaires (y = 100*x + bruit) definies plus haut// Etape 2 : creez 4 pipelines avec le meme pretraitement mais des trainers differents// Etape 3 : mesurez le temps d'entrainement avec Stopwatch pour chaque algorithme// Etape 4 : comparez RMSE et temps dans un tableau resumeConsole.WriteLine("Exercice a completer : comparaison de 4 algorithmes");
Exercice a completer : comparaison de 4 algorithmes
Exercice 2 : Arret precoce et compromis performance/temps
Explorez le compromis entre nombre d’arbres, qualite du modèle et temps d’entrainement. L’objectif est d’identifier le point optimal ou ajouter des arbres n’apporte plus de gain significatif.
Objectifs : 1. Créer un jeu de données de regression non-lineaire (quadratique avec bruit) 2. Entrainer LightGbm avec différentes valeurs de numberOfTrees (10, 50, 200) 3. Mesurer le temps d’entrainement avec System.Diagnostics.Stopwatch 4. Evaluer le RMSE sur train et test pour chaque configuration 5. Identifier le point de rendements decroissants
Indice : Utilisez context.Regression.Trainers.LightGbm("y", numberOfTrees: 10). Comparez le gap entre RMSE train et RMSE test pour detecter le surapprentissage.
// Exercice 2 : Experience d'arret precoce (early stopping)// TODO etudiant : Observez l'impact du nombre d'arbres sur les metriques et le temps d'entrainement// Indice : FastTree et LightGbm acceptent numberOfLeaves, numberOfTrees comme hyperparametres// Etape 1 : creez un jeu de donnees de regression non-lineaire (x, x*x + bruit)// Etape 2 : entrainez LightGbm avec numberOfTrees=10, 50, 200 et mesurez le temps (Stopwatch)// Etape 3 : evaluez le RMSE sur train et test pour chaque configuration// Etape 4 : identifiez le point ou ajouter des arbres n'apporte plus de gain significatifConsole.WriteLine("Exercice a completer : arret precoce et nombre d'arbres");
Exercice a completer : arret precoce et nombre d'arbres
Exercice 3 : Effet du pretraitement (normalisation/encodage) sur la performance
Explorez comment le pretraitement des features influence la qualite des predictions et le temps d’entrainement. L’objectif est de comprendre l’impact de la normalisation et de l’encodage sur differents algorithmes.
Objectifs : 1. Reprendre le jeu de donnees lineaires (y = 100*x + bruit) defini plus haut 2. Comparer 2 pipelines de pretraitement : - Pipeline A : Concatenate brut (sans normalisation) - Pipeline B : NormalizeMeanVariance + OneHotEncoding sur les features categorielles 3. Entrainer SDCA et LightGbm sur chaque pipeline 4. Comparer RMSE train/test + temps d’entrainement pour les 4 configurations (A-SDCA, A-LightGbm, B-SDCA, B-LightGbm) 5. Interpreter : quel algorithme beneficie le plus du pretraitement ? Pourquoi LightGbm est generalement plus robuste aux features non normalisees ?
Conseil : commencez par SDCA (sensible a l’echelle des features) puis comparez avec LightGbm (robuste grace au tree splitting). Documentez vos observations dans une cellule markdown apres l’execution.
// Exercice 3 : Effet du pretraitement (normalisation/encodage) sur la performance// TODO etudiant : Comparez l'impact du pretraitement sur SDCA vs LightGbm// Indice : context.Transforms.NormalizeMeanVariance() applique une standardisation (mean=0, std=1)// Indice : context.Transforms.OneHotEncoding() encode les colonnes categorielles en binaire// Etape 1 : creez 2 pipelines (Pipeline A brut, Pipeline B normalise+onehot) sur le meme jeu de donnees// Etape 2 : entrainez SDCA sur chaque pipeline et mesurez RMSE train/test + temps (Stopwatch)// Etape 3 : faites de meme avec LightGbm// Etape 4 : present les 4 resultats dans un tableau resume et interpretezConsole.WriteLine("Exercice a completer - Effet du pretraitement sur la performance");// Votre code ici :// var pipelineA = context.Transforms.Concatenate(...);// var pipelineB = context.Transforms.Concatenate(...)// .Append(context.Transforms.NormalizeMeanVariance(...))// .Append(context.Transforms.OneHotEncoding(...));// var trainerSdca = context.Regression.Trainers.Sdca(labelColumnName: "Label");// var modelA_SDCA = pipelineA.Append(trainerSdca).Fit(trainData);// ...
Exercice a completer - Effet du pretraitement sur la performance
Exercice 4 : Comparaison SDCA vs LightGbm sur données sinusoïdales
Créez un jeu de données sinusoïdal (\(y = \sin(x) + \text{bruit}\)) et comparez les performances de SDCA vs LightGbm sur ce type de données non-linéaires.
Objectifs : 1. Générer des données sinusoïdales avec du bruit aléatoire 2. Entraîner un modèle SDCA et un modèle LightGbm 3. Comparer les RMSE sur le jeu de test 4. Expliquer pourquoi un modèle performe mieux que l’autre
Différence avec le twin Python : le jumeau scikit-learn traite le même exercice (son Exercice 3) avec les équivalents LinearRegression/GradientBoosting. Ici vous manipulez les vrais trainers ML.NET (Sdca, LightGbm) sur un DataFrameMicrosoft.Data.Analysis — comparez vos conclusions entre les deux plateformes.
Conseil : comparez les RMSE sur train ET test pour détecter le surapprentissage. Utilisez MathF.Sin(x) pour générer les données ; SDCA est un algorithme linéaire, LightGbm approxime par morceaux (arbres).
// Exercice 4 : Comparaison SDCA vs LightGbm sur données sinusoïdales// TODO: Créer un MLContext avec seed fixeMLContext sinusContext =null;// TODO étudiant : remplacer par new MLContext(seed: 42)// TODO: Générer les données sinusoïdales// Indice: utilisez Enumerable.Range et MathF.Sinvar rand =newRandom(42);var xSinus = Enumerable.Range(0,1000).Select(i => i *0.01f).ToArray();var ySinus = xSinus.Select(x =>/* appliquez sin(x) + bruit */0f).ToArray();// TODO: Créer le DataFramevar dfSinus =newDataFrame();// Ajoutez les colonnes X et y// TODO: Diviser en train/testvar sinusSplit = sinusContext?.Data?.TrainTestSplit(dfSinus)??default;// TODO: Créer le pipeline SDCAIEstimator<ITransformer> sdcaSinusPipeline =null;// TODO: Créer le pipeline LightGbmIEstimator<ITransformer> lgbmSinusPipeline =null;// TODO: Entraîner les deux modèlesITransformer sdcaSinusModel =null;ITransformer lgbmSinusModel =null;// TODO: Évaluer SDCA sur train et testRegressionMetrics sdcaSinusTrainMetric =null;RegressionMetrics sdcaSinusTestMetric =null;// TODO: Évaluer LightGbm sur train et testRegressionMetrics lgbmSinusTrainMetric =null;RegressionMetrics lgbmSinusTestMetric =null;// Affichage des résultatsif(sinusContext !=null&& sdcaSinusTrainMetric !=null&& lgbmSinusTrainMetric !=null){ Console.WriteLine("=== Comparaison SDCA vs LightGbm sur données sinusoïdales ==="); Console.WriteLine($"SDCA - RMSE Train: {sdcaSinusTrainMetric?.RootMeanSquaredError:F4}, RMSE Test: {sdcaSinusTestMetric?.RootMeanSquaredError:F4}"); Console.WriteLine($"LightGbm - RMSE Train: {lgbmSinusTrainMetric?.RootMeanSquaredError:F4}, RMSE Test: {lgbmSinusTestMetric?.RootMeanSquaredError:F4}");}else{ Console.WriteLine("Exercice a completer : implementez les TODO pour comparer SDCA et LightGbm");}// TODO: Analysez les résultats - quel modèle est meilleur et pourquoi ?
Exercice a completer : implementez les TODO pour comparer SDCA et LightGbm
Résumé
Ce notebook a couvert l’entraînement des modèles et AutoML avec ML.NET :
Entraîneur non-linéaire basé sur les arbres de décision
Surapprentissage
Modèle performant sur train mais pas sur test
Sous-apprentissage
Modèle insuffisamment puissant pour les données
AutoMLExperiment
Recherche automatique du meilleur algorithme et hyperparamètres
Hyperparamètre
Paramètre externe contrôlant le processus d’entraînement
Points clés : - Choisir le bon entraîneur dépend de la nature linéaire ou non-linéaire des données - L’optimisation des hyperparamètres (HPO) est un processus itératif d’essais et d’erreurs - AutoML simplifie la HPO en explorant automatiquement les configurations possibles - Un bon modèle minimise la perte à la fois sur le train set et le test set
Algorithmes d’entraînement - Shalev-Shwartz, S., & Zhang, T. (2013). Stochastic Dual Coordinate Ascent Methods for Regularized Loss Minimization. Journal of Machine Learning Research, 14, 567-599. — algorithme SDCA, entraîneur linéaire de ML.NET. - Friedman, J. H. (2001). Greedy Function Approximation: A Gradient Boosting Machine. Annals of Statistics, 29(5), 1189-1232. — Gradient Boosting Decision Trees (GBDT), fondement des entraîneurs FastTree et RandomForest de ML.NET. - Ke, G., Meng, Q., Finley, T., Wang, T., Chen, W., Ma, W., Ye, Q., & Liu, T.-Y. (2017). LightGBM: A Highly Efficient Gradient Boosting Decision Tree. NeurIPS. — entraîneur LightGbm utilisé tout au long du notebook.
Automated Machine Learning (AutoML) - Hutter, F., Kotthoff, L., & Vanschoren, J. (2019). Automated Machine Learning: Methods, Systems, Challenges. Springer. — AutoML et optimisation des hyper-paramètres (HPO), base de l’AutoMLExperiment de ML.NET.
Framework (ML.NET) - Ahmed, Z., Amizadeh, S., Bilenko, M., et al. (2019). DOI: 10.1145/3292500.3330667 — Machine Learning at Microsoft with ML.NET. ACM SIGKDD (KDD).