← Retour au blog

Reproductibilité et environnements

Lucian BLETAN

“Ça marche sur ma machine” est la phrase qui hante tout projet de données ou de machine learning. L’impossibilité de reproduire un résultat entre l’environnement d’un développeur et la production est une source majeure d’erreurs et de perte de temps. La reproductibilité n’est pas une option, c’est la base de la confiance. Pour l’atteindre, il faut systématiquement figer l’environnement, contrôler les sources d’aléatoire et travailler avec des jeux de données de test stables.

le problème vs la solution

Sans environnement contrôlé, les résultats sont imprévisibles. Avec une image immuable, le comportement est identique partout.

problème: non reproductible

pc du développeur

ça marche

serveur de production

ça casse

solution: reproductible

image docker unique

pc du développeur

serveur de production

ça marche

prérequis

  • Un système de gestion de versions (Git) pour le code.
  • L’utilisation de conteneurs (Docker) pour encapsuler les environnements.
  • Des jeux de données d’exemple versionnés pour les tests.

idées clefs

La reproductibilité repose sur trois piliers fondamentaux.

reproductibilité

environnement figé

image docker immuable

versions de librairies fixées

aléatoire contrôlé

seed global pour les générateurs

données stables

snapshot de données

golden dataset pour les tests

pas à pas

étape 1: figer l’environnement avec une image immuable

L’environnement (système d’exploitation, librairies, dépendances) doit être identique partout. Un Dockerfile est la meilleure façon de le décrire et de le construire.

# Dockerfile
FROM python:3.9-slim

WORKDIR /app

# Copier le fichier des dépendances
COPY requirements.txt .

# Installer les versions exactes des librairies
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "src/main.py"]

Ensuite, on construit une image unique qui sera utilisée en développement, en test et en production.

# Construire l'image avec un tag unique basé sur le hash du commit
docker build -t mon-application:sha-abcdef1 .

étape 2: contrôler l’aléatoire avec des seeds

De nombreuses opérations en data science (initialisation de poids d’un modèle, division d’un jeu de données) sont aléatoires. Pour garantir que le résultat soit le même à chaque exécution, il faut fixer la “graine” (seed) du générateur de nombres aléatoires au début de chaque script.

import random
import numpy as np
import torch

# Fixer le seed pour toutes les librairies pertinentes
SEED = 42

random.seed(SEED)
np.random.seed(SEED)
torch.manual_seed(SEED)

étape 3: utiliser des jeux de données d’exemple stables

Tester un code sur une base de données de production qui change constamment rend les tests non reproductibles. La solution est de créer des “snapshots” : des extraits de données fixes et versionnés, dédiés aux tests.

# Créer une fixture de test à partir d'un échantillon de données
# Ce fichier sera commité dans Git (ou DVC si trop gros) et utilisé par la CI.
cp data/production_sample_oct2022.parquet tests/fixtures/training_sample.parquet

pièges frequents

  • Symptôme: “Ça marche sur ma machine mais pas en CI”.

    • Cause: L’environnement du développeur a divergé de celui de la production (versions de librairies différentes, etc.).
    • Correctif: Utiliser une image Docker unique pour le développement local et pour la CI/production.
  • Symptôme: Les métriques d’un modèle changent légèrement à chaque entraînement, même avec le même code.

    • Cause: Un seed a été oublié dans une des librairies utilisées.
    • Correctif: Fixer les seeds au tout début du script pour toutes les sources d’aléatoire.
  • Symptôme: Les tests passent en CI mais le code échoue en production sur un cas particulier.

    • Cause: Les données de test sont trop simples et ne représentent pas la complexité des données réelles.
    • Correctif: Créer des snapshots de données qui incluent les cas limites et les “edge cases” observés en production.

faq

  • Est-ce que Docker est la seule solution pour figer un environnement ? Non, mais c’est la plus standard et la plus portable. Des alternatives comme Conda ou des environnements virtuels Python avec des fichiers de dépendances (requirements.txt) bien gérés peuvent aussi fonctionner, mais sont souvent moins robustes.

  • Comment gérer les différences de matériel (cpu vs gpu) ? C’est un des cas où la reproductibilité parfaite est difficile. La solution est d’avoir des images Docker spécifiques pour chaque architecture (-cpu, -gpu). De plus, il faut être conscient que certaines opérations mathématiques peuvent donner des résultats très légèrement différents entre CPU et GPU, ce qui peut nécessiter de définir des tolérances dans les tests.