这款售价 8 美元的微控制器正在本地运行语言模型!

Transcript

00:00:00这是一个拥有 2890 万参数的语言模型,现在正以逐字生成的方式输出文本
00:00:08它运行在一块售价仅约 8 美元的芯片上。这里没有 Wi-Fi,也没有向服务器发送任何数据,
00:00:14一切都在 ESP32S3 内部运行,这块微控制器的内存比 90 年代的电脑还要少
00:00:22。这太不可思议了。这究竟是怎么做到的?背后的奥秘是什么?我们又该
00:00:29如何构建类似的东西?这些都是很好的问题,我们将在今天的视频中一一解答
00:00:34。过程会非常有趣,让我们开始吧。ESP32S3 这块芯片提供了
00:00:46512 KB 的 SRAM,这就是芯片用于计算的高速内存总量。正常情况下,
00:00:54如果你尝试在里面运行大语言模型,整个模型都必须正好挤进这块空间。
00:01:00此前有人在这种芯片上成功运行的最大语言模型,上限只有 26 万个参数。而
00:01:08当前这个模型的参数量几乎是其 110 倍,做成这件事的是乌克兰开发者 Slava S。那么
00:01:16秘诀到底是什么?他们是怎么做到的?又是如何把 2890 万参数的模型塞进 8 美元的芯片里的?
00:01:24其实,这个变通方案源自谷歌在 Gemma 中使用的概念,叫做“逐层嵌入”。语言模型的大部分
00:01:31参数并不参与计算,它们只是安静地呆在嵌入表里等待被读取。
00:01:37如果大部分参数仅用于查表,就不需要高速内存。因此你可以
00:01:44将该表保留在缓慢且便宜的 Flash 闪存中,仅在需要时提取当前 token 所需的行。而
00:01:52真正负责计算和思考下一个 token 的一小部分——注意力头和前馈网络,则留在 SRAM 中。
00:01:59好了,计算部分搞定了。但问题依然存在:我们该如何把这么大的模型装进这么小的芯片?
00:02:05拥有 2500 万行的嵌入表存放在 Flash 闪存中,这是模型全部 2890 万
00:02:12参数中最大的组成部分。而在这种特定的芯片上,Flash 既便宜又庞大,拥有 16 MB 空间。
00:02:20因此,与其试图将那个大表塞进区区 512 KB 的 SRAM 中,
00:02:26不如让它直接留在 Flash 里。我们只需从中提取约 6 行,对应模型 6 层中的每一层。
00:02:33总共大概只有 450 字节。不过在太激动之前,我必须说明一点:
00:02:40这是一个非常简单且原始的模型。它不同于常见的 GPT 式大语言模型,不能为你生成代码,
00:02:47也无法回答复杂领域的难题。因为如果你尝试在普通数据集上训练这种规模的普通模型,
00:02:532800 万参数吐出来的只会是乱码。但这个模型本身是在
00:03:01Tiny Stories 数据集上训练的,该数据集由微软研究员构建,内容故意设计得很简单,
00:03:08即使是只有几百万参数的微型模型,也能学会编写连贯的故事。而在没有操作系统、
00:03:15没有 Python 解释器的芯片上直接用纯 C 语言运行它的灵感,来自于著名的 Andrei
00:03:22Karpathy 的 Llama2.c 项目。该项目向我们证明:仅凭几百行可移植的 C 代码,
00:03:28就可以训练小型语言模型并进行推理。这也正是整个
00:03:35项目构建的蓝图。没有 Karpathy,这一切可能根本无法实现。简而言之,
00:03:40这就是它的工作原理。现在让我们尝试亲自动手构建并将其运行在芯片上,看看性能如何。
00:03:47要亲自构建这个项目,首先需要合适的硬件,具体来说是一块带有 16 MB
00:03:54Flash 和 8 MB PSRAM 的 ESP32S3,也就是 N16R8 版本。这非常
00:04:03重要,还记得我们讨论过存放在 Flash 中的 2500 万行嵌入表吗?单独来看,
00:04:10一旦训练并导出,它的体积大概在 15 MB 左右。而只有 4 MB 或 8 MB Flash 的开发板
00:04:17根本装不下它。因此如果你想买一块开发板跟着做,这是你首先要确认的规格。
00:04:22当我第一次查看该项目的实际操作说明时,发现环境配置分散在几个不同的文件中,
00:04:28而且假设读者具备不少我当时并不掌握的背景知识。所以
00:04:34我没有完全照搬文档步骤,而是编写了一个一键式脚本来处理所有事情:
00:04:40检查开发板、安装工具链、准备数据、训练、导出、验证、
00:04:47编译并烧录,一气呵成。让我们来运行这个脚本吧。顺便友情提示一下,
00:04:55如果你跟着做,整个脚本大约需要 25 分钟才能跑完。即便你一步步手动操作,
00:05:00耗时也差不多。这是因为有太多独立的命令需要全程看管,
00:05:05而且大部分时间其实都花在了训练 Tiny Stories 模型上。
00:05:11在我的 MacBook 上训练大约花了 13 分钟。训练完成后,你会看到面板上的 LED 灯
00:05:18开始闪烁,这标志着我们即将加载模型。模型加载完毕后,
00:05:24我们就能看到关于一个小女孩的故事的第一个基础示例。确实,
00:05:29生成速度达到了每秒 9 个 token。但你会注意到在某个时刻,
00:05:33故事会重新开始。也就是说模型进入了某种死循环。如果你想
00:05:39输入自定义提示词,我也附带了一个示例脚本,可以用它来运行你自己的
00:05:44自定义提示词。在这个例子中,我们来开头写一个关于机器人的故事。另外需要注意的是,如果你
00:05:50更改了提示词,就必须重新向 ESP32 烧录固件。这是该方法的一个局限,
00:05:56它一次只能生成预先烧录好的那一个提示词。正如你所见,
00:06:02故事里确实提到了机器人,而且这次的故事也确实有所不同。
00:06:08但请注意段落结尾之后发生了什么:它又绕回了那个小女孩
00:06:13的故事。我也不知道为什么会这样,但显然模型倾向于偏回那个
00:06:19关于小女孩的特定故事。我们再试一个例子,这次用
00:06:24每部《星球大战》电影开头的著名名言,看看它会
00:06:30带我们走向何方。这个结果很有意思,可以看到模型立刻又偏回了
00:06:36小女孩的叙事。我猜对于这种规模的模型来说,它甚至不理解
00:06:42什么是“星系”,这大概就是它在这种情况下忽略我们特定提示词的原因。
00:06:47下一段再次开始了同样的故事。因此尽管这个实验
00:06:53令人印象深刻,亲眼看到模型在微型芯片上每秒输出 9 个 token 确实令人震撼,
00:06:59但它很大程度上仍是一个局限性极强的概念验证。正如我们所见,无论你问模型什么,它
00:07:06总是会偏回讲故事,因为这就是它训练的唯一内容。不过如果你觉得这个测试
00:07:11有意思,我还做过另一个类似领域的视频,测试了第一代树莓派
00:07:18能否在本地运行真实的大语言模型。感兴趣的话可以去看看那个视频。以上
00:07:24就是全部内容了,朋友们。这就是在 ESP32 芯片上运行 2890 万参数语言模型的方法。我们测试过了,
00:07:32它确实有效。向做出了这个项目的 Slava 致敬!大家对这个实验有什么看法呢?
00:07:38你能想到这种实现方式在现实世界中的实际应用场景吗?欢迎在
00:07:43下方评论区分享你的想法。朋友们,如果你喜欢这种技术拆解视频,
00:07:48请点赞视频支持一下。同时别忘了
00:07:53订阅我们的频道。我是来自 Betterstack 的 Andres,我们下期视频再见!

Description

A developer got a 28.9-million-parameter language model running entirely offline on an $8 ESP32-S3 microcontroller, a chip with just 512KB of RAM, using a memory trick borrowed from Google's Gemma architecture called Per-Layer Embeddings. In this video we break down how the trick actually works, reproduce the entire training and flashing process ourselves from a bare board, and put the model through some prompt tests of our own, including one it stubbornly refuses to follow. If you're curious how far you can push AI onto hardware that was never meant to run it, this one's for you. 🔗 Relevant Links Esp32-ai: https://github.com/slvDev/esp32-ai build_and_flash.sh: https://gist.github.com/andrisgauracs/ce459630660f82cf4ca7e43aa81604c7 run_prompt.sh: https://gist.github.com/andrisgauracs/e84b842d0f5e301485ecbf6654b0838e ❤️ More about us Radically better observability stack: https://betterstack.com/ Written tutorials: https://betterstack.com/community/ Example projects: https://github.com/BetterStackHQ 📱 Socials Twitter: https://twitter.com/betterstackhq Instagram: https://www.instagram.com/betterstackhq/ TikTok: https://www.tiktok.com/@betterstack LinkedIn: https://www.linkedin.com/company/betterstack 📌 Chapters: 00:00 Running an LLM on an $8 Chip 00:43 The ESP32’s Memory Problem 01:12 How Did They Make It Work? 01:30 The Per-Layer Embedding Trick 02:04 Fitting 28.9 Million Parameters 02:36 What This Tiny LLM Can Actually Do 02:58 TinyStories and Karpathy’s llama2.c 03:41 Building It Ourselves 03:47 Choosing the Right ESP32 04:23 The One-Shot Installation Script 04:52 Training and Flashing the Model 05:24 Testing the LLM at 9 Tokens per Second 05:38 Trying Custom Prompts 06:21 The Star Wars Prompt Test 06:51 Is an ESP32 LLM Actually Useful? 07:23 Final Thoughts

Community Posts

No posts yet. Be the first to write about this video!

Write about this video