Keyword Spotting Demo 软件演示了如何使用MAX78000 EVKIT 识别大量关键字。
KWS20 演示软件使用第二版 Google 语音命令数据集,其中包含 35 个关键字和超过 100K 的话语:
https://storage.cloud.google.com/download.tensorflow.org/data/speech_commands_v0.02.tar.gz
此演示使用了完整数据集中的以下 20 个关键字子集:
[‘up’, ‘down’, ‘left’, ‘right’, ‘stop’, ‘go’, ‘yes’, ‘no’, ‘on’, ‘off’, ‘one’, ‘two’, ‘three’, ‘four’, ‘five’, ‘six’, ‘seven’, ‘eight’, ‘nine’, ‘zero’]
其余关键字和无法识别的词属于“Unknown”类别。
导航到 KWS20 演示软件所在的目录并构建项目:
$ cd /Examples/MAX78000/CNN/kws20_demo
$ make
如果是第一次安装工具后,或者更新了外设文件,请先清理驱动再重建工程:
$ make distclean
# Specify the board used
ifeq "$(BOARD)" ""
BOARD=EvKit_V1
#BOARD=FTHR_RevA
endif
# Specify the board used
ifeq "$(BOARD)" ""
#BOARD=EvKit_V1
BOARD=FTHR_RevA
endif
注意:如果您使用的是 Eclipse,还请确保通过以下方式将 Board 环境变量的值更改为“FTHR_RevA”:
右键单击项目名称 > 属性 > C/C++ 构建 > 环境 > Board"
将 USB 电缆连接到 CN1 (USB/PWR) 并打开电源开关 (SW1)。
将 PICO 适配器连接到 JH5 SWD 接头。
如果您使用的是 Windows,请在 MinGW shell 中使用 OpenOCD 加载固件映像:
openocd -s $MAXIM_PATH/Tools/OpenOCD/scripts -f interface/cmsis-dap.cfg -f target/max78000.cfg -c "program build/MAX78000.elf reset exit"
如果使用 Linux,请执行此步骤:
./openocd -f tcl/interface/cmsis-dap.cfg -f tcl/target/max78000.cfg -c "program build/MAX78000.elf verify reset exit"
确保在加载固件后移除 PICO 适配器。
确保在 JP20-CLK(INT 位置)安装跳线,如下所示:
注:板载外部振荡器 Y3 用于生成 I2S 时钟。I2S 采样率为 16kHz,以匹配数据集的语音样本。
重新上电后,如果 TFT 显示屏为空白,或如下图显示不正确,请按 RESET (SW5)。
TFT 显示屏显示它已准备就绪。按 PB1 开始:
一旦红色 LED2 亮起,初始化就完成了,可以接受关键字了。如果 PICO 适配器仍连接到 SWD,请将其断开并重启。
可以检测到以下单词:
['up', 'down', 'left', 'right', 'stop', 'go', 'yes', 'no', 'on', 'off', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'zero']
MAX78000 KWS20 演示固件可识别关键字并报告结果和置信度。
麦克风 (U15) 位于 EVKIT 上的 JH4 和 JH5 接头之间,(MK1) 位于 MAX78000 Feather 板上的 J5 和 J7 音频连接器之间。
将 USB 电缆连接到 CN1 USB 连接器。
如果您使用的是 Windows,请在 MinGW shell 中使用 OpenOCD 加载固件映像:
openocd -s $MAXIM_PATH/Tools/OpenOCD/scripts -f interface/cmsis-dap.cfg -f target/max78000.cfg -c "program build/MAX78000.elf reset exit"
如果使用 Linux,请执行此步骤:
./openocd -f tcl/interface/cmsis-dap.cfg -f tcl/target/max78000.cfg -c "program build/MAX78000.elf verify reset exit"
KWS20 演示在通电或按下复位按钮 (SW4) 后自动启动。TFT 显示器是可选的,不随 MAX78000 Feather 板提供。用户应使用 PC 终端程序观察 KWS20 演示结果,如“使用调试终端”部分所述。
可在此处订购兼容 MAX78000 Feather 的 2.4’’ TFT FeatherWing 显示器:
https://learn.adafruit.com/adafruit-2-4-tft-touch-screen-featherwing
这款 TFT 显示器完全组装有双插座,供 MAX78000 Feather 插入。
要使用启用的 TFT 功能编译代码,请使用 project.mk 中的以下设置:
ifeq "$(BOARD)" "FTHR_RevA"
PROJ_CFLAGS += -DENABLE_TFT
endif
使用 TFT 显示器时,请将其电源开关保持在“ON”位置。TFT“重置”按钮也可用作羽化重置。按 PB1 (SW1) 按钮开始演示。
PB1(SW1)按钮的位置如下图所示:
调试终端显示有关状态和检测到的单词的更多信息。
连接到 CN1 (USB/PWR) 的 USB 电缆提供电源和串行通信。
要配置 PC 终端程序,请选择正确的 COM 端口和设置,如下所示:
打开电源或按下重置按钮后,终端窗口中将出现以下消息:
检测词后终端显示:
KWS20 demo的软件组成如下图所示:
KWS20 v.3 卷积神经网络 (CNN) 模型由具有 8 层的1D CNN 和一个完全连接的层组成,用于从用于训练的 20 个单词词典中识别关键字。
class AI85KWS20Netv3(nn.Module):
"""
Compound KWS20 v3 Audio net, all with Conv1Ds
"""
# num_classes = n keywords + 1 unknown
def __init__(
self,
num_classes=21,
num_channels=128,
dimensions=(128, 1), # pylint: disable=unused-argument
bias=False,
**kwargs
):
super().__init__()
self.drop = nn.Dropout(p=0.2)
# Time: 128 Feature :128
self.voice_conv1 = ai8x.FusedConv1dReLU(num_channels, 100, 1,
stride=1, padding=0,
bias=bias, **kwargs)
# T: 128 F: 100
self.voice_conv2 = ai8x.FusedConv1dReLU(100, 96, 3,
stride=1, padding=0,
bias=bias, **kwargs)
# T: 126 F : 96
self.voice_conv3 = ai8x.FusedMaxPoolConv1dReLU(96, 64, 3,
stride=1, padding=1,
bias=bias, **kwargs)
# T: 62 F : 64
self.voice_conv4 = ai8x.FusedConv1dReLU(64, 48, 3,
stride=1, padding=0,
bias=bias, **kwargs)
# T : 60 F : 48
self.kws_conv1 = ai8x.FusedMaxPoolConv1dReLU(48, 64, 3,
stride=1, padding=1,
bias=bias, **kwargs)
# T: 30 F : 64
self.kws_conv2 = ai8x.FusedConv1dReLU(64, 96, 3,
stride=1, padding=0,
bias=bias, **kwargs)
# T: 28 F : 96
self.kws_conv3 = ai8x.FusedAvgPoolConv1dReLU(96, 100, 3,
stride=1, padding=1,
bias=bias, **kwargs)
# T : 14 F: 100
self.kws_conv4 = ai8x.FusedMaxPoolConv1dReLU(100, 64, 6,
stride=1, padding=1,
bias=bias, **kwargs)
# T : 2 F: 128
self.fc = ai8x.Linear(256, num_classes, bias=bias, wide=True, **kwargs)
def forward(self, x): # pylint: disable=arguments-differ
"""Forward prop"""
# Run CNN
x = self.voice_conv1(x)
x = self.voice_conv2(x)
x = self.drop(x)
x = self.voice_conv3(x)
x = self.voice_conv4(x)
x = self.drop(x)
x = self.kws_conv1(x)
x = self.kws_conv2(x)
x = self.drop(x)
x = self.kws_conv3(x)
x = self.kws_conv4(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
CNN 输入是 128x128=16384 个 8 位带符号语音样本。
要调用网络训练,请执行脚本:
(ai8x-training) $ ./scripts/train_kws20_v3.sh
如果是第一次,并且本地不存在数据集,scrip会自动下载谷歌语音命令数据集(1秒关键词.wav文件,16KHz采样,16位)到/data/KWS/raw,并处理它使适当的训练、测试和验证数据集集成在 /data/KWS/process/dataset.pt 中。处理步骤通过使用增强技术(如添加白噪声、随机时移和拉伸)来扩展训练数据集,以改善训练结果。此外,每个 16000 个样本单词示例都用零填充,使其成为 128x128=16384 个语音样本。扩充过程将数据集的大小增加了三倍,可能需要 30 分钟才能完成。
AI8X模型训练和量化中描述了网络训练方法的细节
训练未量化网络后,可以通过执行脚本进行评估:
(ai8x-training) $ ./scripts/evaluate_kws20_v3.sh
训练时产生的CNN权重需要量化:
(ai8x-synthesis) $ ./scripts/quantize_kws20_v3.sh
量化的细节在AI8X 模型训练和量化中有描述
网络综合脚本生成通过/失败 C 示例代码,其中包括初始化 MAX78000 CNN 加速器、加载量化 CNN 权重和输入样本以及卸载分类结果的必要函数。具有预期结果的示例输入是此自动生成的代码的一部分以进行验证。以下脚本生成所有示例项目,包括kws20_v3:
(ai8x-synthesis) $ ./gen-demos-max78000.sh
kws20_v3准系统C 代码部分用于 KWS20 演示。特别是,CNN 初始化、权重(内核)和用于加载/卸载权重和样本的辅助函数已从kws20_v3移植到 KWS20 Demo。
KWS20 演示有两种模式:使用麦克风(实时)或离线处理:
#define ENABLE_MIC_PROCESSING
在此模式下,EVKIT I2S Mic 被初始化为以 16KHz 32 位样本运行。在主循环中,检查 I2S 缓冲区并将采样存储到 pChunkBuff缓冲区中。
如果未定义 ENABLE_MIC_PROCESSING,则应将包含 16 位样本的头文件(例如kws_five.h)包含在要用作输入的项目中。要从 wav 文件创建头文件,请使用包含的实用程序来记录 wav 文件并将其转换为头文件。
# record 3sec of 16-bit 16KHz sampled wav file
$ python VoiceRecorder.py -d 3 -o voicefile.wav
# convert to header
$ python RealtimeAudio.py -i voicefile.wav -o voicefile.h
下图为 KWS20 Demo 固件中的处理过程:
从麦克风/文件中收集的样本是 18/16 位符号的,并被转换为 8 位符号以输入 CNN。如果是麦克风模式,则使用高通滤波器滤除捕获样本中的直流电平。缩放样本以 128 个样本(字节)的块存储在pPreambleCircBuffer循环缓冲区中。
可以调整固件中的以下参数:
#define SAMPLE_SCALE_FACTOR 4 // multiplies 16-bit samples by this scale factor before converting to 8-bit
#define THRESHOLD_HGIH 350 // voice detection threshold to find beginning of a keyword
#define THRESHOLD_LOW 100 // voice detection threshold to find end of a keyword
#define SILENCE_COUNTER_THRESHOLD 20 // [>20] number of back to back CHUNK periods with avg < THRESHOLD_LOW to declare the end of a word
#define PREAMBLE_SIZE 30*CHUNK// how many samples before beginning of a keyword to include
#define INFERENCE_THRESHOLD 49 // min probability (0-100) to accept an inference
当最后 128 个样本中样本的平均绝对值超过阈值时,标记单词的开头。
当观察到平均绝对阈值低于THRESHOLD_LOW的SILENCE_COUNTER_THRESHOLD背靠背样本块时,会发出单词结束信号。
CNN 需要 1 秒的样本 (128*128) 才能开始处理。此窗口从单词开头前的PREAMBLE_SIZE个样本开始,到 16384
个样本后结束。如果较早确定了一个字的结尾,则 pAI85Buffer 样本缓冲区用零填充。CNN 相关的 API 函数在cnn.c中。它们用于加载权重和数据,启动CNN,等待CNN完成处理并卸载结果。
如果开发合成新的网络,需要从自动生成的kws20示例工程中移植新的权重文件和相关API函数。此外,如果训练网络中 128x128
样本集的输入层或组织发生变化,则应更改AddTranspose()函数以反映 CNN 内存中新的样本数据排列。
KWS20 例程已经嵌入到example里面,可新建直接调用
注意需要插SD卡,才可以正常运行程序
选择开发MAXIM项目
新建kws20例程
选择相关
新建成功如下
编译成功如下
-下载验证
打印如下:
18:17:42.528 ->
18:17:42.528 ->
18:17:42.528 -> ANALOG DEVICES
18:17:42.531 -> Keyword Spotting Demo
18:17:42.533 ->
18:17:42.533 -> Ver. 3.1.0 (10/17/22)
18:17:42.533 ->
18:17:42.533 ->
18:17:42.533 -> ***** Init *****
18:17:42.534 -> pChunkBuff: 128
18:17:42.536 -> pPreambleCircBuffer: 3840
18:17:42.538 -> pAI85Buffer: 16384
18:17:42.792 -> SD card mounted.
18:17:42.794 -> Creating directory...
18:17:42.910 -> Directory "001" created.
18:17:42.913 -> Changed directory to "001"
18:17:42.917 ->
18:17:42.917 -> *** I2S & Mic Init ***
18:17:42.919 ->
18:17:44.916 ->
18:17:44.916 -> *** READY ***
18:18:04.413 -> 301952 Word starts from index: 297984, avg:442 > 350
18:18:05.202 -> 314496: Starts CNN: 1
18:18:05.207 -> 314496: Completes CNN: 1
18:18:05.208 -> CNN Time: 1843 us
18:18:05.209 -> Min: -128, Max: 127
18:18:05.212 -> -----------------------------------------
18:18:05.216 ->
18:18:05.216 -> Detected word: TWO (82.0%)
18:18:05.218 -> -----------------------------------------
18:18:05.222 -> Creating file "0000_TWO" with length 16384
18:18:05.227 -> File opened!
18:18:05.250 -> 16384 bytes written to file!
18:18:05.259 -> File Closed!
18:18:05.259 ->
18:18:05.260 ->
通过对这篇文章我们掌握了MAX7800实现KWS20 demo演示,接下来会有许多有趣的实验,尝试与Arduino通讯做语音小车,进而丰富我们的生活。从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
再次非常感谢大赛支持和胡同学
参考文献:
window10下配置Maxim SDK
数据手册
MAX78000板卡项目汇总
应用笔记
【window下配置Maxim SDK环境】
【MAX78000基础案例演示】
MAX78000 关键字定位演示 v.3