利用树莓派Pico识别音乐流派

本文摘自我所著的《TinyML Cookbook(第二版)。文中使用的代码可在此获取。

准备阶段

本文设计的应用程序旨在持续录制1秒音频片段并进行模型推理,如以下图像所示:

图1:录音与处理任务顺序执行

从上图的任务执行时间线可以看出,特征提取和模型推理总是在音频录制完成后进行,而非同时进行。因此,很明显我们并未处理实时音频流中的某些片段。

与实时关键词检测(KWS)应用不同,后者需捕捉并处理所有音频片段以确保不遗漏任何话语,而本应用中,我们可以放宽这一要求,因为这并不影响应用的有效性。

如我们所知,MFCC特征提取的输入是1秒的Q15格式原始音频。然而,麦克风采集的样本以16位整数形式表示。因此,我们如何将这些16位整数转换为Q15格式?解决方案比你想象的要简单:无需转换音频样本。

要理解这一点,可以考虑Q15定点格式。这种格式能够表示[-1, 1]范围内的浮点值。从浮点转换到Q15需要将浮点值乘以32,768(2^15)。然而,由于浮点表示最初是将16位整数样本除以32,768(2^15)得到的,这意味着16位整数值本质上就是Q15格式。

如何操作…

取带有麦克风连接的树莓派Pico面包板。断开微控制器的数据线,并从面包板上移除按钮及其连接的跳线,因为本示例不需要它们。图2展示了面包板上应有的配置:

图2:面包板上搭建的电子电路

移除面包板上的按钮后,打开Arduino IDE并新建一个草图。

接下来,按照以下步骤在树莓派Pico上开发音乐风格识别应用:

步骤1

TinyML-Cookbook_2E GitHub 仓库下载Arduino TensorFlow Lite库。

下载ZIP文件后,将其导入Arduino IDE。

步骤2

在Arduino IDE中导入MFCCs特征提取算法所需的所有生成的C头文件,但不包括test_src.htest_dst.h

步骤3

复制第6章,在Raspberry Pi Pico上部署MFCCs特征提取算法中开发的草图,用于实现MFCCs特征提取,不包括setup()loop()函数。

移除test_src.htest_dst.h头文件的包含。然后,移除dst数组的分配,因为MFCCs将直接存储在模型的输入中。

步骤4

复制第5章,使用TensorFlow和Raspberry Pi Pico识别音乐流派 – 第一部分 中开发的草图,用于通过麦克风录制音频样本,不包括setup()loop()函数。

导入代码后,移除任何关于LED和按钮的引用,因为它们不再需要。然后,将AUDIO_LENGTH_SEC的定义更改为录制持续1秒的音频:

C++

 

#define AUDIO_LENGTH_SEC 1

步骤5

将包含TensorFlow Lite模型的头文件(model.h)导入Arduino项目。

导入文件后,在草图中包含model.h头文件:

C++

 

#include "model.h"

包含tflite-micro所需的必要头文件:

C++

 

#include 
#include  
#include 
#include 
#include 
#include 

步骤6

声明用于tflite-micro模型和解释器的全局变量:

C++

 

const tflite::Model* tflu_model            = nullptr;
tflite::MicroInterpreter* tflu_interpreter = nullptr;

接着,声明TensorFlow Lite张量对象(TfLiteTensor)以访问模型的输入和输出张量:

C++

 

TfLiteTensor* tflu_i_tensor = nullptr;
TfLiteTensor* tflu_o_tensor = nullptr;

步骤7

声明一个缓冲区(张量竞技场)以存储模型执行过程中使用的中间张量:

C++

 

constexpr int tensor_arena_size = 16384;
uint8_t tensor_arena[tensor_arena_size] __attribute__((aligned(16)));

通过实验测试确定张量竞技场的大小,因为中间张量所需的内存根据底层LSTM操作符的实现方式而变化。我们在Raspberry Pi Pico上的实验发现,该模型仅需要16 KB的RAM用于推理。

步骤8

setup()函数中,以115200波特率初始化串行外设:

C++

 

Serial.begin(115200);
while (!Serial);

串行外设将用于通过串行通信传输识别的音乐流派。

步骤9

setup()函数中,加载存储在model.h头文件中的TensorFlow Lite模型:

C++

 

tflu_model = tflite::GetModel(model_tflite);

接下来,注册tflite-micro支持的所有DNN操作,并初始化tflite-micro解释器:

C++

 

tflite::AllOpsResolver tflu_ops_resolver;

static tflite::MicroInterpreter static_interpreter(
      tflu_model,
      tflu_ops_resolver,
      tensor_arena,
      tensor_arena_size);
tflu_interpreter = &static_interpreter;

步骤10

setup()函数中,分配模型所需的内存,并获取输入和输出张量的内存指针:

C++

 

tflu_interpreter->AllocateTensors();
tflu_i_tensor = tflu_interpreter->input(0);
tflu_o_tensor = tflu_interpreter->output(0);

步骤11

setup()函数中,使用Raspberry Pi Pico SDK初始化ADC外设:

C++

 

adc_init();
adc_gpio_init(26);
adc_select_input(0);

步骤12

loop()函数中,准备模型的输入。为此,录制1秒钟的音频片段:

C++

 

// 重置音频缓冲区
buffer.cur_idx = 0;
buffer.is_ready = false;

constexpr uint32_t sr_us = 1000000 / SAMPLE_RATE;
timer.attach_us(&timer_ISR, sr_us);

while(!buffer.is_ready);

timer.detach();

录制音频后,提取MFCCs:

C++

 

mfccs.run((const q15_t*)&buffer.data[0],
          (float *)&tflu_i_tensor->data.f[0]);

如前述代码片段所示,MFCCs将直接存储在模型的输入中。

步骤13

运行模型推理并返回通过串行通信的分类结果:

C++

 

tflu_interpreter->Invoke();

size_t ix_max = 0;
float pb_max = 0;
for (size_t ix = 0; ix < 3; ix++) {
  if(tflu_o_tensor->data.f[ix] > pb_max) {
    ix_max = ix;
    pb_max = tflu_o_tensor->data.f[ix];
  }
}

const char *label[] = {"disco", "jazz", "metal"};

Serial.println(label[ix_max]);

现在,将微型USB数据线插入Raspberry Pi Pico。连接后,编译并上传草图到微控制器。

之后,在Arduino IDE中打开串行监视器,并将智能手机靠近麦克风播放迪斯科、爵士或金属歌曲。应用程序现在应该识别出歌曲的音乐类型,并在串行监视器上显示分类结果!

结论

本文中,您已了解如何将经过训练的音乐流派分类模型部署到Raspberry Pi Pico上,运用tflite-micro实现。

Source:
https://dzone.com/articles/recognizing-music-genres-with-the-raspberry-pi-pic