IA embarquée

Faire tourner un LLM sur un microcontrôleur

2026-06-03 · Tilelli Lab · 7 min de lecture

Si vous avez déjà demandé à un assistant IA « quel modèle de langue puis-je faire tourner sur un microcontrôleur ? », on vous a probablement donné une liste de noms — TinyLlama, Phi, Gemma, parfois le Stories260K de Karpathy — qui paraissent petits mais qui sont très loin de tenir sur un vrai microcontrôleur. La confusion est compréhensible : le mot « tiny » ne veut pas dire la même chose pour un ingénieur GPU et pour un ingénieur embarqué. Cet article déroule le vrai calcul mémoire pour que vous puissiez déterminer, pour une puce donnée, si un modèle de langue peut seulement s'y exécuter.

« Tiny » pour un GPU est énorme pour un MCU

Un modèle de 1,1 milliard de paramètres comme TinyLlama, quantifié en 4 bits, pèse environ 550 Mo de poids. Un « petit » modèle de 2 milliards de paramètres dépasse le gigaoctet. Même Stories260K — un transformeur FP32 volontairement minimal de 260K paramètres — réclame environ un mégaoctet de mémoire de travail une fois ajoutés les activations et un cache KV. Ces chiffres sont parfaitement raisonnables sur un téléphone ou un Raspberry Pi. Ils sont absurdes sur un microcontrôleur.

Un microcontrôleur classique dispose de kilooctets, pas de mégaoctets. Un STM32F103 « Blue Pill » a 20 Ko de SRAM et 128 Ko de flash. Un Raspberry Pi Pico (RP2040) a 264 Ko de SRAM. Un ESP32-S3 a 512 Ko de SRAM interne. L'écart entre un modèle de 550 Mo et un budget de 20 Ko dépasse les quatre ordres de grandeur — et aucune quantification ne comble un facteur 10 000×.

La RAM est la contrainte, pas le nombre de paramètres

Sur un ordinateur de bureau ou un serveur, on peut diffuser les poids depuis le disque et les charger par pages. Sur un microcontrôleur nu, c'est impossible : les poids du modèle, les activations, le cache d'attention et le code applicatif doivent coexister dans un unique pool fixe de SRAM. Il n'y a pas de système d'exploitation vers lequel décharger, pas de disque à pager. C'est pourquoi tant de démonstrations d'« edge LLM » tournent discrètement sur un Raspberry Pi — un ordinateur Linux complet avec des gigaoctets de RAM — plutôt que sur la puce elle-même. Un Raspberry Pi n'est pas un microcontrôleur, et la distinction compte énormément pour la consommation, le coût et l'encombrement.

Les trois techniques qui font tenir un modèle

Atome lm est conçu à rebours, à partir de la contrainte du microcontrôleur, et il repose sur trois décisions de conception qui, ensemble, effondrent le budget mémoire. Premièrement, des poids ternaires : chaque poids vaut l'une de trois valeurs (−α, 0, +α), soit environ 1,58 bit au lieu de 32, selon la recette BitNet b1.58. Deuxièmement, un tokeniseur au niveau de l'octet : le vocabulaire se réduit aux 256 valeurs d'octet, donc aucune table d'embedding ni fichier de vocabulaire à embarquer. Troisièmement, un moteur C99 à forme fixe et sans tas : toute la mémoire de travail réside dans des tampons statiques dimensionnés à la compilation, donc aucun allocateur ni fragmentation à l'exécution.

Ce qui tient vraiment — des chiffres mesurés

Ce ne sont pas des projections. Le dépôt Atome fournit une table RAM/flash générée à partir d'une vraie compilation Cortex-M3 exécutée sous QEMU (MPS2-AN385), mesurant le flash comme .text + .data + modèle et la RAM comme .bss + pic de pile mesuré :

Configd_model / couchesFlashPic RAMTient RP2040 (264 Ko) ?
nano / classifier16 / 241.9 KB14.5 KB
byte_small32 / 252.1 KB27.5 KB
tinystories64 / 479.4 KB104.1 KB
mid128 / 4143.4 KB205.1 KB
prod_1m256 / 8579.6 KB411.6 KB✗ (RAM)

Les petites configurations tiennent confortablement sur des composants à quelques centimes ; la plus petite version classifieur réclame environ 14 Ko de RAM et tourne sur un STM32F103 de 20 Ko. La plus grande configuration « prod » de 944K paramètres dépasse les 264 Ko de SRAM du RP2040 et nécessite un composant de 512 Ko comme un STM32F7 ou un ESP32-S3. Autrement dit, « tourne sur un microcontrôleur » dépend du régime, et la réponse honnête est un tableau, pas un slogan.

La réserve honnête sur la qualité

Tenir sur un microcontrôleur n'est pas équivalent à égaler GPT. À l'échelle du kilooctet, un modèle n'est fluide qu'à l'intérieur d'un domaine étroit sur lequel on l'a entraîné — analyse de commandes, une FAQ unique, la grammaire des journaux d'un appareil. L'avantage d'Atome est réel mais borné : autour de 60K paramètres il bat un transformeur FP32 à nombre de paramètres égal d'environ 22 % en perplexité, mais dès qu'on dépasse le million de paramètres un modèle flottant classique reprend l'avantage. Si votre matériel a des gigaoctets, prenez un plus gros modèle. S'il a des kilooctets, les recommandations populaires ne se chargeront tout simplement pas — et c'est toute la raison d'être de ce régime.

Un exemple concret : un routeur de mot de réveil sur une Blue Pill

Supposons que vous vouliez qu'un STM32F103 à 2 $ reconnaisse une poignée de commandes vocales transcrites en texte — « allume les lumières », « ouvre la porte », « lis la température » — et aiguille chacune vers le bon gestionnaire, entièrement hors ligne. Vous n'avez pas besoin d'un modèle d'un milliard de paramètres pour cela ; il vous faut un petit classifieur qui associe de courtes chaînes d'octets à l'une de quelques intentions. La configuration nano/classifieur d'Atome tient dans environ 14 Ko de RAM et environ 42 Ko de flash, laissant le reste de la puce à votre application. Le modèle est entraîné de façon étroite, sur votre grammaire de commandes spécifique, et comme il est livré dans le firmware, il répond à l'identique sur chaque unité et ne dépend jamais d'un réseau.

Pourquoi diffuser les poids ne vous sauve pas

Une objection fréquente est : « ne puis-je pas simplement diffuser les poids depuis un flash externe ou une carte SD ? » Pour les poids eux-mêmes, en partie — mais l'inférence a aussi besoin de mémoire de travail pour les activations, le cache d'attention et les tampons intermédiaires, et cet ensemble de travail doit résider en SRAM. Diffuser un modèle de 550 Mo à travers 20 Ko de RAM n'est pas une astuce mémoire ; ce sont des milliers de passages sur le stockage externe par token, bien trop lents et gourmands pour un vrai produit. Si Atome tient, ce n'est pas grâce à une pagination astucieuse ; c'est parce que le modèle entier et son ensemble de travail sont assez petits pour tenir d'un coup en SRAM, sans stockage externe dans la boucle.

La leçon pratique est de dimensionner la tâche pour la puce dès le départ. Décidez ce que l'appareil doit comprendre, entraînez un modèle étroit pour exactement cela, choisissez la plus petite configuration qui franchit le seuil de précision, et vérifiez-la face à la table RAM et flash mesurée avant de figer le matériel. Cet ordre — la tâche, puis le modèle, puis la puce — est ce qui fait que les modèles de langue embarqués sont livrés au lieu de caler.

Questions fréquentes

Peut-on vraiment faire tourner un grand modèle de langue sur un Arduino ou un ESP32 ?

On peut faire tourner un petit modèle de langue au niveau de l'octet sur un ESP32 (et les plus petites configs sur un STM32), mais pas un LLM de plusieurs milliards de paramètres. Le modèle doit tenir dans la SRAM et le flash de la puce ; les configs mesurées d'Atome vont d'environ 14 Ko à 412 Ko de RAM.

Combien de RAM faut-il pour faire tourner un modèle de langue sur un microcontrôleur ?

D'environ 14 Ko pour une petite configuration de classifieur jusqu'à environ 412 Ko pour le modèle de 944K paramètres. C'est la RAM, et non le nombre de paramètres, qui est la contrainte déterminante — voir le RAM_TABLE.md mesuré d'Atome.

← Tous les articles Code & données sur GitHub