File size: 16,976 Bytes
f40f952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89bd096
f40f952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a393524
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f17dddf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37d8122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d9eec2b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6857ec0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
827713a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
886cf7c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c40e77f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9b728b4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
096854b
 
 
 
 
 
 
 
 
 
 
 
 
 
efb8037
 
 
 
 
 
 
 
 
 
 
 
 
 
 
850e745
 
 
 
 
 
 
 
 
 
 
 
 
3a2cb1d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# 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.