ESP32S3와 16MB 플래시로 실시간 입력받는 온디바이스 LLM 만들기
TuBrief 편집팀
2026년 8월 12일
0
컴퓨터/소프트웨어원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
커뮤니티의 다른 글
댓글 (0)
Log in to leave a comment
아직 작성된 글이 없습니다
원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
Log in to leave a comment
아직 작성된 글이 없습니다
8달러짜리 ESP32-S3 보드에서 2,890만 파라미터 언어 모델을 돌려보겠다고 마음먹으면 금방 막막해집니다. 시연 영상에서는 잘만 돌아가는 모델이 내가 만든 하드웨어 주변기기와 만나면 바로 먹통이 되니까요. SRAM은 512KB에 불과하고, 문장 하나 바꿀 때마다 15MB짜리 파티션을 새로 구워야 하면 개발하다 화부터 납니다. 이 제약을 뚫고 실제 키패드 입력을 받아 작동하는 기기를 만들려면 메모리 캐싱과 입출력 버퍼를 처음부터 다르게 짜야 합니다.
테스트 문장 하나 바꾸겠다고 보드를 새로 굽는 짓은 시간 버리는 길입니다. 비동기 UART 인터럽트랑 FreeRTOS 세마포어를 묶어두면 보드를 재부팅할 필요가 없습니다. 시리얼 모니터나 키패드로 문장을 치는 족족 모델이 바로 알아먹습니다.
이 구성을 갖춰두면 프롬프트 수정과 테스트에 드는 시간을 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 모델을 쪼개서 얹을 수 있습니다. 2,500만 파라미터에 달하는 임베딩 테이블은 16MB SPI 플래시에 두고, Output Head 가중치(310만 파라미터)와 KV 캐시는 8MB PSRAM에 넣습니다. 가장 자주 쓰이는 559K 파라미터 Dense Compute Core와 Hot Activation 버퍼만 512KB SRAM에 박아두는 겁니다.
속도를 초당 14토큰 이상으로 올리는 작업은 생각보다 까다롭습니다.
__attribute__((noinline)) 속성을 딱 붙여줍니다. 컴파일러가 알아서 인라인화를 진행하면 I-RAM 캐시 미스가 나면서 연산 시간이 94.9ms에서 155.2ms로 오히려 떡락합니다.C 언어로 그냥 포팅만 했을 때는 초당 0.57토큰이라는 절망적인 속도가 나옵니다. 하지만 INT8 스테이징과 SRAM 프리페치까지 마치면 초당 14.0토큰을 넘깁니다.
| 최적화 단계 | 토큰당 연산 지연 시간 | 초당 토큰 생성 수 | 주요 적용 기술 |
|---|---|---|---|
| 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_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_ON)을 실행합니다. 슬립 상태에 들어가도 SPI 플래시와 RAM 전원은 유지해야 데이터가 날아가지 않습니다.3.7V 1000mAh 리튬폴리머 배터리로 연산을 계속 돌리면 4.7시간밖에 안 갑니다. 하지만 라이트 슬립 대기 모드에서는 전류가 0.24mA(0.88mW)로 뚝 떨어집니다. 대기 시간이 섞이는 실제 사용 환경에서는 평균 전류가 15~30mA 수준으로 유지되어 배터리 사용 시간이 3배 이상 늘어납니다.