Cortex-0 / docs /decisions.md
Frankenstein-Labs's picture
release: Cortex-0 (Phases 0-12)
3a2cb1d verified
|
Raw History Blame Contribute Delete
17 kB

Journal des décisions (ADR léger)

Chaque décision structurante est enregistrée ici : contexte → décision → conséquences.


ADR-000 — Initialisation du projet

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : construire une IA multimodale from scratch, sans aucun poids pré-entraîné.
  • Décision : démarrer par une Phase 0 de fondations (structure, config, docs, tests TDD rouges) avant tout code de modèle.
  • Conséquences : socle stable, vérifiable, avant d'écrire la moindre couche de neurones.

ADR-001 — Interdiction stricte des modèles pré-entraînés

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : le cahier des charges interdit transformers.AutoModel, CLIP, BLIP, LLaVA, Whisper, Wav2Vec, ViT pré-entraîné, Qwen, Llama, DeepSeek, Mistral, GPT.
  • Décision : n'autoriser que PyTorch, numpy, torchaudio (I/O), torchvision (transforms), tokenizers (entraînement de notre tokenizer), datasets, huggingface_hub, FastAPI, Gradio, pytest, ruff, Docker.
  • Conséquences : transformers n'est pas une dépendance. Un test automatique (Phase 0) échoue si un import interdit apparaît dans src/.

ADR-002 — Positional encoding : RoPE pour le texte, appris pour l'image/audio

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : le texte est une séquence de longueur variable (longue portée, besoin d'extrapolation) ; l'image et l'audio ont une structure de grille/trames de taille fixe.
  • Décision : RoPE (rotary) pour l'encodeur/décodeur texte ; embedding positionnel appris pour le ViT et l'encodeur audio.
  • Conséquences : meilleure extrapolation en longueur pour le texte ; simplicité et suffisance pour des grilles de taille fixe. Détails en architecture.md.

ADR-003 — Profile 50M honnête

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : le cahier des charges demande « ~50M params (n_layer=6, n_head=6, n_embd=384, ctx=512) », mais cette combinaison avec vocab 32k donne ~22.9 M (lié) / ~35.2 M (non lié).
  • Décision : conserver le profil demandé et ajouter text_model_50m (n_embd=512, n_head=8, n_layer=6, embeddings non liés ≈ 51.6 M). Documenter l'écart.
  • Conséquences : transparence ; l'utilisateur choisit le profil. Pas de fausse déclaration de taille.

ADR-004 — Aucun secret en dur ; HF_TOKEN par variable d'environnement

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : publication sur un dépôt Hugging Face privé/public.
  • Décision : le token est lu depuis HF_TOKEN (via .env gitignoré). Jamais dans le code, la config, les notebooks ou les commits.
  • Conséquences : .env et .env.example séparés ; .gitignore bloque .env.

ADR-005 — Tests unitaires sur CPU, entraînement sur Colab

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : machine de développement = CPU seul (4 cœurs, 15 Go, pas de GPU).
  • Décision : toutes les tailles de test dans configs/model.yaml > test sont minuscules ; l'entraînement réel se fait via un notebook Colab par phase.
  • Conséquences : pytest reste rapide ; aucune promesse d'entraînement local.

ADR-006 — Une phase à la fois, validation explicite requise

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : règle 1 du cahier des charges.
  • Décision : ne jamais passer à la phase suivante sans tests verts + commit/push Hub
    • validation explicite (« phase X validée »).
  • Conséquences : progression lente mais contrôlée et vérifiable.

ADR-007 — Licence Apache-2.0

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : la Phase 0 avait posé un placeholder MIT, explicitement à remplacer.
  • Décision : adopter Apache-2.0. Le texte intégral est dans LICENSE, la model card (README.md) porte license: apache-2.0, et pyproject.toml déclare license = { text = "Apache-2.0" }.
  • Conséquences :
    • Licence permissive avec clause de brevet explicite (section 3), avantageuse pour un projet modèle/IA réutilisé par des tiers.
    • Obligation de conserver les notices et de signaler les fichiers modifiés en cas de redistribution.
    • Plus verbeuse que MIT ; aucune contrainte copyleft.

ADR-008 — Nom du modèle : Cortex-0

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : le projet était désigné « OpenDevin Multimodal ». L'auteur fixe l'identité publique du modèle.
  • Décision : nommer le modèle Cortex-0 (README, configs/model.yaml > project.name, model card, package pyproject.toml → cortex-0). Le dépôt Hugging Face conserve Frankenstein-Labs/opendevin-multimodal jusqu'à la Phase 12 (renommage prévu alors).
  • Conséquences : identité claire du modèle ; une variable PROJECT_NAME=Cortex-0 et un futur renommage de dépôt clairement planifié. Aucune ambiguïté entre nom du modèle et nom du dépôt.

ADR-009 — Configuration finale verrouillée

  • Date : 2026-10-10

  • Statut : accepté

  • Contexte : l'auteur a figé les paramètres structurants à l'issue de la Phase 0.

  • Décision :

    Paramètre Valeur
    Licence Apache-2.0
    Nom du modèle Cortex-0
    Organisation HF Frankenstein-Labs
    Dépôt cible Frankenstein-Labs/opendevin-multimodal
    MoE (Phase 10) 20 experts, top-2
    Langue principale français
    Matériel CPU (dev/tests) + Colab (entraînement)
  • Conséquences : configs/model.yaml > moe.n_experts passe de 8 à 20 ; le coût mémoire du MoE augmente d'autant (tous les experts résident en mémoire), ce qui sera réévalué lors de la Phase 10.


ADR-010 — Tokenizer : BPE ByteLevel, corpus FR plafonné, 19 tokens spéciaux

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : la Phase 1 exige un BPE de 32 000 tokens sur corpus français public, 100 % from scratch, capable de gérer accents, emojis et caractères inconnus.
  • Décision :
    • BPE avec pre_tokenizer=ByteLevel(add_prefix_space=False), byte_fallback=True (sur le modèle), min_frequency=2.
    • initial_alphabet=ByteLevel.alphabet() : indispensable pour un round-trip exact.
    • 19 tokens spéciaux réservés en premier (4 base + 6 raisonnement + 9 modalités), ids 0..18 fixes → stables entre runs.
    • Corpus plafonné à ~150–200 Mo de wikimedia/wikipedia (config 20231101.fr), en streaming (pas de téléchargement des ~6 Go).
    • Corpus « propre » : pas d'en-tête de licence ni de boilerplate.
  • Conséquences :
    • Round-trip exact pour toute entrée, y compris hors corpus.
    • vocab_size traité comme borne supérieure ; échec explicite si le corpus est trop pauvre (pas de résultat trompeur).
    • Mesuré : 32 000 tokens en 21,8 s en local (CPU) sur 150 Mo.
    • Recherche d'un vocabulaire « 32000 exact » : atteint, donc aucune réduction de scope nécessaire.

ADR-011 — Transformer texte : RoPE, pre-norm, attention causale à la main

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : Phase 2 — coder un transformer decoder-only from scratch, sans transformers ni nn.MultiheadAttention.
  • Décision :
    • RoPE (rotation des paires de dimensions de Q/K) plutôt qu'un embedding positionnel absolu appris : position relative dans Q·K, zéro paramètre, meilleure extrapolation, réutilisable pour toutes les modalités.
    • Pre-norm (x = x + F(LN(x))) : gradient non multiplié par la norme sur le chemin résiduel → entraînement plus stable.
    • Masque causal triangulaire à -inf avant softmax.
    • FFN GELU à deux couches, ffn_mult=4.
    • lm_head optionnellement lié aux embeddings.
    • Génération (temperature, top-k, top-p, glouton) écrite à la main, sans model.generate.
  • Conséquences :
    • Causalité et invariance relative prouvées par tests, pas supposées.
    • Le profil demandé (n_embd=384, n_layer=6) fait 22.9 M, pas 50 M : écart documenté, le profil text_model_50m (512 dim, non lié) fait bien 51.6 M.
    • Mesuré en local : overfit d'un mini-corpus FR 10.45 → 0.011 en 68 s.

ADR-012 — Entraînement texte : données memmap uint16, AdamW sélectif, cosine manuel

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : Phase 3 — entraîner le transformer texte sur corpus public, en pur PyTorch (pas de Trainer).
  • Décision :
    • Tokenisation en tableau uint16 (train.bin/val.bin) + np.memmap : 2 octets/token, zéro copie RAM, découpe val séquentielle (pas de fuite).
    • AdamW avec weight decay appliqué seulement aux tenseurs dim >= 2.
    • Warmup linéaire + cosinus écrits à la main.
    • Gradient clipping 1.0, autocast bf16/fp16 sur GPU.
    • Checkpoints last.pt/best.pt, logs JSONL.
  • Conséquences :
    • L'entraînement réel peut tourner sur CPU (mesuré) comme sur Colab GPU.
    • La cible ppl < 30 est budgétée, pas garantie sur CPU ; le notebook Colab est le chemin nominal. Aucun chiffre annoncé sans mesure.

ADR-013 — Encodeur image ViT : patchs, position apprise, attention bidirectionnelle

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : Phase 4 — encodeur image from scratch, aligné sur l'espace texte.
  • Décision :
    • Patch embedding par convolution noyau/pas = patch_size.
    • Positional embedding appris (grille fixe) plutôt que RoPE 2D.
    • Attention bidirectionnelle (causal=False) : vital, sinon le CLS ne voit pas les patchs (bug réellement rencontré et corrigé).
    • Token CLS pour le résumé global (pool cls), alternative mean.
    • Projecteur MLP LayerNorm -> Linear -> GELU -> Linear vers text_dim.
    • Générateur d'images jouets maison (9 classes forme x couleur) pour tester sans données externes.
  • Conséquences :
    • Le drapeau causal de l'attention est partagé texte (causal) / encodeurs (non causal).
    • Overfit vérifié : classification acc > 0.9, reconstruction MSE < 0.05 (CPU).

ADR-014 — CLIP maison : lots à légendes uniques, masque de padding, clipping

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : Phase 5 — alignement image-texte from scratch.
  • Décision :
    • Loss contrastive symétrique écrite à la main (InfoNCE lignes+colonnes).
    • Masque d'attention jusqu'au pooling texte (ignorer les PAD).
    • Lots construits avec des légendes uniques (_build_batches) : sans cela, l'appariement 1-1 est violé et la perte collapse.
    • logit_scale apprise (température), embeddings normalisés L2.
    • Gradient clipping 1.0 ; lr modéré (2e-3) — un lr élevé collapse.
    • Métrique de retrieval au niveau des classes.
  • Conséquences :
    • Convergence réelle mesurée : retrieval 0.81 (hasard 0.11), loss 2.20 -> 0.15.
    • Deux bugs silencieux identifiés et corrigés avec tests de régression.

ADR-015 — VLM : fusion par embeddings, décalage des labels, métrique de grounding

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : Phase 6 — VLM génératif image+texte from scratch.
  • Décision :
    • Fusion par injection d'embeddings (inputs_embeds) : patchs projetés insérés entre <|image_start|> et <|image_end|>.
    • Labels décalés (labels[t]=ids[t+1]) ; perte masquée par ignore_index=-100.
    • Métrique principale = exactitude teacher-forced (grounding) ; la génération libre est rapportée séparément comme métrique plus difficile.
  • Conséquences :
    • Bug silencieux évité : labels non décalés → loss 0.0006 mais génération cassée.
    • Mesuré CPU : légende 0.85 / forme 0.80 / couleur 1.00 (teacher-forced), génération libre 0.35 (biais d'exposition assumé).

ADR-016 — Audio : mel maison, encodeur bidirectionnel, données synthétiques

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : Phase 7 — encodeur audio from scratch.
  • Décision :
    • Mel-spectrogramme écrit à la main (torch.fft + filtres mel) car torchaudio est absent de l'environnement (plus « from scratch », zéro dépendance audio).
    • Encodeur : patch embedding 2D (fréquence × temps) + blocs bidirectionnels.
    • Données : voyelles synthétiques (formants F0/F1/F2, 10 classes), faute d'accès audio dans l'environnement de dev.
  • Conséquences :
    • Transcription parfaite sur le jeu jouet (acc 1.00). Parole réelle non testée : réduction de scope assumée et documentée.

ADR-017 — Modèle complet : un décodeur pour trois modalités

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : Phase 8 — texte + image + audio dans un seul modèle.
  • Décision :
    • Un unique décodeur texte ; image et audio projetés puis injectés comme tokens spéciaux dans la même séquence (fusion précoce).
    • Dans un lot multi-tâches, n'encoder que les lignes contenant la modalité.
    • Métrique principale : exactitude teacher-forced par tâche ; génération libre rapportée séparément.
  • Conséquences :
    • Mesuré CPU : image 0.92 / audio 1.00 / mixte 0.93 (teacher-forced) ; génération libre mixte 0.17 (limite assumée, modèle de taille jouet).

ADR-018 — Vidéo : ViT partagé sur frames + transformer spatio-temporel

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : Phase 9 — vidéo (frames + audio synchronisés).
  • Décision :
    • Vidéos jouets = forme colorée qui se déplace (direction = tâche temporelle).
    • VideoEncoder = ViT partagé par frame + embedding temporel appris + transformer spatio-temporel bidirectionnel sur tous les n_frames × n_patches tokens.
    • n_frames petit (4) à cause du coût quadratique de l'attention.
  • Conséquences :
    • Grounding mesuré CPU : vidéo 0.78, vidéo+audio 0.85 (18 classes).
    • Génération libre 0.0 : limite assumée et documentée.

ADR-019 — MoE 20 experts top-2 dans le FFN

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : Phase 10 — capacité accrue à coût de calcul borné.
  • Décision :
    • MoEFFN remplace le FFN dense ; config imposée : 20 experts, top-2.
    • Routeur linéaire top-k + renormalisation des portes + bruit d'exploration.
    • Loss auxiliaire Switch-Transformer (coef 0.01) pour équilibrer le routage.
    • Calcul épars : chaque expert ne traite que ses tokens.
  • Conséquences :
    • Mesuré CPU : perplexité val 1.005, entropie de charge 0.9999 (routage équilibré).
    • 14.86M paramètres totaux / 5.42M actifs par token (~2.7x).
    • Tous les experts résidents en mémoire ; routage à vectoriser à grande échelle.

ADR-020 — Mémoire : RAG (mode A) + apprentissage permanent (mode B)

  • Date : 2026-10-10
  • Statut : accepté (mode B : expérimental)
  • Contexte : Phase 11 — « apprendre des cours ».
  • Décision :
    • Mode A (RAG) : embeddings maison par feature hashing IDF + index numpy cosinus ; réponse extractive verbatim avec sources (vidéo = transcription + légendes frames).
    • Mode B (apprentissage permanent) : quelques pas de gradient à l'ingestion, avec tampon de rejeu. Marqué EXPÉRIMENTAL ET INSTABLE, tests qui prouvent l'oubli.
  • Conséquences :
    • Mode A fiable, sans hallucination ; mode B honnête mais instable, non garanti.

ADR-008 — Nom du modèle « Cortex-0 » vs nom du dépôt (renommage différé)

  • Date : 2026-10-10
  • Statut : accepté
  • Contexte : le modèle s'appelle Cortex-0, mais le dépôt Hub reste Frankenstein-Labs/opendevin-multimodal pour ne pas casser les liens déjà publiés.
  • Décision : ne pas renommer le dépôt à ce stade ; documenter l'écart (nom de modèle « Cortex-0 », dépôt « opendevin-multimodal ») dans le README. Un renommage éventuel (redirection Hub) est laissé à une décision ultérieure.
  • Conséquences : README et carte de modèle portent « Cortex-0 » ; le remote reste stable.

ADR-021 — Phase 12 : moteur unique, API FastAPI, démo Gradio, Docker

  • Date : 2026-10-10
  • Statut : accepté
  • Décision :
    • Un CortexEngine unique (texte/image/audio/vidéo) partagé par l'API et la démo.
    • API FastAPI testée par TestClient ; handlers Gradio testés sans serveur.
    • Décodage d'entrées sans dépendance lourde (numpy/Pillow/wave), vidéo en (T,H,W,3).
    • CORTEX_CHECKPOINT/HF_TOKEN au runtime ; aucun poids pré-entraîné dans l'image.
  • Conséquences : 14 tests Phase 12 ; publication du checkpoint + carte avec licence Apache-2.0.