2000円台の開発ボードと自作AIモデルで音声解析──XIAO ESP32S3 Sense × Edge Impulseで金属と木材を聞き分ける

FabScene(ファブシーン)

Seeed Studioの 「XIAO ESP32S3 Sense」 は、Wi-FiとBluetoothを搭載した小型マイコン「ESP32」をベースにした開発ボードだ。1600×1200解像度のOV2640カメラセンサーとデジタルマイクを備えながらも、親指ほどのサイズに収まるコンパクトさが特徴。13個のGPIOによる拡張性や他ハードとの連携のしやすさ、そして国内で2500〜3000円前後という手頃な価格も魅力だ。

電子工作やIoT開発の定番であるESP32のポテンシャルを小さなボードに凝縮し、AIによる解析まで幅広くこなせるXIAO ESP32S3 Sense。筆者は以前、このボードのカメラとSeeed StudioのAIプラットフォーム「SenseCraft AI」を活用して、1000円札と1万円札を見分けるお札検出ロボを制作し、その手軽さと精度の高さに確かな手応えを感じられた。

FabScene(ファブシーン)
前回の記事「Arduino感覚でAI開発──2000円台のカメラ付きボード「XIAO ESP32S3 Sense」でお札検出ロボをつくる

今回は視覚ではなく聴覚にフォーカスし、マイクを活用して音の種類を判別する仕組みづくりに挑戦した。AIモデルの制作には「Edge Impulse」を活用。この小さなボードのポテンシャルをさらに深掘りしていこう。

目次

マイクとmicroSDカードを気軽に活用

FabScene(ファブシーン)

XIAO ESP32S3 Senseの同梱物は上の通り。Espressif製のESP32-S3R8チップを搭載したボード本体(XIAO ESP32S3)と、OV2640カメラセンサーとデジタルマイク、microSDカードスロットなどを備えた拡張ボードが専用コネクタで接続されている。そのほか、冷却用のヒートシンクとWi-Fi/Bluetoothアンテナ、拡張ボードやセンサーに接続するためのピンヘッダーが付属している。

前回は拡張ボードのカメラセンサーだけを活用したが、今回はデジタルマイクとmicroSDカードスロットを活用。マイクで音を取り込み、データの保存・書き出しから始めてみよう。

FabScene(ファブシーン)

まずは公式Wikiのチュートリアルに従って、マイクとmicroSDカードの動作確認を行う。拡張ボードにFAT32形式でフォーマットしたmicroSDカード(別売り)を差し込み、XIAO ESP32S3 Sense本体と接続。USB Type-CでPCと接続し、Arduino IDEでシリアル通信できる環境を整えておく(環境構築は前回記事を参照のこと)。

マイクの制御にはArduinoのI2Sライブラリを使用する。なお、ボードマネージャでインストールする「esp32」のバージョンが2.0.Xか3.0.Xかでコードが異なる点に注意しよう。今回は v2.0.16を使用し、2.0.X系のプログラムを参照した。

まずは周囲の音を取得し、Arduino IDEのシリアルプロッタで波形を表示するサンプルコードを書き込んだ。GPIO41がマイクデータ、GPIO42がクロックとして設定され、I2S通信で制御されていることがわかる。

#include <I2S.h>

void setup() {
  Serial.begin(115200);
  while (!Serial) {
  }

  I2S.setAllPins(-1, 42, 41, -1, -1);
  if (!I2S.begin(PDM_MONO_MODE, 16000, 16)) {
    Serial.println("Failed to initialize I2S!");
    while (1); // do nothing
  }
}

void loop() {
  int sample = I2S.read();
  if (sample && sample != -1 && sample != 1) {
    Serial.println(sample);
  }
}

サンプルコードからコメントを削除したもの

FabScene(ファブシーン)
静寂時と音楽再生時で波形に差が出た

同様に、microSDカードに音声を書き込むサンプルコードで実験。ESP32のPSRAM機能を利用するため、スケッチを書き込む前に 「ツール」→「PSRAM」→「OPI PSRAM」 を選択しておこう(デフォルトは「Disabled」になっている)。

FabScene(ファブシーン)
PSRAMの設定を変更する
FabScene(ファブシーン)

こちらのサンプルでは20秒間の録音を行い、“arduino_rec.wav” というファイル名で保存を行う。実行後にmicroSDカードを取り出して確認すると、しっかりファイルが生成されていた。

FabScene(ファブシーン)

ただし、再生してみると音声の最初と最後に「ブツッ」というノイズが入っていた。音声編集ソフト(Audacity)で波形を確認すると、冒頭と末尾で振幅が急に変化しており、これがクリック音として聞こえる原因のようだ。

ChatGPTによると、これは「I2Sマイクが電源ON直後にDCオフセット(直流ずれ)を出力する」典型的な現象とのこと。人の耳は振幅の急な変化をクリック音として認識するため、根本的には DCオフセット除去やフェードイン/フェードアウトの処理が必要になるという。とはいえ、まずはマイクが正常に動作し、microSDカードに録音データを保存できることが確認できた。

AIモデルで「Yes/No」の音声を判別

マイクの動作が確認できたところで、いよいよXIAO ESP32S3 Senseの本領発揮といこう。機械学習モデルをデプロイすれば、クラウドを介さず端末単体でデータ解析を行うことができる。前回はSeeed StudioのAIプラットフォーム「SenseCraft AI」を利用したが、今回は「Edge Impulse」を使ってモデルを制作する。

FabScene(ファブシーン)
Edge Impulse のWebページからスクリーンショット

Edge Impulseは、データ収集・前処理・機械学習モデルの訓練をすべてブラウザ上で完結できるプラットフォーム(および運営会社の名称)だ。学習済みのモデルをデバイスに合わせた形式で書き出せるのが特徴で、その中にはArduinoライブラリ形式も含まれている。Seeed Studio製ボードとの親和性も高く、XIAO ESP32S3 Senseを使ったデモも公式に公開されている。

FabScene(ファブシーン)
Seeed Studio公式Wikiより引用

詳細は後述するが、公式Wikiで紹介されているZIP形式のライブラリをArduino IDEに取り込み、サンプルスケッチを動かすだけで「Yes」「No」の音声を判別するモデルを実行できた。Edge Impulseで作成したモデルがXIAO ESP32S3 Sense内で動作し、「Yes」「No」「Noise(それ以外)」の確率を算出し、Yesの確率が一定以上になると、LEDが点灯する仕組みのようだ。

FabScene(ファブシーン)

この仕組みを応用すれば、「Aという音」「Bという音」「Noise(それ以外)」といった複数の音を聞き分けるモデルが作れそうだ。今回は入門編として、金属と木材を叩いた音を分類するAIモデルを制作してみることにする。

たとえば喫茶店の呼び鈴の音と、机を軽く叩いた音を区別できれば、「ベルが鳴ったときだけ反応する装置」なども実現できそうだ。小さなマイクが耳となって周囲を聞き分ける、そんなスマートな使い方を目指してみよう。

FabScene(ファブシーン)
今回作るもののイメージ図

モデル制作(1) 教師音源の準備

Edge Impulseでは、音声の教師データを複数の方法で収集できる。PCマイクを使うと実機の環境や特性が異なってしまい、またデバイスから直接アップロードする「Data Forwarder」機能にはやや準備が必要だ。そこで今回は、XIAO ESP32S3 Sense内蔵マイクで録音し、microSDカードに直接保存してからまとめてアップロードする方法を採用した。

FabScene(ファブシーン)

データごとに毎回PCを操作するのは手間がかかるため、XIAO ESP32S3 SenseのGPIOを活用して収音用の簡易回路を組んだ。ボタンを押すと1秒後にLEDが点灯して録音を開始し、1秒間の録音が終わるとLEDが消灯するシンプルな構成だ。

GPIOを4ピン使用し、LED制御と3つのタクトスイッチ入力の検知に割り当てている。これを「呼び鈴(BELL)」「木皿(WOOD)」「無音(NOISE)」の3系統に分け、それぞれのボタンを押すたびにファイル名を更新してmicroSDカードに保存する仕組みにした。この方法なら、録音後にファイル名を手動で変更したり、フォルダを整理したりする必要がない。

FabScene(ファブシーン)
呼び鈴の録音
FabScene(ファブシーン)
木皿を2回叩く音の録音
FabScene(ファブシーン)

使用したプログラムはmicroSDカードに保存するサンプルを改良したもので、主な工夫点は次の2つだ。
・void record_wav() に引数としてファイル名を渡せるように変更
・録音開始時の「ブツッ」というクリック音を軽減するため、ノイズ除去処理を追加
コードの詳細はこちらのリンクから参照してほしい。

FabScene(ファブシーン)

録音した音声は「呼び鈴」「木皿」「無音」の3クラスそれぞれ約40個ずつ。microSDカードに蓄積されたデータをPCにコピーし、内容を確認して、うまく録音できていないものや想定と異なる音が混ざっているものを削除した。最終的に、各クラスおよそ35個のクリーンなデータを準備できた。

モデル制作(2) Edge Impulseにデータをアップする

FabScene(ファブシーン)

教師データの準備ができたので、これを使って判別モデルを作っていこう。まずは Edge Impulseにアクセスし、アカウントを作成。「Create New Project」から新しいプロジェクトを立ち上げる。

FabScene(ファブシーン)

ダッシュボード右上の「Target」をクリックすると、モデルを実行するデバイスを指定できる。歴代のRaspberry Piや、Arduino UNO Q、Seeed StudioのWio Terminalなどが選択肢として用意されているが、XIAO ESP32S3 Senseはリストに含まれていない。そのため、ここでは「Custom」を選択して以下のように設定した。

  • Target Device:Custom
  • Processor family:ESP32
  • Clock rate:240
  • Accelerator:None
  • Device ID:設定なし
  • Custom device name:任意
  • RAM:1
  • ROM (Flash):4
  • Latency:100ms
FabScene(ファブシーン)

デバイス設定が完了したら「Getting Started」の枠内にある「Add existing data」を選択する。なお「Collect new data」を選ぶと、スマートフォンやPC、デバイスから直接録音して新規データを収集でき、「Upload mode」ではTensorFlow LiteやONNX形式の既存モデルをアップロードすることも可能だ。

FabScene(ファブシーン)

このポップアップでは一番左の「Upload data」を選択する。

FabScene(ファブシーン)

ここでは個別のファイル、もしくはフォルダ単位でデータをアップロードできる。該当のファイルを選択したのち、「Upload into category」設定では「Automatically split between training and testing」を選択する。これはアップロードしたデータを学習用とテスト用に自動で振り分ける設定で、今回はデフォルトのままで問題ない。

「Label」設定ではアップロードするデータごとに任意のラベルを付与できる。今回は「bell」「wood」「noise」をそれぞれ割り当てた。

FabScene(ファブシーン)

アップロードが完了すると、左メニューの「Data Acquisition」>「Dataset」タブからデータを確認できる。波形プレビュー上で音声を再生したり、一部をクロップ(切り抜き)したりすることも可能だ。極端な外れ値や、ノイズの多いデータがあればこの段階で削除しておこう。

モデル制作(3) 分類用モデルを制作

続いてアップロードした音声データをもとに、分類モデルを作成する。Edge Impulseでは、生データ(音声や加速度など)から特徴を抽出し、機械学習モデルを学習・実行するまでの一連の流れを 「Impulse」 と呼ぶ。左側のメニューから 「Create impulse」 を選択し、データ処理や分類方式を設定していこう。

FabScene(ファブシーン)
Create Impulse のページ

赤い背景の「Time Series Data」では解析単位を設定する。今回は以下のように設定したが、もし音源の長さが異なる場合は Window size を調整するとよい。

  • Window size:1000 ms — 録音が1秒なのでぴったり
  • Window increase (stride):500 ms — 50%重なりで学習データを増やす
  • Frequency (Hz):16000 — 録音時のサンプリング周波数と一致
  • Zero-pad data:ON — 長さが不足しても自動で補完される

左から2番目の 「Add a processing block」 では、音声データから特徴を抽出する手法として 「Audio (MFCC)」 を選択し、任意の名前をつける。MFCCは人間の聴覚特性に近い形で音の特徴を数値化する技術で、音声分類では定番の処理手法のようだ。

さらに右隣の 「Add a learning block」 では、学習の目的を選択する。「Regression(予測)」や「Anomaly Detection(異常検知)」なども選べるが、今回は音の種類を分類したいので 「Classification(分類)」 を選択し、名前を設定する。

最後に右下の緑色ボタン 「Save Impulse」 をクリックして保存しよう。

FabScene(ファブシーン)
MFCC「Parameter」タブ


続いて、左メニューから先ほど追加した 「MFCC(任意の名前)」 を選択する。ここでは音声を分析し、音の高さなど人間の耳で感じる特徴を数値化していく。これが後の学習で「音の違い」を判断するための基礎データとなる。

設定項目には Frame length(分析区間の長さ) や Filter number(分析の解像度) などがあり、音の細かさや解析範囲を調整できる。基本的にはデフォルト設定、もしくは 「Autotune Parameters」 に任せれば問題ない。

FabScene(ファブシーン)
MFCC「Generate Features」タブ

Parametersの設定が終わったらタブを変え 「Generate features」 を実施。少し待つと、録音した音源がMFCC特徴量として可視化され、グラフ上にプロットされる。3種類の音が、なんとなく別グループとしてばらけている様子が見てとれた。

FabScene(ファブシーン)

さらに左メニューから「Classifier(任意の名前)」を選択し、ニューラルネットワークの構造と学習条件を設定する。層の構成、ドロップアウト率、学習回数(Epoch)、学習率(Learning Rate)などの項目を設定できるが、AI初心者にはパラメータ名だけ見ても理解しづらい部分が多い。筆者はChatGPTのサポートを借りつつ、数値を入力していった。

設定が整ったら、画面下部の 「Save & Train」 をクリック。すると、Edge Impulseがクラウド上で自動的にトレーニングを実行し、学習済みモデルが生成された。

FabScene(ファブシーン)

トレーニングの結果は画面右側に表示される。今回の結果は ACCURACY(正答率)100%となり、グラフも音の種類ごとに明確に分かれており、思いがけず高精度な分類ができたようだ。ただし、データ数が少ない場合は「過学習(overfitting)」が起きている可能性もあるため、本来であればサンプルを追加して再検証するのが望ましいようだ。

モデル制作(4) Arduino用にライブラリを書き出し、スケッチに読み込む

学習済みモデルの再訓練や検証もできるが、今回はスキップ。完成したモデルをXIAO ESP32S3 Senseに実装するため、Arduino環境向けライブラリとして書き出していく。

FabScene(ファブシーン)
「Deployment」からArudino Library用データをBuildしたところ

左側メニューから 「Deployment」 を選ぶと、デバイスに書き込むための各種出力形式を用意できる。今回は学習したモデルをArduino環境で動かすため、検索窓から「Arduino Library」を選択。画面下の 「Build」 をクリックすると、数十秒ほどで ZIP形式のArduinoライブラリが書き出される。

このZIPファイルをArduino IDEにインポートすれば、Edge Impulseで学習したモデルをそのままデバイスに書き込み、リアルタイム推論を実行できるようになる。

FabScene(ファブシーン)
Arduino IDEで、Edge Impulseから書き出したライブラリをインストール
FabScene(ファブシーン)
ライブラリ内の構成。Edge Impulseが自動生成したヘッダーファイルを確認しておく。

インストールしたライブラリの中には、学習モデルを呼び出すためのヘッダーファイル(.h)が含まれている。「書類 > Arduino > libraries > (Edge Impulseのプロジェクト名) > src」にあるヘッダーファイル名を確認しておこう。このファイルをArduinoのプログラム側で読み込む(#include)することで、Edge Impulseの学習モデルを呼び出すことができる。

FabScene(ファブシーン)
Seeed Studio公式Wikiより引用


「Yes」「No」を判別するサンプルコードをベースに、自作モデルへと中身を差し替えていく。具体的には、ソースコード内で読み込まれているヘッダーファイルを、Edge Impulseで書き出した自分のモデルのヘッダーファイル名に変更する。これで、サンプルコードの判定対象を今回の学習データ(金属/木材)に置き換えることができた。

FabScene(ファブシーン)
ヘッダーファイルの名前を書き換え、同様のスケッチを実行

書き換え後にスケッチを実行すると、シリアルモニタ上に bell / noise / wood の3分類が表示されるようになった。Edge Impulseで設定したラベルが正しく反映され、音の種類ごとの推定確率が出力されているのが確認できる。どのラベルがどの順番で表示されるかは、書き出されたライブラリ内の定義を参照すると分かりやすいだろう。

完成!金属と木材を聞き分けるエッジAI

学習モデルをArduino上で動かすことができたので、次はその結果を「見える化」してみよう。分類結果の確率値をProcessingなどの描画プログラムで受け取り、バーグラフとして可視化すれば、リアルタイムに「音を聞き分ける」様子を視覚的に確認できそうだ。

FabScene(ファブシーン)
Arduino側のプログラムで確率値を送信
FabScene(ファブシーン)
Processingで値を受け取り、グラフに表示

Arduinoで推論した確率値をシリアル通信でProcessingに送信し、受け取った数値をもとに左から順に 「bell」「noise」「wood」 のバーが伸びるプログラムを制作(Arduinoのプログラムはこちら、Processingのプログラムはこちら)。XIAO ESP32S3 Senseに書き込み、周囲の音を聴かせてみると……

FabScene(ファブシーン)

結果はおおむね良好!何もしていない状態では中央の noise が高く表示され、木を叩くと wood のバーが上昇、ベルを鳴らすと bell のバーが大きく反応する。無音時にも wood が反応しているのは、2回叩く際の間の無音部分がノイズとして分類されているためだと考えられる。

こうして、手のひらサイズのボード上で「金属か木材か」をリアルタイムに聞き分けるエッジAIが完成。まだまだ荒削りではあるが、判別の精度は、教師データを増やす、あるいは Edge Impulse側で特徴抽出や分類パラメータを調整することでさらに改善できそうだ。

まとめ

XIAO ESP32S3 Sense上で自作のAIモデルを動かし、金属と木材を聞き分けることに成功した。AIを組み込むデバイスとしてだけでなく、音源を収集する装置としても活用できたのは、GPIOが豊富でハードとの連携もしやすいボードならではのメリットと言えるだろう。マイクからいかにきれいに音を集めるかには、まだまだ改善の余地がありそうだ。

また、試作時にいくつかのパターンに挑戦したが、拍手と指パッチンのように似た音は判別が難しく、木材も一度叩いただけでは判別精度が上がらなかった。音源を増やしたり、より特徴的なサンプルを選んで教師データを整理することで、さらに精度を上げられるだろう。

Edge Impulseの設定フローは最初こそ少し長く感じたが、データのアップロードから特徴抽出、学習、モデル書き出しまでを一度通してみると、仕組みがなんとなく理解できる。音声だけでなく、カメラや加速度センサーなどにも対応しているため、他のプロトタイピングにも意欲を刺激された。そして、そうしたAI活用を始める際に、XIAO ESP32S3 Senseは良きパートナーとなってくれる存在だ。低コストでとっつきやすい、小さな相棒として活用してみてほしい。

本記事はSponsored記事です。
提供:Seeed Studio / Seeed 株式会社

fabsceneの更新情報はXで配信中です

この記事の感想・意見をSNSで共有しよう
  • URLをコピーしました!

ライター/編集者。大学で3Dプリンターと出会いものづくりの面白さに目覚め、デジタルファブリケーションの世界へ。卒業後、研究員として2年半ほど従事したのち、ものづくりを中心としたライターとして独立。
2023年には墨田区でファブ施設「京島共同凸工所」の運営をスタート。文章と場づくりを行き来しながら、街での生活を満喫している。工房での日々を綴った自主制作本「京島の十月」が販売中。

目次