Correction - Examen Deep Learning
Filière: IIR - Niveau 5ème Année
Session: Février 2025
Date: 15/02/2025
Durée: 1h30mn
I- QCM (4 points - 1 point par question)
Question 1: Valeur des modèles ML dans l'évaluation du risque de crédit
Réponse correcte: ✓ They can predict loan default probabilities based on applicant data.
Justification: Les modèles de machine learning analysent les données historiques des demandeurs pour prédire
les probabilités de défaut de paiement, ce qui aide les institutions financières à prendre des décisions éclairées.
Question 2: Technique de réduction du nombre de features
Réponse correcte: ✓ Dimensionality reduction
Justification: La réduction de dimensionnalité (PCA, t-SNE, LDA, etc.) permet de réduire le nombre de
variables tout en conservant l'information importante.
Question 3: Fonction train_test_split dans Scikit-learn
Réponse correcte: ✓ It splits your dataset into training and testing subsets
Justification: Cette fonction divise les données en ensembles d'entraînement et de test selon un ratio spécifié
(généralement 80/20 ou 70/30).
Question 4: Langage le plus utilisé en ML
Réponse correcte: ✓ Python
Justification: Python est le langage dominant en ML grâce à ses bibliothèques (NumPy, Pandas, Scikit-learn,
TensorFlow, PyTorch, Keras) et sa facilité d'utilisation.
II- Partie Analyse (8 points)
Programme 1 (4 points) - Analyse LSTM pour prédiction de prix
Commentaires ligne par ligne:
python
# Import des bibliothèques nécessaires pour le deep learning et la manipulation de données
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from [Link] import MinMaxScaler
from [Link] import Sequential
from [Link] import LSTM, Dense, Dropout
# Chargement des données de prix immobiliers depuis un fichier CSV
data = pd.read_csv('house_prices.csv')
# Séparation des features (variables explicatives) et de la cible (prix)
features = [Link]('Price', axis=1).values
target = data['Price'].values
# Normalisation des features entre 0 et 1 pour améliorer l'apprentissage
scaler = MinMaxScaler()
features_scaled = scaler.fit_transform(features)
# Reshape des features au format requis par LSTM: (samples, timesteps, features)
# Ajout d'une dimension pour représenter 1 timestep
features_reshaped = [Link](features_scaled,
(features_scaled.shape[0], features_scaled.shape[1], 1))
# Division des données en ensembles d'entraînement (80%) et de test (20%)
X_train, X_test, y_train, y_test =
train_test_split(features_reshaped, target, test_size=0.2, random_state=42)
# Construction du modèle LSTM séquentiel
model = Sequential()
# Première couche LSTM avec 50 unités, retournant des séquences
[Link](LSTM(50, return_sequences=True, input_shape=(X_train.shape[1], 1)))
# Dropout de 20% pour éviter le surapprentissage
[Link](Dropout(0.2))
# Deuxième couche LSTM avec 50 unités, ne retournant que la dernière sortie
[Link](LSTM(50, return_sequences=False))
# Dropout de 20%
[Link](Dropout(0.2))
# Couche dense de sortie avec 1 neurone pour la prédiction du prix
[Link](Dense(1))
# Compilation du modèle avec l'optimiseur Adam et MSE comme fonction de perte
[Link](optimizer='adam', loss='mean_squared_error')
# Entraînement du modèle sur 50 époques avec des batchs de 32
[Link](X_train, y_train, epochs=50, batch_size=32,
validation_data=(X_test, y_test))
# Évaluation du modèle sur l'ensemble de test
loss = [Link](X_test, y_test)
print(f'Test Loss: {loss}')
# Prédiction des prix sur l'ensemble de test
predictions = [Link](X_test)
Résultats attendus:
Ce programme produit:
1. Affichage pendant l'entraînement: 50 époques montrant l'évolution de la loss d'entraînement et de
validation
2. Test Loss: Une valeur MSE sur les données de test (ex: 15000.45)
3. Predictions: Un array NumPy contenant les prix prédits pour chaque maison de l'ensemble de test
Objectif: Prédiction de prix immobiliers en utilisant un réseau LSTM à 2 couches avec régularisation par
Dropout.
Programme 2 (4 points) - Analyse RNN pour séries temporelles
Commentaires ligne par ligne:
python
# Import des bibliothèques pour RNN et visualisation
import numpy as np
import pandas as pd
import [Link] as plt
from [Link] import MinMaxScaler
from [Link] import Sequential
from [Link] import SimpleRNN, Dense
# Chargement des données et création d'une série temporelle
df = pd.read_csv('house_prices.csv')
time = [Link](len(df))
prices = df['Price'].values
# Normalisation des prix entre 0 et 1
scaler = MinMaxScaler(feature_range=(0, 1))
prices_scaled = scaler.fit_transform([Link](-1, 1))
# Fonction pour créer des séquences temporelles
# Transforme une série en paires (X: séquence, y: valeur suivante)
def create_sequences(data, seq_length):
X, y = [], []
for i in range(len(data) - seq_length):
[Link](data[i:i+seq_length])
[Link](data[i+seq_length])
return [Link](X), [Link](y)
# Création de séquences de 10 pas de temps
seq_length = 10
X, y = create_sequences(prices_scaled, seq_length)
X = [Link](X, ([Link][0], [Link][1], 1))
# Division temporelle: 80% entraînement, 20% test
train_size = int(len(X) * 0.8)
X_train, X_test = X[:train_size], X[train_size:]
y_train, y_test = y[:train_size], y[train_size:]
# Construction d'un modèle RNN simple
model = Sequential([
SimpleRNN(50, activation='relu', return_sequences=False,
input_shape=(seq_length, 1)),
Dense(1)
])
[Link](optimizer='adam', loss='mse')
# Entraînement du modèle
[Link](X_train, y_train, epochs=50, batch_size=16,
validation_data=(X_test, y_test))
# Prédiction sur l'ensemble de test
y_pred = [Link](X_test)
# Dénormalisation des prédictions et des valeurs réelles
y_pred_inv = scaler.inverse_transform(y_pred)
y_test_inv = scaler.inverse_transform(y_test)
# Visualisation des résultats
[Link](figsize=(10, 5))
[Link](time[seq_length+train_size:], y_test_inv,
label='Actual Prices', color='blue')
[Link](time[seq_length+train_size:], y_pred_inv,
label='Predicted Prices', color='red', linestyle='dashed')
[Link]('Time')
[Link]('House Price')
[Link]()
[Link]('House Price Prediction using RNN')
[Link]()
Résultats attendus:
Ce programme produit:
1. Affichage pendant l'entraînement: Progression sur 50 époques avec loss et val_loss
2. Graphique: Un plot comparant les prix réels (bleu) et prédits (rouge pointillé) sur l'ensemble de test
3. Arrays:
y_pred_inv : Prédictions dénormalisées
y_test_inv : Valeurs réelles dénormalisées
Objectif: Prédiction de séries temporelles de prix immobiliers avec un RNN simple, visualisation des
performances.
Différence avec Programme 1: Utilise SimpleRNN au lieu de LSTM, approche séquentielle temporelle avec
fenêtre glissante de 10 pas.
III- Problème (8 points) - Prédiction du prix du blé
Question 1: Paradigme de programmation (1.5 points)
Réponse: Machine Learning
Justification:
Le problème nécessite de prédire une valeur future à partir de données historiques (série temporelle)
La programmation classique nécessiterait de coder explicitement toutes les règles, ce qui est impossible
pour capturer les patterns complexes des variations de prix
Le ML permet au modèle d'apprendre automatiquement les tendances, saisonnalités et patterns à partir
des données historiques
Les variations de prix du blé dépendent de multiples facteurs (climat, offre/demande, événements
économiques) difficiles à modéliser manuellement
Question 2: Langages et bibliothèques (1.5 points)
Langage: Python
Bibliothèques recommandées:
1. Manipulation de données:
pandas : Chargement et manipulation des données temporelles
numpy : Calculs numériques et opérations sur arrays
2. Prétraitement:
[Link] : MinMaxScaler pour normalisation
sklearn.model_selection : train_test_split
3. Deep Learning:
tensorflow/keras : Construction du modèle RNN/LSTM
Ou PyTorch : Alternative pour plus de flexibilité
4. Visualisation:
matplotlib : Traçage des courbes de prix
seaborn : Visualisations avancées
Justification:
Python est le standard en ML/DL avec l'écosystème le plus riche
TensorFlow/Keras offre une API simple pour les réseaux récurrents
Ces bibliothèques sont optimisées et bien documentées
Question 3: Discussion du Dataset (1.5 points)
Structure du Dataset nécessaire:
1. Colonnes:
Date : Horodatage (jour/mois/année)
Prix_Ble : Prix du blé (variable cible)
Volume (optionnel): Volume de transactions
Variables exogènes potentielles: météo, indices économiques, etc.
2. Caractéristiques:
Temporalité: Données ordonnées chronologiquement
Fréquence: Quotidienne, hebdomadaire ou mensuelle
Période: Au moins 2-3 ans de données pour capturer les patterns saisonniers
Qualité: Sans valeurs manquantes ou avec imputation appropriée
3. Prétraitement nécessaire:
Normalisation/standardisation des prix
Création de features temporelles (jour de la semaine, mois, trimestre)
Détection et traitement des outliers
Division temporelle (pas de shuffle aléatoire!)
4. Sources possibles:
Données boursières agricoles
FAO (Organisation des Nations Unies pour l'alimentation)
Ministères de l'Agriculture
APIs financières (Yahoo Finance, Quandl)
Question 4: Architecture du modèle (1.5 points)
Modèle proposé: LSTM (Long Short-Term Memory)
Architecture:
Input Layer: (sequence_length, 1)
↓
LSTM Layer 1: 64 unités, return_sequences=True
↓
Dropout: 0.2
↓
LSTM Layer 2: 32 unités, return_sequences=False
↓
Dropout: 0.2
↓
Dense Layer 1: 16 unités, activation='relu'
↓
Dense Output: 1 unité (prédiction du prix)
Justification du choix LSTM:
1. Mémoire à long terme: LSTM peut capturer les dépendances à long terme dans les séries temporelles
(tendances saisonnières du blé)
2. Évite le vanishing gradient: Contrairement aux RNN simples, LSTM maintient l'information sur de
longues séquences
3. Gestion de la saisonnalité: Les prix agricoles ont des patterns saisonniers que LSTM capture bien
4. Performance prouvée: LSTM est l'état de l'art pour la prédiction de séries temporelles financières
Alternatives possibles:
GRU (plus simple, moins de paramètres)
Transformer (pour datasets très larges)
Ensemble LSTM + Features externes (météo, indices économiques)
Hyperparamètres:
Sequence length: 30-60 jours
Batch size: 32
Epochs: 100-200 avec early stopping
Optimizer: Adam
Loss: MSE (Mean Squared Error)
Question 5: Code complet (2 points)
python
# ============================================
# ÉTAPE 1: IMPORTS ET CONFIGURATION
# ============================================
import numpy as np
import pandas as pd
import [Link] as plt
from [Link] import MinMaxScaler
from [Link] import mean_squared_error, mean_absolute_error
from [Link] import Sequential
from [Link] import LSTM, Dense, Dropout
from [Link] import EarlyStopping
import warnings
[Link]('ignore')
# ============================================
# ÉTAPE 2: CHARGEMENT ET EXPLORATION DES DONNÉES
# ============================================
# Chargement du dataset
df = pd.read_csv('prix_ble.csv', parse_dates=['Date'])
df = df.sort_values('Date')
df.set_index('Date', inplace=True)
print(f"Données chargées: {len(df)} observations")
print(f"Période: {[Link]()} à {[Link]()}")
print([Link]())
print([Link]())
# Vérification des valeurs manquantes
print(f"\nValeurs manquantes: {df['Prix_Ble'].isna().sum()}")
# Visualisation de la série temporelle
[Link](figsize=(14, 5))
[Link]([Link], df['Prix_Ble'], label='Prix du blé historique')
[Link]('Date')
[Link]('Prix (MAD/tonne)')
[Link]('Évolution historique du prix du blé')
[Link]()
[Link](True)
[Link]()
# ============================================
# ÉTAPE 3: PRÉTRAITEMENT DES DONNÉES
# ============================================
# Extraction des prix
prices = df['Prix_Ble'].[Link](-1, 1)
# Normalisation entre 0 et 1
scaler = MinMaxScaler(feature_range=(0, 1))
prices_scaled = scaler.fit_transform(prices)
print(f"\nPrix min: {[Link]()}, Prix max: {[Link]()}")
# ============================================
# ÉTAPE 4: CRÉATION DES SÉQUENCES
# ============================================
def create_sequences(data, seq_length):
"""
Crée des séquences pour l'apprentissage supervisé
Args:
data: données normalisées
seq_length: longueur de la fenêtre temporelle
Returns:
X: séquences d'entrée, y: valeurs cibles
"""
X, y = [], []
for i in range(len(data) - seq_length):
[Link](data[i:i+seq_length, 0])
[Link](data[i+seq_length, 0])
return [Link](X), [Link](y)
# Définir la longueur de séquence (60 jours pour capturer ~2 mois)
sequence_length = 60
X, y = create_sequences(prices_scaled, sequence_length)
print(f"\nNombre de séquences créées: {len(X)}")
# Reshape pour LSTM: [samples, timesteps, features]
X = [Link](([Link][0], [Link][1], 1))
# ============================================
# ÉTAPE 5: DIVISION TEMPORELLE TRAIN/TEST
# ============================================
# Division: 80% entraînement, 20% test (SANS SHUFFLE!)
train_size = int(len(X) * 0.8)
X_train = X[:train_size]
y_train = y[:train_size]
X_test = X[train_size:]
y_test = y[train_size:]
print(f"Taille ensemble d'entraînement: {len(X_train)}")
print(f"Taille ensemble de test: {len(X_test)}")
# ============================================
# ÉTAPE 6: CONSTRUCTION DU MODÈLE LSTM
# ============================================
model = Sequential([
# Première couche LSTM
LSTM(64, return_sequences=True, input_shape=(sequence_length, 1)),
Dropout(0.2),
# Deuxième couche LSTM
LSTM(32, return_sequences=False),
Dropout(0.2),
# Couche Dense intermédiaire
Dense(16, activation='relu'),
# Couche de sortie
Dense(1)
])
# Compilation du modèle
[Link](
optimizer='adam',
loss='mean_squared_error',
metrics=['mae']
)
# Affichage de l'architecture
[Link]()
# ============================================
# ÉTAPE 7: ENTRAÎNEMENT DU MODÈLE
# ============================================
# Callback pour arrêt anticipé
early_stop = EarlyStopping(
monitor='val_loss',
patience=15,
restore_best_weights=True
)
# Entraînement
history = [Link](
X_train, y_train,
epochs=200,
batch_size=32,
validation_data=(X_test, y_test),
callbacks=[early_stop],
verbose=1
)
# ============================================
# ÉTAPE 8: VISUALISATION DE L'APPRENTISSAGE
# ============================================
[Link](figsize=(12, 5))
# Loss
[Link](1, 2, 1)
[Link]([Link]['loss'], label='Train Loss')
[Link]([Link]['val_loss'], label='Validation Loss')
[Link]('Epoch')
[Link]('Loss (MSE)')
[Link]('Évolution de la fonction de perte')
[Link]()
[Link](True)
# MAE
[Link](1, 2, 2)
[Link]([Link]['mae'], label='Train MAE')
[Link]([Link]['val_mae'], label='Validation MAE')
[Link]('Epoch')
[Link]('MAE')
[Link]('Évolution de l\'erreur absolue moyenne')
[Link]()
[Link](True)
plt.tight_layout()
[Link]()
# ============================================
# ÉTAPE 9: ÉVALUATION ET PRÉDICTIONS
# ============================================
# Prédictions sur l'ensemble de test
y_pred_scaled = [Link](X_test)
# Dénormalisation
y_test_inv = scaler.inverse_transform(y_test.reshape(-1, 1))
y_pred_inv = scaler.inverse_transform(y_pred_scaled)
# Métriques d'évaluation
mse = mean_squared_error(y_test_inv, y_pred_inv)
mae = mean_absolute_error(y_test_inv, y_pred_inv)
rmse = [Link](mse)
print(f"\n{'='*50}")
print(f"ÉVALUATION DU MODÈLE")
print(f"{'='*50}")
print(f"MSE (Mean Squared Error): {mse:.2f}")
print(f"MAE (Mean Absolute Error): {mae:.2f}")
print(f"RMSE (Root Mean Squared Error): {rmse:.2f}")
print(f"{'='*50}")
# ============================================
# ÉTAPE 10: VISUALISATION DES RÉSULTATS
# ============================================
# Dates correspondant aux prédictions
test_dates = [Link][train_size+sequence_length:]
[Link](figsize=(14, 6))
[Link](test_dates, y_test_inv, label='Prix réel', color='blue', linewidth=2)
[Link](test_dates, y_pred_inv, label='Prix prédit', color='red',
linestyle='--', linewidth=2)
[Link]('Date', fontsize=12)
[Link]('Prix du blé (MAD/tonne)', fontsize=12)
[Link]('Prédiction du prix du blé - Ensemble de test', fontsize=14)
[Link](fontsize=11)
[Link](True, alpha=0.3)
plt.tight_layout()
[Link]()
# ============================================
# ÉTAPE 11: PRÉDICTION POUR FÉVRIER 2025
# ============================================
# Utiliser les 60 derniers jours pour prédire février 2025
last_sequence = prices_scaled[-sequence_length:].reshape(1, sequence_length, 1)
# Prédiction
prediction_scaled = [Link](last_sequence)
prediction = scaler.inverse_transform(prediction_scaled)
print(f"\n{'='*50}")
print(f"PRÉDICTION POUR FÉVRIER 2025")
print(f"{'='*50}")
print(f"Prix du blé prédit: {prediction[0][0]:.2f} MAD/tonne")
print(f"{'='*50}")
# ============================================
# ÉTAPE 12: SAUVEGARDE DU MODÈLE
# ============================================
[Link]('model_prix_ble_lstm.h5')
print("\nModèle sauvegardé: model_prix_ble_lstm.h5")
# Sauvegarde du scaler
import joblib
[Link](scaler, 'scaler_prix_ble.pkl')
print("Scaler sauvegardé: scaler_prix_ble.pkl")
# ============================================
# ÉTAPE 13: ANALYSE DE RÉSIDUS (BONUS)
# ============================================
residuals = y_test_inv - y_pred_inv
[Link](figsize=(14, 5))
# Histogramme des résidus
[Link](1, 2, 1)
[Link](residuals, bins=30, edgecolor='black')
[Link]('Résidu (MAD/tonne)')
[Link]('Fréquence')
[Link]('Distribution des résidus')
[Link](True, alpha=0.3)
# Résidus dans le temps
[Link](1, 2, 2)
[Link](range(len(residuals)), residuals, alpha=0.6)
[Link](y=0, color='red', linestyle='--')
[Link]('Index')
[Link]('Résidu (MAD/tonne)')
[Link]('Résidus dans le temps')
[Link](True, alpha=0.3)
plt.tight_layout()
[Link]()
print("\n✅ Pipeline complet terminé!")
Barème détaillé
QCM (4 points): 1 point par bonne réponse
Partie Analyse (8 points):
Programme 1: 4 points
Commentaires pertinents: 2 points
Explication des résultats: 2 points
Programme 2: 4 points
Commentaires pertinents: 2 points
Explication des résultats: 2 points
Problème (8 points):
Question 1 (paradigme): 1.5 points
Question 2 (langages/bibliothèques): 1.5 points
Question 3 (dataset): 1.5 points
Question 4 (architecture): 1.5 points
Question 5 (code): 2 points
Structure complète: 1 point
Qualité et commentaires: 1 point
Total: 20 points
Conseils pour les étudiants
1. Pour les séries temporelles: Ne jamais mélanger (shuffle) les données - respecter l'ordre chronologique
2. Normalisation: Toujours normaliser avant LSTM/RNN
3. Validation: Utiliser une validation temporelle, pas de validation croisée aléatoire
4. Overfitting: Utiliser Dropout et Early Stopping
5. Métriques: Pour les prix, utiliser RMSE et MAE (plus interprétables que MSE)