Ce qui coûte cher dans un petit modèle
Dans un modèle de cette taille, la table d'embedding pèse autant que les couches elles-mêmes : chaque entrée du vocabulaire coûte 160 nombres. On veut donc le plus petit vocabulaire qui découpe encore correctement le kabyle. J'ai entraîné quatre tokenizers BPE sur le corpus et mesuré leur fertilité — le nombre de jetons par mot — sur des lignes jamais vues.
| Vocabulaire | Jetons par mot | Remarque |
|---|---|---|
| 1 024 | 2,642 | plus petit que tous les tokenizers génériques |
| 2 048 | 2,297 | à égalité avec NLLB-200 |
| 4 096 | 2,049 | |
| 8 192 | 1,863 | celui de KabyLLM complet |
| NLLB-200 (256 204 entrées) | 2,269 | |
| Qwen3 (151 669 entrées) | 2,746 |
Le résultat vaut d'être lu deux fois : avec 2 048 entrées, on découpe le kabyle aussi finement que NLLB-200 et son vocabulaire de 256 204 entrées — cent vingt-cinq fois plus grand — et nettement mieux que Qwen3. Un vocabulaire entraîné sur la langue visée vaut mieux qu'un vocabulaire immense entraîné sur cent autres.
Cent vingt-trois millions de caractères, quelques millions de paramètres
Le corpus est celui de KabyLLM : 123,1 millions de caractères de kabyle, soit 47,9 millions de jetons avec ce tokenizer. Le modèle est un décodeur Transformer de 4 couches, 160 de largeur, 192 jetons de contexte, embeddings partagés avec la tête de sortie : 1 593 280 paramètres.
Mesure retenue : les bits par caractère, qui ramènent la perte au caractère et rendent comparables deux tokenizers différents. Tous les chiffres qui suivent sont mesurés sur la même fin de corpus, jamais vue à l'entraînement. Un premier run de 4 200 pas sur processeur s'arrêtait à 2,09. Sur un GPU T4, 20 000 pas en 16 minutes font descendre le nano à 1,83 bits par caractère — et la courbe baissait encore au dernier pas : le modèle n'a pas atteint sa limite.
Un chiffre à ne pas mettre en face : mon KabyLLM complet, 36,3 millions de paramètres, affiche 1,98 bits par caractère, mais sur 6 600 messages de discussion après fine-tuning, pas sur ce corpus de livres. Même unité, autre jeu de validation : aligner les deux laisserait croire qu'un modèle vingt-trois fois plus petit fait mieux, ce que rien ici ne montre.
03 · La quantificationHuit bits par poids, et ce que ça coûte
Pour qu'un modèle tienne dans une page web, il faut le réduire encore après l'entraînement. Chaque tenseur est ramené à des entiers de 8 bits avec sa propre échelle. Le fichier final pèse 2,07 Mo — deux fois moins qu'en float16.
Et le prix ? Mesuré, pas supposé : la perte de validation passe de 3,262 à 3,269, soit +0,21 %, et les bits par caractère de 1,83 à 1,84. Sur le run local, plus court, le coût n'était que de +0,07 %. C'est le genre d'arbitrage qu'on ne peut pas éluder quand le modèle doit tourner chez le visiteur.
04 · Ce que ce modèle n'est pasUn petit modèle reste un petit modèle
Il faut le dire clairement : à cette taille, le modèle apprend l'orthographe, la morphologie et des tournures fréquentes du kabyle, pas des connaissances. Il ne répond pas à des questions, il n'a pas de faits, et il se contredit volontiers. Ce qu'il démontre est ailleurs : qu'une langue peu dotée peut avoir son modèle exécutable partout, sans serveur, sans compte, sans connexion — y compris dans une salle de classe.
Le corpus lui-même laisse des traces : il a été construit en décodant des PDF, et il en reste des scories — on voit parfois passer un (cid:13) dans les générations. Le modèle apprend ce qu'on lui donne, scories comprises ; les nettoyer est le prochain gain facile.
Le portage est vérifié comme les autres, avec les poids servis dans cette page : le découpage BPE du navigateur est identique à celui de Python (8 textes sur 8), le cache clés-valeurs donne exactement les mêmes logits que le recalcul complet, et l'écart avec PyTorch reste à 8,6·10⁻⁶. Comptez 8 ms par jeton.