# Examen - Généralisation des Modèles ML Ce document contient des questions pour tester et renforcer votre compréhension des concepts du lab. --- ## Partie 1 : Questions Théoriques (QCM) ### Question 1 : Définition de la généralisation Qu'est-ce qu'un modèle qui généralise bien ? A) Un modèle avec 100% d'accuracy sur le training set B) Un modèle qui performe bien sur des données jamais vues C) Un modèle qui converge rapidement D) Un modèle avec beaucoup de paramètres
Voir la réponse **Réponse : B** Un modèle qui généralise bien est capable de prédire correctement sur des données qu'il n'a jamais vues pendant l'entraînement. C'est la métrique la plus importante en ML. La performance sur le training set seule ne suffit pas (option A peut indiquer de l'overfitting).
--- ### Question 2 : Split des données Pourquoi utilise-t-on 3 ensembles (Train/Validation/Test) au lieu de 2 ? A) Pour avoir plus de données B) Le validation set détecte l'overfitting pendant l'entraînement C) C'est une convention arbitraire D) Pour ralentir l'entraînement
Voir la réponse **Réponse : B** Le validation set permet de détecter l'overfitting pendant l'entraînement et d'ajuster les hyperparamètres sans biaiser l'évaluation finale. Le test set reste complètement isolé pour une évaluation non biaisée. Si on n'avait que Train/Test, on serait tenté d'ajuster les hyperparamètres en fonction du test set, ce qui invaliderait son rôle.
--- ### Question 3 : Early Stopping Que fait l'Early Stopping quand `patience=3` et `min_delta=0.01` ? A) Arrête après 3 epochs B) Arrête si val_loss n'améliore pas de 0.01 pendant 3 epochs consécutifs C) Arrête si train_loss augmente D) Réduit le learning rate de 0.01
Voir la réponse **Réponse : B** L'Early Stopping surveille la val_loss. Si elle ne diminue pas d'au moins min_delta (0.01) pendant patience (3) epochs consécutifs, l'entraînement s'arrête et les meilleurs poids sont restaurés. Cela prévient l'overfitting.
--- ### Question 4 : Learning Rate Scheduler Avec `ReduceLROnPlateau(factor=0.5, patience=2)` et LR initial de 0.05, quel sera le LR après 2 epochs sans amélioration ? A) 0.05 B) 0.025 C) 0.0125 D) 0.01
Voir la réponse **Réponse : B** Après 2 epochs sans amélioration de val_loss, le LR est multiplié par factor (0.5). Donc : 0.05 × 0.5 = 0.025. Si val_loss stagne encore 2 epochs, il sera réduit à 0.0125, etc.
--- ### Question 5 : Normalisation Pourquoi normaliser les features avec StandardScaler ? A) Pour rendre les données plus lisibles B) Pour accélérer le code C) Pour que toutes les features contribuent équitablement au gradient D) Pour réduire la taille des données
Voir la réponse **Réponse : C** Sans normalisation, les features à grande échelle (ex: revenu en milliers) dominent le gradient descent par rapport aux features à petite échelle (ex: age). StandardScaler transforme toutes les features pour avoir moyenne=0 et écart-type=1, permettant une convergence plus rapide et stable.
--- ## Partie 2 : Analyse de Cas ### Cas 1 : Diagnostic d'overfitting Analysez ces métriques : ``` Epoch 5: train_loss=0.25, val_loss=0.28, train_acc=92%, val_acc=90% Epoch 10: train_loss=0.10, val_loss=0.30, train_acc=97%, val_acc=89% Epoch 15: train_loss=0.05, val_loss=0.38, train_acc=99%, val_acc=85% ``` **Questions :** 1. Quel problème identifiez-vous ? 2. À quelle epoch aurait dû s'arrêter le modèle ? 3. Quelles solutions proposez-vous ?
Voir l'analyse complète **1. Problème : Overfitting sévère** Signes : - train_loss diminue continuellement (0.25 → 0.05) - val_loss **augmente** (0.28 → 0.38) - Gap croissant entre train_acc et val_acc (99% vs 85%) - Le modèle mémorise au lieu de généraliser **2. Arrêt optimal : Epoch 5** C'est le point où val_loss est la plus basse (0.28) et le gap train/val est minimal (2%). **3. Solutions :** - Early stopping avec patience=2-3 - Régularisation : L2, Dropout - Simplifier l'architecture (moins de neurones/couches) - Augmenter les données d'entraînement - Réduire le nombre d'epochs max
--- ### Cas 2 : Matrice de confusion ``` Prédictions 0 1 Réel 0 [[180 20] 1 [ 5 195]] ``` **Questions :** 1. Calculez l'accuracy 2. Calculez la precision pour la classe 1 3. Calculez le recall pour la classe 0 4. Le modèle est-il équilibré ?
Voir les calculs **1. Accuracy** ``` Accuracy = (TP + TN) / Total = (195 + 180) / (180 + 20 + 5 + 195) = 375 / 400 = 93.75% ``` **2. Precision (classe 1)** ``` Precision = TP / (TP + FP) = 195 / (195 + 20) = 195 / 215 = 90.7% ``` **3. Recall (classe 0)** ``` Recall = TN / (TN + FP) = 180 / (180 + 20) = 180 / 200 = 90% ``` **4. Équilibre : Oui** Les performances sont similaires pour les deux classes (90-91%). Pas de biais flagrant vers une classe. Le modèle généralise bien sur les deux types de prédictions.
--- ### Cas 3 : Choix d'hyperparamètres Vous avez ces résultats sur le validation set : | Config | LR initial | Patience | Epoch arrêt | Val accuracy | |--------|------------|----------|-------------|--------------| | A | 0.1 | 2 | 5 | 85% | | B | 0.05 | 3 | 10 | 97% | | C | 0.01 | 5 | 25 | 92% | **Question :** Quelle configuration choisissez-vous et pourquoi ?
Voir l'analyse **Choix : Configuration B** **Raisons :** - **Meilleure performance** : 97% d'accuracy (la plus élevée) - **Convergence raisonnable** : 10 epochs (ni trop rapide comme A, ni trop lent comme C) - **LR équilibré** : 0.05 permet exploration + affinage **Pourquoi pas A ?** - Trop rapide (5 epochs) → risque d'underfitting - Accuracy basse (85%) → le modèle n'a pas assez appris **Pourquoi pas C ?** - Trop lent (25 epochs) → coût d'entraînement élevé - Accuracy inférieure à B (92% < 97%) - LR trop faible (0.01) → convergence lente **Important** : Cette décision est basée sur le validation set. L'évaluation finale se fera sur le test set.
--- ## Partie 3 : Exercices Pratiques ### Exercice 1 : Prédire le comportement Code : ```python early_stop = EarlyStopping( monitor='val_loss', patience=2, min_delta=0.05, restore_best_weights=True ) ``` Historique d'entraînement : ``` Epoch 1: val_loss = 0.50 Epoch 2: val_loss = 0.45 Epoch 3: val_loss = 0.43 Epoch 4: val_loss = 0.42 Epoch 5: val_loss = 0.41 ``` **Questions :** 1. À quelle epoch le modèle s'arrêtera-t-il ? 2. Quels poids seront restaurés ?
Voir la solution **1. Arrêt : Epoch 5** Analyse epoch par epoch : - Epoch 1 → 2 : amélioration de 0.05 (0.50 - 0.45 = 0.05) ✅ = min_delta - Epoch 2 → 3 : amélioration de 0.02 (0.45 - 0.43 = 0.02) ❌ < min_delta (compteur = 1) - Epoch 3 → 4 : amélioration de 0.01 (0.43 - 0.42 = 0.01) ❌ < min_delta (compteur = 2) - **Compteur atteint patience=2 → STOP** **2. Poids restaurés : Epoch 2** Les meilleurs poids sont ceux de l'epoch 2 (dernière fois où min_delta a été atteint). val_loss = 0.45.
--- ### Exercice 2 : Compléter le code Complétez ce code pour implémenter un modèle avec généralisation : ```python from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler import tensorflow as tf # Données X, y = make_classification(n_samples=1000, n_features=10, random_state=42) # TODO: Normaliser X scaler = ___________ X = scaler.___________ # TODO: Split en Train (64%), Val (16%), Test (20%) X_trainval, X_test, y_trainval, y_test = train_test_split(X, y, test_size=___, random_state=42) X_train, X_val, y_train, y_val = train_test_split(X_trainval, y_trainval, test_size=___, random_state=42) # TODO: Créer le modèle (2 couches denses) model = tf.keras.Sequential([ tf.keras.layers.Dense(___, activation='___', input_shape=(10,)), tf.keras.layers.Dense(___, activation='___'), tf.keras.layers.Dense(1, activation='sigmoid') ]) # TODO: Compiler avec Adam (lr=0.01) model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=___), loss='___', metrics=['accuracy'] ) # TODO: Early stopping (patience=3, min_delta=0.01) early_stop = tf.keras.callbacks.EarlyStopping( monitor='___', patience=___, min_delta=___, restore_best_weights=True ) ```
Voir la solution ```python from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler import tensorflow as tf # Données X, y = make_classification(n_samples=1000, n_features=10, random_state=42) # Normaliser X scaler = StandardScaler() X = scaler.fit_transform(X) # Split en Train (64%), Val (16%), Test (20%) X_trainval, X_test, y_trainval, y_test = train_test_split(X, y, test_size=0.2, random_state=42) X_train, X_val, y_train, y_val = train_test_split(X_trainval, y_trainval, test_size=0.2, random_state=42) # Créer le modèle (2 couches denses) model = tf.keras.Sequential([ tf.keras.layers.Dense(32, activation='relu', input_shape=(10,)), tf.keras.layers.Dense(16, activation='relu'), tf.keras.layers.Dense(1, activation='sigmoid') ]) # Compiler avec Adam (lr=0.01) model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=0.01), loss='binary_crossentropy', metrics=['accuracy'] ) # Early stopping (patience=3, min_delta=0.01) early_stop = tf.keras.callbacks.EarlyStopping( monitor='val_loss', patience=3, min_delta=0.01, restore_best_weights=True ) ``` **Explications :** - **StandardScaler()** : Normalisation (moyenne=0, std=1) - **test_size=0.2** : 20% pour test, puis 20% de 80% = 16% pour validation - **Dense(32/16, 'relu')** : Architecture progressive avec non-linéarité - **learning_rate=0.01** : Valeur standard pour démarrer - **'binary_crossentropy'** : Loss pour classification binaire - **monitor='val_loss'** : Surveiller l'overfitting
--- ### Exercice 3 : Débugger le code Ce code a un problème. Identifiez-le et corrigez-le : ```python X, y = make_classification(n_samples=500, n_features=15, random_state=42) # Split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.2, random_state=42) # Normalisation scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_val = scaler.fit_transform(X_val) X_test = scaler.fit_transform(X_test) # Entraînement model.fit(X_train, y_train, validation_data=(X_val, y_val), epochs=50) # Évaluation y_pred = model.predict(X_test) ``` **Question :** Quel est le problème ? Comment le corriger ?
Voir le problème et la solution **Problème : Data leakage dans la normalisation** Ligne problématique : ```python X_val = scaler.fit_transform(X_val) # ❌ ERREUR X_test = scaler.fit_transform(X_test) # ❌ ERREUR ``` **Pourquoi c'est un problème ?** `fit_transform()` calcule la moyenne et l'écart-type **sur les données fournies**. En utilisant `fit` sur val et test, vous introduisez une fuite d'information : le scaler "voit" les statistiques de ces ensembles. **Solution correcte :** ```python # Normalisation scaler = StandardScaler() X_train = scaler.fit_transform(X_train) # ✅ fit + transform sur train X_val = scaler.transform(X_val) # ✅ transform seulement (utilise stats de train) X_test = scaler.transform(X_test) # ✅ transform seulement (utilise stats de train) ``` **Règle d'or :** Ne jamais `fit` sur validation ou test. Toujours utiliser les statistiques (moyenne, écart-type) calculées sur le training set uniquement.
--- ## Partie 4 : Questions Ouvertes ### Question 1 : Trade-offs Expliquez le trade-off entre un learning rate élevé et un learning rate faible.
Voir la réponse attendue **Learning Rate élevé (ex: 0.1)** Avantages : - Convergence rapide (moins d'epochs nécessaires) - Échappe aux minima locaux - Exploration large de l'espace des solutions Inconvénients : - Peut "sauter" au-dessus de l'optimum - Instabilité (loss qui oscille) - Risque de divergence **Learning Rate faible (ex: 0.001)** Avantages : - Convergence précise vers l'optimum - Stabilité (descente graduelle) - Moins de risque de divergence Inconvénients : - Convergence très lente - Risque de bloquer dans un minimum local - Nécessite beaucoup d'epochs **Solution : Learning Rate adaptatif** Utiliser un scheduler comme ReduceLROnPlateau pour combiner les avantages : commencer avec un LR élevé (exploration rapide) puis réduire progressivement (affinage précis).
--- ### Question 2 : Biais d'évaluation Pourquoi est-il crucial de NE JAMAIS utiliser le test set pour ajuster les hyperparamètres ?
Voir la réponse attendue **Raison : Biais d'optimisation** Si vous ajustez les hyperparamètres (patience, learning rate, architecture) en regardant les performances sur le test set, vous introduisez un biais : vous **optimisez indirectement pour le test set**. **Conséquence :** Le test set perd son rôle d'évaluation non biaisée. Les performances mesurées seront surestimées car le modèle a été "ajusté" pour ce dataset spécifique. **Analogie :** C'est comme un étudiant qui révise en regardant les questions de l'examen final. Il aura une bonne note, mais ça ne reflète pas sa vraie compréhension du sujet. En production, sur de vraies nouvelles données, le modèle performera moins bien. **Processus correct :** 1. **Train set** : Entraîner le modèle 2. **Validation set** : Ajuster les hyperparamètres 3. **Test set** : Évaluation finale (UNE SEULE FOIS, aucun ajustement après) Le test set doit rester "caché" jusqu'à l'évaluation finale.
--- ### Question 3 : Cas réel Vous déployez votre modèle en production. Après 1 mois : - Performance sur données de production : 75% - Performance sur test set (lab) : 97% Quelles sont les causes possibles et les solutions ?
Voir l'analyse **Causes possibles :** 1. **Distribution shift (concept drift)** - Les données de production sont différentes des données d'entraînement - Solution : Réentraîner régulièrement avec nouvelles données 2. **Biais dans le test set** - Le test set ne représente pas bien la réalité - Solution : Collecter un test set plus représentatif 3. **Overfitting au lab** - Le modèle a été trop optimisé pour les données du lab - Solution : Cross-validation, datasets plus variés 4. **Features manquantes en production** - Certaines features utilisées en train ne sont pas disponibles en prod - Solution : Pipeline de features robuste, monitoring 5. **Problèmes de preprocessing** - Normalisation différente entre train et production - Solution : Versionner le scaler, pipeline unifié 6. **Données de mauvaise qualité en production** - Valeurs manquantes, erreurs de saisie - Solution : Validation des données en entrée **Actions immédiates :** 1. Analyser la distribution des données de production vs train 2. Identifier les features qui dérivent le plus 3. Monitorer les prédictions incertaines 4. Réentraîner avec un mix train + production 5. Mettre en place un système de feedback loop
--- ## Partie 5 : Flashcards (Révision rapide) ### Epoch
Définition Une passe complète sur l'ensemble du training set
### Batch
Définition Sous-ensemble de données traité simultanément (ex: 32 échantillons)
### Loss function
Rôle Mesure l'écart entre prédictions et vraies valeurs. Le modèle cherche à la minimiser.
### Backpropagation
Définition Méthode de calcul des gradients via la chaîne des dérivées. Permet de mettre à jour les poids.
### ReLU
Formule et rôle f(x) = max(0, x). Introduit la non-linéarité, évite vanishing gradient.
### Sigmoid
Utilisation Classification binaire. Transforme la sortie en probabilité [0, 1].
### Precision
Formule TP / (TP + FP). Parmi les prédictions positives, combien sont correctes ?
### Recall
Formule TP / (TP + FN). Parmi les vrais positifs, combien ont été détectés ?
### Overfitting
Signes Train accuracy >> Test accuracy. Val_loss augmente alors que train_loss diminue.
### Underfitting
Signes Train et test accuracy basses et similaires. Le modèle est trop simple.
--- ## Barème et Auto-évaluation **Partie 1 (QCM)** : 5 points (1 point par question) **Partie 2 (Analyse de cas)** : 9 points (3 points par cas) **Partie 3 (Exercices pratiques)** : 9 points (3 points par exercice) **Partie 4 (Questions ouvertes)** : 9 points (3 points par question) **Total : 32 points** **Échelle :** - 28-32 points : Excellent (87-100%) - 24-27 points : Très bien (75-86%) - 20-23 points : Bien (62-74%) - 16-19 points : Assez bien (50-61%) - < 16 points : Revoir les concepts fondamentaux --- ## Conseils de révision 1. **Commencez par les flashcards** pour mémoriser les définitions 2. **Faites les QCM** pour tester votre compréhension théorique 3. **Pratiquez les exercices de code** pour la manipulation concrète 4. **Analysez les cas** pour développer l'intuition 5. **Répondez aux questions ouvertes** pour la réflexion approfondie **Astuce :** Ne regardez pas les réponses immédiatement. Essayez d'abord de répondre, puis vérifiez et comprenez vos erreurs. Bon apprentissage ! 🚀