mcpField
X
xiao-edgeimpulse-train

xiao-edgeimpulse-train

github.com/shain1912数据与数据库057 次安装6 周前更新
代码仓库

关于 xiao-edgeimpulse-train

xiao-edgeimpulse-train 是面向 XIAO ESP32S3 的 Edge Impulse 模型训练流程,使用 REST API 而非 edge-impulse-cli。它涵盖数据集上传、impulse 创建、训练、Arduino 库下载及设备端集成与故障处理。

主要功能

  1. 01上传音频和图像数据集
  2. 02创建音频或视觉 impulse
  3. 03通过 REST API 生成特征并训练模型
  4. 04构建并下载 Arduino 库
  5. 05提供 ESP32-S3 内存与推理集成指引

适用场景

  1. 01为 XIAO ESP32S3 训练关键词识别模型
  2. 02为开发板训练图像分类模型
  3. 03下载并安装 Arduino 推理库
  4. 04排查视觉任务的内存和摄像头集成问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/shain1912/esp32-skills --skill xiao-edgeimpulse-train

安装后在 Claude Code 中输入/xiao-edgeimpulse-train确认已加载。

详细介绍

XIAO ESP32S3 的 Edge Impulse 训练流水线(REST API,已验证)

以下所有步骤均已端到端执行并验证(2026-07)。不需要使用 edge-impulse-cli——请勿尝试安装它(其 serialport@8 依赖项在 Node 22+ 上需要 VS C++ 构建工具)。

步骤 0 — API 密钥(询问用户)

向用户索取 Edge Impulse 管理员 API 密钥(ei_...),或在用户指明后从项目的 .env 中读取 (EI_API_KEY=...)。

  • 自动创建的项目密钥角色为“Ingestion & deployment”——它可以 上传数据,但不能创建 impulse 或开始训练(症状: insufficient permissions (valid roles: [admin]))。
  • 如有需要,告知用户:Studio → Dashboard → Keys → Add new API key → Role Admin (full access) → 立即复制完整密钥(此后列表中显示的密钥会被截断)。
  • 获取项目 ID:使用 x-api-key 标头调用 GET https://studio.edgeimpulse.com/v1/api/projects → projects[0].id。
  • PowerShell 警告:$pid 是只读保留变量——请使用 $proj。

步骤 1 — 上传数据集(ingestion API)

每个文件发送一个 POST 请求;标签来自 x-label 标头:

curl.exe -s -X POST -H "x-api-key: $key" -H "x-label: $cls" `
  -F "data=@$($f.FullName)" https://ingestion.edgeimpulse.com/api/training/files

WAV:16 kHz、16 位、单声道。图像:保持原样的 jpg/png。上传完所有内容后, 自动拆分训练集/测试集:POST /v1/api/$proj/rebalance。

一个项目对应一个模型。要针对其他任务重新训练,请先清空数据: POST /v1/api/$proj/raw-data/delete-all(先归档任何已部署的 lib zip)。

步骤 2 — 创建 impulse

POST https://studio.edgeimpulse.com/v1/api/$proj/impulse(使用 POST,不是 PUT)。

音频(关键词检测)——MFCC 块中的 implementationVersion: 4 为 必需项;否则会使用 v1,导致特征生成失败,并显示 “mel filterbank contains all zeros”:

{"inputBlocks":[{"id":1,"type":"time-series","name":"Time series data","title":"Time series data","windowSizeMs":1000,"windowIncreaseMs":500,"frequencyHz":16000,"padZeros":true}],
 "dspBlocks":[{"id":2,"type":"mfcc","name":"MFCC","axes":["audio"],"title":"MFCC","implementationVersion":4}],
 "learnBlocks":[{"id":3,"type":"keras","name":"Classifier","dsp":[2],"title":"Classification"}]}

视觉(图像分类,MobileNet 迁移学习):

{"inputBlocks":[{"id":1,"type":"image","name":"Images","title":"Image data","imageWidth":96,"imageHeight":96,"resizeMode":"squash"}],
 "dspBlocks":[{"id":2,"type":"image","name":"Image","axes":["image"],"title":"Image","implementationVersion":1}],
 "learnBlocks":[{"id":3,"type":"keras-transfer-image","name":"Transfer learning","dsp":[2],"title":"Transfer learning (Images)"}]}

步骤 3 — 生成特征,然后训练

# start: returns a job id
POST /v1/api/$proj/jobs/generate-features   body: {"dspId":2,"calculateFeatureImportance":false}
# poll until finished (10-15 s interval):
GET  /v1/api/$proj/jobs/$jobId/status   -> job.finished / job.finishedSuccessful
# on failure read newest-first logs:
GET  /v1/api/$proj/jobs/$jobId/stdout   -> stdout[0..] .data

# train (after features succeed):
POST /v1/api/$proj/jobs/train/keras/3
#   audio body:  {"trainingCycles":100,"learningRate":0.005}
#   vision body: {"trainingCycles":20,"learningRate":0.0005}

准确率显示在训练作业的标准输出中(val_accuracy 行)。每个轮询 循环的总等待时间都要短于工具超时限制——在新的调用中继续轮询, 不要一次性休眠很长时间。

步骤 4 — 构建并下载 Arduino 库

POST /v1/api/$proj/jobs/build-ondevice-model?type=arduino   body: {"engine":"tflite-eon"}
# poll job, then:
GET /v1/api/$proj/deployment/download?type=arduino   -> save as <name>.zip

安装:使用 arduino-cli config get directories.user 查找 sketchbook, 解压到 <sketchbook>\libraries\<project>_inferencing。zip 通常会嵌套一个文件夹——请将其内容移到外层,使 src\<project>_inferencing.h 存在。 按任务(音频/视觉)分别归档 zip——切换任务会覆盖库。

步骤 5 — 设备端修复(ESP32-S3,视觉任务必需)

  1. 切换库后首次编译时使用 --clean。 arduino-cli 缓存会为相同的库名称/版本保留过期对象文件—— 症状:出现 objs.a ... is not an object 链接错误,或修改后看似毫无变化(字节大小相同)。
  2. Tensor arena 溢出导致崩溃(Failed to allocate persistent buffer ... EI_MAX_OVERFLOW_BUFFER_COUNT + 启动时 Guru Meditation):编辑 src\edge-impulse-sdk\porting\ei_classifier_porting.h——接近文件末尾处, #if defined(CONFIG_IDF_TARGET_ESP32S3) 会硬编码 EI_MAX_OVERFLOW_BUFFER_COUNT 30,且没有 #ifndef 保护,因此 -D 标志和 模型文件默认值都会被忽略。将 30 改为 2048,然后使用 --clean。
  3. 将 arena 放入 PSRAM——将以下内容添加到 sketch 中(SDK 的分配器是 弱符号),并使用 --board-options PSRAM=opi 构建:
#include "esp_heap_caps.h"
void *ei_malloc(size_t size) {
  void *p = heap_caps_aligned_alloc(16, size, MALLOC_CAP_SPIRAM);
  if (!p) p = heap_caps_aligned_alloc(16, size, MALLOC_CAP_DEFAULT);
  return p;
}
void *ei_calloc(size_t n, size_t s) { void *p = ei_malloc(n*s); if (p) memset(p,0,n*s); return p; }
void ei_free(void *ptr) { heap_caps_free(ptr); }

第 6 步——集成推理草图

  • 通过静态缓冲区模式(signal.get_data)馈入数据,不要使用 EI 示例中的 <I2S.h> 代码(该代码在 esp32 core 3.x 上会出问题——请使用 ESP_I2S.h)。
  • 视觉特征打包:每个像素对应一个浮点数 = (r<<16)|(g<<8)|b。
  • XIAO Sense 上的摄像头画面会旋转 90°:缩小画面时顺时针旋转(sx = y*W/H; sy = H-1-(x*H/W)),否则准确率会骤降。通过将同一帧分别按 3 种方式(不旋转/顺时针/逆时针)分类并进行比较,实测验证方向。
  • 音频电平差异:麦克风音频远低于满量程训练 WAV——最佳解决方法是通过设备麦克风采集训练数据。
  • 摄像头自动白平衡需要预热:实际拍摄前先抓取并丢弃约 8 帧。

评论

支持 Markdown