TuBrief
구독 채널
비디오
커뮤니티

使用 ESP32S3 和 16MB Flash 打造实时输入的端侧大模型

TuBrief 편집팀
2026년 8월 12일
0
Computing/Software

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

中文한국어العربيةEspañolDeutschEnglishFrançaisहिन्दीPortuguêsРусскийBahasa Indonesia日本語

관련 영상

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

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

Better Stack

커뮤니티의 다른 글

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

2026년 9월 13일

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

2026년 9월 13일

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

2026년 9월 13일

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

2026년 9월 13일

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

使用 ESP32S3 和 16MB Flash 打造实时输入的端侧大模型

当你下定决心要在 8 美元的 ESP32-S3 开发板上运行一个 2890 万参数的语言模型时,很快就会感到束手无策。演示视频里运行得好好的模型,一放到自己做的硬件外设上就会立刻死机。SRAM 只有 512KB,而且每次修改一句话都要重新烧录 15MB 的分区,这让人在开发时火冒三丈。要想突破这个限制,做出能够直接接收键盘输入并正常工作的设备,必须从头重新规划内存缓存和输入输出缓冲区。

无需每次重新烧录,通过串口注入提示词

为了测试一句话而去重新烧录开发板简直是浪费时间。将异步 UART 中断和 FreeRTOS 信号量结合起来,就无需重启开发板。通过串口监视器或键盘输入文字,模型就能立刻理解。

  1. 将 GPIO 16/17 引脚指定为 UART_NUM_2 端口,并将硬件 FIFO 阈值设为 120 字节以开启接收中断。
  2. 在内置 SRAM 中创建一个 2048 字节的环形缓冲区,防止在推导运算进行时因数据溢出而崩溃。
  3. 附加一个能够检测换行符的流式解析器,并使用 43,056 字节的 BTK1 编码器库将输入文本直接转换为 Token ID 数组。
  4. 设置 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) |
+------------------+ +-------------------+ +--------------------+

`

通过逐层嵌入分配与 SRAM 缓存实现每秒 14 个 Token 的速度

采用 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 以上的过程比想象中要棘手。

  1. 在 matvec_i8_range 运算函数上加上 __attribute__((noinline)) 属性。如果由编译器自行进行内联,反而会因为 I-RAM 缓存未命中(Cache Miss),导致运算时间从 94.9ms 暴跌至 155.2ms。
  2. 将 ple_model_proj 运算和 qkv 运算分配到 ESP32-S3 的 Dual Xtensa LX7 双核上。只有双核同时运转才能达到应有的速度。
  3. 扩大预取缓冲区,将前几层的嵌入数据提前加载到 SRAM 的剩余空间中,从而打通 Flash 内存瓶颈。

如果仅仅是使用 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 预取

控制 210mA 电流的轻度睡眠(Light Sleep)管理

如果以 240MHz 频率持续运行双核,功耗电流会飙升至 210mA (777mW)。开发板发烫且不说,电池也会瞬间耗尽。必须通过 esp_pm_configure 命令,在没有推导任务时将频率降至 40MHz 并启用自动轻度睡眠。

  1. 在 esp_pm_config_esp32s3_t 结构体中,将 max_freq_mhz 设为 240,min_freq_mhz 设为 40,并开启 light_sleep_enable。
  2. 执行 esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_ON)。即使进入睡眠状态,也必须保持 SPI Flash 和 RAM 的供电,以免数据丢失。
  3. 使用 uart_set_wakeup_threshold 和 esp_sleep_enable_uart_wakeup 设置唤醒中断,以便在串口信号输入的瞬间唤醒 CPU。

如果使用 3.7V 1000mAh 锂聚合物电池持续运行运算,只能坚持 4.7 小时。但在轻度睡眠待机模式下,电流会骤降至 0.24mA (0.88mW)。在夹杂着待机时间的实际使用环境中,平均电流可维持在 15~30mA 左右,从而将电池续航时间延长 3 倍以上。