Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Pipeline DVC : rejouer un entraînement ML à l'identique

Par mis à jour le

Améliorer cette page

Un pipeline DVC décrit dans un fichier dvc.yaml les étapes d'un entraînement, leurs entrées et leurs sorties, et dvc repro ne rejoue que ce qui a changé. On n'a plus à se souvenir qu'il faut générer les données avant d'entraîner, ni à deviner si un changement d'hyperparamètre oblige à tout refaire : DVC compare les empreintes et décide.

Cette leçon prolonge celles sur le projet reproductible et le versionnement des données. Public : intermédiaire. Elle transforme deux scripts lancés à la main en un pipeline de deux étapes, le rejoue sur un clone vierge, et montre la propriété qui justifie l'outil : un paramètre modifié ne relance que l'étape qu'il touche.

  • Décrire une étape de pipeline avec ses commandes, dépendances, paramètres et sorties.
  • Séparer la configuration (params.yaml) des étapes (dvc.yaml).
  • Rejouer le pipeline avec dvc repro et expliquer pourquoi il ne relance rien quand rien n'a changé.
  • Lire dvc.lock pour comprendre comment DVC détecte un changement.
  • Publier les métriques avec metrics: et les comparer avec dvc metrics.
  • Reconstruire les mêmes métriques sur un clone vierge.

La leçon suppose les deux leçons précédentes du module Reproduire : un environnement verrouillé par uv.lock, une graine dans params.yaml, et la mécanique DVC de la leçon précédente (dvc init, remote S3 vers le même bucket Garage, variables AWS_ACCESS_KEY_ID et AWS_SECRET_ACCESS_KEY chargées dans le terminal). Le lab repart d'un dépôt neuf : DVC et son remote s'y installent comme dans la leçon précédente (uv add dvc dvc-s3, dvc init, dvc remote add). Aucune connaissance supplémentaire de DVC n'est requise. Versions mesurées : DVC 3.67.1, dvc-s3 3.3.0, uv 0.12.10, scikit-learn 1.9.1.

Un enchaînement de scripts lancés à la main n'a ni ordre écrit, ni mémoire de ce qui est à jour. Le scénario du lab est courant : on génère les données avec un script, on entraîne avec un autre, et quand un collègue change n_arbres (le nombre d'arbres de la forêt), personne ne sait s'il faut régénérer les données. Les métriques publiées n'ont jamais pu être refaites par quelqu'un d'autre.

Un pipeline écrit rend explicites trois choses. L'ordre : l'entraînement dépend du fichier produit par la génération. Les entrées de chaque étape : code, données, paramètres. Les sorties : fichiers produits, métriques. Avec ces trois informations, un outil peut décider seul de ce qu'il faut rejouer, ce qu'un humain fait mal à chaque fois.

Le pipeline a deux étapes : donnees produit le CSV, entrainer le consomme et écrit les métriques. Les paramètres vivent dans params.yaml, groupés par étape : la graine et le nombre de lignes pour les données, la graine, le nombre d'arbres et la part de test pour l'entraînement.

Lisez le schéma de gauche à droite : chaque flèche est une dépendance. L'étape entrainer reçoit deux entrées, le fichier produit par donnees et ses propres paramètres. C'est ce graphe que DVC parcourt pour décider de ce qui est à jour. dvc dag en affiche la version texte.

Les paramètres donnees.graine et donnees.lignes alimentent l'étape donnees, qui exécute genere-metriques.py et produit data/metriques.csv. Ce fichier et les paramètres entrainement.seed, entrainement.n_arbres et entrainement.part_test alimentent l'étape entrainer, qui exécute train.py et écrit metrics.json, suivi par Git.params.yamldonnees.graine, lignesétape donneesgenere-metriques.pydata/metriques.csvétape entrainertrain.pyparams.yamlentrainement.seed, n_arbres, part_testmetrics.json(suivi par Git)
Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %
donnees:
graine: 42
lignes: 5000
entrainement:
seed: 42
n_arbres: 50
part_test: 0.2

Le fichier params.yaml ci-dessus est la configuration du lab. Le script train.py lit la section entrainement, comme dans la leçon sur le projet reproductible, mais avec n_arbres en plus, qui règle la taille de la forêt. Le script le lit dans params.yaml et le passe au modèle :

params = yaml.safe_load(open("params.yaml", encoding="utf-8"))
modele = RandomForestRegressor(
n_estimators=params["entrainement"]["n_arbres"],
n_jobs=1,
random_state=params["entrainement"]["seed"],
)

Chaque étape déclare sa commande (cmd), ses dépendances (deps), les paramètres qu'elle lit (params) et ses sorties (outs, metrics). DVC rejoue une étape dès qu'une de ses dépendances, un de ses paramètres ou sa commande a changé.

stages:
donnees:
cmd: uv run python genere-metriques.py --graine ${donnees.graine} --lignes ${donnees.lignes} --sortie data/metriques.csv
deps:
- genere-metriques.py
params:
- donnees.graine
- donnees.lignes
outs:
- data/metriques.csv
entrainer:
cmd: uv run python train.py
deps:
- train.py
- data/metriques.csv
params:
- entrainement.seed
- entrainement.n_arbres
- entrainement.part_test
metrics:
- metrics.json:
cache: false

La syntaxe ${donnees.graine} fait lire à DVC la valeur dans params.yaml, ce qui évite de la dupliquer dans la commande. Le fichier data/metriques.csv est une sortie de la première étape et une dépendance de la seconde : c'est ce lien qui fixe l'ordre. Les commandes dvc stage add écrivent le même fichier, mais l'écrire à la main reste plus lisible pour deux étapes.

Une sortie déclarée dans outs est stockée dans le cache DVC et poussable vers le remote, comme un fichier suivi par dvc add. Si le CSV était déjà suivi par dvc add (leçon précédente), le retirer du suivi d'abord par dvc remove data/metriques.csv.dvc (le fichier reste, seul le pointeur disparaît) : un fichier ne peut pas avoir deux propriétaires. L'option cache: false sur metrics.json garde ce petit fichier dans Git et pas dans le bucket, ce qui rend les métriques lisibles dans l'historique. Dans la première leçon, metrics.json restait une simple sortie hors de Git ; ici DVC en fait une métrique suivie, donc versionnée.

dvc repro exécute les étapes dans l'ordre du graphe, saute celles qui sont à jour, puis écrit dvc.lock. Ce fichier enregistre, pour chaque étape, l'empreinte de la commande, des dépendances, des paramètres et des sorties. Il se versionne avec le reste.

Deux points de départ sont possibles, et l'un des deux seulement correspond à votre dépôt.

Cas (a), dépôt neuf du lab. Le dépôt ne contient que les scripts et params.yaml. Le mkdir est indispensable : le générateur n'écrit pas dans un dossier absent, et DVC ne le crée pas avant de lancer la commande.

Fenêtre de terminal
git init
uv add dvc dvc-s3
uv run dvc init
uv run dvc remote add -d stockage s3://dvc-donnees
uv run dvc remote modify stockage endpointurl http://127.0.0.1:3900
uv run dvc remote modify stockage region garage
mkdir -p data
uv run dvc repro
git add dvc.yaml dvc.lock params.yaml metrics.json train.py genere-metriques.py pyproject.toml uv.lock .dvc data/.gitignore .gitignore
git commit -m "Pipeline données et entraînement"
uv run dvc push

La liste du git add couvre tout ce dont un clone a besoin : le code (train.py, genere-metriques.py), l'environnement (pyproject.toml, uv.lock), la configuration du remote (.dvc) et le pipeline (dvc.yaml, dvc.lock). Sans .dvc, le clone ne sait pas où est le bucket.

Cas (b), suite de la leçon précédente. Le CSV est déjà suivi par dvc add et le .gitignore racine ignore encore metrics.json. Il faut retirer le pointeur, laisser dvc repro reprendre le CSV, et enregistrer la suppression.

Fenêtre de terminal
uv run dvc remove data/metriques.csv.dvc
uv run dvc repro
sed -i '/^metrics.json$/d' .gitignore
git add dvc.yaml dvc.lock params.yaml metrics.json data/metriques.csv.dvc data/.gitignore .gitignore
git commit -m "Pipeline données et entraînement"
uv run dvc push

Le sed retire metrics.json du .gitignore racine : sans cela, git add refuse ce fichier (« paths are ignored »), alors qu'il doit être versionné. Le git add du pointeur data/metriques.csv.dvc, supprimé par dvc remove, enregistre cette suppression dans le commit : sans elle, un clone récupérerait encore le pointeur et DVC refuserait la sortie en double. Dans le cas (a), ni le pointeur ni la ligne metrics.json n'existent : ne les ajoutez pas, git add échouerait sur un chemin inconnu.

À la première exécution, les deux étapes tournent. Ensuite, dvc.lock sert de référence : à chaque dvc repro, DVC recalcule les empreintes et les compare aux valeurs enregistrées. Le dvc push envoie les sorties dans le bucket pour qu'un autre poste les récupère par dvc pull.

Voici l'extrait de dvc.lock pour l'étape donnees, empreintes et tailles remplacées par des repères :

schema: '2.0'
stages:
donnees:
cmd: uv run python genere-metriques.py --graine 42 --lignes 5000 --sortie
data/metriques.csv
deps:
- path: genere-metriques.py
hash: md5
md5: <empreinte>
size: <taille>
params:
params.yaml:
donnees.graine: 42
donnees.lignes: 5000
outs:
- path: data/metriques.csv
hash: md5
md5: <empreinte>
size: <taille>

DVC replie la commande sur deux lignes quand elle est longue : c'est le même YAML. Lisez-le comme un relevé : la commande avec les valeurs résolues, l'empreinte de chaque dépendance, la valeur de chaque paramètre et l'empreinte de chaque sortie. Si une seule de ces valeurs diffère au prochain dvc repro, l'étape est rejouée.

Sans changement, dvc repro ne rejoue rien ; avec un n_arbres modifié, il rejoue entrainer seul. Le lab l'a mesuré : pas de ligne « Running stage » au second lancement, Stage 'donnees' didn't change, skipping pour l'étape de données, et seule l'étape d'entraînement relancée quand le nombre d'arbres change.

ChangementÉtape donneesÉtape entrainer
Aucunsautéesautée
entrainement.n_arbressautéerejouée
donnees.grainerejouéerejouée (son entrée a changé)
Contenu de train.pysautéerejouée

Pourquoi donnees n'est-elle pas relancée quand on change n_arbres ? Parce que cette étape ne déclare pas ce paramètre : DVC ne regarde que ce qui est listé. Le corollaire est un piège : un paramètre lu par le script mais absent de la liste params ne déclenche jamais de rejeu. La liste du dvc.yaml doit être complète.

Pour le constater, passez entrainement.n_arbres de 50 à 60 dans params.yaml, puis lancez :

Fenêtre de terminal
uv run dvc params diff
uv run dvc repro
uv run dvc metrics diff

dvc params diff compare params.yaml au dernier commit et montre le changement avant de rejouer. dvc repro doit afficher Stage 'donnees' didn't change, skipping, puis relancer entrainer seul. dvc metrics diff compare ensuite les métriques à celles du dernier commit, et dvc metrics show affiche celles d'aujourd'hui sous forme de tableau.

Avec n_arbres à 60, la sortie mesurée dans le lab est la suivante. Les chiffres exacts dépendent des versions verrouillées, mais le sens de la lecture est stable : HEAD est le dernier commit, workspace votre état courant.

Path Param HEAD workspace
params.yaml entrainement.n_arbres 50 60
Path Metric HEAD workspace Change
metrics.json r2 0.78135 0.78608 0.00473
metrics.json rmse 23.31062 23.05688 -0.25374

Comment reproduire les métriques sur un clone vierge ?

Section intitulée « Comment reproduire les métriques sur un clone vierge ? »

Un clone vierge reconstruit l'environnement depuis le verrou, récupère les sorties dans le bucket, puis dvc repro --force rejoue le pipeline et redonne les mêmes métriques. Les quatre sources de variation de la première leçon sont couvertes : le code par Git, les bibliothèques par uv.lock, le hasard par la graine de params.yaml, les données et leur enchaînement par dvc.yaml et dvc.lock.

Fenêtre de terminal
git clone <depot> clone && cd clone
uv sync --locked
uv run dvc pull
uv run dvc repro --force
git diff metrics.json

uv sync --locked crée le .venv à l'identique. dvc pull ramène du bucket les sorties poussées, sans rien recalculer. Un simple dvc repro dirait seulement que tout est à jour ; --force rejoue les deux étapes malgré tout. Le metrics.json du clone, versionné, vient de Git : git diff metrics.json ne doit rien afficher après le rejeu, c'est la preuve que le pipeline recalcule les mêmes chiffres et qu'il est reproductible par quelqu'un d'autre que son auteur.

SymptômeCause probableCorrection
dvc repro rejoue tout à chaque lancementUne sortie ou une dépendance change à chaque exécution (horodatage, fichier non déterministe)Rendre le script déterministe, sinon DVC voit un changement permanent
Changer n_arbres ne rejoue rienLe paramètre est absent de la liste params de l'étapeAjouter entrainement.n_arbres à params
dvc repro sur un clone régénère le CSV au lieu de le récupérerLes sorties ne sont pas dans le cache local : DVC rejoue l'étape donnees (Running stage 'donnees'), sans erreurLancer dvc pull avant dvc repro, et dvc push après chaque dvc repro qui produit des sorties
ERROR: output 'data/metriques.csv' is specified in: - donnees - data/metriques.csv.dvcLe CSV est suivi à la fois par dvc add et par outsRetirer le suivi dvc add avec dvc remove data/metriques.csv.dvc (supprime le pointeur et l'entrée du .gitignore, garde le fichier)
Les métriques diffèrent de celles du dépôtEnvironnement non reconstruit depuis le verrouuv sync --locked, puis relancer dvc repro
dvc.lock apparaît modifié sans raisonParamètres ou dépendances changésRelire git diff dvc.lock : il dit quelle empreinte a bougé

Le lab vous remet deux scripts, un params.yaml et un pyproject.toml, dans un dépôt neuf : installez-y DVC et son remote comme dans la leçon précédente. Vous décrivez ensuite les scripts en pipeline DVC de deux étapes, la seconde devant s'appeler entrainer (la validation la cherche par ce nom), vous le publiez avec ses sorties dans le bucket, et vous prouvez trois choses : un clone vierge redonne les mêmes métriques, un dvc repro sans changement ne rejoue rien, et la modification de n_arbres ne rejoue que l'entraînement. La validation lit le dvc.yaml, le bucket, les métriques et ce que DVC rejoue réellement. Comme pour la leçon précédente, démarrez le socle S3 avec scripts/socle-demarrer.sh.

  • Un pipeline écrit donne l'ordre, les entrées et les sorties de chaque étape ; DVC décide seul de ce qui est à jour.
  • dvc.yaml décrit les étapes (cmd, deps, params, outs, metrics), params.yaml porte la configuration.
  • dvc repro compare les empreintes à dvc.lock : rien n'a changé, rien ne tourne ; un paramètre change, seule l'étape qui le lit rejoue.
  • Un paramètre absent de la liste params ne déclenche jamais de rejeu : la liste doit être complète.
  • metrics: avec cache: false garde metrics.json dans Git ; dvc metrics show et dvc metrics diff les lisent.
  • Un clone vierge reconstruit l'environnement avec uv sync --locked, récupère les sorties avec dvc pull, puis dvc repro --force recalcule les mêmes métriques.
  • DVC rejoue un graphe, il n'orchestre pas : planification et cluster relèvent d'une autre brique.

Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn