TIP
GitHub : kyegomez/OpenMythos | PyPI : open-mythos | Licence : MIT
Présentation du projet
En avril 2026, Anthropic a lancé Claude Mythos — le prochain modèle de la famille Claude, conçu pour le raisonnement. Il se démarque par des capacités inédites sur des tâches d’ingénierie logicielle, de cybersécurité (notamment la découverte et l’exploitation de vulnérabilités zero-day), etc. Cependant, Mythos n’est pour l’instant accessible que de manière limitée via « Project Glasswing », à un nombre restreint de partenaires de recherche en sécurité défensive : il est encore loin d’être publié de façon exhaustive.
OpenMythos est la réponse open source de la communauté à cette architecture fermée : porté par des développeurs indépendants, Kye Gomez a reconstruit l’architecture centrale de Mythos à partir de premiers principes, en s’appuyant sur des articles et références de recherche publiquement disponibles. Ce n’est pas une version officielle, ni une fuite de poids : c’est une reconstruction théorique (theoretical reconstruction) — l’objectif étant de permettre aux chercheurs et développeurs de valider expérimentalement des idées similaires.
Son avancée centrale est le Recurrent-Depth Transformer (RDT) : les mêmes poids de Transformer sont réexécutés jusqu’à 16 fois (configurable) dans un seul passage avant (single forward pass). L’itération se fait ainsi dans un espace latent continu, pour « réfléchir » de manière répétée, plutôt que d’empiler des centaines de couches distinctes, chacune avec ses propres poids. Un modèle récurrent de 770M paramètres atteint une qualité proche d’un Transformer standard d’environ 1,3B — avec, en contrepartie, environ la moitié des paramètres.
Difficulté / Durée / Résultats
Niveau d’entrée, environ 30 minutes : vous ferez tourner votre premier forward d’OpenMythos, afin de comprendre l’essence du raisonnement en boucle, le principe de l’injection stable LTI, et comment le MoE FFN peut élargir la largeur du modèle sans augmenter les paramètres d’activation.
Public cible
Vous avez des bases en architecture LLM et vous cherchez à approfondir le mécanisme de « raisonnement en boucle » ainsi que sa réalisation logicielle, avec 1 à 5 ans d’expérience de développement. Si les questions suivantes vous intéressent, OpenMythos est un bon point de départ :
- Pourquoi l’idée « plus de boucles = raisonnement plus profond » a, elle-même, un socle théorique
- Comment les contraintes de dynamique LTI garantissent que l’entraînement en boucle ne diverge pas
- Comment le MoE + partage de poids récurrents trouvent un nouvel équilibre entre nombre de paramètres et quantité de calcul
Dépendances clés et environnement
- Python 3.10+
- PyTorch 2.0+ (le support CUDA accélère l’inférence)
- Optionnel :
flash-attn >= 2.8.3(accélère l’attention GQA, IO optimisé) - Matériel minimal : le CPU peut lancer un toy demo, le GPU permet un entraînement complet
# CPU uniquement
pip install open-mythos
# avec Flash Attention 2 (nécessite CUDA + outils de build)
pip install "open-mythos[flash]"
Structure complète du projet
open_mythos/
├── main.py # Cœur : la classe OpenMythos, MythosConfig et tous les composants d’architecture
├── moda.py # Modules MoE / LoRA, etc.
├── tokenizer.py # MythosTokenizer (encapsule openai/gpt-oss-20b)
├── variants.py # Tailles prédéfinies : mythos_1b ~ mythos_1t
├── docs/
│ ├── open_mythos.md # Référence complète de l’API
│ └── datasets.md # Recommandations pour choisir les jeux de données d’entraînement
training/
└── 3b_fine_web_edu.py # Script d’entraînement pour modèle 3B (single card / multi-card)
examples/
├── moda_example.py # Démo MoE FFN + LoRA Adapter
└── variants_example.py # Comparaison de paramètres entre plusieurs variantes de tailles
tests/
├── test_main.py # Tests unitaires du module principal
├── bench_vs_transformer.py # Comparaison de benchmarks avec un Transformer standard
└── small_benchmark.py # Benchmarks de performance à petite échelle
Étapes pas à pas
Étape 1 — Installation
pip install open-mythos
WARNING
La compilation de flash-attn nécessite CUDA Toolkit et nvcc. Si l’installation échoue dans un environnement sans nvcc, OpenMythos dégradera automatiquement l’implémentation pour utiliser l’attention native standard de PyTorch. Cela n’affecte pas la correction (correctness), seulement la vitesse.
Étape 2 — Construire la configuration
Tous les hyperparamètres sont transmis via MythosConfig. Pour comprendre quelques champs clés :
from open_mythos.main import MythosConfig
cfg = MythosConfig(
vocab_size=1000, # Taille du vocabulaire ; demo avec petit vocabulaire
dim=256, # Dimension des couches cachées (hidden)
n_heads=8, # Nombre de têtes Query
n_kv_heads=2, # Nombre de têtes KV (GQA : moins de têtes que Q permet d’économiser de la VRAM)
max_seq_len=128, # Longueur maximale de séquence (limite supérieure de RoPE en pré-calcul)
max_loop_iters=4, # Profondeur de boucle T ; réglable à la hausse pour l’inférence
prelude_layers=1, # Nombre de couches standards dans la section Prelude
coda_layers=1, # Nombre de couches standards dans la section Coda
attn_type="mla", # "mla" ou "gqa" ; voir l’étape 5
n_experts=8, # Nombre total d’experts MoE
n_shared_experts=1, # Nombre d’experts permanents (activés pour chaque token)
n_experts_per_tok=2, # Nombre top-K d’experts activés par token
expert_dim=64, # Dimension cachée de chaque expert
lora_rank=8, # Rang de l’adapter LoRA pour la profondeur
)
MythosConfig dispose d’un constructeur par défaut ; un simple MythosConfig() utilisera des valeurs prédéfinies de taille intermédiaire.
Étape 3 — Initialiser le modèle et exécuter un forward
import torch
from open_mythos.main import OpenMythos, MythosConfig
cfg = MythosConfig()
model = OpenMythos(cfg)
# Statistiques : nombre de paramètres
total = sum(p.numel() for p in model.parameters())
print(f"Parameters: {total:,}")
# Forward : input_ids shape (B, T), logits shape (B, T, vocab_size)
ids = torch.randint(0, cfg.vocab_size, (2, 16)) # batch=2, seq=16
logits = model(ids, n_loops=4) # 4 itérations de raisonnement en boucle
print(f"Logits shape: {logits.shape}") # torch.Size([2, 16, 32000])
n_loops contrôle la profondeur de boucle. La valeur par défaut provient de cfg.max_loop_iters. Pendant l’inférence, vous pouvez l’augmenter : c’est une caractéristique clé du RDT : extrapolation de profondeur (depth extrapolation). En clair : vous entraînez le modèle avec N boucles, puis en inférence vous pouvez en utiliser N+k pour traiter des problèmes plus complexes.
Étape 4 — Génération autoregressive
# Générer de nouveaux tokens (jusqu’à 8), profondeur de boucle = 8
out = model.generate(ids, max_new_tokens=8, n_loops=8)
print(f"Generated shape: {out.shape}") # torch.Size([2, 24])
La méthode generate conserve un KV cache en interne : lors du premier appel, elle traite le prompt complet ; ensuite, à chaque appel, elle ne décode qu’un token. temperature contrôle la randomisation de l’échantillonnage, et top_k limite l’espace de choix :
out = model.generate(
ids,
max_new_tokens=64,
n_loops=16,
temperature=0.8, # plus bas = plus déterministe
top_k=40, # 0 = désactivé
)
Étape 5 — Choisir le mécanisme d’attention : MLA vs GQA
# Multi-Latent Attention (par défaut, recommandé pour de grands contextes)
cfg_mla = MythosConfig(
attn_type="mla",
kv_lora_rank=512, # Dimension latente de KV mise en cache (plus petit = moins de VRAM)
q_lora_rank=1536, # Dimension de compression pour Q
qk_rope_head_dim=64, # Dimension par tête avec RoPE
qk_nope_head_dim=128, # Dimension par tête sans RoPE
v_head_dim=128,
)
# Grouped Query Attention (économe en VRAM ; efficace avec flash-attn)
cfg_gqa = MythosConfig(
attn_type="gqa",
n_kv_heads=4, # moins que n_heads ; KV cache réduit de n_heads/n_kv_heads fois
)
Le choix entre les deux : MLA compresse le KV en une mise en cache de vecteurs latents de faible rang, ce qui réduit la VRAM d’environ 10 à 20 fois, mais nécessite de reconstruire K/V à chaque fois (une projection linéaire). GQA met en cache directement les têtes KV complètes : avec Flash Attention 2, l’IO est optimal. En production, MLA consomme moins de VRAM ; en phase de développement, GQA est souvent plus simple à déboguer.
Étape 6 — Vérifier la stabilité de la boucle : test du rayon spectral
Le problème le plus facile à rencontrer en entraînement RDT est la divergence en boucle : le state caché (hidden state) s’amplifie exponentiellement à chaque itération. OpenMythos garantit la stabilité par construction grâce à l’injection stable LTI. La méthode de vérification consiste à contrôler le rayon spectral ρ(A) :
# Récupérer la matrice d’état discrétisée A_discrete
A = model.recurrent.injection.get_A() # shape (dim,)
rho = torch.linalg.eigvals(A).abs().max().item()
print(f"Spectral radius ρ(A) = {rho:.4f}")
assert rho < 1.0, f"Unstable: ρ(A) = {rho:.4f} >= 1"
WARNING
Si, lors d’un entraînement personnalisé, vous constatez rho >= 1, n’essayez pas de corriger manuellement les paramètres : cela signifie que votre paramétrisation de l’injection LTI est contournée. Vérifiez si vous n’avez pas, par erreur, affecté directement injection.log_A ou injection.log_dt.
Étape 7 — Utiliser des variantes de taille prédéfinies
Vous ne voulez pas configurer MythosConfig à la main ? variants.py fournit des préréglages de 1B à 1T :
from open_mythos import mythos_1b, mythos_3b, mythos_10b, mythos_50b, mythos_100b
# mythos_7b() renvoie un MythosConfig
cfg = mythos_3b()
model = OpenMythos(cfg)
print(f"Variant 3B : {sum(p.numel() for p in model.parameters()):,} params")
| Variante | dim | Experts | Profondeur de boucle | Contexte | Sortie max |
|---|---|---|---|---|---|
mythos_1b | 2048 | 64 | 16 | 4k | 4k |
mythos_3b | 3072 | 64 | 16 | 4k | 4k |
mythos_10b | 4096 | 128 | 24 | 8k | 4k |
mythos_100b | 8192 | 256 | 32 | 1M | 128k |
Étape 8 — Exécuter les scripts d’entraînement
Le projet inclut un script d’entraînement du modèle 3B sur le dataset FineWeb-Edu :
# Une seule GPU
python training/3b_fine_web_edu.py
# Multi GPU (détecte automatiquement le nombre de GPU)
torchrun --nproc_per_node=$(python -c "import torch; print(torch.cuda.device_count())") \
training/3b_fine_web_edu.py
TIP
Par défaut, l’entraînement utilise le sous-ensemble sample-10BT (30B tokens), pratique pour valider rapidement. Pour lancer le sous-ensemble complet 100BT, modifiez le paramètre dataset_name dans le script pour "sample-100BT".
Configurations d’entraînement clés :
# training/3b_fine_web_edu.py (paramètres clés)
optimizer = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.1)
# Précision : bfloat16 pour H100/A100, float16 + GradScaler pour les vieilles cartes
# Schedule : 2000 steps de warmup → décroissance cosinus
# Tokenizer : openai/gpt-oss-20b via MythosTokenizer
Dépannage des problèmes fréquents
1. Explosion de VRAM : le piège de la combinaison nombre de boucles × taille de batch
La phase de boucle de RDT n’est pas identique à un Transformer standard où les couches sont indépendantes : à chaque étape de boucle, l’état KV de tous les tokens s’accumule dans le cache. Faire 16 boucles × séquence de 4096 × batch de 8 entraîne une pression mémoire de plusieurs fois celle d’un modèle classique.
Solution : commencez avec un petit n_loops (par ex. 4) pour valider, puis augmentez progressivement une fois la convergence atteinte ; le batch doit être ajusté par mise à l’échelle linéaire, pas fixé à l’identique.
2. Absence de Flash Attention, mais vous voulez accélérer
Si la compilation de flash-attn échoue (fréquent sur Windows + environnement CUDA), OpenMythos basculera automatiquement sur l’attention native de PyTorch. Notez que cette dégradation n’affecte pas la correction, uniquement la vitesse : dans les scénarios de petits batchs, l’écart est souvent limité.
3. Échec du test de rayon spectral : entraînement qui diverge
Si vous modifiez la paramétrisation de LTIInjection, ou si, pendant le fine-tuning, vous figez (freeze) la mauvaise couche entraînant la destruction des paramètres d’injection, vous observerez ρ(A) >= 1. Ne clippez pas directement les paramètres : revenez à l’initialisation par défaut et redémarrez. La contrainte LTI repose sur la structure paramétrisée, pas sur une correction « après coup ».
4. Arrêt anticipé dû à ACT : le nombre réel de boucles est insuffisant
act_threshold=0.99 signifie que chaque position s’arrête dès qu’elle a accumulé 99% de probabilité. Si, sur certaines tâches, vous constatez que le nombre réel d’itérations est bien inférieur à n_loops, inspectez la distribution de difficulté des tokens dans les données : des tokens trop faciles déclenchent le halting trop tôt, et les tokens complexes n’obtiennent alors pas la profondeur nécessaire.
5. Crash du routage MoE : certains experts ne s’activent jamais
Le load-balancing auxiliary loss à la DeepSeekMoE dépend d’un ajustement dynamique de router_bias. Si vous n’utilisez pas ce mécanisme d’ajustement dès le départ lors de l’entraînement, le routeur va converger rapidement vers l’activation d’un petit nombre d’experts (généralement les 1–2 premiers). Dans le projet, MoEFFN.forward contient une place-holder pour l’ajustement du bias, mais dans un script d’entraînement personnalisé, vous devez appeler régulièrement la logique de mise à jour du bias.
6. Qualité de génération faible : comment régler temperature et top_k
| Scénario | temperature | top_k | Remarque |
|---|---|---|---|
| Code / Math | 0.3–0.5 | 10–20 | faible aléa |
| Écriture créative | 0.7–0.9 | 0 (désactivé) | forte diversité |
| Débogage / validation d’inférence | 0.0 (glouton) | 1 | maximum de déterminisme |
Lecture complémentaire / Directions avancées
Articles clés
| Article | Problème résolu |
|---|---|
| Loop, Think & Generalize (2025) | Comment une boucle Transformer effectue un raisonnement implicite dans l’espace latent |
| Parcae (Prairie et al., 2026) | Lois de scaling qui garantissent la stabilité en boucle via les contraintes LTI |
| DeepSeekMoE (Dai et al., 2024) | Conception fine du routage MoE + experts partagés |
| DeepSeek-V2 MLA (2024) | Principe de compression KV de Multi-Latent Attention |
| Relaxed Recursive Transformers (Bae et al., 2024) | Comment les adapters LoRA améliorent la capacité de représentation en boucle sans ajouter trop de paramètres |
Directions avancées
1. Adapter LoRA personnalisé : actuellement, lora_rank est global et identique partout. Vous pouvez le remplacer par une configuration par couche, afin d’utiliser des forces d’adaptation différentes selon la profondeur de boucle.
2. Balayage du seuil ACT : la valeur par défaut 0.99 est un repère empirique. Lancez une recherche sur grille de 0.8–0.999 : sur certaines tâches, 0.95 peut être meilleur que 0.99 (un arrêt anticipé évite l’overthinking).
3. Expériences sur l’extrapolation de profondeur : entraînez avec un n_loops fixe, puis en inférence balayez n_loops et tracez une courbe « nombre de boucles → précision sur la tâche aval ». En théorie, vous devriez observer une forme de décroissance exponentielle : c’est l’une des propriétés les plus importantes et vérifiables du RDT.
4. Comparaison avec un Transformer standard : utilisez le script bench_vs_transformer.py pour comparer, à nombre de paramètres égal, l’écart entre le modèle en boucle et le modèle standard sur des tâches de generalization compositionnelle / systématique. C’est un des scénarios où le RDT montre le plus d’avantages.