基于TensorFlow Lite Micro在物联网设备上玩转TinyML之离线语音唤醒

简介: 本文介绍如何基于HaaS EDU K1进行TFLite-Micro离线语音模型的部署。通过本文将学习到离线语音识别全链路开发流程。从语音数据集采集到模型训练,再到模型部署的TinyML(微型机器学习)整个生命周期。

1. 案例简介

随着机器学习的发展,TinyML(微型机器学习)已在你的家里、车里、甚至口袋里工作了。什么是TinyML呢?它是属于机器学习的一个子领域,包含了算法、硬件和软件,能够基于传感器数据分析,并在极地功耗的设备上运行。比如家里的天猫精灵、苹果的Siri和亚马逊的Alexa等语音助手是TinyML的一个完美应用,它们提供了语音用户接口(AUI),让用户不需要操作屏幕、鼠标或键盘就可以进行交互,给用户提供了一种全新的交互方式,这些语音助手几乎无处不在。从独立的智能音箱到几乎所有手机都内置了某种语音助手。

在大部分情况下,语音识别、自然语言处理以及语音合成等饭中工作都是在云端完成的,由性能强大的服务器运行大型机器学习模型。当用户提出问题时,将以wav或其他音频流的形式被发送到云端。云端识别出音频流的含义并进行回复响应。语音助手真正需要的音频是唤醒设备后的数据。如果能在不发送数据的情况下检测到这个唤醒词,并在听到唤醒词之后才开始音频流的传输,这样既能够保护用户的隐私、节省电池电量和带宽,而且可以在没有网络的情况下唤醒。

这也是TinyML的用武之地。要在低功耗的芯片上运行,意味着要训练一个监听唤醒词的微型模型,嵌入到微控制设备中,它就可以一直监听唤醒词,当检测到唤醒词后通知操作系统开始捕获音频并发送到云端。

在本章中,将教大家如何使用预先训练的检测模型,在HaaS EDU K1上进行唤醒词检测模型的部署,并使用Tensorflow Lite Micro推理引擎进行推理。随后将教大家如何使用Tensorflow训练脚本训练一个自己的唤醒词,再进行设备端部署。本案例主要有三个部分组成:

  1. 语音采集:接入模拟麦克风(Mic1输入);
  2. 语音识别:说出“打开”和“关闭”识别后,OLED将显示“Turn on...”和“Turn off”;
  3. 语音播报:执行指令的同时,播报本地TTS(mp3)。


开始学习之前我们先看一下案例效果:

1.1 涉及知识点

  • 唤醒词数据采集、模型训练、模型部署
  • 设备端模拟MIC声音采样
  • 设备端音频特征提取
  • TFLite-Micro推理引擎应用
  • 设备端命令识别、响应
  • 设备端喇叭播放mp3文件
  • 文件系统应用
  • OLED显示字符

2. 方案介绍

整个方案的框架如下:

  • 提供批量音频录制工具进行数据收集;
  • 提供TF模型训练脚本进行唤醒词训练;
  • 提供完整设备端模型部署方案;

基于该方案,你将学习到TinyML的整个生命周期:

3. 开发环境搭建

3.1 硬件准备

如果有HaaS语音扩展板,直接插入即可:

HaaS智能语音.jpg

如果没有HaaS语音扩展板,请按照如下步骤接入麦克风和喇叭:

HaaSEDU-kws接线图.png

HaaS EDU K1硬件排线图请参考
https://help.aliyun.com/document_detail/205267.html


购买链接仅供参考!!我们不负责商家发货的品质保障等问题!!

名称

数量

参考链接

HaaS EDU K1开发版

1

HaaS EDU K1购买链接

microUSB数据线

1

普通microusb线即可

模拟MIC

1

模拟MIC参考链接

喇叭

1

喇叭参考链接

杜邦线

数条

NA

3.2 环境搭建

参考《HaaS EDU K1快速开始》中HaaS Studio章节完成AliOS Things开发环境搭建。

3.2.1 案例代码下载

该案例相关的源代码下载可参考《创建工程》,该案例是C/C++案例。
其中:

  • 选择解决方案: “TFLite-Micro离线语音快捷词唤醒案例”或者“tflite_micro_speech_demo”
  • 选择开发板: HaaS EDU K1

3.2.2 代码编译、烧录

参考《HaaS EDU K1快速开始》完成代码的编译及烧录,在烧录前,请先完成3.2.1的步骤,再进行编译烧录。

3.2.2.1 文件件系统烧录

本组件例子中使用到到的本地语料存放在代码中hardware/chip/haas1000/prebuild/data/目录下mp3目录,除烧录tflite_micro_speech_demo image外,需烧录littlefs文件系统,请将hardware/chip/haas1000/package.yaml文件中以下代码段的注释打开后重新编译:

program_data_files:    - filename: release/write_flash_tool/ota_bin/littlefs.bin
      address: 0xB32000

3.2.3 打开串口

参考《HaaS EDU K1快速开始》打开串口进行LOG查看。

4. 软件架构

离线语音唤醒框架.png

  • KWS Demo应用程序: 主要打通实现AI语音引擎的初始化,欢迎语播报。
  • ai_agent组件:是AliOS Things上的AI引擎核心模块,后端接入不同的推理引擎,本案例中使用了TFLite-Micro推理引擎。
  • uVoice组件:是AliOS Things上智能语音解决方案的核心组件,提供了本地音频,URL音频,TTS合成等基础功能,音频格式支持mp3, m4a, wav, opus等主流格式,本案例中使用它来进行本地mp3语料的响应播报。
  • A2SA组件:是AliOS Things上音频服务框架,兼容ALSA应用接口访问,支持音频硬件驱动抽象,多音频驱动加载/卸载,VFS接口支持等功能。

4.1 代码结构

├── cp_resources.py     # 拷贝本地语料到/prebuild/data目录,编译进文件系统
├── main.c
├── maintask.c
├── Makefile
├── micro_speech        # 语音识别程序
├── oled                # OLED显示程序
│   ├── oled.c
│   └── oled.h
├── package.yaml        # 编译系统配置文件
├── player              # 播放器程序
│   ├── player.c
│   └── player.h
├── README.md
├── recorder            # 录音程序
│   ├── recorder.c
│   └── recorder.h
├── resources
│   └── mp3             # 本地mp3语料
├── SConstruct

4.2 设备端工作流程

在HaaS EDU K1上的整个工作流程如下图:

设备端工作流程.png

4.3 程序主体

以下代码是执行唤醒词识别主体,setup对TFLite-Micro模型推理引擎进行初始化,loop中执行上图中整个流程,从音频采集到命令响应的全部流程在该函数中实现,详细逻辑请参考代码。

// The name of this function is important for Arduino compatibility.voidsetup()
{
//   tflite::InitializeTarget();//RegisterDebugLogCallback(callback);// Set up logging. Google style is to avoid globals or statics because of// lifetime uncertainty, but since this has a trivial destructor it's okay.// NOLINTNEXTLINE(runtime-global-variables)statictflite::MicroErrorReportermicro_error_reporter;
error_reporter=&micro_error_reporter;
// Map the model into a usable data structure. This doesn't involve any// copying or parsing, it's a very lightweight operation.model=tflite::GetModel(g_model);
if (model->version() !=TFLITE_SCHEMA_VERSION)
    {
TF_LITE_REPORT_ERROR(error_reporter,
"Model provided is schema version %d not equal ""to supported version %d.",
model->version(), TFLITE_SCHEMA_VERSION);
return;
    }
// Pull in only the operation implementations we need.// This relies on a complete list of all the ops needed by this graph.// An easier approach is to just use the AllOpsResolver, but this will// incur some penalty in code space for op implementations that are not// needed by this graph.//// tflite::AllOpsResolver resolver;// NOLINTNEXTLINE(runtime-global-variables)statictflite::MicroMutableOpResolver<4>micro_op_resolver(error_reporter);
if (micro_op_resolver.AddDepthwiseConv2D() !=kTfLiteOk)
    {
return;
    }
if (micro_op_resolver.AddFullyConnected() !=kTfLiteOk)
    {
return;
    }
if (micro_op_resolver.AddSoftmax() !=kTfLiteOk)
    {
return;
    }
if (micro_op_resolver.AddReshape() !=kTfLiteOk)
    {
return;
    }
// Build an interpreter to run the model with.statictflite::MicroInterpreterstatic_interpreter(
model, micro_op_resolver, tensor_arena, kTensorArenaSize, error_reporter);
interpreter=&static_interpreter;
// Allocate memory from the tensor_arena for the model's tensors.TfLiteStatusallocate_status=interpreter->AllocateTensors();
if (allocate_status!=kTfLiteOk)
    {
TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
return;
    }
// Get information about the memory area to use for the model's input.model_input=interpreter->input(0);
if ((model_input->dims->size!=2) || (model_input->dims->data[0] !=1) ||        (model_input->dims->data[1] !=         (kFeatureSliceCount*kFeatureSliceSize)) ||        (model_input->type!=kTfLiteInt8))
    {
TF_LITE_REPORT_ERROR(error_reporter,
"Bad input tensor parameters in model");
return;
    }
model_input_buffer=model_input->data.int8;
// Prepare to access the audio spectrograms from a microphone or other source// that will provide the inputs to the neural network.// NOLINTNEXTLINE(runtime-global-variables)staticFeatureProviderstatic_feature_provider(kFeatureElementCount,
feature_buffer);
feature_provider=&static_feature_provider;
staticRecognizeCommandsstatic_recognizer(error_reporter);
recognizer=&static_recognizer;
previous_time=0;
RespondCommandThreadInit();
}
// The name of this function is important for Arduino compatibility.voidloop()
{
// Fetch the spectrogram for the current time.constint32_tcurrent_time=LatestAudioTimestamp();
inthow_many_new_slices=0;
TfLiteStatusfeature_status=feature_provider->PopulateFeatureData(
error_reporter, previous_time, current_time, &how_many_new_slices);
// LOG("current_time: %d, previous_time: %d, how_many_new_slices: %d\n", current_time, previous_time, how_many_new_slices);if (feature_status!=kTfLiteOk)
    {
TF_LITE_REPORT_ERROR(error_reporter, "Feature generation failed");
return;
    }
previous_time=current_time;
// If no new audio samples have been received since last time, don't bother// running the network model.if (how_many_new_slices==0)
    {
//LOG("[lk added]how_many_new_slices is 0\n");return;
    }
// Copy feature buffer to input tensorfor (inti=0; i<kFeatureElementCount; i++)
    {
model_input_buffer[i] =feature_buffer[i];
    }
// Run the model on the spectrogram input and make sure it succeeds.TfLiteStatusinvoke_status=interpreter->Invoke();
if (invoke_status!=kTfLiteOk)
    {
TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed");
return;
    }
// Obtain a pointer to the output tensorTfLiteTensor*output=interpreter->output(0);
// Determine whether a command was recognized based on the output of inferenceconstchar*found_command=nullptr;
uint8_tscore=0;
boolis_new_command=false;
TfLiteStatusprocess_status=recognizer->ProcessLatestResults(
output, current_time, &found_command, &score, &is_new_command);
if (process_status!=kTfLiteOk)
    {
TF_LITE_REPORT_ERROR(error_reporter,
"RecognizeCommands::ProcessLatestResults() failed");
return;
    }
// Do something based on the recognized command. The default implementation// just prints to the error console, but you should replace this with your// own function for a real application.RespondToCommand(error_reporter, current_time, found_command, score,
is_new_command);
}

5. 案例体验

当程序烧录完成后,直接喊出“打开",“关闭”,就可以看到视频所示的效果。目前只支持近场唤醒,唤醒距离1米左右。由于这个“打开”,“关闭”唤醒的语料有限,唤醒因不同人有差异。建议按照章节6中自己训练一个唤醒词或者使用数据集中的英文语料“on/off”试试。

6. 自训练唤醒词

本案例是自训练了一个“打开”,“关闭”快捷唤醒词。本小节将带你训练一个新的快捷唤醒词。

从录音采集到部署到HaaS EDU K1的整个详细流程如下:


工程化流程细节.png

6.1 语料采集

语料采集是一个比较耗费人力的事情,通常商业化工程中语料收集有专人或专门的数据公司收集整理,这里提供了一个使用Python写一个录音工具,方便你快速录音。

依赖项安装

#pip install pyaudio或者
#conda install pyaudio

录音配置

  • 语音文件长度一秒
  • 单声道、16KHz、wav格式
  • 快、中、慢三种不同速度进行录制
  • 录制次数100次以上,次数越多效果越好
  • 相对安静环境

6.1.1 唤醒词录制

录制时看到“开始录音,请说话......”即可立即说出唤醒词,比如“打开”、“关闭”。由于我们检测一秒的唤醒词,所以在注意要在一秒内说完整整个唤醒词,录制一次后会自动回放确认是否录制完整,如果录制完整,按回车键继续下一次录制,如果录制不完整或有其他杂音,按其他任意键删除刚才的录音再继续下一次录制。

执行命令:

#python micro_speech/train/record.py

record.png

毫无疑问,这个教学案例是教你如何录制一个人的声音,如果想要达到商业化的识别率,就至少需要500人以上的声音录制。如果仅仅录制你一个人的唤醒词,那么仅识别你的声音是可以的,但其他人在唤醒时的成功率就会低很多。这个案例重点是教你了解唤醒词训练部署的原理。

6.1.2 背景噪音录制

为了更好的识别,需要录制一些背景噪音,模型训练时会学习唤醒词和背景噪音的差别。背景噪音可以录制1~2分钟。模型训练时会自动从中随机选择片段作为背噪加入唤醒词中进行学习。


执行命令:

#python micro_speech/train/record_noise.py

record_noise.png

录制背景噪音,放到dataset/_background_noise_目录。

6.1.3 创建自己的数据集

训练脚本中默认采样的预训练数据集是Google发布的Speech Commands(语音命令)数据集,该数据集是英文数据集。这里我们以录制中文的“打开”,“关闭”为例,每个词录制100次。录制完成后分别命名为dakai和guanbi两个文件夹放入自定义的my_dataset目录,然后从Speech Commands中选择几个单词house、marvin、wow等唤醒词作为“未知”类别放入到my_only_dataset目录,它的作用是模型训练时能够从这些唤醒词中识别想要的dakai和guanbi命令,dakai和guanbi可以理解为正面示例,“未知”类别为反面示例。整个命令词个数尽量限制在十个以下,这样训练的时间不会过久。如果你有其他同样长度且与录音配置中格式一样的唤醒词,也可以加入进来。另外如果录制的是100次唤醒词,那么其他作为“未知”类别的唤醒词的录音示例个数也尽量在100左右。录制的背景噪音放入到_background_noise_目录,训练时脚本将自动从中随机选取一秒片段作为背景噪音加入到“无声”类别中。

6.2 模型训练

6.2.1 PC端训练

PC上在VSCode中使用jupyter notbook插件打开tflite_micro_speech_demo/micro_speech/train/train_micro_speech_model.ipynb进行其他唤醒词的训练。

前提:
参考《HaaS AI之VSCode中搭建Python虚拟环境》搭建完开发环境后,安装tensorflow 1.15版本:

#conda create --name tf python=3.6#conda activate tf#conda install tensorflow=1.15

pc.png

6.2.2 阿里云PAI平台训练

如果PC性能有限,使用阿里云PAI平台进行训练也是一个不错的选择,PAI-DSW是一款云端机器学习开发IDE,为您提供交互式编程环境,适用于不同水平的开发者。你可以根据根据需要选择个人版、GPU特价版或探索者版(免费),相关使用手册DSW新手使用手册
以使用DSW个人版为例:

  1. 登录PAI控制台
  2. 在左侧导航栏,选择模型开发和训练 > 交互式建模(DSW)。
  3. 在页面左上方,选择目标地域。
  4. 在Notebook建模服务页面,单击创建实例。
  5. 在配置实例向导页面,配置参数,镜像选择tensorflow1.15-gpu-py36-cu101-ubuntu18.04版本。

pai.png

6.2.3 模型配置

无论在什么平台上进行训练,脚本中需要对训练的参数进行一定的配置:

唤醒词配置

WANTED_WORDS就是你训练的唤醒词。比如:
WANTED_WORDS="yes, on",yes/on对应于数据集dataset目录的唤醒词语料文件夹。这里跟你你要训练的唤醒词修改。

训练步数配置

如果你的唤醒词仅仅走数百条甚至数10条,那么训练的步数不用太久,修改:
TRANINGS_STEPS="1200, 300"
如果你有上千条以上,训练的步数可以增加:
TRANINGS_STEPS="15000, 3000"
为了防止训练欠拟合或者过拟合,训练的时间长短需要反复验证,找到最优的结果。

数据集配置

如果使用自己的数据集,请修改:
DATASET_DIR =  './dataset/'

6.3 模型部署

模型部署在HaaS EDU K1上,主要有三个步骤:


  1. 模型替换:将生成的模型文件model.cc替换micro_speech/micro_features/model.cc文件
  2. 标签更新:在cc替换micro_speech/micro_features/micro_model_settings.cc中,将标签名更换为你训练的快捷词,比如“打开”、“关闭”。由于标签与模型的输出张量元素是按照顺序进行匹配的,因此,需要按照将标签提供给训练脚本的顺序列出这些标签。
  3. 业务逻辑更新:在micro_speech/command_responder.cc中根据标签更新相应的业务逻辑。目前在听到“打开”后,会打开HaaS EDU K1上R/G/B LED灯。你也可以修改逻辑比如通过WiFi打开远程的风扇或灯。这里可以充分发挥你的想象力打造一些比较有意思的场景应用。

7. 总结

本案例在HaaS EDU K1上基于TFLite-Micro推理引擎进行语音唤醒词的部署。也提供了从唤醒词采集到模型训练,模型部署的全链路开发流程,帮助您深入理解在低功耗MCU上如何进行离线语音识别的开发部署,期待您打造更多属于你的离线唤醒词应用。

相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
目录
相关文章
|
16天前
|
物联网 5G 智能硬件
物联网卡:物联网卡不支持语音通话,是如何实现设备间的数据传输和通信的?
物联网卡(IoT SIM卡)通常被设计用于支持物联网(IoT)设备之间的数据传输,而不直接支持语音通话功能。这是因为物联网设备主要关注的是数据的收集、传输和处理,而不是语音通信。为了实现设备间的数据传输和通信,物联网卡及其背后的技术采用了多种方法,主要包括但不限于以下几种方式:
物联网卡:物联网卡不支持语音通话,是如何实现设备间的数据传输和通信的?
|
18天前
|
传感器 机器学习/深度学习 存储
物联网设备精细化管理系统解决方案
随着科技的进步,物联网技术作为新一代信息技术的核心部分,正在深刻改变各行业的生产和管理方式。其在资产管理、智慧城市、能源管理和智慧医疗等多个领域的广泛应用,不仅提高了运营效率,还促进了资源优化配置和精细化管理。本文详细介绍了物联网的基础概念及其在设备精细化管理系统中的具体应用方案,展示了如何通过智能感知层建设、数据处理分析平台以及精细化管理应用,实现设备的实时监控、预测性维护和能耗管理等功能,从而帮助企业提升竞争力,降低成本,并推动社会向更智能化、绿色化的方向发展。
52 2
物联网设备精细化管理系统解决方案
|
1天前
|
物联网
物联网卡不能使用在什么设备上
“物联网卡不能使用在什么设备上”这一操作或规定,通常基于物联网卡的特性、使用条款以及设备兼容性等因素。以下是对这一问题的详细分析和操作建议:
|
4天前
|
存储 监控 物联网
医疗物联网设备精细化管理系统解决方案
华汇数据智慧医院物联网管理系统解决方案是一种集物联网、云计算、大数据和人工智能等先进技术于一体的综合性解决方案,旨在提升医院的运营效率、医疗质量和患者满意度。
19 3
|
9天前
|
安全 物联网
物联网卡不能更换设备使用吗
物联网卡(IoT SIM卡)是否允许更换设备使用,这主要取决于物联网服务提供商的具体政策和服务条款。通常,物联网卡是为特定设备或应用场景设计的,因此一些服务提供商会限制卡的更换使用,主要是出于安全、管理、网络优化和避免滥用等考虑
|
17天前
|
物联网 数据安全/隐私保护
物联网:物联网卡不能使用在什么设备上
物联网卡是专为物联网设备设计的SIM卡,旨在连接非传统的、嵌入式或远程的设备到互联网。由于其特定的用途和设计,物联网卡并不适用于所有类型的设备,尤其是在以下几个方面,物联网卡通常不能或不建议使用在以下设备上:
|
1月前
|
安全 物联网 定位技术
2G网络和基站的撤销对物联网设备的影响
2G网络和基站的撤销对物联网设备的影响是多方面的,以下是对这一影响的详细分析:
2G网络和基站的撤销对物联网设备的影响
|
17天前
|
物联网 智能硬件
物联网卡:当物联网设备用卡使用在非物联网设备上会被管控吗
当设备物联网卡被检测到在非物联网设备上使用时,可能会遇到一系列的反应或后果,这主要取决于运营商的政策和物联网卡的设计目的。物联网卡通常是为非物联网设备(如智能家居设备、智能城市基础设施、车联网设备等)设计的,其流量套餐、网络连接速度、服务协议以及费用结构都与普通SIM卡有所不同。以下是一些可能发生的情况:
|
19天前
|
消息中间件 存储 NoSQL
物联网设备频繁断网,如何打赢智慧社区的流量洪峰之战?
本文详细介绍了智慧社区中物联网(IOT)技术的应用,重点讨论了物联网流量洪峰的处理方法。文章分析了上行和下行消息的特点,并提出了上下行拆分、多泳道消息队列、实时消息优先处理、连接计算存储分离及推拉结合的消息策略,以优化消息队列,确保系统稳定运行。通过这些技术手段,智慧社区的物联网设备能在各种场景中保持高效运作。
32 2
|
1月前
|
传感器 物联网 人机交互
物联网:物联网,作为新一代信息技术的重要组成部分,通过智能感知、识别技术与普适计算等通信感知技术,将各种信息传感设备与互联网结合起来而形成的一个巨大网络,实现了物物相连、人物相连,开启了万物互联的新时代。
在21世纪,物联网(IoT)作为新一代信息技术的核心,正以前所未有的速度重塑生活、工作和社会结构。本文首先介绍了物联网的概念及其在各领域的广泛应用,强调其技术融合性、广泛的应用范围以及数据驱动的特点。接着,详细阐述了物联网行业的现状和发展趋势,包括政策支持、关键技术突破和应用场景深化。此外,还探讨了物联网面临的挑战与机遇,并展望了其未来在技术创新和模式创新方面的潜力。物联网行业正以其独特魅力引领科技发展潮流,有望成为推动全球经济发展的新引擎。

相关产品

  • 物联网平台