# ML EnerVision Pipeline d'entrainement du modele de prevision de consommation energetique. Contexte complet : [ADR 0005](../docs/adr/0005-modele-prediction-lightgbm.md) (choix du modele) et [ML-START.md](../ML-START.md) (mecanisme d'acces aux donnees). | Element | Choix | |--------------|-----------------------------------------------| | Python | 3.14 | | Gestionnaire | uv (`uv.lock` fait foi) | | Modele | LightGBM (regression, un seul modele global) | | Suivi | MLflow (parametres, metriques, artefact) | | Lint/format | ruff | | Typage | mypy en mode strict | | Tests | pytest, donnees synthetiques uniquement | Projet Python independant de `apps/backend` : le service FastAPI n'a aucune raison d'embarquer LightGBM/MLflow en dependance de production juste pour un script d'entrainement lance a la main. ## Installation ```bash uv sync --all-groups ``` ## Donnees Deux sources, qui produisent le meme schema en sortie de `enervision_ml.data` (voir le module pour le detail) : - **CSV** (`--csv`), chemin de demarrage : lit directement `ml/data/all_sites_combined.csv`, le jeu de donnees fourni pour le jalon J3. Ce dossier est ignore par git (gros fichier, local a chaque poste) : recuperer le CSV et `dataset_metadata.json` aupres de l'equipe et les placer dans `ml/data/` avant d'entrainer sur cette source. - **PostgreSQL** (par defaut, sans `--csv`) : connexion directe a `reading` + `site` via `ML_DATABASE_URL`, le chemin cible decrit dans `ML-START.md`. Le role PostgreSQL dedie `enervision_ml` (lecture seule) n'est pas encore provisionne (dette assumee, cf. ADR 0003 et ADR 0005) ; en attendant, pointer `ML_DATABASE_URL` vers la meme base que le backend suffit en developpement. ## Entrainement ```bash uv run python -m enervision_ml.train --csv data/all_sites_combined.csv # ou, une fois la base peuplee et ML_DATABASE_URL positionnee : uv run python -m enervision_ml.train ``` Ecrit le modele entraine dans `models/lightgbm-consumption.txt` (`Booster.save_model()`, dossier ignore par git) et journalise la run dans MLflow : parametres, MAE/RMSE/MAPE du modele **et** de la baseline de persistance saisonniere (consommation de la meme heure, une semaine avant), et l'artefact modele. Sans `MLFLOW_TRACKING_URI`, MLflow ecrit dans un magasin SQLite local (`./mlflow.db`, ignore par git) : `uv run mlflow ui` pour le consulter. `--test-fraction` (0.15 par defaut) fixe la part la plus recente de l'historique reservee a la validation. La coupure est **chronologique**, jamais un tirage aleatoire de lignes : un tirage aleatoire laisserait des lignes de validation "voir" des lignes d'entrainement via leurs lags/moyennes glissantes, une fuite qui masquerait un surapprentissage. ## Commandes ```bash uv run ruff check . # lint uv run ruff format . # format uv run mypy enervision_ml tests # typage strict uv run pytest # tests ``` Depuis la racine du monorepo, via le `Makefile` : `make install-ml`, `make ml-lint`, `make ml-typecheck`, `make ml-test`, `make ml-check`, `make ml-train` (`CSV=chemin` optionnel). ## Ou ecrire les tests Aucun test ne touche PostgreSQL ni un serveur MLflow distant : `enervision_ml.data.load_from_csv` et le chargement CSV de test suffisent a exercer `build_features` sur des donnees reelles ou synthetiques, et `enervision_ml.train.train()` accepte un `tracking_uri` SQLite isole (`tmp_path` pytest) pour un test de bout en bout sans effet de bord. `enervision_ml.data.load_from_database` n'est pas encore couvert : il n'existe aucune base PostgreSQL a interroger en CI ni dans cet environnement de developpement pour le moment. ## Piege a connaitre `enervision_ml.features.build_features` est **le seul endroit** qui doit construire les features du modele, a l'entrainement comme au futur scoring (service #37, pas encore construit). Si les deux divergent meme legerement (une fenetre de moyenne glissante calculee differemment, par exemple), le modele recoit en production des features qui ne ressemblent plus a ce qu'il a appris, et ses predictions deviennent silencieusement mauvaises sans qu'aucune erreur ne se declenche. Ne jamais reecrire cette logique ailleurs : importer `enervision_ml.features`.