Ingénierie
Une valeur par défaut inversée entre deux fichiers
Quand la configuration d'un modèle ne mentionne pas tie_word_embeddings, phi3 suppose false et llama suppose true. Copiez l'une ou l'autre et vous obtenez un modèle juste sur une famille et discrètement faux sur l'autre.
Mis à jour 2026-09-12Mesuré 2026-09-06
Voici un défaut impossible à trouver en testant un seul modèle, et trivial à trouver en en testant deux.
Dans mlx-lm, quand le config.json d'un modèle ne mentionne pas tie_word_embeddings, la
valeur par défaut diffère selon le fichier d'architecture. phi3.py suppose false.
llama.py suppose true. Les deux sont corrects pour les modèles pour lesquels ils ont été
écrits, et aucun des deux n'est une règle générale.
Donc si vous portez une architecture et que vous copiez la valeur par défaut du fichier que vous avez lu en premier, vous aurez raison sur cette famille et tort sur l'autre. Et « tort » ici ne veut pas dire une exception.
Ce que ce drapeau contrôle réellement
Un modèle de langue possède une table de plongements qui transforme, à l'entrée, des identifiants de jetons en vecteurs, et une projection qui transforme, à la sortie, des vecteurs en scores sur le vocabulaire. Ces deux matrices ont la même forme, transposée.
Liées signifie qu'il s'agit des mêmes poids : la projection de sortie est la transposée du
plongement d'entrée, et le fichier contient une matrice. Déliées signifie qu'elles sont
séparées, apprises indépendamment, et le fichier en contient deux — la seconde généralement
appelée lm_head.weight.
Lier économise beaucoup de mémoire sur un petit modèle, où la matrice de vocabulaire peut représenter une part substantielle des paramètres. Délier donne au modèle plus de capacité. Des familles différentes ont fait des choix différents, et c'est pour cela que ce drapeau existe.
Pourquoi se tromper reste silencieux
Si vous supposez lié alors que le modèle est délié, vous utilisez le plongement d'entrée comme projection de sortie. La matrice a la bonne forme. La multiplication réussit. Vous obtenez des logits.
Ce sont des logits calculés avec la mauvaise matrice, donc la distribution de sortie du modèle n'est pas celle qu'il a appris à produire — mais ce n'est pas du bruit non plus, parce que les deux matrices sont apparentées dans un modèle entraîné avec elles séparées. Le texte reste fluide. Il devient seulement moins bon, d'une manière qui se lit comme « cette quantisation perd un peu » ou « ce modèle n'est pas terrible ».
Le sens inverse est plus bruyant : supposer délié alors que les poids sont liés revient à chercher
lm_head.weight et à ne pas le trouver, ce qui au moins échoue.
Le correctif consiste à cesser de deviner
La réponse fiable n'est pas une meilleure valeur par défaut. C'est de regarder les poids.
Si lm_head.weight est présent dans les safetensors, les plongements sont déliés — parce qu'un
modèle délié doit livrer cette matrice, et qu'un modèle lié n'a aucune raison de le faire. S'il
est absent, ils sont liés.
Cette vérification n'est pas une heuristique. C'est le fait lui-même : la présence du tenseur est ce que délié veut dire au niveau du fichier. Un champ de configuration est une affirmation à propos du fichier, et là où les deux divergent, le fichier gagne.
L'ordre est donc : lire le champ de configuration s'il existe, et s'il n'existe pas, chercher le tenseur. Ne jamais se rabattre sur une constante.
Vérifier un modèle en trente secondes
Puisque la réponse est dans les poids, voici la recette pratique, qui ne demande aucun téléchargement.
Ouvrez le modèle sur Hugging Face et regardez la liste des fichiers. Si vous voyez
lm_head.weight dans un index de safetensors, ou un fichier dont le nom le suggère, les
plongements sont déliés. Sur un modèle fragmenté, le fichier d'index —
model.safetensors.index.json — contient une weight_map qui liste chaque nom de tenseur, et
c'est un simple fichier JSON que vous pouvez lire dans le navigateur.
Ouvrez ensuite config.json et cherchez tie_word_embeddings. Trois issues :
- Il dit
trueet il n'y a pas delm_head.weight— cohérent, lié, rien à se demander. - Il dit
falseetlm_head.weightexiste — cohérent, délié, de même. - Il ne dit rien — c'est le cas courant, et celui où les deux bibliothèques divergent. Ce sont les poids qui tranchent.
La quatrième combinaison, où la configuration et les poids se contredisent, est rare et mérite d'être traitée comme un dépôt cassé plutôt que comme une énigme à résoudre.
Le motif général
Ceci est une instance de quelque chose qui vaut la peine d'être reconnu, parce que cela se répète dans tous les moteurs de modèles.
Les implémentations de référence sont écrites par famille, et leurs valeurs par défaut sont un
savoir local. Une valeur dans llama.py n'est pas une affirmation sur les modèles de langue ;
c'est une affirmation sur llama. Lire un fichier et généraliser à partir de lui, c'est ainsi qu'on
hérite d'une hypothèse qui n'a jamais été destinée à voyager.
La même forme apparaît ailleurs dans le même dépôt. Les biais d'attention, par exemple : qwen2 en
a sur les projections de requête, de clé et de valeur, et ne les déclare nulle part, parce que
dans mlx-lm ils vivent dans l'architecture plutôt que dans la configuration. Llama les rend
optionnels via attention_bias. Un portage qui ne lit que la configuration se trompe sur qwen2 ;
un portage qui ajoute toujours des biais se trompe sur llama. Regarder si le tenseur existe répond
aux deux.
Ce qui est la même règle que tout à l'heure, et elle se généralise :
Quand la configuration et les poids ne s'accordent pas sur ce qu'est un modèle, les poids sont le modèle.
Comment l'attraper avant de publier
La seule raison pour laquelle ceci a été trouvé plutôt que livré, c'est que la justesse est ici vérifiée contre une référence et non en lisant la sortie.
mlx-lm produit des oracles : pour un modèle et une invite donnés, la séquence exacte de jetons
et les logits bruts. Un portage doit les reproduire. Une mauvaise projection de sortie change les
logits immédiatement et visiblement — en nombres, pas en impressions — et le test échoue dès le
premier jeton.
Si vous portez des architectures et que vous n'avez pas cela, mieux vaut le construire avant la deuxième famille qu'après la dixième. L'alternative est de lire du texte généré et de se forger une impression, et une impression ne sait pas distinguer « mauvaise matrice » de « petit modèle ».
Une réserve sur la comparaison des logits, puisque c'est le travail du même après-midi : la tolérance ne peut pas descendre en dessous d'un pas du type des logits. Qwen3 produit des logits en bfloat16, où à une magnitude de 16 un pas vaut 0,125 — exiger 0,05 revient donc à exiger l'égalité bit à bit tout en l'appelant une tolérance.
Ce que cela coûte quand c'est juste
Cela vaut un paragraphe, parce que le drapeau n'est gratuit dans aucun sens et que l'arbitrage est réel.
Sur un petit modèle, la matrice de vocabulaire est une grande part de l'ensemble. Un modèle avec un vocabulaire de 128 000 jetons et une taille cachée de 2 048 porte environ 262 millions de paramètres dans cette seule matrice — ce qui, sur un modèle d'un milliard de paramètres, représente à peu près un quart. Lier divise ce coût par deux, et sur un modèle aussi petit la mémoire économisée fait la différence entre tenir confortablement et ne pas tenir.
Sur un grand modèle, la même matrice est une erreur d'arrondi, et la capacité supplémentaire que donne le déliement vaut davantage que la mémoire. C'est pourquoi le choix est corrélé à la taille, et pourquoi une valeur par défaut juste pour une famille est fausse pour l'autre : les deux bibliothèques n'étaient pas négligentes. Chacune décrivait ses propres modèles.
La version courte
tie_word_embeddingsvaut par défautfalsedans phi3 ettruedans llama, dans la même bibliothèque.- Se tromper produit un texte fluide et moins bon, pas une erreur.
- Ne choisissez pas de valeur par défaut : vérifiez si
lm_head.weightest dans les poids. - Même règle pour les biais d'attention, et pour tout ce que la configuration peut omettre.
Une dernière chose, puisque c'est la question que cela soulève toujours : non, vous ne pouvez pas le deviner au nom du modèle, à son nombre de paramètres ni à sa famille. Deux modèles du même éditeur, publiés à un mois d'écart, peuvent différer. La liste des fichiers est le seul endroit où vit la réponse.
Vérifié contre mlx-lm 0.31.3 le 6 septembre 2026.