🔧 Vigilance — Détection d’Anomalies Temps Réel (MLOps)
Vision : plateforme complète de détection d’anomalies en temps réel, démontrant une maîtrise bout-en-bout du MLOps — de la modélisation à la mise en production, avec observabilité et gestion du cycle de vie des alarmes.
Contexte : projet personnel, conçu comme un système (event model, workers découplés, registries versionnés) et non comme une suite de scripts
Durée : 1 200+ heures de développement (2025-2026)
Périmètre : 3 machines simulées (capteurs numériques, flux 1 event/s/machine), extensible par simple enregistrement de dataset
Où en est ce projet : - ✅ Fait et fonctionnel : pipeline de détection (3 canaux + fusion), cycle de vie d’alarme, dashboard 40+ pages, observabilité Prometheus/Grafana, résilience (DLQ, backups, reprise après crash) - 🚧 Prévu, pas encore construit : boucle de feedback opérateur (validation humaine → réentraînement automatique), score de santé agrégé par machine - 🔭 Exploratoire : GATv2/Transformer sur graphes de capteurs (prototype existant, pas intégré au pipeline)
🧑💼 Vue d’ensemble
En une phrase : un système qui surveille en continu des capteurs industriels et prévient automatiquement quand quelque chose d’anormal se produit — avant que ça ne devienne une panne coûteuse.
Le problème : sur une ligne de production, un capteur qui dérive lentement (roulement qui s’use, capteur qui se désétalonne) passe souvent inaperçu jusqu’à la panne. Détecter ce genre de signal faible, en continu et sans intervention humaine, est la promesse du “monitoring intelligent” — le même principe que les outils de supervision utilisés par Netflix ou Uber pour surveiller leurs services, appliqué ici à des capteurs physiques.
Ce que le système fait concrètement : - Il regarde chaque capteur en continu et compare son comportement à trois façons différentes de définir “anormal” (pour ne pas rater un type de dérive qu’une seule méthode manquerait) - Quand une anomalie est confirmée, il ouvre un ticket unique (pas un spam d’alertes répétées pour le même problème) et lui donne un niveau de gravité - Un tableau de bord affiche en direct l’état de toutes les machines, avec une explication de pourquoi chaque alerte a été levée — pas juste “anomalie détectée”, mais “ce facteur précis est responsable” - Le système sait aussi surveiller sa propre santé : temps de réponse, erreurs, charge — comme le ferait une équipe SRE pour un site web
Pourquoi c’est difficile : le vrai défi n’est pas de détecter une anomalie évidente, mais d’éviter à la fois les fausses alertes (qui usent la confiance des opérateurs) et les anomalies manquées — tout en restant utilisable en continu, sans surveillance humaine constante.
Ce que ça démontre : la capacité à concevoir un système complet — pas juste un modèle qui prédit, mais tout ce qu’il faut autour pour que ce modèle soit fiable, observable et utilisable en production.
De trois signaux à un ticket unique
flowchart TD
A["3 machines simulées<br/>1 événement/s · reprise après crash"] --> B[worker_features]
B --> C1["1 · Statique<br/>IsolationForest"]
B --> C2["2 · Temporel ponctuel<br/>résidu Ridge, 8 lags"]
B --> C3["3 · Temporel séquentiel<br/>reconstruction PCA, 16 pas"]
B --> C4["Règles capteur<br/>valeur figée, dérive"]
C1 --> D["Fusion<br/>XGBoost"]
C2 --> D
C3 --> D
D --> E["Explication<br/>SHAP par événement"]
C4 --> E
E --> F["**Un ticket par épisode**<br/>hystérésis · escalade · SLA"]
F --> G["Cockpit Streamlit<br/>40+ pages, rôles RASCI"]
En clair, sans le schéma : trois machines simulées émettent un événement par seconde, avec reprise après coupure. Quatre détecteurs les jugent en parallèle — un statique (IsolationForest), deux temporels (résidu Ridge sur 8 retards, reconstruction PCA sur 16 pas) et un jeu de règles capteur. Seuls les trois premiers sont fusionnés par XGBoost ; les règles capteur rejoignent directement l’explication SHAP. Le tout est regroupé en un ticket par épisode — hystérésis, escalade, SLA — que le cockpit Streamlit présente selon les rôles RASCI.
Ce que ce flux montre, et qu’une liste de workers ne montre pas : trois détections parallèles et décorrélées ne produisent pas trois alertes, mais un seul incident, expliqué et suivi jusqu’à sa clôture. C’est la différence entre un détecteur et un système.
L’implémentation, pour qui veut vérifier
Neuf workers, barrières Redis atomiques (à 3 puis à 2), file de rejet, reprise après crash sur index persisté. Les canaux unsup_stat, unsup_temp_point, unsup_temp_seq et sensor_fault alimentent worker_sup, puis worker_model_interpreter, worker_correlation_drift et worker_novelty_rules_unsup_sup. Diffusion au cockpit par liste Redis et Pub/Sub.
⚙️ Exécution distribuée
| Composant | Réalité technique |
|---|---|
| Pool CPU | 3 réplicas de workers universels (consomment toutes les queues queue:cpu:*) |
| Pool GPU | 1 worker CUDA 12.8 (queues queue:gpu:*) |
| Synchronisation | Queues Redis par étape, barrières multi-parents, fusion des prédictions |
| Résilience | Dead Letter Queue rejouée (30 s), archiveur Parquet (300 s), backup des registries (1 h, 24 rétentions) |
| Registries | JSON versionnés (modèles, features, seuils, alertes, drift, data_versions) — écriture atomique write-tmp → os.replace |
Détecteurs (3 canaux réellement décorrélés)
| Canal | Algorithme | Coût d’inférence |
|---|---|---|
| Statique | IsolationForest | ~1 ms/event |
| Temporel ponctuel | Résidu de prévision Ridge sur 8 lags | 0.05 ms/event |
| Temporel séquentiel | Reconstruction PCA sur fenêtres de 16 pas | 0.12 ms/event |
Historique par machine partagé entre réplicas via Redis (1 aller-retour par event), calibration sigmoïde alignée (p97 train → proba 0.5), warm-up dégradé propre.
🎫 Cycle de vie d’alarme — un épisode = un ticket
Machine à états côté backend (pas dans l’UI) :
IDLE ──(N ticks anormaux consécutifs)──► OPEN (1 ticket)
OPEN ──(ticks anormaux)──► même ticket : occurrences++, pic, escalade de sévérité
OPEN ──(hystérésis : N ticks normaux consécutifs)──► AUTO_RESOLVED
- Un tick normal isolé ne fragmente pas l’épisode (anti-scintillement)
- Concurrence des 3 réplicas gérée sans verrou :
SET NXà l’ouverture,GETDELà la clôture → un seul écrivain par transition - Clôture opérateur avec cooldown anti-réouverture ; champs opérateur (assignation, notes) jamais écrasés par le backend
📊 Dashboard Streamlit (40+ pages, 7 sections)
Navigation native st.navigation, matrice RASCI par page (opérateur / analyste / technicien / admin) :
| Section | Contenu |
|---|---|
| 📡 Monitoring | Global live, monitoring local, comparaison de flotte, pires instabilités, dérives |
| 🚨 Alertes | Alertes actives (SLA countdown), assignation, escalade, événements similaires passés |
| 🔍 Investigation | Étude d’anomalie, graphe causal, analyse contrastive, décisions modèles, replay |
| ✅ Feedback | Validation d’anomalies, corrections, qualité des labels |
| 📈 Reporting | Statistiques d’anomalies, historique maintenance, rapports planifiés |
| 🔧 Technicien | Contrôle bootstrap, gestion modèles/seuils, workers du DAG, feature sets |
| ⚙️ Admin | Règles d’alertes, santé système, audit log, gestion utilisateurs |
🔭 Observabilité
- Prometheus : latence et erreurs par étape du DAG (
worker_step_duration_seconds,worker_step_errors_total), métriques Redis (exporter dédié) - Grafana : dashboards pipeline + infrastructure, embarquables dans le cockpit
- cAdvisor : CPU/RAM par conteneur
- SLA opérationnel : countdown par sévérité d’alerte, suivi des dépassements dans le cockpit
🧠 Interprétabilité intégrée au flux
- SHAP calculé par event dans le pipeline (worker dédié), facteur principal remonté jusqu’à la carte d’alerte
- Profils de normalité par cluster (z-mean + SHAP) calculés au bootstrap et versionnés au registre
- Corrélations baseline par machine → détection de dérive de corrélation en ligne
🔄 Bootstrap « Cartographe »
- Entraînement complet d’une machine (5 modèles + profils d’interprétation) : ~1,5 s
- Skip par modèle (fichier présent → chargé pour le vote, absent → ré-entraîné)
- Vote majoritaire 2/3 des canaux non supervisés → clusters → classifieur supervisé → règles de nouveauté
🛠️ Stack technique réelle
| Catégorie | Technologies |
|---|---|
| Langages | Python 3.11 |
| Data | Polars, Pandas, NumPy, Parquet |
| ML | Scikit-learn, XGBoost, PyTorch (CUDA 12.8) |
| Interprétabilité | SHAP |
| Infrastructure | Docker Compose (14 services), Redis 7 |
| Monitoring | Prometheus, Grafana, cAdvisor, redis-exporter |
| Dashboard | Streamlit ≥ 1.36 (st.navigation) |
🎯 Compétences démontrées
- Architecture événementielle : DAG distribué, barrières atomiques, workers découplés, fusion d’états
- Fiabilité : DLQ, archivage, backups, reprise exacte après redémarrage, dégradation propre (warm-up, TTL)
- Gestion d’alarmes : machine à états, hystérésis, escalade, déduplication en épisode unique — le cœur métier d’un système de monitoring industriel
- MLOps : registries versionnés, bootstrap conditionnel, compatibilité descendante des modèles picklés
- Observabilité : métriques par étape, SLA, monitoring infra
- UX opérationnelle : 40+ pages organisées par rôle RASCI, du cockpit temps réel à l’audit
🚀 Évolutions prévues
- Court terme : boucle de feedback fermée avec Aegis-RCA — les diagnostics de cause racine validés (ou corrigés) par un opérateur deviennent des labels pour réentraîner la couche supervisée au-delà du binaire anomalie/pas-anomalie ; score de santé agrégé par machine, sparkline d’épisode sur les cartes d’alerte, Redis comme source de vérité unique des tickets
- Moyen terme : GATv2/Transformer sur graphes de capteurs (prototype existant), online learning, multi-sites
- Long terme : RUL (durée de vie restante), maintenance prescriptive
Code source : dépôt privé, accès sur demande
Dernière mise à jour : Août 2026
Contact : cyril.bgs.dev@gmail.com