Aller au contenu principal

Depannage — Entrainement et serialisation de modeles

Depannage 30 min Module 2

Introduction

Ce guide couvre les problemes les plus courants rencontres lors de l'entrainement, l'evaluation et la serialisation de modeles ML. Chaque probleme est presente avec ses symptomes, causes, solutions et mesures preventives.


1. Incompatibilite de version lors du chargement de modeles

Symptome

ModuleNotFoundError: No module named 'sklearn.ensemble._forest'

ou

UserWarning: Trying to unpickle estimator RandomForestClassifier from version 1.2.0
when using version 1.4.0. This might lead to breaking code or invalid results.

Cause

Le modele a ete serialise avec une version differente de scikit-learn que celle utilisee pour le charger. Les structures de classes internes changent entre les versions.

Solution

# Option 1: Match the scikit-learn version
pip install scikit-learn==1.2.0 # match the version used during training

# Option 2: Re-train and re-serialize with current version
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
joblib.dump(model, 'model_new_version.joblib')

Prevention

import sklearn
import json

metadata = {
"python_version": "3.10.12",
"sklearn_version": sklearn.__version__,
"numpy_version": np.__version__,
"serialized_date": "2025-01-15",
}

with open('model_metadata.json', 'w') as f:
json.dump(metadata, f, indent=2)
Bonne pratique

Toujours sauvegarder un fichier requirements.txt ou metadata.json avec les versions exactes de toutes les dependances a cote de votre modele serialise.


2. Surapprentissage — Performance d'entrainement elevee, performance de test faible

Symptome

Training Accuracy: 0.9990
Test Accuracy: 0.7523
Gap: 0.2467 ← Trop grand !

Cause

Le modele a memorise le bruit des donnees d'entrainement au lieu d'apprendre des patterns generalisables. Causes courantes :

  • Modele trop complexe (trop d'arbres, profondeur illimitee)
  • Pas assez de donnees d'entrainement
  • Trop de features par rapport au nombre d'echantillons
  • Pas de regularisation

Solution

# Solution 1: Add regularization
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(C=0.1, penalty='l2') # C small = more regularization

# Solution 2: Reduce model complexity
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(
n_estimators=100,
max_depth=5, # limit depth
min_samples_leaf=10, # require minimum samples per leaf
max_features='sqrt', # use subset of features
random_state=42
)

# Solution 3: Feature selection
from sklearn.feature_selection import SelectKBest, f_classif
selector = SelectKBest(f_classif, k=10)
X_train_selected = selector.fit_transform(X_train, y_train)

# Solution 4: Cross-validation to detect early
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X_train, y_train, cv=5)
print(f"CV Score: {scores.mean():.4f} ± {scores.std():.4f}")
# Large std = overfitting risk
Signal d'alerte

Si l'ecart entre la performance d'entrainement et de test depasse 10 points de pourcentage, c'est probablement du surapprentissage. Si l'ecart-type des scores de validation croisee est superieur a 0.05, le modele est instable.

Prevention

StrategieQuand l'utiliser
Validation croisee systematiqueToujours
Regularisation (L1, L2)Modeles lineaires
Limiter la profondeur / complexiteArbres de decision, Random Forest
Augmenter les donneesPetit jeu de donnees (< 1000 echantillons)
Arret precoceDeep learning, boosting
DropoutReseaux de neurones

3. Sous-apprentissage — Performance faible partout

Symptome

Training Accuracy: 0.6234
Test Accuracy: 0.6102

Cause

Le modele est trop simple pour capturer les patterns dans les donnees.

Solution

# Solution 1: Use a more complex model
from sklearn.ensemble import GradientBoostingClassifier
model = GradientBoostingClassifier(n_estimators=200, max_depth=5)

# Solution 2: Add polynomial features
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, interaction_only=True)
X_train_poly = poly.fit_transform(X_train)

# Solution 3: Engineer better features
# (domain-specific — combine or transform existing features)

# Solution 4: Reduce regularization
model = LogisticRegression(C=10.0) # higher C = less regularization

4. Fuite de donnees — Resultats trop beaux pour etre vrais

Symptome

Cross-Validation Accuracy: 0.9999
Test Accuracy: 0.6543

Des scores de validation irrealistes qui chutent drastiquement sur l'ensemble de test.

Cause

Des informations de l'ensemble de test ont fuite dans le processus d'entrainement. Sources courantes :

Source de fuiteExemple
Mise a l'echelle avant le decoupagescaler.fit(X_all) avant train_test_split
Feature incluant la cibleColonne 100% correlee avec y (ex. : "diagnosis_code")
Donnees dupliqueesMeme patient dans train et test
Ordre temporel non respecteDonnees futures dans l'ensemble d'entrainement

Solution

# ❌ WRONG: Scaling before split (data leakage!)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X) # fits on ALL data
X_train, X_test = train_test_split(X_scaled, ...)

# ✅ CORRECT: Scaling after split
X_train, X_test = train_test_split(X, ...)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # fit ONLY on train
X_test_scaled = scaler.transform(X_test) # transform only

# ✅ BEST: Use Pipeline (automatically prevents leakage)
from sklearn.pipeline import Pipeline
pipeline = Pipeline([
('scaler', StandardScaler()),
('clf', RandomForestClassifier())
])
pipeline.fit(X_train, y_train) # scaler sees only training data
La fuite de donnees est le bug le plus dangereux en ML

Elle produit des metriques faussement excellentes qui ne se reproduisent jamais en production. Verifiez toujours : mon modele a-t-il vu, directement ou indirectement, des donnees de l'ensemble de test pendant l'entrainement ?

Prevention

  1. Toujours utiliser des Pipelines — ils s'assurent que le pretraitement ne voit que les donnees d'entrainement
  2. Verifier les correlations — une feature correlee a >0.95 avec la cible est suspecte
  3. Inspecter les doublons — s'assurer qu'aucun echantillon n'apparait dans plusieurs decoupages
  4. Respecter l'ordre temporel pour les donnees de series temporelles

5. Erreurs de serialisation

5a. Pickle/Joblib — Objets personnalises non serialisables

Symptome

PicklingError: Can't pickle <class 'function'>: attribute lookup builtins.function failed

Cause

Le pipeline contient des fonctions lambda, des closures ou des objets non serialisables.

Solution

# ❌ WRONG: Lambda in pipeline
from sklearn.preprocessing import FunctionTransformer
transformer = FunctionTransformer(lambda x: x ** 2) # lambdas can't pickle

# ✅ CORRECT: Named function
def square_transform(x):
return x ** 2

transformer = FunctionTransformer(square_transform)

5b. Echec de conversion ONNX

Symptome

RuntimeError: Unable to find a shape calculator for type 'MyCustomTransformer'

Cause

ONNX ne supporte pas tous les transformers/estimateurs scikit-learn.

Solution

# Check supported converters
from skl2onnx import supported_converters
print("Supported models:")
for name in sorted(supported_converters()):
print(f" - {name}")

# Workaround: serialize pipeline in parts
# Save the custom preprocessing separately
joblib.dump(custom_preprocessor, 'preprocessor.joblib')

# Convert only the model to ONNX
from skl2onnx import convert_sklearn
onnx_model = convert_sklearn(sklearn_model, initial_types=initial_type)
Compatibilite ONNX

Les modeles scikit-learn les plus courants (LinearRegression, LogisticRegression, RandomForest, SVM, KNN, GradientBoosting) sont supportes. Consultez la liste des convertisseurs avant de planifier une conversion.

5c. Le modele charge donne des resultats differents

Symptome

Original model accuracy: 0.9500
Loaded model accuracy: 0.8700 ← Different !

Cause

  • Le pretraitement n'a pas ete serialise avec le modele
  • Les donnees de test ont ete transformees differemment
  • La version de scikit-learn est differente

Solution

# ✅ Always serialize the COMPLETE pipeline
full_pipeline = Pipeline([
('scaler', StandardScaler()),
('clf', RandomForestClassifier())
])
full_pipeline.fit(X_train, y_train)

# Save
joblib.dump(full_pipeline, 'full_pipeline.joblib')

# Load and verify immediately
loaded = joblib.load('full_pipeline.joblib')
original_pred = full_pipeline.predict(X_test[:5])
loaded_pred = loaded.predict(X_test[:5])
assert np.array_equal(original_pred, loaded_pred), "Mismatch detected!"

6. Problemes de memoire avec les grands modeles

Symptome

MemoryError: Unable to allocate 2.50 GiB for an array

ou le processus est tue par l'OS (killed/OOM).

Cause

Le modele est trop grand pour la memoire disponible. Les Random Forest avec beaucoup d'arbres profonds sont les plus gourmands en memoire.

Solution

# Solution 1: Reduce model size
model = RandomForestClassifier(
n_estimators=50, # fewer trees
max_depth=10, # limit depth
max_leaf_nodes=100, # limit leaves
)

# Solution 2: Use compression when saving
joblib.dump(model, 'model.joblib', compress=9) # max compression

# Solution 3: Use memory-mapped loading for large files
model = joblib.load('model.joblib', mmap_mode='r')

# Solution 4: Monitor memory usage
import sys
model_size_mb = sys.getsizeof(model) / (1024 * 1024)
print(f"Model in memory: {model_size_mb:.1f} MB")
ParametreEffet sur la memoireCompromis
n_estimators ↓⬇️ ReduitMoins de performance
max_depth ↓⬇️ Reduit significativementRisque de sous-apprentissage
max_leaf_nodes ↓⬇️ ReduitMoins de precision
compress=9Fichier plus petit sur disqueChargement plus lent
mmap_mode='r'Chargement paresseuxAcces plus lent

7. Mauvaises metriques malgre un pipeline correct

Symptome

Toutes les etapes semblent correctes, mais les metriques sont mauvaises.

Diagnostic

# Step 1: Check data quality
print(f"Missing values:\n{X_train.isnull().sum()[X_train.isnull().sum() > 0]}")
print(f"\nDuplicate rows: {X_train.duplicated().sum()}")
print(f"\nClass distribution:\n{y_train.value_counts(normalize=True)}")

# Step 2: Check feature relevance
from sklearn.feature_selection import mutual_info_classif
mi = mutual_info_classif(X_train_scaled, y_train)
feature_importance = pd.Series(mi, index=X_train.columns).sort_values(ascending=False)
print(f"\nTop 10 features by mutual info:")
print(feature_importance.head(10))

# Step 3: Verify no constant/quasi-constant features
low_variance = X_train.columns[X_train.std() < 0.01]
if len(low_variance) > 0:
print(f"\n⚠️ Low variance features: {list(low_variance)}")

# Step 4: Try a simple baseline
from sklearn.dummy import DummyClassifier
dummy = DummyClassifier(strategy='most_frequent')
dummy.fit(X_train, y_train)
print(f"\nBaseline (majority class): {dummy.score(X_test, y_test):.4f}")
print(f"Your model: {model.score(X_test, y_test):.4f}")
Regle de la ligne de base

Si votre modele ne bat pas significativement un DummyClassifier, le probleme est dans les donnees, pas dans le modele. Concentrez-vous sur l'ingenierie des features et la qualite des donnees.


8. Avertissements de convergence

Symptome

ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.

Cause

L'algorithme d'optimisation n'a pas converge dans le nombre d'iterations alloue.

Solution

# Solution 1: Increase max iterations
model = LogisticRegression(max_iter=1000) # default is 100

# Solution 2: Scale your features
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)

# Solution 3: Try a different solver
model = LogisticRegression(solver='saga', max_iter=500)

# Solution 4: Reduce regularization strength
model = LogisticRegression(C=10.0, max_iter=500)
N'ignorez pas les avertissements

Les messages ConvergenceWarning ne sont pas de simples avertissements — un modele qui n'a pas converge produit des resultats non fiables. Corrigez toujours cet avertissement avant de continuer.


9. Reference rapide — Tableau de diagnostic

SymptomeCause probableAction immediate
ModuleNotFoundError au chargementIncompatibilite de versionVerifier la version sklearn dans les metadonnees
Score train >> Score testSurapprentissageReduire la complexite, ajouter de la regularisation
Les deux scores train et test basSous-apprentissageModele plus complexe, plus de features
Scores CV irrealistes (>0.99)Fuite de donneesVerifier le pipeline, l'ordre des operations
PicklingErrorObjet non serialisableRemplacer les lambdas par des fonctions nommees
Erreur de conversion ONNXTransformer non supporteVerifier la liste de compatibilite
MemoryErrorModele trop grandReduire n_estimators, max_depth
ConvergenceWarningPas assez d'iterationsAugmenter max_iter, mettre a l'echelle les features
Scores ne battent pas la ligne de baseDonnees inadequatesIngenierie des features, verifier la qualite des donnees
Precision du modele charge differentePipeline incompletSerialiser le pipeline complet

Checklist de debogage

Quand vous rencontrez un probleme, suivez cette checklist systematiquement :

  1. ☐ Verifier les versions des dependances (Python, sklearn, numpy)
  2. ☐ Verifier les fuites de donnees (mise a l'echelle apres le decoupage ?)
  3. ☐ Comparer les scores train vs test (ecart < 10% ?)
  4. ☐ Verifier les scores de validation croisee (ecart-type raisonnable ?)
  5. ☐ Tester un DummyClassifier comme ligne de base
  6. ☐ Verifier les valeurs manquantes et les doublons
  7. ☐ Verifier que le pipeline complet est serialise
  8. ☐ Tester le chargement et la prediction du modele serialise
  9. ☐ Verifier les avertissements dans les logs (ConvergenceWarning, etc.)
  10. ☐ Reproduire le probleme dans un environnement propre