https://blog.tensorflowcn.cn/2020/01/photobooth-lite-on-raspberry-pi-with-tensorflow-lite.html
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhanerZLp5kGU6wO5EYrjrJMWEqYTpu5vMGaMMjV_U85PkXPGF2x172Huknziu5Uy3erVUg8FjaKlgis0Gw5uZWHWHHDimJwPZFK1yanzciBOUSO7uhGATQXiKNPjORBokGRd18rwNX28Q/s1600/gif1.gif
作者:Lucia Li,TensorFlow Lite 实习生
|
智能照相亭应用程序实时运行的示例。 |
我们很高兴展示在树莓派上使用 TensorFlow 构建智能照相亭应用程序的体验(我们目前尚未开源代码)。它可以捕捉微笑的脸庞并自动记录。此外,您还可以使用语音命令与它进行交互。得益于
Tensorflow Lite 框架,我们构建了该应用程序,使其能够轻松地在实时处理微笑面部检测和语音命令识别。
为什么要在树莓派上构建应用程序?
树莓派不仅是一个广泛使用的嵌入式平台,而且体积小巧,价格便宜。我们决定使用 TensorFlow Lite,因为它专门为移动设备和物联网设备设计,非常适合树莓派。
构建照相亭应用程序演示需要什么?
我们在配备 1GB RAM 和安装了 32 位 ARMv7 操作系统的树莓派 3B+ 上实现了我们的照相亭应用程序。我们的应用程序具有图像输入和音频输入,因此我们还需要一台摄像头和一个麦克风。此外,我们需要一个显示器进行显示。总成本低于 **$100 美元**。以下是详细列表:
- 树莓派($35)
‣ 参数
» 四核 64 位处理器,主频为 1.4GHz。
» 1GB LPDDR2 SRAM。
- 摄像头,用于捕捉图像(约 $15 以上)
- 麦克风,用于采样音频数据(约 $5 以上)
- 7 英寸显示器(约 $20 以上)
在我们的照相亭应用程序中,涉及两项关键技术。从摄像头图像输入中,我们需要能够检测是否存在微笑的面部。从麦克风音频输入中,我们需要能够识别是否存在“是”或“否”的语音命令。
如何检测微笑的面部?
使用单个模型来检测面部并预测生成的微笑分数,同时兼顾高精度和低延迟,是困难的。因此,我们通过三个步骤来检测微笑的面部:
|
微笑面部检测工作流程 |
- 应用面部检测模型来检测给定图像中是否存在面部。
- 如果存在面部,则将其从原始图像中裁剪出来。
- 使用裁剪后的面部图像,应用面部属性分类模型来测量它是否是一个微笑的面部。
我们尝试了各种选项来减少检测微笑面部的延迟:
- 为了减少内存并加快执行速度,我们利用了 TensorFlow 模型优化工具箱的 训练后量化。在这个 教程 中,您可以看到在自己的 TensorFlow Lite 模型中使用它有多么容易。
- 我们调整了从摄像头捕捉到的原始图像的大小,使其长宽比固定。压缩比可以是 4 或 2,具体取决于其原始大小。我们试图使图像大小小于 160x160(原始设计大小为 320x320)。较小的输入会显着减少推理时间,如下表所示。在我们的应用程序中,从摄像头捕捉到的原始图像大小为 640x480,因此我们将其调整为 160x120。
- 我们没有使用原始图像进行面部属性分类,而是裁剪了标准面部并放弃了背景。它减少了输入大小,同时保留了有用信息。
- 我们使用多线程进行推理。
下表显示了我们应用的策略的影响。我们使用
Tensorflow Lite benchmark_model 来评估面部检测模型在树莓派上的性能:
|
面部检测延迟比较 |
整个检测微笑面部的流程,包括我们之前提到的三个步骤,在单线程上的平均耗时为 **48.1ms**,这意味着我们实现了实时微笑面部检测。
面部检测
我们的面部检测模型由一个 8 位修改版的 MobileNet v1 主体和一个深度乘数为 0.25 的 SSD-Lite 头组成。它的大小仅略大于 200kB。为什么这个模型如此小?首先,TensorFlow Lite 模型基于 Flatbuffer,它比基于 protobuf 的 TensorFlow 模型更小。其次,我们应用了 8 位量化模型。第三,我们修改后的 MobileNet v1 比原始模型具有更少的通道。
与大多数面部检测模型类似,我们的模型输出边界框的位置和 6 个地标,包括左眼、右眼、鼻尖、嘴巴中心、左耳耳屏和右耳耳屏。我们还应用非极大值抑制来过滤重复的面部。我们的面部检测 TensorFlow Lite 模型的推理时间约为 30ms。这意味着我们的模型可以在树莓派上实时检测面部。
|
边界框和 6 个地标的示例。 |
面部裁剪器
检测到的面部可能具有不同的方向和不同的尺寸。为了统一它们以获得更好的分类效果,我们旋转、裁剪并调整了原始图像的大小。此函数的输入是我们从面部检测模型中获得的 6 个地标的位置。利用 6 个地标,我们可以计算旋转欧拉角和调整大小比率。通过这种方式,我们可以获得一个 128x128 的标准面部。下图显示了我们的面部裁剪器函数的一个示例。蓝色边界框是面部检测模型的输出,而红色边界框是我们计算出的裁剪边界框。我们将边界线复制到图像外部的像素上。
|
面部裁剪器插图 |
面部属性分类
我们的面部属性分类模型也是一个 8 位量化 MobileNet 模型。以 128x128 的标准面部作为输入,模型输出一个 0 到 1 之间的浮点变量来预测微笑概率。模型还输出一个 90 维向量来预测年龄,范围从 0 到 90。它在树莓派上的推理时间可以达到约 30ms。
如何识别语音命令?
实时语音命令识别也可以分为三个步骤:
- 预处理:我们使用滑动窗口来存储最新的 1 秒音频数据,与上次录制相比,有 512 帧不同。
- 推理:给定 1 秒的音频输入,我们可以应用语音命令识别模型来获取四个类别(“是”/“否”/“静音”/“未知”)的概率。
- 后处理:我们将当前推理结果与之前的结果平均。当某个单词的平均概率超过某个阈值时,我们判断检测到一个语音命令。
下面将详细解释这三个步骤。
预处理
我们使用
PortAudio,这是一个开源库,可以从麦克风获取音频数据。下图显示了我们如何存储音频数据。
|
音频流处理 |
由于我们的模型使用 1 秒的音频数据,采样率为 16kHz 进行训练,因此我们的数据缓冲区大小为 16,000 字节。数据缓冲区也充当循环缓冲区。我们每次更新 512 帧。此外,我们记录一个偏移量,它指示上次更新的结束位置。当缓冲区的尾部已满时,我们将从缓冲区的头部继续。当我们要获取音频数据进行推理时,我们将从偏移量开始读取,并一直读取到偏移量之前的帧。
语音命令识别
我们在许多 TensorFlow 示例中公开找到了我们使用的
语音命令识别模型。它由音频频谱图、MFCC、2 个卷积层和 1 个全连接层组成。该模型的输入是 1 秒的音频数据,采样率为 16kHz。数据集是公开的,或者您可以自己训练。该数据集包含 30 个类别的语音命令数据。由于我们只需要“是”和“否”,因此我们忽略了所有其他类别,标记为“未知”。
此外,我们还使用了其他方法来提高延迟性能:
- 我们剪掉了半数通道。TensorFlow Lite 模型压缩后的大小约为 1.9 MB。
- 我们使用了 4 个输出通道的最后一个全连接层,而不是通常的 12 个通道,因为我们只需要 4 个类别。
- 我们使用多线程进行推理。
在训练中,我们将背景音量设置为 0.3,以提高模型的噪声容忍度。我们还将静音百分比设置为 25%,将未知百分比设置为 25%,以平衡训练集。
后处理
|
音频流后处理 |
由于我们获取的音频数据可能只涵盖了半句话,因此单次预测结果并不精确。我们存储了不超过 1.5 秒之前的录音时间的前一次结果,以获得平均预测结果。它极大地提高了关键词检测的实时性能。我们保留的前一次结果的数量很大程度上取决于我们的推理时间。例如,我们的模型在树莓派上的推理时间约为 160ms,这意味着我们最多可以保留 9 个前一次结果。
下一步?
我们希望很快在 TensorFlow Lite Github 存储库中开源此示例的代码。有关如何开始使用 TensorFlow Lite 的更多信息,请参阅
此处 和其他参考示例
此处。
请告诉我们您的想法或
与我们分享您的 TensorFlow Lite 使用案例。
致谢
Lucia Li、Renjie Liu、Tiezhen Wang、Shuangfeng Li、Lawrence Chan、Daniel Situnayake、Pete Warden。