MOG (Model Object Graph) est un format binaire pour stocker de grands modèles de langage. Il regroupe tout ce qu’il faut pour exécuter l’inférence dans un seul fichier.

À l’exécution, il n’est pas nécessaire d’inspecter les fragments du checkpoint, les fichiers du tokenizer ou les métadonnées propres à un framework. Une implémentation de moins de 200 lignes de C peut charger tous les modèles pris en charge.

Structure du fichier

La première partie du fichier contient les métadonnées. Elle identifie l’architecture du modèle avec sa configuration, contient le tokenizer et enregistre l’emplacement de chaque tenseur. Le reste du fichier contient les données encodées des tenseurs.

En-tête

Chaque fichier MOG commence par un petit préambule suivi de la configuration du modèle. Le préambule contient la signature du fichier, la version du format et l’identifiant de l’architecture, ce qui permet au runtime de vérifier le format. La configuration contient les paramètres nécessaires pour construire le modèle, comme sa dimension cachée, son nombre de couches et sa longueur de contexte. MOG utilise une seule structure de configuration capable de représenter toutes les architectures prises en charge. La configuration est écrite directement dans le fichier lors de l’export, puis chargée par une seule lecture de structure, sans analyse manuelle.

Tokenizer

La section du tokenizer contient les données nécessaires pour reproduire le tokenizer BPE (byte-pair encoding) du modèle pendant l’inférence. Elle stocke le vocabulaire ainsi que le graphe de fusions qui détermine comment les jetons sont combinés lors de l’encodage.

Le vocabulaire est stocké sous deux formes optimisées pour chaque sens de la tokenisation : une correspondance directe entre les identifiants de jetons et le texte pour le décodage, et un vocabulaire trié lexicographiquement pour la recherche dichotomique lors de l’encodage. Le graphe de fusions est stocké comme un tableau trié de paires de jetons, ce qui permet de retrouver efficacement les règles de fusion.

Répertoire des tenseurs

Le répertoire des tenseurs est un tableau d’enregistrements de taille fixe, avec un enregistrement pour chaque emplacement de tenseur défini par l’architecture du modèle. Chaque enregistrement contient les dimensions et l’encodage du tenseur, ainsi que les offsets absolus de ses données et de son éventuel buffer d’échelles dans la charge utile.

La disposition du répertoire correspond à la structure des tenseurs du runtime, ce qui permet de le charger par une seule copie mémoire. Lors du chargement, les offsets enregistrés sont convertis en pointeurs relatifs au fichier mappé. Les enregistrements correspondant aux tenseurs absents du modèle restent vides.

Charge utile

La charge utile est une séquence contiguë de tenseurs encodés, stockés dans l’ordre du répertoire. Chaque tenseur occupe un buffer de données contigu et peut également avoir un buffer d’échelles contigu.

Recettes

Les fichiers MOG peuvent être générés à partir d’un checkpoint Hugging Face local avec qpack. Il utilise une recette pour sélectionner les valeurs de configuration, les données du tokenizer et les tenseurs stockés dans le fichier de sortie. La recette attribue également à chaque tenseur son nom dans le runtime et son encodage, ce qui permet de modifier la quantification tenseur par tenseur.

Les dépôts de modèles ne suivent pas tous la même convention de nommage. Cette entrée sélectionne un tenseur d’embedding dans le checkpoint, lui attribue le nom MOG embed et choisit son encodage :

{
"name": "embed",
"file": "weights",
"path": "model.language_model.embed_tokens.weight",
"encoding": "int4_g64_f32"
}

Les couches d’un Transformer répètent les mêmes rôles de tenseurs. Une recette peut exprimer ces correspondances une seule fois avec une boucle :

{
"for": "layer",
"range": [0, 4],
"entries": [
{
"name": "layers.{layer}.q_proj",
"file": "weights",
"path": "model.language_model.layers.{layer}.self_attn.q_proj.weight",
"encoding": "int4_g64_f32"
}
]
}

Les recettes permettent d’itérer rapidement sur les encodages. Pour tester une nouvelle combinaison, modifiez la recette JSON et exportez un autre fichier MOG. Vous pouvez, par exemple, remplacer les nombres à virgule flottante sur 16 bits d’une projection par des entiers groupés sur 8 bits, essayer un autre schéma de compactage d’entiers sur 4 bits ou conserver certains poids en virgule flottante sur 32 bits. Vous pouvez ensuite comparer chaque encodage selon la taille du modèle et la vitesse d’inférence avec le même runtime.

Essayer

Qpack inclut consumer.c, un chargeur minimal pour les fichiers MOG de confiance. Il lit la configuration du modèle, le tokenizer et le répertoire des tenseurs, puis convertit les offsets enregistrés en pointeurs vers les tenseurs.

Pour plus de détails sur le format MOG, consultez la spécification MOG.