TP4 Parties 2-4 : pipeline.py (split -> train --register -> promote) + workflow Forgejo Actions (PR -> main) + requirements
This commit is contained in:
50
.forgejo/workflows/pipeline.yml
Normal file
50
.forgejo/workflows/pipeline.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
name: pipeline
|
||||
|
||||
# Partie 4 : le pipeline ML est rejoue automatiquement a chaque Pull Request
|
||||
# vers la branche principale (Q4.1). Autres declencheurs possibles (Q4.4) :
|
||||
# push sur main, tag de release, planification (schedule/cron), declenchement
|
||||
# manuel (workflow_dispatch).
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
train-and-register:
|
||||
runs-on: docker
|
||||
# Le runner (mode docker, reseau mlops-net) lance le job dans ce conteneur.
|
||||
# On y monte en lecture seule les donnees source du fil rouge et le magasin
|
||||
# de certificats du host (pour faire confiance a la CA interne ENI MLOps).
|
||||
container:
|
||||
image: node:20-bookworm
|
||||
volumes:
|
||||
- /data/modelling:/data/modelling:ro
|
||||
- /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro
|
||||
steps:
|
||||
- name: Recuperation du code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Installation de Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Installation des dependances
|
||||
run: pip install -r requirements.txt
|
||||
|
||||
- name: Execution du pipeline (split -> train --register -> promote)
|
||||
run: python pipeline.py
|
||||
env:
|
||||
# Serveur MLflow (basic auth) : URLs HTTPS via Caddy, resolues sur mlops-net.
|
||||
MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_TRACKING_URI }}
|
||||
MLFLOW_TRACKING_USERNAME: ${{ secrets.MLFLOW_TRACKING_USERNAME }}
|
||||
MLFLOW_TRACKING_PASSWORD: ${{ secrets.MLFLOW_TRACKING_PASSWORD }}
|
||||
MLFLOW_EXPERIMENT_NAME: ${{ secrets.MLFLOW_EXPERIMENT_NAME }}
|
||||
# Artefacts sur S3 Garage (log_model).
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
MLFLOW_S3_ENDPOINT_URL: ${{ secrets.MLFLOW_S3_ENDPOINT_URL }}
|
||||
# CA interne ENI MLOps (requests/boto3 n'utilisent pas le store systeme par defaut).
|
||||
REQUESTS_CA_BUNDLE: /etc/ssl/certs/ca-certificates.crt
|
||||
AWS_CA_BUNDLE: /etc/ssl/certs/ca-certificates.crt
|
||||
# Import du package lab depuis la racine du depot.
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
70
pipeline.py
Normal file
70
pipeline.py
Normal file
@@ -0,0 +1,70 @@
|
||||
"""Pipeline ML automatise : split -> entrainement (--register) -> promotion.
|
||||
|
||||
Orchestre en une seule commande (`python pipeline.py`) les etapes du fil rouge
|
||||
menant a la mise a disposition du modele dans le MLflow Model Registry :
|
||||
|
||||
1. split : (re)cree data/{train,validation,test}.parquet depuis /data/modelling
|
||||
(strategie de split figee dans lab/constants.py) ;
|
||||
2. train : entraine la strategie de service (`full`) et enregistre une
|
||||
nouvelle version du modele dans le Registry (log_model + --register) ;
|
||||
3. promote : (re)pointe l'alias `champion` vers cette nouvelle version.
|
||||
|
||||
Chaque etape est un sous-processus lance avec `check=True` : si une etape echoue,
|
||||
le pipeline s'arrete immediatement avec un code de sortie non nul et n'execute
|
||||
aucune etape suivante (Partie 2, Q2.2). Le pipeline est reexecutable sans effet
|
||||
de bord indesirable (idempotence, Q2.3) : le split est deterministe, `--register`
|
||||
empile proprement une nouvelle version, et l'alias `champion` est repointe
|
||||
(jamais duplique).
|
||||
|
||||
Les etapes reutilisent telles quelles les CLI du package `lab/` (memes commandes
|
||||
qu'une execution manuelle des TP precedents) : le pipeline ne fait que les
|
||||
enchainer et calculer le numero de la version a promouvoir.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from mlflow import MlflowClient
|
||||
|
||||
from lab import constants
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [pipeline] %(message)s")
|
||||
logger = logging.getLogger("pipeline")
|
||||
|
||||
|
||||
def run_step(title: str, module_args: list[str]) -> None:
|
||||
"""Execute une etape (module `lab`) dans un sous-processus ; stoppe si elle echoue."""
|
||||
logger.info("=== ETAPE %s : python -m %s", title, " ".join(module_args))
|
||||
subprocess.run([sys.executable, "-m", *module_args], check=True)
|
||||
|
||||
|
||||
def latest_model_version(name: str) -> int:
|
||||
"""Numero de la derniere version enregistree du modele (celle qui vient d'etre creee)."""
|
||||
client = MlflowClient()
|
||||
versions = client.search_model_versions(f"name = '{name}'")
|
||||
if not versions:
|
||||
raise RuntimeError(f"Aucune version enregistree pour le modele '{name}'.")
|
||||
return max(int(mv.version) for mv in versions)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
strategy = constants.SERVING_STRATEGY
|
||||
name = constants.REGISTERED_MODEL_NAME
|
||||
alias = constants.MODEL_ALIAS
|
||||
|
||||
# 1. Preparation des jeux de donnees (deterministe).
|
||||
run_step("split", ["lab.split.cli"])
|
||||
|
||||
# 2. Entrainement + enregistrement d'une nouvelle version dans le Model Registry.
|
||||
run_step("train", ["lab.modeling.cli", strategy.value, "--register"])
|
||||
|
||||
# 3. Promotion : repointer l'alias vers la version qui vient d'etre enregistree.
|
||||
version = latest_model_version(name)
|
||||
run_step("promote", ["lab.registry.cli", "promote", "--version", str(version), "--alias", alias])
|
||||
|
||||
logger.info("Pipeline termine avec succes : %s v%s -> alias '%s'", name, version, alias)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
14
requirements.txt
Normal file
14
requirements.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
# Dependances runtime du pipeline (Partie 4 : "installer les dependances").
|
||||
# Versions figees sur l'environnement de reference de la VM (venv /opt/venvs/mlops,
|
||||
# Python 3.14) pour garantir la reproductibilite et la coherence avec le serveur
|
||||
# MLflow (3.13.0) et l'API de service (chargement du modele enregistre).
|
||||
mlflow==3.13.0
|
||||
scikit-learn==1.9.0
|
||||
scipy==1.17.1
|
||||
numpy==2.4.6
|
||||
pandas==2.3.3
|
||||
pyarrow==24.0.0
|
||||
typer==0.26.7
|
||||
boto3==1.43.0
|
||||
botocore==1.43.0
|
||||
s3fs==2026.6.0
|
||||
Reference in New Issue
Block a user