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,我们下期视频再见!
Community Posts
No posts yet. Be the first to write about this video!
Write about this video