LLM на ESP32: как нейросеть размером с рассказ умещается в плату за $8
Звучит как шутка: языковая модель на микроконтроллере. Но энтузиасты доказали обратное — на ESP32-S3 уже крутятся локальные LLM размером 28–42 млн параметров со скоростью около 9 токенов в секунду, без единого обращения в облако.
Что это за «модели»
Полноценные LLM (Llama, Mistral и даже NanoGPT) на микроконтроллере не запустятся — ни память, ни вычисления не сойдутся. Но в 2023–2024 годах появились так называемые tiny LLM — архитектурно те же трансформеры (Llama-arch), просто крошечные:
- Stories260K (0.26M параметров) — обучается на датасете TinyStories за минуты на одном GPU;
- Stories3M (3.3M) — уже пишет осмысленные детские рассказы;
- Stories42M (42M) — предел для одиночного ESP32-S3;
- 28.9M-модель с трюком per-layer embeddings (заимствован из Gemma) — именно она даёт те самые ~9–10 токенов/с на плате N16R8.
Чатить с такой моделью нельзя, но она умеет генерировать короткие тексты, завершать истории и выполнять простые шаблонные задачи. Для демо, образования и «умного железа с характером» — больше чем достаточно.
Почему именно ESP32-S3
- Векторные инструкции PIE в ядре Xtensa — аппаратное SIMD-ускорение матричных операций, без которого нужной скорости не снять;
- PSRAM — внешняя память, куда ложатся веса (512 КБ встроенной SRAM тут бесполезны);
- Flash от 16 МБ — квантованная 28.9M-модель весит ~15 МБ и размещается прямо в flash.
Требования
- Плата ESP32-S3 с внешней PSRAM — минимум 2 МБ для маленьких моделей, лучше 8 МБ (например, ESP32-S3 N16R8: 16 МБ flash + 8 МБ PSRAM).
- ESP-IDF — официальный фреймворк Espressif, настроенный под плату.
- Квантованная модель — веса сжаты из float32 в int8: экономия памяти в 4 раза при практически той же скорости. Для 28.9M это ~14.9 МБ вместо ~58 МБ.
Установка: краткий алгоритм
1. Окружение. Установите ESP-IDF (или ESP-IDF + VS Code с ESP-IDF Extension) и выберите плату с PSRAM.
2. Внешняя память. В idf.py menuconfig убедитесь, что PSRAM включена: Component config → ESP System Settings → Main SPI → SPI RAM.
3. Проект. Отличная стартовая точка — doryiii/esp32-llm: оптимизированный порт llama2.c Карпатого, поддерживает INT8- и F32-модели:
git clone https://github.com/doryiii/esp32-llm.git
cd esp32-llm
Модели (.bin + токенайзер) кладутся в spiffs_data — для 260K и 3M-моделей они уже в репозитории.
4. Движок. В idf.py menuconfig → LLM Configuration выберите INT8-движок (llm8.c) и путь к модели. INT8 использует SIMD-инструкции PIE и выходит почти на потолок пропускной способности памяти (~12–13 токенов/с).
5. Сборка и прошивка:
idf.py set-target esp32s3
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor # порт зависит от ОС и адаптера
В мониторе последовательного порта — потоковая генерация текста со скоростью ~9 токенов/с.
Почему это вообще работает
Ключевые оптимизации, которые делают трюк возможным:
- горячий цикл матричного умножения написан под SIMD PIE с учётом требований к выравниванию памяти;
- де-квантование эмбеддинг-таблицы «на лету» — экономит до ~3 МБ RAM вместо хранения целой таблицы;
- активации (q, k, v) держатся в быстрой on-chip SRAM, а не в PSRAM;
- модель стримится из flash — веса не загружаются целиком в RAM.
Парадокс: второе ядро Xtensa не используется — узкое место не в вычислениях, а в пропускной способности памяти.
Ограничения
- контекст крошечный (десятки токенов), «понимание» — на уровне детского рассказа;
- 9 токенов/с — это «печатающая машинка», а не интерактивный чат;
- для экспериментов — отлично, для продакшена — пока нет.
Итог
LLM на ESP32 — это не замена облачным моделям, а доказательство того, что порог входа в «локальный интеллект» упал до уровня $8 и одного вечера с паяльником. Начните с Stories260K, поднимитесь до 28.9M — и вы будете писать рассказы на микроконтроллере, полностью офлайн.
Полезные ссылки:
- doryiii/esp32-llm — движок и примеры;
- tinyllamas — крошечные модели;
- обсуждение на форуме esp32.com;
- CNX-Software — новости про tiny-LLM на микроконтроллерах.