「google/speech-embedding」を試す
以下で試したウェイクワード実装で使用されていた。
Kaggleで公開されていて、2020年と結構古め。
概要
このモジュールは、16kHzのサンプリングレートを使用してオーディオから埋め込みベクトルを生成します。
入力特徴
必要なオーディオ入力:
- Tensor バッチサイズ × サンプル数
- サンプリングレート: 16kHz
- 各サンプルは-1から1の間の32ビット浮動小数点数である必要があります。
このモジュールは、提供されたオーディオサンプルから以下のパラメーターを使用して独自の32次元ログメル特徴量を計算します:
- STFTウィンドウサイズ: 25ms
- STFTウィンドウステップ: 10ms
- メルバンド範囲: 60Hz - 3800Hz
- メル周波数ビン: 32
アーキテクチャ
音声埋め込みモジュールは、5つの畳み込みブロックのスタックを使用します。各畳み込みブロックは5つの層から構成されます:
- 1x3畳み込み層
- 3x1畳み込み層
- 最大プール層
- 1x3畳み込み層
- 3x1畳み込み層
詳細な情報は当社の論文から入手可能です:James Lin, Kevin Kilgour, Dominik Roblek, Matthew Sharifi 「Training Keyword Spotters with Limited and Synthesized Speech Data」
このアーキテクチャにより、最初の埋め込みには12400サンプル(775msまたは76特徴ベクトル)が必要です。以降の埋め込みベクトルは、さらに1280サンプル(80msまたは8特徴ベクトル)が必要です。
以下のスニペットは、予想される埋め込み長を計算します。
embedding_length = 1 + (sample_length - 12400) // 1280
微調整
モジュールは、
trainable=True
に設定し、バッチ正規化をトレーニングモードに設定するタグ{"train"}
を付けたグラフバージョンをインポートすることで、タスクに合わせて微調整可能です。
module = hub.Module( "https://kaggle.com/models/google/speech-embedding/frameworks/TensorFlow1/variations/speech-embedding/versions/1", trainable=True, tags={"train"} )
サンプルのColaboratoryノートブック
以下のサンプルのColaboratoryノートブックでモジュールの動作を確認してください:
- speech_commands.ipynb は、音声コマンドデータセットでキーワード検出モデルを訓練する方法を示します。
- record_train.ipynb は、自分の音声でキーワード検出モデルを訓練する方法を示します(マイクが必要です)。
UsageはどうやらTensorFlow 1系らしく、また用意されているノートブックもトレーニング用途らしいので、上のウェイクワード実装である「local-wake」のコードも参考にするのが良さそう。このあたり。
今回はColaboratoryで。
まず、パッケージ。ミニマムでこの辺りが必要になるが、Colaboratoryだとデフォルトでインストールされている。
!pip freeze | egrep -i "librosa|tensorflow|tensorflow_hub"
librosa==0.11.0
tensorflow==2.19.0
tensorflow-datasets==4.9.9
tensorflow-hub==0.16.1
tensorflow-io-gcs-filesystem==0.37.1
tensorflow-metadata==1.17.2
tensorflow-probability==0.25.0
tensorflow-text==2.19.0
tensorflow_decision_forests==1.12.0
オーディオファイルを用意する。今回は上の「local-wake」を試した際に作成したウェイクワード(「ラズパイ」)が含まれる3秒ほどのWAVファイルを用意した。
!ffprobe -i sample-1.wav
(snip)
Input #0, wav, from 'sample-1.wav':
Duration: 00:00:03.00, bitrate: 256 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, 1 channels, s16, 256 kb/s
3秒の16bit PCM WAVファイルで、チャネルはモノラル、サンプリングレートは16kHzとなっている。
モデルに入力可能なオーディオファイルの要件は、
必要なオーディオ入力:
- Tensor バッチサイズ × サンプル数
- サンプリングレート: 16kHz
- 各サンプルは-1から1の間の32ビット浮動小数点数である必要があります。
このアーキテクチャにより、最初の埋め込みには12400サンプル(775msまたは76特徴ベクトル)が必要です。以降の埋め込みベクトルは、さらに1280サンプル(80msまたは8特徴ベクトル)が必要です。
とある。
local-wakeのコードを見ると、librosaを使って16kHz・モノラルにリサンプリングして、32 bit floatのNumPy配列が取得されるので、ここは良しなにやってくれるのだが、オーディオの長さは最低775ms必要でそれ以下だとエラーになるという点には注意が必要。local-wake試した時にあまりに短いWAVファイルを渡すとエラーになっていたのは多分これだよね。
ということで、オーディオファイルからEmbeddingを求めるコードは以下のような感じ。
import librosa
import tensorflow as tf
import tensorflow_hub as hub
import numpy as np
# オーディオファイル
audio_path = "sample-1.wav"
# 音声ファイルの読み込み(16kHz・モノラルにリサンプリング)
y, sr = librosa.load(audio_path, sr=16000)
# embeddingモデルのロード
model = hub.load("https://tfhub.dev/google/speech_embedding/1")
inference_fn = model.signatures['default']
# embeddingの計算
emb = inference_fn(default=tf.constant(y[None, :], dtype=tf.float32))['default']
print(emb)
tf.Tensor(
[[[[ -8.671426 17.906559 7.225528 ... -23.824432 1.7396173
35.309944 ]]
[[ -5.3996644 4.4622955 8.968074 ... -20.414099 7.92331
28.593588 ]]
[[-14.496883 -3.4124908 16.138592 ... -22.974033 2.1091504
38.288452 ]]
...
[[ -5.343011 24.865768 9.801123 ... -28.247948 5.7232685
30.055325 ]]
[[ -3.5368233 23.01561 10.9588585 ... -26.216942 3.9106688
35.337685 ]]
[[ -4.8235335 23.340744 8.02408 ... -25.619957 2.7081103
32.932022 ]]]], shape=(1, 28, 1, 96), dtype=float32)
28フレーム × 96次元 の時系列埋め込みとなっている様子。