使用 ESP32S3 和 16MB Flash 打造实时输入的端侧大模型
TuBrief 편집팀
2026년 8월 12일
0
Computing/Software원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
커뮤니티의 다른 글
댓글 (0)
Log in to leave a comment
아직 작성된 글이 없습니다
원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
Log in to leave a comment
아직 작성된 글이 없습니다
当你下定决心要在 8 美元的 ESP32-S3 开发板上运行一个 2890 万参数的语言模型时,很快就会感到束手无策。演示视频里运行得好好的模型,一放到自己做的硬件外设上就会立刻死机。SRAM 只有 512KB,而且每次修改一句话都要重新烧录 15MB 的分区,这让人在开发时火冒三丈。要想突破这个限制,做出能够直接接收键盘输入并正常工作的设备,必须从头重新规划内存缓存和输入输出缓冲区。
为了测试一句话而去重新烧录开发板简直是浪费时间。将异步 UART 中断和 FreeRTOS 信号量结合起来,就无需重启开发板。通过串口监视器或键盘输入文字,模型就能立刻理解。
xPromptSemaphore 二值信号量。当接收任务完成 Token 编写并调用 xSemaphoreGive 时,等待中的推导任务通过 xSemaphoreTake 获取内存锁并开始运算。具备这套配置后,修改提示词和测试所花费的时间可以缩减 80% 以上。
`
+------------------+ +-------------------+ +--------------------+
| External UART | ---> | HW FIFO Buffer | ---> | SW Ring Buffer |
| (Keypad/Monitor) | | (120 Bytes) | | (2048 Bytes) |
+------------------+ +-------------------+ +--------------------+
|
v
+------------------+ +-------------------+ +--------------------+
| LLM Forward Pass | <--- | xPromptSemaphore | <--- | BTK1 Tokenizer |
| (Inference Task) | | (Binary Lock) | | (43,056 B Library) |
+------------------+ +-------------------+ +--------------------+
`
采用 Google Gemma 3n 研究团队提出的 Per-Layer Embeddings (PLE) 架构,可以将压缩至 4 位的 14.9MB 模型拆分加载。达到 2500 万参数的嵌入表保存在 16MB SPI Flash 中,而 Output Head 权重(310 万参数)和 KV 缓存则放入 8MB PSRAM。最常用的 559K 参数 Dense Compute Core 和 Hot Activation 缓冲区则直接塞进 512KB SRAM 中。
将速度提升到每秒 14 个 Token 以上的过程比想象中要棘手。
matvec_i8_range 运算函数上加上 __attribute__((noinline)) 属性。如果由编译器自行进行内联,反而会因为 I-RAM 缓存未命中(Cache Miss),导致运算时间从 94.9ms 暴跌至 155.2ms。ple_model_proj 运算和 qkv 运算分配到 ESP32-S3 的 Dual Xtensa LX7 双核上。只有双核同时运转才能达到应有的速度。如果仅仅是使用 C 语言进行移植,速度会低至令人绝望的每秒 0.57 个 Token。但完成 INT8 分级(Staging)和 SRAM 预取后,速度可以超过每秒 14.0 个 Token。
| 优化阶段 | 每个 Token 的运算延迟 | 每秒生成 Token 数 | 主要应用技术 |
|---|---|---|---|
| C 纯代码移植 (Baseline) | 1,757.2 ms | 0.57 tok/s | 单核、FP32 运算 |
| PSRAM Head & 标量优化 | 193.9 ms | 4.61 tok/s | Output Head 部署于 PSRAM |
| 双核 FP32 应用 | 139.4 ms | 6.22 tok/s | 双核分层运算 |
| INT8 Staging + SRAM 优化 | 94.9 ms | 9.88 tok/s | INT8 量化、应用 noinline |
| 扩大 SRAM 预取缓冲区 | ~71.4 ms | 14.0+ tok/s | 前期层 SRAM 预取 |
如果以 240MHz 频率持续运行双核,功耗电流会飙升至 210mA (777mW)。开发板发烫且不说,电池也会瞬间耗尽。必须通过 esp_pm_configure 命令,在没有推导任务时将频率降至 40MHz 并启用自动轻度睡眠。
esp_pm_config_esp32s3_t 结构体中,将 max_freq_mhz 设为 240,min_freq_mhz 设为 40,并开启 light_sleep_enable。esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_ON)。即使进入睡眠状态,也必须保持 SPI Flash 和 RAM 的供电,以免数据丢失。uart_set_wakeup_threshold 和 esp_sleep_enable_uart_wakeup 设置唤醒中断,以便在串口信号输入的瞬间唤醒 CPU。如果使用 3.7V 1000mAh 锂聚合物电池持续运行运算,只能坚持 4.7 小时。但在轻度睡眠待机模式下,电流会骤降至 0.24mA (0.88mW)。在夹杂着待机时间的实际使用环境中,平均电流可维持在 15~30mA 左右,从而将电池续航时间延长 3 倍以上。