在8美元的ESP32-S3上训练的SLM
摘要
Qapla'是一个项目,演示了在8美元的ESP32-S3微控制器上从头训练一个小型Transformer语言模型,表明无需GPU或数据中心即可实现设备端训练。
查看缓存全文
缓存时间: 2026/08/05 07:51
Carloscodix/qapla
来源:https://github.com/Carloscodix/qapla
本文由 AI 协助撰写。注意:协助并不代表由 AI 写作。它的意思是 AI 做了修改、审阅和部分补充,但作者是人类(至少我是这么认为的)。
Qapla’ 项目
这就是你如何在八美元的 ESP32-S3 上从零训练一个 transformer。
没人要求、但人人都需要的(克林贡语)GPT。
在 ESP32-S3 上进行 Qapla’ 训练
我们为什么需要它? 因为我们想当然地认为训练模型需要 GPU 或数据中心。并不总是如此:有时,一个像八美元微控制器这样小巧廉价的东西就足以从零训练一个模型。
请再读一遍:训练。从零开始。 不是运行一个预煮好的模型。是训练。前向传播、反向传播和权重更新,全部在芯片内部完成。
什么是 Qapla’?
边缘 AI 并不是什么新鲜事。TinyML 已经做单片机上的推理好多年了;Andrej Karpathy 的极简项目 llama2.c 的社区移植版将约 26 万参数的 transformer 放到了 ESP32 上;而就在最近,一个出色的项目让近 2900 万参数的模型在 8 美元的 ESP32-S3 上跑了起来。这些都是非常优秀的作品,虽然它们碰巧与这个实验在时间上有所重叠,但它们并不是我们参考的模型。
Slava S.(slvDev)的 esp32-ai(https://github.com/slvDev/esp32-ai)项目以及其他类似项目都有一个共同点:它们是推理。模型诞生在别处——GPU、数据中心——用它的数据训练好,量化好,然后才加载到芯片上让它运行。大脑在外面烹制好,端到芯片上。
我们问了自己一个不同的问题:当模型无法在外面诞生时,会发生什么? 当它无法预训练——因为它需要学习的数据直到设备就位之后才存在——无法随身携带那些数据,也没有互联网可以下载时,该怎么办?
我们知道你在想什么:“好吧,但是……为什么会有人需要在 ESP32 上训练 transformer?” 这是个合理的问题。也许答案是“根本没有理由”。但是……如果我们发挥一下创意,想象这个场景:一个传感器被螺栓固定在一片田野中央的农业机械上,它必须学习那台特定机器的正常振动(与世界上任何其他机器都不同),以便在出问题之前发现异常并安排维护,避免故障发生(而且,你别想抓住我的破绽:我说了没有互联网,但是……LoRa?;)。或者想象一个土地里的传感器,它学习那块特定土壤如何干燥——它自己的土质、日照、排水——并在植物受苦之前预测何时需要浇水。在这些情况下(以及我们能想到的其他情况),数据在设备安装之前并不存在:没有人能预训练它。芯片必须就地独自实时学习。
我们手边没有农业机械可以用来做实验。所以,为了测试 ESP32 的真实学习能力,我们围绕唯一拥有的东西设计了实验:语言。 一个八美元的芯片,在无人帮助的情况下,从零学习一门语言,能走多远?
在微控制器上训练到底意味着什么?
在八美元微控制器内部训练,施加了数据中心没有的游戏规则。而这些规则决定了其他一切:
老规矩,内存说了算。 ESP32-S3 只有几 MB RAM/PSRAM,而不是千兆字节。这限制了模型的大小:我们说的是几十万参数,而不是几百万。一个能“装下”并在芯片上训练的模型,必然是小的。
小模型决定任务。 这种规模的模型可以学习语言的结构(单词如何构成、音位配列、一些语法),但无法学习整个语言的深层语义。任务必须按照模型的规模裁剪。
语料库决定结果。 对于小模型,你不需要千兆字节的文本。你需要一个紧凑、干净、结构化的语料库。而且,如果你要发布它,它还必须没有版权麻烦。
把这三个约束放在一起——小模型、窄任务、干净紧凑的语料——问题就变得具体了:哪种语言能同时满足所有这些条件?
我可以说我们进行了一场头脑风暴来决定第一阶段用哪种语言做实验,但有时候还是坚持老话“第一个想法通常就是好想法”更好……而在这种特殊情况下,最先想到的语言……是克林贡语。
克林贡语
是的,克林贡语。星际迷航中战士们的语言。如果你继续读下去,你会发现这个选择中,工程师的成分比宅的成分更多,而不是看起来那样。
克林贡语不是随便吐出外星噪音就完事的胡言乱语。它由语言学家马克·奥克兰德(Marc Okrand)于 1984 年创造,是一种具有系统音系、语法和构词法的构造语言:它有不同寻常的语序(宾语-动词-主语)和规则严格的形态学。换句话说:它有真实的结构可供学习,这正是小模型证明自己真正在学习、而不是死记硬背噪音所需要的。
而且它符合我们的约束:
- 结构丰富,词汇有限。 有足够的语法让模型捕捉到东西,但语料库又足够小,以适应微控制器的规则。
- 字母表精简。 逐字符工作时,约 30 个符号的词汇表让模型保持微小——这正是 ESP32 内存的要求。
- 干净、自由的语料库。 有一个社区词典采用开放许可证(boQwI’),所以我们可以在不侵犯他人合法领域的情况下训练和分享。
换句话说:克林贡语是理想的试验场。一门真实的语言,有真实语法,但规模小到可以放在手心里。在研究把引擎推向——也许在项目的另一个阶段——真正有母语使用者的少数民族语言之前,这里是完美的挤压实验室。萨米语?克丘亚语?纳瓦特尔语?那……是另一个故事了。
哦,是的:这无疑很酷。一个低成本芯片在 1.3 英寸 OLED 上低语克林贡语,有点宅,但也有点魔法。但那……只是额外奖励。
qapla’. (克林贡语中“成功”的意思。它似乎是合适的名字。)
它不是什么(让我们诚实一点)
为了不让任何人带着错误的想法离开,也因为严谨很重要:
它不是口袋 ChatGPT。 它不聊天、不回答问题、不推理。它是一个微小的生成模型,学习语言的形状,而不是其含义。
它不会生成语义完美的克林贡语。 它学习结构——前缀、后缀、语序、短语听起来的样子——并生成看起来像克林贡语且遵守其许多规则的文本。但不要期待一个语言学学者会毫无怨言签字认可的完整有意义句子(如果企业中有人收到我们 ESP32 的消息,很可能会导致外交事件)。而且无论如何,世界上没有足够的克林贡语来实现这一点,所需的那种模型也装不进芯片。
它不是伪装的推理。 任何地方都没有隐藏的预训练模型。芯片从随机权重开始,对克林贡语没有先验知识,从零学习。你所看到的是真正的学习,不是在外面做好然后端上来的模型。
它不快。 说正经的:我们已经说烂了,但是……它是一个八美元的微控制器,不是 GPU!训练需要数小时。这正是重点:它很慢,但仍然有效。
它是:一个谦逊的微控制器以创客精神,完全在板载从零训练一个语言模型的证明。不多不少。这可不是小事。
它是如何工作的
下面是真正重要的内容,你可以在代码中自行验证。整个学习周期都在板载完成:
在 ESP32-S3 内部:
- ✓ 权重的随机初始化(注意种子,呃哼)
- ✓ 读取和分词语料库
- ✓ 前向传播
- ✓ 损失计算(交叉熵)
- ✓ 反向传播(手动推导的梯度)
- ✓ 权重更新(带动量的 SGD + 余弦学习率)
- ✓ 将检查点保存到 flash(LittleFS)
- ✓ 使用学习到的权重生成文本
在 ESP32-S3 之外:
- ✗ 什么都没有。
架构
这里没有什么新东西。它是一个微小但完整的 transformer:一个块,单头因果注意力,权重绑定,ReLU FFN 和 LayerNorm。它逐字符工作,词汇表约 31 个符号。总共有约 319,000 个参数。
手动反向传播
这里没有 PyTorch,也没有 autograd。前向传播的每个导数都用 C 语言显式写出。为了确保没有错误,每个梯度都与前向传播的中心有限差分进行校验——最大相对误差 1.07e-08,阈值为 1e-4。内核还使用 ESP-IDF 构建,并在 QEMU 的 xtensa 模拟下运行,然后才碰真实硅片。
这两项检查都在 tests/ 中,它们针对本仓库发布的头文件运行,所以你不需要相信我们的一面之词:
cc -O2 -DHANDGPT_DOUBLE -DNV=11 -DNC=16 -DNT=8 tests/gradcheck.c -lm -o gradcheck && ./gradcheck
这是最微妙的部分,也是观看时最有趣的部分。
壮举不在于参数:而在于内存
一个 319K 参数的模型“只”占用约 1.3 MB。但训练不仅仅是持有权重。你需要同时、全部在内存中:权重、同样大小的梯度副本、优化器动量用的另一个副本、另一个用于保留最佳模型,再加上反向传播所需的全部中间激活值,以及语料库。芯片的 PSRAM 中总共有好几 MB。
这就是推理(权重就够了)和训练(权重 + 梯度 + 动量 + 激活值)之间的真正区别。而这正是这个项目的与众不同之处:它不是存一个模型来运行它,而是训练它,连同随之而来的所有一切。
复现它
我们训练所用的语料库在仓库里(corpus/klingon.txt,Apache 2.0,可通过 corpus/build_corpus.py 重新生成),所以你可以直接克隆并运行,而无需寻找数据。但有趣的实验不是重复我们的——而是把它指向你的文本。
你需要什么: 一个带 PSRAM 的 ESP32-S3(N16R8)、一个通过 I2C 连接的 SH1106 OLED(可选,但它是乐趣的一半),以及 PlatformIO。
# 1. 我们的,用于复现……
python tools/gen_header.py corpus/klingon.txt src/corpus_klingon.h
# ……或者你的,用于发现新东西
python tools/gen_header.py your_text.txt src/corpus_klingon.h
# 2. 构建并烧录
pio run -t upload
# 3. 看着它学习:损失实时下降
pio device monitor
就这样。芯片从随机权重开始,训练,并定期保存它见过的训练损失移动平均最低的检查点。(没有验证集分割,所以这是训练损失检查点,不是严格意义上的“最佳模型”。)下次启动时它会加载并生成。中途拔掉电源,你会失去自上次检查点以来学到的一切;完成后拔掉,大脑仍然在那里。
一个警告: 这需要数小时。很多小时。甚至好几天。这不是 bug:这是在八美元的 ESP32-S3 上从零训练一个 transformer。
数据
所有这一切都发生在芯片内部,由一个手机充电器供电。
训练
| 参数 | ~319,000 |
| 词汇表 | 31 个字符 |
| 上下文 | 32 个字符 |
| 优化器 | SGD 动量(0.9)+ 余弦学习率 |
| 步数 | 5,000 |
| 时长 | 插入充电器约 2 天 |
| 硬件 | ESP32-S3 N16R8 + SH1106 OLED |
损失在下降,正如屏幕上看到的那样:
| 步数 | 损失(批次) | 移动平均 |
|---|---|---|
| 1,495 | 2.193 | 2.137 |
| 2,549 | 1.982 | 2.035 |
| 4,905 | 1.996 | 1.871 |
(我们没有第一次启动的照片:等我们想到要记录它时,芯片已经跑了好一阵子了。)
最后一步
移动平均才是重要的:每个批次的损失波动很大(取决于它拿到哪些句子),但平均值稳步下降。芯片最终停在约 1.87。
而这是它吐出来的东西
生成的克林贡语
(是的,屏幕上写着 KlinGPT。项目在最终定名 Qapla’ 之前有过几个更糟糕的名字,KlinGPT 留在了 OLED 上,因为它是链条中的第一个环节。)
hIngan motlh puS ruq tuq DujDaq SISwI' nge'vI'
vIn SuvwI' yIvwI' qarghtaHvIS SIchoH
它不是完全有意义的克林贡语——我们警告过你——但看看这些形态:
SuvwI'是战士:词根Suv(战斗)加上后缀-wI'(“做……的人”)。一个真实的词,构词正确。DujDaq是在船上:Duj(船)加上方位后缀-Daq。qarghtaHvIS带有-taHvIS(当……时,持续 + 状语),一个复合后缀,恰好放在它该在的位置。- 而
hIngan离tlhIngan只差两个字母,那正是“克林贡人”这个词。
其他一些词构词良好但不存在。没有人给模型规则、语法标签或形态切分——只有原始文本,逐字符输入。它从中捕捉到了足够的规律性,将词根和后缀重新组合成站得住脚的形状。
其中有多少是真正的泛化,有多少是语料库的统计回声,我们无法从两个样本中告诉你。这是一个在小型语料库上训练的 319K 参数模型:期待两者混合吧。没有争议的是它发生在哪里——在一个八美元的微控制器内部,无人帮助。
那么接下来呢?
任何有时间、好奇心和足够毅力的人都可以手写反向传播,并在微控制器上训练一个小模型。那不是难点。
有意思的部分在接下来:用真实任务将引擎推到极限——一门真实语言,有真正的母语使用者,语料库比克林贡语能提供的要大得多。那是实验室结束、真正的工程开始的地方:让一个能力更强的模型在一个并未变大的芯片上装下并学习。
我们有一两个想法。但那,如果发生的话,是另一个故事了。
许可证
代码采用 Apache 2.0。拿去用吧,随便改,喂给它你自己的语言。
所有训练语料均来自自由许可的来源(boQwI’ / klingon-assistant-data,Apache 2.0)。克林贡语由马克·奥克兰德创造;克林贡语、星际迷航及相关标志均为其各自所有者的财产(CBS Studios / Paramount)。这是一个开源、教育和研究项目,与它们没有隶属关系,也未获其背书。来源和许可的详细信息请参阅 CORPUS.md。
哦,还有,随机数生成器的种子是 1701。如果你不知道为什么……那么,也许,只是也许,这不是你的仓库 ;)
相似文章
在8美元微控制器上运行2890万参数的大语言模型
一位开发者演示了如何在仅8美元的ESP32-S3微控制器上运行一个2890万参数的语言模型,利用Google的逐层嵌入技术将大部分参数存储在闪存中,实现了设备端每秒约9.5个token的文本生成速度。
我在ESP32 Dev Kit V1上运行了完整的LLM模型(仅用81KB内存)
一位开发者成功在ESP32 Dev Kit V1上运行了量化至INT4的520万参数MoE LLM,仅使用81KB SRAM,通过从闪存流式加载专家,实现了约每秒5个token的速度。
@omarsar0:小型模型的推理能力正在变得非常强。这令人兴奋,因为 SLM 可以在 harness 层释放巨大潜力……
TheWebAI 发布了 TwIL-LM3-Pro,这是一个 3.6B 参数的开源 SLM,可本地运行,在 BIG-Bench Hard 上取得 95.4 分,超过 Qwen3-8B 的 63.7 分,其后训练流程包括形式逻辑微调、权重合并以及针对程序化验证器的强化学习。
从零开始在8GB显存上训练LLM。我开心
构建了一个仓库,用于在8GB显存上从零训练一个微型语言模型(25M参数),支持MTP,但指出mHC和BitNet的局限性。
ESP32S3集群运行1.58位(BitNet)语言模型
本项目实现了一个分布式流水线推理引擎,在一个由七个ESP32S3微控制器组成的集群上运行一个0.5B BitNet语言模型,采用1.58位量化和SPI菊花链通信。