Raspberry Pi Picoで音楽ジャンルを認識する

この記事は、私の本TinyML Cookbook, Second Editionからの抜粋です。記事で使用されているコードはこちらで見ることができます。

準備

この記事で設計するアプリケーションは、1秒の音声クリップを連続的に記録し、モデル推論を実行することを目的としています。次の図に示すように:

図1:録音と処理タスクが逐次実行されている

前述の図に示されたタスク実行タイムラインから、特徴抽出とモデル推論が常に音声録音の後に行われ、同時には行われないことがわかります。したがって、ライブ音声ストリームの一部セグメントを処理していないことは明らかです。

リアルタイムのキーワードスポッティング(KWS)アプリケーションとは異なり、それは音声ストリームのすべての部分をキャプチャして処理し、話された単語を逃すことがないようにする必要がありますが、ここでは、この要件を緩和できます。なぜなら、アプリケーションの有効性を損なわないからです。

私たちが知っているように、MFCC特徴抽出の入力は、Q15形式の1秒の生音声です。しかし、マイクで取得されたサンプルは16ビット整数値として表されます。したがって、16ビット整数値をQ15に変換する方法は?解決策はあなたが考えるよりも単純です:音声サンプルを変換する必要はありません。

理解するために、Q15固定小数点形式を考えてみましょう。この形式は、[-1, 1]の範囲内の浮動小数点値を表現できます。浮動小数点からQ15への変換は、浮動小数点値に32,768(2^15)を掛けることで行われます。しかし、浮動小数点表現が16ビット整数サンプルを32,768(2^15)で除算することに由来するため、16ビット整数値が本質的にQ15形式であることを意味します。

方法…

マイクが取り付けられたブレッドボードを持ってきて、ラズベリーパイピコに接続されたデータケーブルを切り離し、このレシピには必要ないプッシュボタンとそれに接続されたジャンパーをブレッドボードから取り外します。図2は、ブレッドボードに何があるかを示しています:

図2: ブレッドボード上に構築された電子回路

プッシュボタンをブレッドボードから取り外した後、Arduino IDEを開き、新しいスケッチを作成します。

それでは、ラズベリーパイピコで音楽ジャンル認識アプリケーションを開発するための手順を以下に示します:

ステップ1

Arduino TensorFlow LiteライブラリをTinyML-Cookbook_2E GitHub リポジトリからダウンロードしてください。

ZIPファイルをダウンロードした後、Arduino IDEにインポートします。

ステップ2

MFCCs特徴抽出アルゴリズムに必要なすべての生成されたCヘッダーファイルをArduino IDEにインポートしますが、test_src.htest_dst.hは除きます。

ステップ3

第6章、Raspberry Pi PicoにMFCCs特徴抽出アルゴリズムを展開で開発されたスケッチをコピーしてMFCCs特徴抽出を実装しますが、setup()およびloop()関数は除きます。

test_src.hおよびtest_dst.hヘッダーファイルのインクルードを削除します。次に、dst配列の割り当てを削除します。なぜなら、MFCCsは直接モデルの入力に格納されるためです。

ステップ4

第5章、TensorFlowとRaspberry Pi Picoで音楽ジャンルを認識– Part 1で開発されたスケッチをコピーしてマイクでオーディオサンプルを記録しますが、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();

オーディオの録音後、MFCCを抽出します。

C++

 

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

前述のコードスニペットからわかるように、MFCCはモデルの入力に直接保存されます。

ステップ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]);

さあ、micro-USBデータケーブルをRaspberry Pi Picoに差し込みましょう。接続したら、スケッチをコンパイルしてマイクロコントローラにアップロードします。

その後、Arduino IDEでシリアルモニタを開き、スマートフォンをマイクの近くに置いてディスコ、ジャズ、またはメタルの曲を再生してください。アプリケーションは、曲の音楽ジャンルを認識し、シリアルモニタに分類結果を表示するはずです!

結論

この記事では、tflite-microを使用してRaspberry Pi Picoに音楽ジャンル分類のトレーニング済みモデルを展開する方法を学びました。

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