📖 GUIDE INTERACTIF

Spatial Graph
Classifier

Apprenez à classifier automatiquement les pièces d'un bâtiment BIM — sans aucun machine learning, juste de la géométrie et de la topologie.

Commencer le guide → Aller à l'utilisation

C'est quoi ce projet ?

Un outil qui devine la fonction de chaque pièce (chambre, cuisine, SDB…) à partir d'un modèle Revit — sans jamais lire les noms.

🏠

Le problème

Dans un modèle Revit, chaque pièce a un nom donné par l'architecte (« Séjour », « CH1 », « SDB »…). Mais ces noms sont incohérents d'un projet à l'autre. On veut deviner la fonction réelle de chaque pièce sans ces noms.

🧠

La solution : classification aveugle

Le classifieur analyse uniquement la géométrie (surface, fenêtres, portes) et la topologie (qui est connecté à qui dans le graphe spatial). Pas de machine learning — juste des règles métier architecturales organisées en 5 passes successives.

📊

Les résultats

97.7% de précision sur 1 217 pièces (multi-projets) et 93.4% sur 362 pièces (projet LD-CLL). Le tout avec zéro dépendance externe — Python stdlib uniquement.

💡
Graphe spatial ? C'est une représentation du bâtiment comme un réseau : chaque pièce est un nœud, chaque porte/fenêtre/mur crée un lien entre deux nœuds. Ce graphe est exporté depuis Revit en JSON.

Installation

3 étapes, 2 minutes, zéro dépendance à installer.

1

Python ≥ 3.10

Vérifiez votre version :

$ python --version
Python 3.12.4 # ✓ OK si ≥ 3.10
2

Cloner le dépôt

$ git clone https://github.com/Lksdlvx/spatial-graph-classifier.git
$ cd spatial-graph-classifier
3

C'est tout !

Aucune dépendance à installer (pip install non nécessaire). Le projet n'utilise que la bibliothèque standard Python.

Pas de requirements.txt à installer, pas de virtualenv obligatoire, pas de GPU. Tout tourne sur CPU en quelques secondes.

Structure du projet

Où trouver quoi dans le dépôt.

📂 data/ — Les données d'entrée+
Contient les fichiers JSON de graphes spatiaux exportés depuis Revit.

spatial_graph_P1.json — Multi-projets (1 217 pièces labellisées)
spatial_graph_P2.json — Projet LD-CLL (362 pièces)
spatial_graph_P3.json à P5.json — Datasets supplémentaires

Ces fichiers sont en lecture seule. Ne les modifiez pas.
⚙️ src/ — Le code source+
blind_classifier.pyLe cœur : toutes les règles de classification (5 passes)
apartment_clustering_v2.py — Regroupe les pièces par appartement
export_viewer.py — Génère le viewer HTML interactif
_baseline.py — Lance le benchmark d'accuracy
rules/ — 8 modules de règles modularisés (géométrique, topologique…)
wl/ — Algorithme de hashing Weisfeiler-Lehman
🌐 output/ — Les résultats+
Contient les viewers HTML générés (~10 Mo chacun). Ce sont des fichiers autonomes que vous pouvez ouvrir dans n'importe quel navigateur.

Chaque viewer affiche :
• Le graphe interactif (vis.js) avec les pièces colorées
• Les polygones des pièces avec murs et séparateurs
• La trace step-by-step de chaque règle appliquée

Ce dossier est .gitignored (non versionné).
🚀 classify_launcher.py — L'interface web+
Un serveur web local (port 8500) qui offre une interface graphique pour :

1. Sélectionner un fichier JSON
2. Lancer la classification et voir l'accuracy
3. Générer et ouvrir le viewer HTML

C'est la méthode recommandée pour les débutants.

Utilisation

Deux façons de lancer le classifieur : interface web ou ligne de commande.

🖥️ Méthode 1 : Interface web (recommandé)

La manière la plus simple. Lance un serveur local avec une UI pour tout contrôler.

$ python classify_launcher.py

🔬 Spatial Graph Classifier — http://localhost:8500
# → Votre navigateur s'ouvre automatiquement

1. Cliquez sur un dataset (P1, P2…) ou collez le chemin d'un JSON
2. Cliquez « Lancer la classification » pour voir l'accuracy
3. Cliquez « Générer le Viewer HTML » pour la visualisation complète
4. Cliquez « Ouvrir le Viewer ↗ » pour explorer le résultat

⌨️ Méthode 2 : Ligne de commande

Pour les utilisateurs avancés ou l'automatisation.

Classification + Viewer interactif :

$ python src/export_viewer.py data/spatial_graph_P1.json

# → Génère output/spatial_graph_P1_viewer.html
# → Ouvrez ce fichier dans votre navigateur

Benchmark d'accuracy uniquement :

$ python src/_baseline.py

accuracy_P1: 97.7
accuracy_P2: 93.4
score: 96.0
⏱️
Temps d'exécution — La classification prend ~10-30 secondes. La génération du viewer (avec graphe + polygones + trace) prend ~30s à 2 min selon la taille du dataset.

Le pipeline de classification

Comment le classifieur devine la fonction de chaque pièce, passe par passe.

Passe 0 — Entrées structurelles

Détecte les entrées d'appartement par analyse de graphe pur (betweenness + closeness centrality). Identifie les nœuds « ponts » entre parties communes et intérieur.

Structurel

Passe 0.5 — Template Matching (WL)

Calcule une empreinte unique de chaque appartement (Weisfeiler-Lehman). Si elle matche un des 24 templates connus → classification instantanée avec confiance 1.0.

Isomorphisme

Passe 1 — Géométrie pure

9 règles basées sur la surface, le nombre de portes/fenêtres, le ratio de séparateurs. Ex : « surface 2-3m² + 0 fenêtre + 0 séparateur → WC ».

Géométrie

Passe 2 — Propagation topologique

Utilise le voisinage des pièces déjà classées (« ancres ») pour deviner les pièces restantes. Ex : « WC connecté uniquement à une chambre → SDB ».

Topologie

Passe 3 — Contexte d'appartement

Vérifie la cohérence au niveau de l'appartement entier : unicité de la cuisine, détection de la buanderie dans les grands logements, récupération des cuisines manquantes.

Contexte

Passe 4 — Correction par cluster

Dernier filet de sécurité : si un appartement n'a pas de cuisine, de séjour ou de WC, tente de reclasser une pièce ambiguë pour combler le manque.

Correction

Post-passes — 8 règles de raffinement

Corrections fines par WL local, détection de hubs, reclassement corridor↔entrée, toilet→buanderie, storage→WC. Dernière couche d'optimisation.

Raffinement
🔒
Immutabilité — Les pièces classées avec confiance 1.0 (Passes 0 et 0.5) sont verrouillées. Aucune passe ultérieure ne peut les modifier. Cela garantit la stabilité du pipeline.

Autoresearch : la recherche autonome par IA

Comment un agent IA peut faire de la recherche expérimentale pendant que vous dormez — et comment nous l'avons appliqué à ce projet.

🧬 Le concept de Karpathy

Autoresearch est un framework créé par Andrej Karpathy (ex-directeur IA chez Tesla, co-fondateur d'OpenAI) en mars 2026. L'idée fondatrice : au lieu d'écrire du code, on écrit un programme pour l'agent qui écrit le code.

Le concept repose sur trois piliers :

1. Un fichier modifiable — L'agent n'a le droit de modifier qu'un seul fichier (ex: train.py). Cela limite le périmètre d'action et rend chaque changement auditable.
2. Une métrique objective — Un script d'évaluation immuable mesure la performance (ex: val_bpb). Pas de subjectivité : le score monte ou descend.
3. Un programme Markdown — Le fichier program.md remplace le chercheur humain. C'est un document qui décrit la boucle expérimentale, les règles de décision (keep/discard), et les gardes anti-régression.
💡
L'analogie clé — Dans la recherche classique, un doctorant lit des papiers, forme une hypothèse, code l'expérience, la lance, analyse les résultats. Autoresearch compresse ce cycle à ~5 minutes et le répète 100 fois par nuit. Le matin, on se réveille avec un log de 100 expériences et (idéalement) un modèle amélioré.

🔄 La boucle PROPOSE → RUN → EVALUATE → DECIDE

Le cœur d'autoresearch est une boucle infinie en 4 étapes :

① PROPOSE — Former une hypothèse

L'agent lit le code, analyse les erreurs du dernier run, et propose une modification ciblée. Ex : « Baisser le seuil de surface WC de 3.0 à 2.8m² ».

Hypothèse

② RUN — Exécuter l'expérience

L'agent modifie le fichier, fait un git commit, puis lance le script d'évaluation. La sortie est redirigée vers un log pour ne pas polluer le contexte.

Exécution

③ EVALUATE — Mesurer le résultat

L'agent extrait la métrique du log (grep "^score:"). Si le grep est vide → crash. Sinon, il compare au score précédent.

Mesure

④ DECIDE — Keep ou Discard

Si le score s'améliore et que les gardes anti-régression passent → keep, on avance. Sinon → discard, git reset --hard HEAD~1. On log le résultat dans results.tsv et on recommence.

Décision

💬 Exemple : une nuit d'autoresearch (Karpathy)

Voici à quoi ressemble le results.tsv après une session autonome sur nanochat :

# commit val_bpb mem_gb status description
a1b2c3d 0.9979 44.0 keep baseline
b2c3d4e 0.9932 44.2 keep increase LR to 0.04
c3d4e5f 1.0050 44.0 discard switch to GeLU activation
d4e5f6g 0.0000 0.0 crash double model width (OOM)
e5f6g7h 0.9918 44.1 keep reduce warmup steps to 100
... ~95 autres expériences pendant la nuit

Chaque ligne = une expérience complète (~5 min). L'agent a exploré des changements d'architecture, d'optimiseur, de taille de batch — trouvant des améliorations que des chercheurs humains avaient manquées.

🏗️ Application à notre projet

Nous avons adapté le framework autoresearch à la classification de pièces BIM. L'adaptation est remarquable car notre domaine n'utilise aucun réseau de neurones — c'est de la recherche sur des règles métier.

Karpathy (original)
Fichier modifiable : train.py
Métrique : val_bpb (↓ mieux)
Durée/run : 5 min (GPU)
Domaine : architecture LLM
Notre adaptation
Fichier modifiable : blind_classifier.py
Métrique : score combiné (↑ mieux)
Durée/run : ~30 sec (CPU)
Domaine : règles BIM

Ce que l'agent explore dans notre cas :

Seuils géométriques — surface min/max, sep_ratio, glazing_ratio
Ordre des règles — réarranger la priorité des passes
Nouveaux discriminants — combiner des features existantes
Gardes de sécurité — ajouter des pré-conditions pour éviter les faux positifs
Simplification — supprimer des règles inutiles (victoire nette si le score tient)

💬 Exemple : une session autoresearch sur notre projet

Voici une interaction réaliste avec l'agent sur notre classifieur :

# L'humain lance la session
Humain: Regarde program.md et lance une session autoresearch.

Agent: Je propose le tag apr30. Création de la branche...
→ git checkout -b autoresearch/apr30
→ Lecture de blind_classifier.py (744 lignes)
→ Baseline : accuracy_P1=97.0 accuracy_P2=93.4 score=95.56

# Expérience 1 — l'agent analyse les erreurs
Agent: J'observe 6 erreurs bathroom→bedroom sur P2.
Les 6 pièces ont area entre 4.0-5.5m² et 1 fenêtre.
Hypothèse : abaisser le seuil bedroom de 8m² à 7m²
→ Modification, commit, run...
→ score=95.82 (+0.26) ✓ Gardes OK
→ KEEP

# Expérience 2
Agent: 4 erreurs corridor→entrance_hall sur P1.
Hypothèse : ajouter une garde sur le degré de connexion
→ score=95.70 (-0.12) — P1 a régressé de 0.3%
→ DISCARD — git reset --hard HEAD~1

# ... l'agent continue seul, expérience après expérience

🚀 Lancer votre propre session

# 1. Ouvrez le repo dans un éditeur IA (Cursor, Gemini CLI, etc.)
# 2. Donnez ce prompt à l'agent :

Regarde autoresearch/program.md et lance une session.
Fais le setup d'abord.

# 3. L'agent crée la branche, lit le code, lance le baseline
# 4. Puis il boucle : hypothèse → test → keep/discard
# 5. Vous revenez 2h plus tard avec ~200 expériences loguées

🔮 Pistes de recherche inexplorées

Au-delà de l'optimisation de seuils, la méthode autoresearch ouvre des axes de recherche radicalement nouveaux :

🧮 Axe 1 — Autoresearch sur le clustering d'appartements+
Idée : Le fichier apartment_clustering_v2.py est actuellement read-only. Mais on pourrait créer un second pipeline autoresearch dédié, avec sa propre métrique (ex: Adjusted Rand Index entre clusters prédits et clusters réels).

Pourquoi c'est intéressant : Un meilleur clustering en amont = des meilleures passes 3/4 en aval. C'est un effet multiplicateur.

Interaction illustrée :
Agent: J'observe que 3 appartements sont fusionnés en 1 cluster sur P2.
Hypothèse: ajouter un critère de séparation par niveau.
→ ARI passe de 0.87 à 0.91. KEEP.
→ Downstream: accuracy_P2 monte de 93.4 à 94.2 (+0.8%).
🌐 Axe 2 — Autoresearch multi-objectif (Pareto)+
Idée : Au lieu d'un score unique, optimiser simultanément accuracy et simplicité du code (nombre de lignes, complexité cyclomatique). L'agent cherche le front de Pareto : les solutions qui sont à la fois précises et simples.

Pourquoi c'est intéressant : Cela formalise le « simplicity criterion » de Karpathy en une vraie métrique. L'agent pourrait découvrir qu'on peut supprimer 30% des règles sans perdre en accuracy.

Métrique proposée :
pareto_score = score × (1 - 0.001 × num_rules)
🔀 Axe 3 — Autoresearch sur l'export Revit lui-même+
Idée : Le plugin Revit qui exporte le JSON (EngineAntigravity) décide quelles features extraire. Un autoresearch en amont pourrait explorer : quelles données supplémentaires du modèle BIM faudrait-il exporter ?

Exemples de features inexplorées :
• Hauteur sous plafond (discriminant cuisine vs SDB)
• Type de revêtement de sol (carrelage = zone humide probable)
• Présence de gaines techniques / colonnes montantes
• Orientation cardinale de la pièce (sud = séjour probable)

Boucle : L'agent propose une feature → on l'ajoute à l'export → on mesure si l'accuracy monte.
🧠 Axe 4 — Autoresearch « adversarial » : générer des cas difficiles+
Idée : Un second agent (l'adversaire) génère des configurations de pièces synthétiques conçues pour tromper le classifieur. Le premier agent doit ensuite corriger les règles pour résister.

Pourquoi c'est intéressant : C'est l'approche GAN appliquée à des règles métier. L'adversaire découvre les failles, le défenseur les colmate. La robustesse explose.

Interaction illustrée :
Adversaire: Je crée une pièce de 9m², 1 porte, 0 fenêtre, sep_ratio=0.4.
→ Le classifieur dit "kitchen". Le label est "storage".
Défenseur: J'ajoute une garde : kitchen requiert ≥1 fenêtre OU sep_ratio>0.6.
→ L'adversaire ne peut plus exploiter ce pattern. Score +0.3%.
📊 Axe 5 — Autoresearch sur les templates WL+
Idée : L'algorithme Weisfeiler-Lehman utilise 24 templates d'appartements connus. Un autoresearch pourrait découvrir automatiquement de nouveaux templates à partir des données existantes.

Boucle :
1. L'agent calcule le hash WL de chaque appartement correctement classé
2. Il identifie les hash récurrents non encore enregistrés
3. Il les ajoute à graph_templates.py comme nouveaux templates
4. Il mesure l'impact sur le score

Potentiel : Chaque nouveau template matché = classification instantanée avec confiance 1.0. C'est le ROI le plus élevé possible par règle ajoutée.
🏢 Axe 6 — Autoresearch cross-domaine : bureaux, hôpitaux, hôtels+
Idée : Aujourd'hui le classifieur cible le logement résidentiel. Mais la méthode autoresearch permet d'adapter le système à d'autres typologies de bâtiments sans expertise humaine préalable.

Nouveau programme : L'agent reçoit un dataset de bureaux labellisé (open-space, salle de réunion, sanitaires, accueil…) et une copie vierge du classifieur. Il part de zéro et construit ses propres règles par exploration autonome.

Potentiel : Un classifieur universel multi-typologies, où chaque domaine a été exploré par des centaines d'expériences automatisées.
⚡ Axe 7 — Autoresearch compétitif : tournoi d'agents+
Idée : Lancer N agents en parallèle sur des branches séparées, chacun avec un program.md légèrement différent (un plus conservateur, un plus radical, un spécialisé sur les faux positifs…). Après 100 expériences chacun, on fusionne les meilleures découvertes.

Variante : Chaque agent travaille avec un LLM différent (Claude, Gemini, GPT) pour maximiser la diversité d'approches.

Interaction illustrée :
Agent-A (conservateur): 12 keeps / 88 discards. Score: 96.1
Agent-B (radical): 4 keeps / 96 discards. Score: 97.3 (!)
Agent-C (spécialiste WL): 8 keeps / 92 discards. Score: 96.5
→ On cherry-pick les 24 keeps et on les combine. Score final: 97.8
🔑
Le méta-enseignement — Le fichier program.md est lui-même un sujet de recherche. Comme le dit Karpathy : « Vous ne programmez plus le programme — vous programmez le programme qui programme le programme. » Itérer sur le program.md (ton, niveau de détail, stratégie d'exploration) peut avoir autant d'impact que les expériences elles-mêmes.

Lire le Viewer HTML

Comment interpréter la visualisation interactive.

🎨 Code couleur des nœuds

Vert — Prédiction correcte
Rouge — Erreur de classification
Bleu — Porte (Door)
Violet — Fenêtre (Window)

🔍 Fonctionnalités du viewer

Filtrer par niveau — Dropdown multi-select pour afficher un ou plusieurs étages
Cliquer sur un nœud — Affiche toutes les propriétés (surface, portes, fenêtres, type prédit…)
Trace step-by-step — Panneau latéral montrant chaque règle appliquée, dans l'ordre
Polygones — Contours des pièces avec murs (noir) et séparateurs (orange)
Zoom/Pan — Molette pour zoomer, glisser pour naviguer

FAQ

Les questions les plus fréquentes.

Comment classifier mon propre fichier JSON ?+
1. Exportez votre graphe spatial depuis Revit (plugin EngineAntigravity)
2. Placez le .json dans le dossier data/
3. Lancez python classify_launcher.py
4. Sélectionnez votre fichier dans l'interface et cliquez « Lancer »

Alternative CLI : python src/export_viewer.py data/mon_fichier.json
Pourquoi « aveugle » ?+
Le classifieur ne lit jamais les noms de pièces donnés par l'architecte dans Revit (« Séjour », « CH1 », etc.). Il n'utilise que la géométrie (surface, portes, fenêtres) et la topologie (connexions entre pièces). Les noms Revit ne servent qu'à évaluer la précision (accuracy) après coup.
Quels types de pièces sont reconnus ?+
12 types : bedroom, living_room, kitchen, bathroom, toilet, entrance_hall, corridor, storage, laundry, balcony, terrace, garden.

Chaque type a des règles spécifiques basées sur la surface, le nombre de fenêtres, la connectivité, et le contexte d'appartement.
Comment améliorer la précision ?+
Le projet inclut une infrastructure d'expérimentation autonome (autoresearch/) :

1. Créez une branche : git checkout -b autoresearch/montest
2. Modifiez les règles dans src/blind_classifier.py
3. Lancez le benchmark : python autoresearch/run_baseline.py
4. Comparez les scores et gardez ou rejetez le changement

Consultez autoresearch/program.md pour le protocole complet.
J'ai une erreur « ModuleNotFoundError »+
Ce projet n'utilise aucune dépendance externe. Si vous avez cette erreur :

• Vérifiez que vous lancez la commande depuis la racine du projet
• Vérifiez votre version Python : python --version (≥ 3.10 requis)
• Sous Windows, essayez python au lieu de python3
Le viewer est très lourd (~10 Mo), c'est normal ?+
Oui, c'est normal. Le viewer HTML est autonome (self-contained) : il embarque toutes les données du graphe, les coordonnées des polygones, et la trace de classification. Pas besoin de serveur pour l'ouvrir — un simple double-clic suffit.