【MAX7800实现KWS20 demo演示】

【MAX7800实现KWS20 demo演示】

  • 1. 概述
  • 2. 关键字定位演示
    • 2.1 构建固件:
    • 2.2 选择板卡
    • 2.3 MAX78000 EVKIT
      • 2.3.1 MAX78000 EVKIT下载程序
      • 2.3.2 MAX78000 EVKIT 跳线设置
      • 2.3.3 MAX78000 EVKIT 操作
    • 2.4 MAX78000 Feather
      • 2.4.1 MAX78000 Feather羽毛板下载固件
      • 2.4.2 MAX78000羽毛板操作
    • 2.5 使用调试终端
  • 3. CNN模型
    • 3.1 网络训练
    • 3.2 网络量化
    • 3.3 网络综合
    • 3.4 KWS20 演示代码
      • 3.4.1 麦克风模式
      • 3.4.2 离线模式
      • 3.4.3 KWS20 演示固件结构
  • 4. MAX7800 羽毛板Eclipse配置
  • 5.小结

在这里插入图片描述

1. 概述

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”类别。

2. 关键字定位演示

2.1 构建固件:

导航到 KWS20 演示软件所在的目录并构建项目:

$ cd /Examples/MAX78000/CNN/kws20_demo
$ make

如果是第一次安装工具后,或者更新了外设文件,请先清理驱动再重建工程:

$ make distclean

2.2 选择板卡

  1. 要为 MAX78000 EVKIT 编译代码,请在 project.mk 中启用BOARD=EvKit_V1:
# Specify the board used
ifeq "$(BOARD)" ""
BOARD=EvKit_V1
#BOARD=FTHR_RevA
endif
  1. 要为 MAX78000 Feather 板编译代码,请在 project.mk 中启用BOARD=FTHR_RevA:
# Specify the board used
ifeq "$(BOARD)" ""
#BOARD=EvKit_V1
BOARD=FTHR_RevA
endif

注意:如果您使用的是 Eclipse,还请确保通过以下方式将 Board 环境变量的值更改为“FTHR_RevA”:

右键单击项目名称 > 属性 > C/C++ 构建 > 环境 > Board"
在这里插入图片描述

2.3 MAX78000 EVKIT

2.3.1 MAX78000 EVKIT下载程序

将 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 适配器。

2.3.2 MAX78000 EVKIT 跳线设置

确保在 JP20-CLK(INT 位置)安装跳线,如下所示:

注:板载外部振荡器 Y3 用于生成 I2S 时钟。I2S 采样率为 16kHz,以匹配数据集的语音样本。

2.3.3 MAX78000 EVKIT 操作

重新上电后,如果 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 音频连接器之间。

2.4 MAX78000 Feather

2.4.1 MAX78000 Feather羽毛板下载固件

将 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"

2.4.2 MAX78000羽毛板操作

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)按钮的位置如下图所示:

在这里插入图片描述

2.5 使用调试终端

调试终端显示有关状态和检测到的单词的更多信息。
连接到 CN1 (USB/PWR) 的 USB 电缆提供电源和串行通信。
要配置 PC 终端程序,请选择正确的 COM 端口和设置,如下所示:

在这里插入图片描述

打开电源或按下重置按钮后,终端窗口中将出现以下消息:

在这里插入图片描述

检测词后终端显示:

在这里插入图片描述

KWS20 demo的软件组成如下图所示:

在这里插入图片描述

3. CNN模型

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 位带符号语音样本。

3.1 网络训练

要调用网络训练,请执行脚本:

(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

3.2 网络量化

训练时产生的CNN权重需要量化:

(ai8x-synthesis) $ ./scripts/quantize_kws20_v3.sh

量化的细节在AI8X 模型训练和量化中有描述

3.3 网络综合

网络综合脚本生成通过/失败 C 示例代码,其中包括初始化 MAX78000 CNN 加速器、加载量化 CNN 权重和输入样本以及卸载分类结果的必要函数。具有预期结果的示例输入是此自动生成的代码的一部分以进行验证。以下脚本生成所有示例项目,包括kws20_v3:

(ai8x-synthesis) $ ./gen-demos-max78000.sh

kws20_v3准系统C 代码部分用于 KWS20 演示。特别是,CNN 初始化、权重(内核)和用于加载/卸载权重和样本的辅助函数已从kws20_v3移植到 KWS20 Demo。

3.4 KWS20 演示代码

KWS20 演示有两种模式:使用麦克风(实时)或离线处理:

#define ENABLE_MIC_PROCESSING

3.4.1 麦克风模式

在此模式下,EVKIT I2S Mic 被初始化为以 16KHz 32 位样本运行。在主循环中,检查 I2S 缓冲区并将采样存储到 pChunkBuff缓冲区中。

3.4.2 离线模式

如果未定义 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

3.4.3 KWS20 演示固件结构

下图为 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 内存中新的样本数据排列。

4. MAX7800 羽毛板Eclipse配置

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 -> 

5.小结

通过对这篇文章我们掌握了MAX7800实现KWS20 demo演示,接下来会有许多有趣的实验,尝试与Arduino通讯做语音小车,进而丰富我们的生活。从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
再次非常感谢大赛支持和胡同学
参考文献:
window10下配置Maxim SDK
数据手册
MAX78000板卡项目汇总
应用笔记
【window下配置Maxim SDK环境】
【MAX78000基础案例演示】
MAX78000 关键字定位演示 v.3

你可能感兴趣的:(MAX78000,windows,MAX78000)