本初心者講座ではこれまでに、SPRESENSEが音声分類に耐えうる精度の「ハイレゾオーディオ入力」を搭載している( 第19回)、そして「DNNRT機能」によりソニー製の推論モデル開発ツール「Neural Network Console」で生成したディープニューラルネットワーク(DNN)の推論モデルを実行できることについて紹介してきました( 第18回)。今回はそれらすべての機能をSPRESENSE上へと統合。エッジ単体で完結するオリジナルのAI音声識別システムを構築する技法を解説いたします。
今回紹介する音声分類システムは、SPRESENSEに接続したコンデンサマイク(APS学習用ボードを利用)で環境音を48kHzで録音し、録音したデータを解析することにより、雨、川、焚き火、海、夜の草原、テント、水中、列車、8環境のいずれの場所に居るかを判定するシステムです(図1)。ソースコード一式は下記のURLからダウンロードすることができます。講座の内容とあわせて是非ご活用ください。
ソースコード|GitHub上、spresense-nnc-step1(tag=v1.2)
目次
音声分類をエッジのみで完結するために解決すべき課題
まず、音声をクラウドを利用せずエッジのみで分析するために解決すべき課題について解説します。
分類に最適なオーディオの長さの選択
今回、環境音の分類対象となる「雨、川、焚き火、海、夜の草原、テント、水中、列車」の8環境は、いずれも周期的な音のパターンを持っています。そのため、オーディオ長が長ければ長いほど、精密な分類が可能となりますが、その分エッジ上で管理しなければならないデータ量も増加します。一方で短すぎると、周期的な特徴を採り逃がしてしまい、分類不能となります。そこで、今回はオーディオ長を0.5秒に設定し、波の音の繰り返しなどの特徴を維持したデータを入力値としました。
適切なサンプリング周波数の選択
アナログ音声から波形の強さ(値)を収集するタイミングを決めるサンプリング周波数を高速にすればするほど波の様子を鮮明に記録することができます。一方で高速なサンプリング周波数を選択すると、1秒間あたりのデータ量が増加します。例えば、DNNRT機能でサンプリング周波数48kHzの0.5秒間の波形データを扱うには 0.5 × 48 × 1024 × 4Byte = 98304byte のメモリが必要となります。なお、サンプリング値から復元可能な波形は、標本化定理により最大1/2のサンプリング周波数の信号です。つまり、48kHzサンプリングで記録したデータからは、最高24kHzの音を復元することができます(復元できる周波数をナイキスト周波数と呼びます)。
オーケストラなどの精密な音は、人の可聴域(約20kHz)を超えるナイキスト周波数が必要となることから、48kHzサンプリングが妥当です。一方、環境音は2kHzを超えるような高音が含まれることはあまりありません(参考:下記YouTube、高音が流れるため視聴の際は、ご注意ください)。そのため、今回はサンプリング周波数として4kHzを選択しました(図2)。
2000 Hz 2 kHz Sine Wave Sound Frequency Tone – YouTube
音声を解析するために必要なバッファの確保
音声データをDNNにより解析するためには、音声の格納に十分なバッファを確保する必要があります。0.5秒間の4kHzの波形データを扱うためには、最低限 0.5 * 4 * 1024 * 4byte = 8192byteのメモリが必要となります(実際のDNNでは、波形データを加工しますので、加工した情報も格納できるバッファも含めた確保が必要となります。DNN内のバッファ確保量については後述します)。
SPRESENSEには、128KBのメモリタイルが12個搭載されていますので( 第2回)、DNNRT機能が十分な量のメモリを確保できるよう、メインプログラムが消費するメモリサイズをSDKコンフィグの設定値”CONFIG_ASMP_MEMSIZE”を縮小し、最適化しておくことにより、さらに多くのデータを扱うことができます。1つのメモリタイルが128KBであることから “0x0002_0000” 単位で調整します(図3:既定値は0x000c_0000)。
分類する音の特性にあわせて波形データを最適化する
それでは、DNNの最適化をはじめましょう。
第19回では0.5秒を48kHzでサンプリングしたWAV形式を扱いました。WAV形式では1つのサンプリング値を16bitの符号付き整数型(signed short)として表現し、DNNRT機能は1つの値を32bitの単精度浮動小数点型(float)として扱います。
WAV形式48kHzサンプリングのデータを4kHzの波形データへとダウンサンプリングする方法は2つ「Neural Network Consoleの提供するSumPooling機能で12個の値の合計を取る方法」と「自身で実装したWAV形式からCSV形式へと変換するプログラムの中で12個の値の合計を取る方法」があります。
Neural Network ConsoleのSumPooling機能でダウンサンプリングする
Neural Network ConsoleのSumPooling機能は、DNN上に格納されたデータを切り出して総和を算出、データをダウンサンプリングする機能です。Neural Network Consoleにブロックを1個追加するだけで処理可能ですが、Neural Network Consoleから生成された推論モデルは、扱うデータすべてをメモリ上に保持するため、0.5 × 48 × 1024 × 4Byte = 98304byte のメモリが必要となります。
Neural Network Console|SumPooling
CSV波形データ生成時にダウンサンプリングする
限られたメモリのみでダウンサンプリングを実現する方法としては、WAV形式のファイルを少しずつ読み出し(fread)、12個の値を合計してCSVファイルへ書き込む(fwrite)方法があります。今回は480エントリ単位(12個のデータ40組:960byte)でWAV形式のファイルを開き、値12個ずつの総和を取り、文字列型に変換しCSVファイルへ書き込みました。Neural Network Consoleほど簡単には実装できませんが、メモリ消費量を調整可能な組み込み向けの実装です(図4)。
モデルのサイズを最適化する
次に、SPRESENSEが実行する推論モデルを最適化します。
SPRESENSEが推論モデルを実行するために利用するDNNRT機能は、DNNを構成する各処理の入出力サイズのうち、最大の入出力バッファサイズのメモリを確保します。メモリの確保はDNNRT機能の提供する「dnn_runtime_initialize関数内のdnn_preallocate_chunk」にて実行されます。メモリの空き容量が十分でない場合はdnn_preallocate_chunk関数が-ENOMEM(-12)を出力します。十分なメモリを確保できるとdnn_preallocate_chunk処理が成功し、dnn_runtime_initialize関数が成功を返します(図5)。
DNN Runtime|Spresense SDKが提供する機能
ニューラルネットワークが必要とするメモリサイズを最適化する
入出力データを扱うために必要なメモリの消費量の最適化が完了しましたので、続いては、ニューラルネットワーク内で必要となるメモリサイズを最適化していきましょう。
Convolution層の最適化
今回の紹介する音声分類の推論モデルは、音声データの中から決められたパターンを抽出することを目的としたDNNです。そのため、パターン抽出を得意とする畳み込みニューラルネットワーク(CNN:Convolution-Neural-Network)を活用し、音声中に含まれる特徴的な波形を探し出します。CNNでは「Convolution層」により入力に対して複数のフィルタを適用し、特徴的なパターンを検出します。フィルタ数を増やすほど、様々な特徴を抽出できますが、メモリの消費量も大きくなります。今回は最適化では、各Convolution層の出力を8個に絞り(8個のフィルタを利用して)特徴を抽出しました(図6上)。
Convolution|Neural Network Console
畳み込みニューラルネットワーク
Affine層の最適化
ニューラルネットワークの後段を構成する「Affine層」は、入力されたデータをすべて統合してN個の特徴量に集約する機能を提供します。今回のDNNでは、雨、川、焚き火、海、夜の草原、テント、水中、列車、8環境に分類するため、入力データを8個の値に集約します。入力データ点数が多い場合、入力から出力を算出する式が長くなるため、推論モデルが大きくなります。dnn_runtime_initializeが消費するメモリ量は減りますが、model.nnbのサイズが増えるため、バランスの良いチューニングが必要となります(図6下)。
モデルの挙動を確認する
以上の最適化を適用したモデルを、4kHzのサンプリング周波数を持つ波形データにより学習(Train)させると、学習が収束しエラー率は2%程度の推論モデルを生成することができます(図7)。
学習後、検証用データにより推論モデルの検証(Evaluate)を実施すると、全ての検証用データに対して、正しい期待値を得られることを確認できます(図8)。
すべての機能をSPRESENSEに統合し、インテリジェント・エッジを実現する
最後に、第19回と今回(第20回)で実装したプログラムをすべて統合し、SPRESENSE上で実行できるバイナリファイルを生成します。評価には、雨、川、焚き火、海、夜の草原、テント、水中、列車の8環境の音をPCで再生し、PCに接続されたスピーカーから発生した音をSPRESENSEに取り付けたコンデンサマイクで録音、推論モデルをDNNRT機能で実行し、いずれの環境に居るかの確率を算出します(図9)。一例として、海の音を流した環境で、SPRESENSEによる推論を実行すると、8個のクラス確率が算出され、海の音の環境である確立が最も高くなることを確認することができます(図10)。
まとめ
本初心者講座では、DNNの推論モデルを生成できるNeural Network Consoleの使い方から、DNNのモデルの選択方法、モデルの学習データを生成する方法、SPRESENSE単体でDNNによる推論処理を実行してオーディオを分析する技法を解説いたしました。近年、組み込みシステムやIoTエッジデバイスには、故障予知、障害検知、音声分類といった波形データを解析するアプリケーションが特に多く求められていることから、こうした波形解析を超低消費電力で実行できるSPRESENSEは実製品向けの開発プラットフォームと言えます。今回紹介した内容を、是非貴社の独自DNNアプリケーション開発へご活用ください。
SPRESENSE SDKを活用して、自社独自のIoTスマートエッジを実現しよう
最後に、本初心者講座では、全20回にわたってSPRESENSEのハードウェアの特徴、開発環境、動作の様子、サンプルプログラムを結合したアプリケーションの開発方法などについて紹介してきました。SPRESENSE SDKを使うことにより、Visual Studio Codeの見やすいUIを通して、マルチコアのデバッグなど、実際の製品開発に欠かせない開発環境を入手し、超低消費電力で高速に動作するアプリケーションを構築することができます。
今後、SPRESENSE SDKを初めて導入する方は「 SPRESENSE SDK スタートガイド (IDE 版)」と「 SPRESENSE SDK チュートリアル」を、SPRESENSE SDKの提供する機能を知りたい方は「 SPRESENSE SDK 開発ガイド」をご参照いただき、さらにアドバンスドな開発に挑戦される方は「 APIリファレンス」をご活用いただくと良いと思います。
是非、次期製品の開発にお役立てください。
こちらも是非
“もっと見る” マルチコア|SPRESENSE編
SPRESENSE×Neural Network Console:第3回|オーディオ解析に必要な学習用データを採取し、PC上で学習・推論を実行する
今回の初心者講座では、SPRESENSEに搭載されたハイレゾオーディオ入力を活用し、環境音を録音し、ディープニューラルネットワークによる音声分類に不可欠な学習用データと検証用データを生成する方法について解説します。また、PC上で動作するNeural Network Consoleによって生成した推論モデルをエッジ・デバイスへ統合するために解決すべき課題を紹介します。
SPRESENSE×Neural Network Console:第2回|異常検知に活用できるニューラルネットワークで波形の扱い方を学ぶ
SPRESENSEのDNNRT機能が扱うことのできるデータは画像だけでなく、産業分野を中心に人気が高まっている「異常検知・故障予知」に活用できる加速度センサーや大気圧センサーなどから収集した波形データも解析することができます。さらにSPRESENSEに内蔵されたハイレゾオーディオ録音機能も周辺環境を可聴域の波形データとして記録することができる優れたセンサーとして利用可能です。そこで、今回の初心者講座では、まず簡単な波形データの解析方法を例に、DNNRT機能から波形データを扱うシステムの構築方法について解説。DNNRT機能を活用した製品開発に必要となる技術を紹介いたします。
SPRESENSE×Neural Network Console:第1回|エッジで推論モデルを実行し、データを分析する
今回はSPRESENSE SDKの提供するAI、ディープニューラルネットワーク(DNN)実行機能である「DNNRT機能」について紹介します。はじめてSPRESENSEの開発環境に触れる方はもちろん、はじめてDNNに取り組む方も安心して技術を学んでいただけるよう、サンプルアプリケーションの開発・解説をから、アプリケーションの変更方法、実際の環境データを使った解析方法まで段階的に解説します。