slvDev/esp32-ai
GitHub: slvDev/esp32-ai
该项目在约8美元的ESP32-S3微控制器上实现了2890万参数语言模型的本地推理,通过Per-Layer Embeddings技术将大部分参数存放于flash中从而突破了内存限制。
Stars: 544 | Forks: 65
# 在 8 美元的微控制器上运行 28.9M 参数的 LLM

这是一个拥有 2890 万(28.9M)参数的语言模型,它可以在 ESP32-S3 上生成文本。
ESP32-S3 是一款售价约 8 美元的微控制器。它直接在芯片本地运行,完全不需要向服务器
发送任何数据,并且能以大约每秒 9 个 token 的速度,将生成的每个词写入与芯片连接的
小屏幕上。人们之前在这类芯片上运行的最后一个语言模型仅有 26 万参数,因此这个模型的
参数量大约是它的 100 倍。它之所以能够运行,是因为该模型的大部分数据都存放在 flash 中,
而不是 RAM 里,这得益于 Google 的 Gemma 模型中一种名为 Per-Layer Embeddings 的技术。
## 核心数据
| | |
| ------------ | ------------------------------------------------------------- |
| 参数 | 存储 28.9M(其中 25M 位于 flash 查找表中) |
| 芯片 | ESP32-S3,约 8 美元,配备 512KB SRAM、8MB PSRAM 和 16MB flash |
| 速度 | 端到端约 9.5 tok/s(纯计算为 9.7 tok/s) |
| 连接性 | 无,一切都在设备上本地运行 |
| 模型大小 | 4-bit 量化下为 14.9MB |
## 困难所在及解决方案
微控制器的快速内存非常有限。ESP32-S3 仅提供 512KB 的 SRAM。
通常,整个模型都必须能从这片内存中访问,这就导致只能运行极小的模型,
这也是为什么之前在这类芯片上运行的模型只有 26 万参数的原因。
解决这个问题的办法是完全不把模型放进快速内存中。语言模型的
大部分参数都保存在一个 embedding 表中,模型主要是从中读取数据而
不进行计算。因此,你可以将那个包含 2500 万行的庞大表格留在低速的 flash 中,
每次只为当前 token 提取所需的少数几行(约 450 字节),而真正
执行计算任务的小部分则保留在快速内存中。这样一来,运行这个大模型的
开销几乎为零,因为你根本不需要加载它的绝大部分内容。它只是静静地待在 flash 里,
每次被少量地读取采样。
这种思路即 Google 在 Gemma 3n 和 Gemma 4 中引入的 Per-Layer Embeddings。
只不过在这里,它是运行在微控制器的内存架构上,而非手机或 GPU 上。
据我所知,此前还没有人在如此小巧的芯片上尝试过这种做法。
```
SRAM (fast, tiny) the "thinking" core, used on every token
PSRAM (medium) the output head and working memory
FLASH (huge, slow) the 25M-param table, about 6 rows read per token (~450 B)
```
## 能做什么,不能做什么
该模型使用 TinyStories 数据集进行训练,因此它能编写简短、简单且基本
连贯的故事。它无法回答问题、遵循指令、编写代码或掌握事实知识。这种
局限性是由模型中实际负责推理的那一小部分决定的,内存优化技巧并
不能改变这一点。这项实践中有趣的地方在于其架构设计——即将大模型塞进
微型芯片中——而不是这个 2890 万参数的模型具体能说出些什么内容。
## 自行运行
固件、接线说明和烧录步骤位于
[`firmware/esp32_llm/README.md`](firmware/esp32_llm/README.md) 中。训练、
消融实验和量化代码位于 `src/` 和 `experiments/` 目录下。完整的方法、
消融测试以及芯片上的实测数据都记录在
[`RESULTS.md`](RESULTS.md) 中。
## 致谢
本项目训练使用的是 TinyStories 数据集:由简短的合成故事组成,
足够简单以确保小型模型也能学会连贯地写作(Ronen Eldan 和 Yuanzhi Li,
Microsoft Research,[arXiv:2305.07759](https://arxiv.org/abs/2305.07759))。另一核心
是 Per-Layer Embeddings,这是 Google 在 Gemma 模型中的设计,
正是它让大模型能够容纳在微小的芯片上。
Andrej Karpathy 的 [llama2.c](https://github.com/karpathy/llama2.c) 让许多人(包括我)
相信,我们完全可以训练一个微型语言模型,并用纯 C 语言运行它。本项目正是
由此孕育而生。
## 开发历程
我特意在这个代码库中保留了杂乱的历史记录。其中包括我在自己的参数统计中
发现的一个 bug,该 bug 曾导致早期的数据偏大,以及在我修复后随之而来的
正确结果。提交历史和 `RESULTS.md` 详细展示了数据的演变过程及其原因。
标签:DLL 劫持, ESP32, 大语言模型, 嵌入式, 微型机器学习, 物联网, 边缘AI, 边缘计算