今天小编给大家带来的是圣地亚哥的Maker Marcelo Rovai 使用 XIAO ESP32S3 Sensor 搭配Edge Impulse 实现的图像分类的项目。
材料清单
硬件
- Seeed XIAO ESP32S3 Sensor
软件
- Arduino IDE
- Edge Impulse Studio
概述
Seeed Studio 发布了一款新型经济实惠的开发板 XIAO ESP32S3 Sense,它集成了摄像头传感器、数字麦克风和 SD 卡支持。该开发板结合了嵌入式 ML 计算能力和摄影功能,是启动 TinyML(智能语音和视觉 AI)的绝佳工具。
XIAO ESP32S3 Sense 主要特点
- 强大的MCU板:采用ESP32S3 32位双核Xtensa处理器芯片,运行频率高达240 MHz,安装多个开发端口,支持Arduino / MicroPython
- 高级功能:可拆卸 OV2640 摄像头传感器,分辨率为 1600*1200,兼容 OV5640 摄像头传感器,集成额外的数字麦克风
- 精心的电源设计:锂电池充电管理能力提供四种功耗模式,深度睡眠模式功耗低至14μA
- 超大内存,更多可能:提供 8MB PSRAM 和 8MB FLASH,支持 SD 卡插槽用于外部 32GB FAT 内存
- 出色的射频性能:支持2.4GHz Wi-Fi和BLE双无线通信,连接U.FL天线支持100m+远程通信
- 拇指大小的紧凑设计:21 x 17.5mm,采用XIAO经典外形,适合可穿戴设备等空间有限的项目
引脚图:
欲了解更多详细信息,请参阅 Seeed Studio WiKi 页面:https://wiki.seeedstudio.com/xiao\_esp32s3\_getting\_started/
第一步,在 Arduino IDE 上安装 XIAO ESP32S3 Sense板载文件
在 Arduino IDE 上,导航至“文件”>“首选项”,然后填写 URL:https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package\_esp32\_dev\_index.json
接下来,打开板管理器。转到“工具”>“开发板”>“开发板管理器”...并输入 esp32。选择并安装最新的软件包:
在工具上,选择主板 (XIAO ESP32S3):
最后使用数据线连接开发板到电脑上,选择ESP32S3的端口即可。
第二步,使用BLINK测试开发板
XIAO ESP32S3 Sense 有一个内置 LED,连接到 GPIO21。因此,您可以修改引脚编号后上传运行 Blink 代码。
#define LED_BUILT_IN 21
void setup() {
pinMode(LED_BUILT_IN, OUTPUT); // Set the pin as output
}
// Remember that the pin work with inverted logic
// LOW to Turn on and HIGH to turn off
void loop() {
digitalWrite(LED_BUILT_IN, LOW); //Turn on
delay (1000); //Wait 1 sec
digitalWrite(LED_BUILT_IN, HIGH); //Turn off
delay (1000); //Wait 1 sec
}
请注意,引脚以反转逻辑工作:低电平打开,高电平关闭
连接Sense模块(扩展板)
购买时,扩展板与主板是分离的,但安装扩展板非常简单。
需要将扩展板上的连接器与XIAO ESP32S3上的B2B连接器对齐,用力按压,听到“咔”的一声,安装完成。
正如简介中所述,扩展板或设备的“传感”部分具有 1600x1200 OV2640 摄像头、SD 卡插槽和数字麦克风。
麦克风测试
让我们从声音检测开始。转到 GitHub(https://github.com/Mjrovai/XIAO-ESP32S3-Sense) 项目并下载草图:_\_XIAOEsp2s3\_Mic\_Test\__(https://github.com/Mjrovai/XIAO-ESP32S3-Sense/tree/main/Mic\_Test/XiaoEsp32s3\_Mic\_Test) 并在 Arduino IDE 上运行它:
当产生声音时,您可以在串行绘图仪上验证它。
将录制的声音(.wav 音频文件)保存到 microSD 卡。
现在让我们使用板载 SD 卡读卡器来保存 .wav 音频文件。为此,我们需要启用 XIAO PSRAM。
ESP32-S3 的 MCU 芯片上只有几百 KB 的内部 RAM。对于某些用途来说,这可能不够,因此 ESP32-S3 可以使用与 SPI 闪存芯片并联的高达 16 MB 的外部 PSRAM(伪静态 RAM)。
外部存储器包含在存储器映射中,并且在有一定限制的情况下,可以与内部数据 RAM 相同的方式使用。
首先,将 SD 卡插入 XIAO,如下图所示(SD 卡应格式化为 FAT32)。
- 下载草图 \_Wav\\_Record\_(https://github.com/Mjrovai/XIAO-ESP32S3-Sense/tree/main/Mic\_Test/Wav\_Record),您可以在 GitHub 上找到它。
- 执行代码(Wav Record)需要使用ESP-32芯片的PSRAM功能,所以上传前先打开:Tools>PSRAM:“OPI PSRAM”>OPI PSRAM
运行代码 _Wav\\_Record.ino_
- 该程序仅在用户打开串口监视器后执行一次,录制20秒并将录制文件保存到microSD卡上,名称为“\_arduino\\_rec.wav\_”。
- 当。。。的时候 ,串口监视器中每1秒输出一次“。”,程序执行完毕,可以借助读卡器播放录制的声音文件。
音质非常棒!
代码如何工作的解释超出了本教程的范围,但您可以在 wiki(https://wiki.seeedstudio.com/xiao\_esp32s3\_sense\_mic/#save-recorded-sound-to-microsd-card) 页面上找到精彩的描述。
测试相机
要测试相机,您应该从 GitHub 下载文件夹 \_take\\_photos\\_command\_。该文件夹包含草图 ( .ino ) 和两个包含相机详细信息的 .h 文件。
- 运行代码:\_take\\_photos\\_command.ino\_。打开串行监视器并发送命令“ capture ”来捕获图像并将其保存在SD卡上:
验证串行监视器上是否选择了 [Both NL & CR]。
以下是拍摄照片示例:
测试WiFi
XIAO ESP32S3 的优势之一是其 WiFi 功能。那么,让我们测试它的无线电,扫描它周围的 WiFi 网络。您可以通过运行板上的代码示例之一来完成此操作。
转到 Arduino IDE 示例并查找 WiFI ==> WiFIScan
在串行监视器上,您应该看到设备范围内的 WiFi 网络(SSID 和 RSSI)。这是我在家里得到的东西:
简单的 WiFi 服务器(打开/关闭 LED)
让我们测试一下设备作为 WiFi 服务器的能力。我们将在设备上托管一个简单的页面,用于发送打开和关闭 XIAO 内置 LED 的命令。
和之前一样,去 GitHub 下载包含 sketch 的文件夹:SimpleWiFiServer。
在运行草图之前,您应该输入您的网络凭据:
const char* ssid = "Your credentials here";
const char* password = "Your credentials here";
您可以使用串行监视器监视服务器的工作情况。
获取 IP 地址并在浏览器中输入:
您将看到一个页面,其中包含可以打开和关闭 XIAO 内置 LED 的链接。
将视频流传输至网络
现在您知道可以从网页向您的设备发送命令,让我们执行相反的操作。让我们拍摄相机捕获的图像并将其流式传输到网页:
从 GitHub 下载包含代码的文件夹:\_XIAO-ESP32S3-Streeming\\_Video.ino\_。 (https://github.com/Mjrovai/XIAO-ESP32S3-Sense/tree/main/Streeming\_Video)
请记住,该文件夹不仅包含 .ino 文件,还包含处理相机所需的几个 .h 文件。
输入您的凭据并运行草图。在串行监视器上,您可以找到要在浏览器中输入的页面地址:
在浏览器上打开页面(等待几秒钟以开始流式传输)。就是这样。
当您将相机定位为捕获 ML 项目的数据集时(例如,使用代码“\_take\\_photos\\_commands.ino\_”),简化相机“看到”的内容可能非常重要。
当然,我们可以同时做这两件事,在页面上显示相机所看到的内容,并发送命令来捕获图像并将图像保存在 SD 卡上。为此,您可以使用代码 Camera\_HTTP\_Server\_STA,该文件夹可以从 GitHub 下载(https://github.com/Mjrovai/XIAO-ESP32S3-Sense/tree/main/Camera\_HTTP\_Server\_STA)。
该程序将执行以下任务:
- 将相机设置为 JPEG 输出模式。
- 创建一个网页(例如==> http://192.168.4.119//)。正确的地址将显示在串行监视器上。
- 如果 server.on ("/capture", HTTP\_GET, serverCapture),则程序拍摄照片并将其发送到 Web。
- 可以使用[旋转]按钮旋转网页上的图像
- [CAPTURE]命令只会预览网页上的图像,并在串行监视器上显示其大小
- [SAVE]命令将图像保存在SD卡上,同时在网络上显示图像。
保存的图像将遵循顺序命名(image1.jpg、image2.jpg)。
该程序可用于图像分类项目的图像数据集捕获。
检查代码;将会更容易理解相机的工作原理。此代码是基于 Rui Santos 的精彩教程:ESP32-CAM 在 Web 服务器中拍照并显示而开发的,我邀请大家访问该教程。
第三步,Tiny ML 图像分类项目
现在我们已经运行了嵌入式摄像头,是时候尝试图像分类了。出于比较目的,我将复制开发用于旧 ESP2-CAM 的相同图像分类项目:
- ESP32-CAM:TinyML 图像分类 - 水果与蔬菜
https://www.hackster.io/mjrobot/esp32-cam-tinyml-image-classification-fruits-vs-veggies-4ab970
我们项目的整体思路是训练模型并在 XIAO ESP32S3 Sense 上进行推理。为了训练,我们应该找到一些数据(事实上,大量的数据!)。
但首先,我们需要一个目标!我们想要分类什么?
对于TinyML,一组与嵌入式设备上的机器学习推理相关的技术,由于限制(在这种情况下主要是内存),我们应该将分类限制为三到四个类别。我们将区分苹果、香蕉和土豆(您可以尝试其他类别)。
因此,让我们找到一个包含这些类别的图像的特定数据集。 Kaggle 是一个好的开始:
https://www.kaggle.com/kritikseth/fruit-and-vegetable-image-recognition
该数据集包含以下食品的图像:
- 水果 - 香蕉、苹果、梨、葡萄、橙子、猕猴桃、西瓜、石榴、菠萝、芒果。
- 蔬菜 - 黄瓜、胡萝卜、辣椒、洋葱、土豆、柠檬、番茄、萝卜、甜菜根、卷心菜、生菜、菠菜、大豆、花椰菜、甜椒、辣椒、萝卜、玉米、甜玉米、红薯、辣椒粉、墨西哥胡椒、生姜、大蒜、豌豆、茄子。
每个类别分为训练(100 张图像)、测试(10 张图像)和验证(10 张图像)。
将数据集从 Kaggle 网站下载到您的计算机。
或者,您可以添加一些来自家庭厨房的香蕉、苹果和土豆的新鲜照片,例如使用上一节中讨论的草图。
第四步,使用 Edge Impulse Studio 训练模型
我们将使用 Edge Impulse Studio 来训练我们的模型。 Edge Impulse 是边缘设备上机器学习的领先开发平台。
在 Edge Impulse 输入您的帐户凭据(或创建免费帐户)。接下来,创建一个新项目:
数据采集
接下来,在 UPLOAD DATA 部分,从您的计算机上传所选类别的文件:
您现在应该拥有训练数据集,分为三类数据:
您可以上传额外的数据以进行进一步的模型测试或拆分训练数据。我将保留原样,以使用尽可能多的数据。
模型设计
脉冲获取原始数据(在本例中为图像),提取特征(调整图片大小),然后使用学习块对新数据进行分类。
如前所述,对图像进行分类是深度学习最常见的用途,但需要使用大量数据来完成此任务。每个类别我们有大约 90 张图像。这个数量够吗?一点也不!
我们需要数千张图像来“教学或建模”来区分苹果和香蕉。但是,我们可以通过使用数千张图像重新训练先前训练的模型来解决这个问题。我们将这种技术称为“迁移学习”(TL)。
通过 TL,我们可以在数据上微调预训练的图像分类模型,即使对于相对较小的图像数据集(我们的案例)也能表现良好。
因此,从原始图像开始,我们将调整它们的大小(96x96)像素,然后将它们输入到我们的迁移学习块中:
预处理(特征生成)
除了调整图像大小之外,我们还应该将它们更改为灰度以保持实际的 RGB 颜色深度。这样,我们的每个数据样本都将具有 9 维、216 个特征 (96x96x1)。保持 RGB 不变,这个尺寸会大三倍。
使用灰度有助于减少推理所需的最终内存量。
不要忘记“保存参数”。这将生成用于训练的特征。
模型训练(迁移学习和数据增强)
2007 年,Google 推出了 MobileNetV1,这是一个通用计算机视觉神经网络系列,专为移动设备而设计,支持分类、检测等功能。 MobileNet 是小型、低延迟、低功耗模型,经过参数化以满足各种用例的资源限制。
尽管基本的 MobileNet 架构已经很小并且延迟很低,但很多时候,特定的用例或应用程序可能需要模型更小、更快。
MobileNet 引入了一个称为宽度乘数的简单参数 α(alpha)来构建这些更小、计算成本更低的模型。宽度乘数 α 的作用是在每一层均匀地细化网络。
Edge Impulse Studio 提供 MobileNet V1(96x96 图像)和 V2(96x96 和 160x160 图像),具有多个不同的 α 值(从 0.05 到 1.0)。例如,使用 V2、160x160 图像和 α=1.0 时,您将获得最高的准确度。当然,这是一个权衡。精度越高,运行模型所需的内存(大约 1.3M RAM 和 2.6M ROM)就越多,这意味着延迟也就越长。
MobileNet V1 和 α=0.10 的另一个极端(大约 53.2K RAM 和 101K ROM)将获得更小的占用空间。
当我们第一次发布这个在 ESP32-CAM 上运行的项目时,我们停留在可能性的较低水平,这保证了小延迟的推理,但不能保证高精度。对于第一遍,我们将保留此模型设计(MobileNet V1 和 α=0.10)。
深度学习使用的另一个重要技术是数据增强。数据增强是一种可以帮助提高机器学习模型的准确性、创建额外的人工数据的方法。
在下面,您可以看到 Edge Impulse 如何对您的数据实施数据增强策略:
# Implements the data augmentation policy
def augment_image(image, label):
# Flips the image randomly
image = tf.image.random_flip_left_right(image)
# Increase the image size, then randomly crop it down to
# the original dimensions
resize_factor = random.uniform(1, 1.2)
new_height = math.floor(resize_factor * INPUT_SHAPE[0])
new_width = math.floor(resize_factor * INPUT_SHAPE[1])
image = tf.image.resize_with_crop_or_pad(image, new_height, new_width)
image = tf.image.random_crop(image, size=INPUT_SHAPE)
# Vary the brightness of the image
image = tf.image.random_brightness(image, max_delta=0.2)
return image, label
在训练期间接触这些变化可以帮助防止模型通过“记住”训练数据中的表面线索来走捷径,这意味着它可以更好地反映数据集中深层的底层模式。
我们模型的最后一层将有 16 个神经元,并具有 10% 的 dropout,以防止过度拟合。这是训练输出:
结果并不好。该模型达到了约 77% 的准确率,但预计在推理过程中使用的 RAM 量相对较小(约 60 KB),这非常好。
模型部署
训练后的模型将作为 .zip Arduino 库部署:
打开 Arduino IDE,然后在 Sketch 下,转到 Include Library 和 add.ZIP Library。选择您从 Edge Impulse Studio 下载的文件,就这样!
在 Arduino IDE 的示例选项卡下,您应该在项目名称下找到草图代码。
打开静态缓冲区示例:
您可以看到第一行代码正是对一个库的调用,其中包含在您的设备上运行推理所需的所有必要内容。
#include <XIAO-ESP32S3-CAM-Fruits-vs-Veggies_inferencing.h>
当然,这是一个通用代码(“模板”),仅获取一个原始数据样本(存储在变量:\_features = { }\_ 上)并运行分类器,进行推理。结果显示在串行监视器上。
我们应该从相机获取样本(图像)并对其进行预处理(调整大小至 96x96、转换为灰度并展平)。这将是我们模型的输入张量。
输出张量将是一个具有三个值(标签)的向量,显示每一类的概率。
返回到您的项目(选项卡图像),复制原始数据示例之一:
将9216个特征复制到剪贴板。这是输入张量(96x96x1 的扁平图像),在本例中为香蕉。通过 _features[ ] = {0xb2d77b, 0xb5d687, 0xd8e8c0, 0xeaecba, 0xc2cf67, ...}_ 上的此输入张量
注意:Edge Impulse 在其 SDK 中包含了 ESP NN 库,其中包含针对各种 Espressif 芯片优化的 NN(神经网络)功能。在本教程发布(5 月 2 日)之前,ESP NN 无法与 ESP32S3(Arduino IDE)配合使用。
如果编译代码并出现错误,则有必要修复此问题。 EI 建议关闭 ESP NN 加速。为此,请在导出的 Arduino 库文件夹中找到 _ei\\_classifier\\_config.h : /scr/edge-impulse-sdk/classifier/_ :
找到 _#define EI\\_CLASSIFIER\\_TFLITE\\_ENABLE\\_ESP\\_NN 1_ 行,并将其从 1 更改为 0:
现在,在运行推理时,您应该获得“香蕉”的最高分。
好消息!我们的设备进行推理,发现输入图像是香蕉。另请注意,推理时间约为 317 毫秒,如果您尝试对视频中的图像进行分类,则最大帧率为 3 fps。
这是比 ESP32 CAM(525 毫秒延迟)更好的结果。
现在,我们应该结合相机并对图像进行实时分类。
转到 Arduino IDE 示例并从您的项目下载草图 \_esp32\\_camera\_:
您应该通过与我们的模型相关的数据更改第 32 至 75 行,这些行定义了相机模型和引脚:
修改后的草图可以从 GitHub 下载:\_xiao\\_esp32s3\\_camera\_(https://github.com/Mjrovai/XIAO-ESP32S3-Sense/tree/main/xiao\\\\\_esp32s3\\\\\_camera)。
请注意,您可以选择将引脚保留为 a.h 文件,就像我们在前面部分中所做的那样。
将代码上传到您的 XIAO ESP32S3 Sense,您就可以开始对水果和蔬菜进行分类了!您可以在串行监视器上检查结果。
测试模型(推理)
用相机拍照,分类结果将显示在串行监视器上:
其他测试:
使用更大的模型进行测试
现在,让我们看看模型尺寸的另一面。我们选择 MobilinetV2 96x96 0.35,输入 RGB 图像。
即使模型更大,准确性也不好,最糟糕的是,运行模型所需的内存量增加了五倍,延迟增加了七倍。因此,为了使我们的模型更好,我们可能需要更多图像来进行训练。
即使我们的模型没有改进,我们还是测试一下 XIAO 是否可以处理这么大的模型。我们将使用静态缓冲区草图进行简单的推理测试。
结果是肯定的!内存在这里不是问题;延迟是!通过实际测试可以看到,XIAO 的推理时间几乎为 2.5 秒(之前为 318 毫秒)。
可选择使用 ESP-NN 加速
尽管 Edge Impulse 尚未发布使用该加速器的 ESP32S3 SDK,但感谢 Dmitry Maslov,我们可以为 ESP32-S3 恢复和修复具有装配优化的 ESP NN。这个解决方案还不是官方的,一旦 EI 修复了与其他板的冲突,就会将其包含在 EI SDK 中。
目前,这仅适用于非 EON 版本。因此,如果在生成库时启用了 EON 编译器,您应该重新部署模型。
同时,您可以从项目 GitHub 下载初步版本,将其解压,并将其替换为以下的 ESP NN 文件夹:\_\\\\_src/edge-impulse-sdk/porting/espressif/ESP-NN\\\\_\_, 在你的 Arduino 库文件夹中。
然后编译草图。替换文件夹后重新启动 IDE 可能会有所帮助。
使用MobilinetV2 96x96 0.35进行推理,以RGB图像作为输入,延迟从2,383ms减少到219ms,减少了十倍以上!
在我的测试中,该选项适用于 MobileNet V2,但不适用于 V1。因此,我再次使用最小版本的 MobileNet V2 训练模型,α 值为 0.05。
请注意,以 480MHz 时钟运行的 Arduino Portenta(或 Nicla)的估计延迟时间为 45 毫秒。
如前所述,部署模型并应用修正,替换 ESP-NN 文件夹后,我得到的推断结果仅为 135 毫秒,这是因为 XIAO 的运行时钟只有 Portenta/Nicla 的一半(240MHz):
结论
XIAO ESP32S3 Sense是一种非常灵活,高性价比且易于编程的设备。该项目证明了TinyML的潜力。记忆不是问题;该设备可以处理许多后处理任务,包括通信。但是您应该考虑到高延迟(没有ESP NN加速器)将限制一些应用程序,尽管XIAO比ESP32-CAM快50%。在我的GitHub存储库中,您可以找到代码的最新版本:XIAO-ESP32S3-Sense。一如既往,我希望这个项目可以帮助其他人在人工智能、电子和物联网的激动人心的世界中找到自己的路!