VOSKによるストリーミング音声認識の使い勝手を改善した話

はじめに

Python音声認識を実行するためのツールとして、最近はVOSKが少しずつ使われるようになってきた。その大きなメリットのひとつはオフラインで動作するという点である。 インストールも容易であり、様々なプラットフォーム上で動作するが、特にMacOSの場合、M1 にも対応したようである

VOSKのサンプルスクリプトは以下のリポジトリにて公開されている。

github.com

例えば "test_microphone.py"はマイク入力からのストリーミング音声認識を実行する。 これらはvoskが提供するモジュールをただ実行するだけのシンプルなスクリプト群である。 各自がアプリケーションに組み込むうえで必要となる、使い勝手の良いインターフェースは自分で仕様を考え、コードを書いて作らねばならない。 Python初心者にはハードルがやや高いものとなっている。

本記事の主旨は表題のように、VOSKのストリーミング音声認識を実行するうえで、単に公式のサンプルスクリプトを動かすだけの何も考えていない状態から脱却し、使い勝手を少し良くしてみようと試みたので、それを紹介するわけである。

改善のヒント

ところで、最近『音声対話システム 基礎から実装まで』(以降、『音声対話システム』)なる書籍が発売された。

www.ohmsha.co.jp

本書は「Python言語による音声対話システムの実装方法を詳しく説明」しているところがウリであり、以下のリポジトリにてソースコードが公開されているのが嬉しい。

github.com

このリポジトリでは音声認識モジュールについても一章を割いて説明している。 紹介されているサンプルスクリプトの不満な点は、

  • Google CloudのSpeech-to-TextのAPIを用いており、オンライン音声認識であること
  • 上記APIを使うまでの設定が手間であること(ユーザ登録やAPIキーの取得など)

が挙げられる。一方で、嬉しい点は

  • マイク入力のためのクラスが定義されており、ストリーミング音声認識がやりやすい
  • 音声認識APIのインタフェースのクラスが定義されている

が挙げられる。

そこで、上記サンプルスクリプトを参考にすれば、VOSKの使い勝手が良くなるのではと考えたのである。

ソースコードと動かし方

デモンストレーション用スクリプトのリンクを置く。後者は発話区間検出機能がついている。

これらを動かすにあたり、以下は必要である。

python3 -m pip install vosk
python3 -m pip install sounddevice

VOSKの音声認識モデルは公式サイトで配布されているものを用いる。

alphacephei.com

vosk-model-small-ja-0.22.tar.gzをダウンロード・解凍し、デモンストレーション用スクリプトと同じところに置く。その際、音声認識モデルのフォルダ名を"model"としておく。要するに、VOSKによる音声認識がすぐ動く状態にしておく。

特徴

『音声対話システム』のサンプルスクリプトではマイク入力を受け取るためにPyAudioを用いていたが、本実装ではマイク入力にsounddeviceを用いることにした。それによりPyAudio関連のモジュールがすっかりなくなっている。

上記デモンストレーションのmain関数を示そう(asr_streaming.py)。

def main(chunk_size=8000):
    """音声認識デモンストレーションを実行.

    Args:
       chunk_size (int): 音声データを受け取る単位(サンプル数)
    """
    SetLogLevel(-1)  # VOSK起動時のログ表示を抑制

    # 入力デバイス情報に基づき、サンプリング周波数の情報を取得
    input_device_info = sd.query_devices(kind="input")
    sample_rate = int(input_device_info["default_samplerate"])

    # マイク入力を初期化
    mic_stream = MicrophoneStream(sample_rate, chunk_size)

    # 音声認識器を構築
    recognizer = KaldiRecognizer(Model("model"), sample_rate)

    # マイク入力ストリームおよび音声認識器をまとめて保持
    VoskStreamingASR = namedtuple(
        "VoskStreamingASR", ["microphone_stream", "recognizer"]
    )
    vosk_asr = VoskStreamingASR(mic_stream, recognizer)

    print("<認識開始>")
    recog_result = get_asr_result(vosk_asr)
    print(f"認識結果: {recog_result}")
    print("<認識終了>")

VOSKの公式サンプルは入力され続ける音声を、無限ループのなかでひたすら文字起こしするものであり、プログラムを終了するにはCtrl-Cで強制終了させるしかない。これはとても使い勝手が悪い。一方で上記のmain関数ではget_asr_result関数を呼び出し、「1発話」分の音声認識を実行できる。関数の実行と1発話の音声認識が紐付くので、他のモジュールでも使いやすい(はずである)。実際、このような設計が『音声対話システム』でも用いられているから。

音声認識自体はVOSKに基づくので、『音声対話システム』のオリジナルに比べて、ソースコードがスッキリしたのもメリットになるだろう。

おわりに

書籍『音声対話システム』のサンプルスクリプトのおかげで、VOSKの音声認識を使いやすくすることができた。

著者の方々にはとても感謝している。