HomeRessources, Guides & Actualités – Actualités de l’intelligence artificielleMemoMarin : L’ingénierie pour le pré-entraînement et le scaling de modèles de fondation

Marin : L’ingénierie pour le pré-entraînement et le scaling de modèles de fondation

La plupart des projets d’apprentissage profond dissimulent leurs échecs sous le tapis. On publie le checkpoint final, un papier bien lissé, et on garde pour soi les centaines de runs avortés à cause d’une divergence de loss ou d’un ordonnanceur de cluster mal configuré.

Marin prend le contre-pied exact de cette habitude. C’est un framework open-source, une plateforme logicielle et un programme de recherche complet dédié à la conception de modèles de fondation.

Le projet ne livre pas de simples poids pré-entraînés. Il expose tout le processus : de la curation des données au filtrage, en passant par la tokenisation, le pré-entraînement, le post-entraînement et l’évaluation.

Les protocoles bruts et les crashs font partie intégrante de la documentation publique. Au-delà des modèles de langage purs, le framework sert aussi de base pour des architectures audio-texte, de l’analyse génomique (ADN) et des modèles de protéines via son sous-dossier marin/experiments.

Modèles de frontière, MoE et la suite Delphi

Le cœur des travaux actuels sur Marin vise le pré-entraînement direct d’un modèle Mixture-of-Experts (MoE) de grande envergure. On parle ici de 5e24 FLOPs et de plus de 500 milliards de paramètres au total, pensé spécifiquement pour la recherche scientifique.

Avant de lancer un run d’une telle démesure, il faut pouvoir anticiper le comportement du modèle à l’échelle. C’est l’objectif de Delphi, la suite d’évaluation et de mise à l’échelle intégrée à Marin, inspirée des travaux de Pythia. Delphi formalise la relation entre 3e18 et 1e23 FLOPs à travers trois briques complémentaires :

  • Une recette de scaling associant budget de calcul et dimensionnement d’architecture (disponible via la classe CompletedAdamHParams).
  • Une suite de modèles entraînés sur le TPU Research Cloud de Google.
  • Une loi d’échelle empirique permettant d’extrapoler les performances des grands modèles à partir des petits (jusqu’à 300 fois au-delà du point d’ajustement).

L’ensemble des checkpoints Delphi est hébergé publiquement sur Hugging Face (marin-community/delphi). Les mélanges de données utilisés reproduisent de manière déterministe les jeux Nemotron-CC, StarCoderData et ProofPile 2.

Les données brutes ayant servi à tracer les figures de scaling sont réunies dans marin-community/delphi-blog-data, avec un lien Weights & Biases par ligne pour auditer chaque run. Le développement a d’ailleurs été tracé ouvertement dans l’issue GitHub #1337.

Auparavant, l’équipe a validé la méthodologie en entraînant un modèle dense de 8 milliards de paramètres qui a dépassé Llama 3.1 8B sur leur banc d’évaluation interne, suivi de Marin 32B. Des travaux approfondis ont également été publiés sur le blog Open Athena concernant l’équilibrage par quantiles des experts dans les MoE (validé à l’échelle 32B-A5B à 1e22 FLOPs) et l’ordonnancement de tâches hétérogènes avec Iris.

Architecture d’exécution : graphes paresseux et Levanter

Marin repose sur JAX et s’appuie sur Levanter pour la distribution de l’entraînement. Contrairement aux scripts impératifs classiques où chaque ligne lance une opération immédiate, un script d’expérimentation Marin construit un graphe acyclique de dépendances paresseuses (lazy handles). Rien ne se télécharge, rien ne s’alloue au moment des imports.

Ce graphe est ensuite abaissé (via lower()) en une spécification d’étapes (StepSpec), puis soumis au moteur StepRunner. Ce dernier fonctionne comme un Makefile : il résout l’ordre topologique des tâches, inspecte les caches disque ou objet, ignore ce qui est déjà calculé et lance uniquement les étapes manquantes.

Tutoriel pas à pas : entraîner son premier modèle sur TinyStories

L’objectif de cet exercice n’est pas d’obtenir un état de l’art, mais d’exécuter la chaîne complète localement sur CPU, de la tokenisation jusqu’à la production des checkpoints.

Voici le script minimal complet :

from fray.cluster import ResourceConfig
from levanter.optim import AdamConfig
from marin.execution.lazy import lower
from marin.execution.step_runner import StepRunner
from marin.experiment.data import tokenized
from marin.experiment.train import train_lm

from experiments.llama import llama_nano
from experiments.marin_tokenizer import marin_tokenizer

# 1. Tokenisation paresseuse du jeu de données
tinystories_tokenized = tokenized(
    name="tokenized/tinystories",
    source="roneneldan/TinyStories",
    tokenizer=marin_tokenizer,
    version="2026.06.28",
    sample_count=1000,  # Limité à 1 000 échantillons par shard pour le test
)

# 2. Définition de l'étape d'entraînement
nano_tinystories_model = train_lm(
    name="checkpoints/marin-nano-tinystories",
    version="2026.06.28",
    model=llama_nano,
    optimizer=AdamConfig(learning_rate=6e-4, weight_decay=0.1),
    datasets={tinystories_tokenized: 1.0},
    batch_size=4,
    seq_len=2048,
    num_train_steps=100,
    z_loss_weight=None,
    evals=None,
    resources=ResourceConfig.with_cpu(),
)

# 3. Exécution du graphe de dépendance
if __name__ == "__main__":
    StepRunner().run([lower(nano_tinystories_model)])

Détaillons les composants de ce pipeline.

1. La tokenisation paresseuse. La fonction tokenized retourne un objet ArtifactStep[TokenizedCache]. L’appel ne déclenche aucun téléchargement immédiat. Le corpus source provient de Hugging Face (roneneldan/TinyStories) et la tokenisation n’aura lieu que si le cache correspondant au hash et à la version spécifiée est absent du stockage.

2. La configuration du modèle. L’objet llama_nano importé depuis experiments.llama décrit une micro-architecture Llama adaptée aux tests locaux sur processeur standard :

from levanter.models.llama import LlamaConfig

llama_nano = LlamaConfig(
    max_seq_len=2048,
    hidden_dim=128,
    intermediate_dim=512,
    num_heads=4,
    num_kv_heads=4,
    num_layers=2,
)

3. L’assemblage de l’entraînement. La fonction train_lm déclare l’étape d’optimisation et retourne un ArtifactStep[LevanterCheckpoint]. Vous lui passez vos hyperparamètres, votre dictionnaire de pondération des datasets (ici 100 % sur TinyStories), la longueur de séquence et le budget d’étapes. Marin déduit automatiquement que l’entraînement dépend de l’étape tinystories_tokenized sans nécessiter de liste explicite de prérequis.

4. Le déclenchement de l’exécution. Dans le bloc principal, lower(nano_tinystories_model) analyse l’arborescence, transforme les descripteurs en étapes réelles, et StepRunner().run(...) lance les calculs.

Pour lancer l’exécution en définissant le répertoire de stockage des résultats :

MARIN_PREFIX=local_store uv run python my_experiment.py

MARIN_PREFIX accepte un chemin local ou un préfixe compatible avec fsspec (par exemple gs://mon-bucket ou s3://mon-bucket). Une fois le script terminé avec la mention INFO step_runner.py -- All steps complete., l’arborescence contient les artefacts finaux :

local_store/
  tokenized/tinystories/2026.06.28/
  checkpoints/marin-nano-tinystories/2026.06.28/

Gestion des échecs, cache et relance d’étapes

Par défaut, StepRunner applique une politique de reprise simple : si une étape a réussi par le passé, elle est ignorée ; si elle a échoué, elle est relancée lors de l’exécution suivante.

Si vous souhaitez interrompre immédiatement l’exécution lorsqu’un échec passé est détecté au lieu de réessayer automatiquement, configurez le flag adéquat :

StepRunner().run([lower(build())], force_run_failed=False)

Pour forcer le recalcul d’une étape qui a déjà abouti, supprimez son dossier d’artefact dans MARIN_PREFIX ou incrémentez simplement la chaîne passée au paramètre version (ex. passer de "v1" à "v2").

Marin inclut un lanceur de test rapide (smoke launcher) pour valider la chaîne d’exécution sans écrire de script dédié :

# Afficher le plan d'exécution CPU sans le lancer
uv run python -m experiments.tutorials.train_tiny_model \
  --device cpu --dataset tinystories --version dev

# Lancer réellement le calcul avec le flag --run
uv run python -m experiments.tutorials.train_tiny_model \
  --device cpu --dataset tinystories --version dev --run

Ce lanceur supporte divers accélérateurs : cpu, h100x1, h100x8, gb200x1, gb200x4, v5litepod-16 et v6e-4. Les datasets tinystories et wikitext sont échantillonnés à 1 000 documents, tandis que fineweb-edu utilise directement un cache pré-tokenisé inclus.

Configuration de l’environnement GPU local (JAX et CUDA 13)

Pour faire tourner Marin sur une machine locale équipée de GPU (sans passer par un gestionnaire de cluster), la pile logicielle exige des versions récentes :

  • Système d’exploitation : Ubuntu 24.04
  • Pilote NVIDIA : version 580 ou supérieure (vérifiable via nvidia-smi, avec support CUDA 13.x)

Synchronisez l’environnement virtuel avec l’extra GPU pour installer JAX ainsi que les roues Python de cuDNN et NCCL :

uv sync --extra=gpu

Si vous utilisez une machine à mémoire unifiée type DGX Spark, XLA tente souvent d’allouer l’intégralité de la mémoire physique disponible dès le démarrage, provoquant des blocages. Vous devez brider cette pré-allocation en exportant : export XLA_PYTHON_CLIENT_MEM_FRACTION=0.5.

Pour lancer l’entraînement sur une machine à 8 GPU H100 :

export MARIN_PREFIX=local_store
export WANDB_ENTITY=mon-entite
uv run python experiments/tutorials/train_tiny_model.py \
  --device h100x8 --dataset wikitext --version dev --run

La déclaration matérielle dans le code configure les ressources et le batch de manière explicite :

from fray.types import ANY_REGION, ResourceConfig

resources = ResourceConfig.with_gpu(
    "H100", count=8, cpu=32, disk="128G", ram="128G", regions=[ANY_REGION]
)
batch_size = 256

L’utilisation de regions=[ANY_REGION] est indispensable. Les fermes de GPU sur des infrastructures comme CoreWeave n’annoncent pas de région GCP statique ; omettre cette option rendrait le job impossible à planifier.

Entraînement multi-accélérateurs sur le cloud avec Iris et CoreWeave

Pour les charges de travail distribuées, Marin orchestre les réservations sur l’infrastructure CoreWeave via l’outil Iris.

Nom du ClusterAccélérateurs disponiblesTopologie
cw-rno2aNVIDIA H1008 cartes par nœud
cw-us-east-02aNVIDIA H1008 cartes par nœud
cw-us-east-08aNVIDIA GB2004 cartes par tiroir de calcul (compute tray)

Pour inspecter la disponibilité des nœuds avant soumission :

uv run iris --cluster=cw-rno2a rpc controller list-backends

La soumission d’une tâche s’effectue depuis la racine du dépôt pour permettre à Iris de charger le fichier local .marin.yaml (qui stocke vos clés d’API Hugging Face ou Weights & Biases) :

uv run iris --cluster=marin job run \
  --target-cluster cw-rno2a \
  --cpu=1 --memory=2G --extra=cpu \
  -- python -m experiments.tutorials.train_tiny_model \
    --device h100x8 --dataset wikitext --version dev --run

Pour le suivi et le diagnostic du travail en cours :

# Suivre les journaux d'exécution en temps réel
uv run iris --cluster=marin job logs -f /mon_utilisateur/mon-job

# Obtenir l'état consolidé du job
uv run iris --cluster=marin job describe /mon_utilisateur/mon-job

Une fois le calcul validé, inspectez le fichier de métriques <MARIN_PREFIX>/users/<mon_utilisateur>/checkpoints/tiny-wikitext-h100x8/dev/tracker_metrics.jsonl. La clé summary["throughput/device_kind"] confirme le type d’accélérateur qui a exécuté les opérations.

Bonnes pratiques de stockage, risques d’egress et cycle de vie

Les pods de calcul déployés sur CoreWeave héritent automatiquement de la variable MARIN_PREFIX et de leurs identifiants de stockage objet via le secret Kubernetes iris-task-env.

Il existe un piège classique sur ces architectures : ne lisez jamais et ne copiez jamais de données depuis Google Cloud Storage (GCS) directement vers un nœud CoreWeave sans validation explicite. Le transfert inter-fournisseurs déclenche des coûts de bande passante sortante (egress) particulièrement élevés.

Pour isoler les fichiers temporaires et les caches éphémères sans saturer vos espaces permanents, utilisez l’utilitaire de compartimentage temporaire avec un TTL (Time To Live) :

from rigging.filesystem.cluster_config import marin_temp_bucket

scratch = marin_temp_bucket(ttl_days=1, prefix="mon-experience")

Lorsque la variable d’environnement MARIN_TEMP_PREFIX est active sur le cluster, cette méthode achemine tous les flux d’écriture jetables vers un bucket local configuré pour détruire automatiquement les données après expiration du délai imparti.

Leave a Reply

Your email address will not be published. Required fields are marked *