|
Download docs/decisions.md from Frankenstein-Labs/Cortex-0: direct link, hf CLI and curl.
- Browser
- Download file 17 kB
-
https://huggingface.co/Frankenstein-Labs/Cortex-0/resolve/main/docs/decisions.md
- Command line
-
hf download hf://Frankenstein-Labs/Cortex-0/docs/decisions.md
-
curl -L -o decisions.md https://huggingface.co/Frankenstein-Labs/Cortex-0/resolve/main/docs/decisions.md
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. | |