Azure Cognitive Service Speech to Text API を調査し、Google Cloud Speech-to-Text APIと比較していく

こんにちは、引越しなどの一連のゴタゴタが済んだ 2020年新卒入社予定の山口です。
今回はAzure Cognitive Service Speech to Text API(以下AST)について調査を行ったので、その結果などを報告します。またGoogle Cloud Speech-to-Text API(以下GST)と比較も行ったので、それについても記述していきます。

ASTの導入

今回はこのリンクの説明を元に導入をしていきます。

  1. Azure側の設定
    説明リンク

    • Azureアカウントの作成(microsoftアカウントが必要)
    • リソースの作成
      今回は以下の画像のようにアカウントを作成しました。

    f:id:optim-tech:20200228163513p:plain

    • リソースを作成したらキーの取得を行います
  2. PC側の設定(環境作成)
    説明リンク

    • 今回はanacondaでpython=3.6の環境を作成
    • ライブラリを追加
      pip install azure-cognitiveservices-speech

今回は試しにこのページのサンプルプログラムを使用します。動かすために少しプログラムを変更します。

キーとリージョンの変更(5行目)

  • 先ほど取得したキーを入力してください。
  • service_regionは以下のリンクを元に変更をしてください。

言語の指定(6行目の後に追加してください。)

  • 以下のコードを追加します。
+ speech_config.speech_recognition_language="ja-JP  

この変更を行い、サンプルプログラムが動かします。このプログラムはマイク音声の冒頭5秒をテキストに変換します。

ASTの対応ファイル形式などの調査

ASTの対応しているファイル形式などを調べてみると、以下の記述があります。

  • Currently, only WAV / PCM with 16-bit samples, 16 kHz sample rate, and a single channel (Mono) is supported.
    (リンク

またAudioConfigクラス・AudioStreamクラスの両方に同じことが書かれていたので、Stream形式に関しても同様の仕様だと考えられます。(リンク)

以上からAST(Python)では16ビットサンプル、16 kHzサンプルレート、1ch(モノラル)のWAV / PCMのみがサポートされている事が分かりました。

また、Azure Cognitive Service Speech to Text REST API(以下AST-REST)という別のAPIがあり、そのAPIではこちらのファイル形式に対応しています。

比較すると以下の通りになります。

対応ファイル形式 音声の長さ リアルタイム認識
AST(Python) WAV 制限なし 可能
AST-REST WAV、OGG 60s 不可

今回はASTを使用します。
「16ビットサンプル、16kHzサンプルレート、1ch、 .WAV形式」の音声ファイルを使い、GSTとの比較をしていきます。

音声ファイル文字起こしプログラムの作成

以下のコードを使用して、文字起こしを行っています。

import azure.cognitiveservices.speech as speechsdk
import time
import re

def main():
    #configの作成
    speech_key, service_region = "key", "japaneast"
    speech_config = speechsdk.SpeechConfig(subscription=speech_key, region=service_region)
    speech_config.speech_recognition_language="ja-JP"

    #audioconfigの作成
    audio_filename = "filename"
    audio_input = speechsdk.AudioConfig(filename=audio_filename)

    # speech_recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config) 
    # にするとマイク入力になります。その時はwhile文を別の手段で抜けられるようにしてください。
    speech_recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config, audio_config=audio_input)
    
    print("Recognizing first result...")
    
    # 設定の関数
    done = False
    def stop_cb(evt):
        print('CLOSING on {}'.format(evt))
        nonlocal done
        done = True

    #認識部分だけを取り出します。    
    def split(evt):
        st = re.search(r'\".+?\"',str(evt))
        print(st.group(0).strip('"'))
    
    # 認識を行った時の設定
    speech_recognizer.recognized.connect(split)

    # 認識が終わる時の設定
    speech_recognizer.session_stopped.connect(stop_cb)
    speech_recognizer.canceled.connect(stop_cb)
    
    # 処理前の時刻
    t1 = time.time() 
    
    # 認識開始
    speech_recognizer.start_continuous_recognition()
    # 音声が終わるまでループを続けます
    while not done:
        time.sleep(.5)
    # 認識終了
    speech_recognizer.stop_continuous_recognition()
    
    # 処理後の時刻
    t2 = time.time()
    # 経過時間を表示
    elapsed_time = t2-t1
    print(f"経過時間:{elapsed_time}")

main()

動作の内容としては音声ファイルをAPI側に投げ、返って結果の中からテキスト部分だけを抽出し表示するスクリプトです。また同時に処理時間も測定します。

ASTとGSTの比較

以前テックブログの方で使用した音源(走れメロスと場内アナウンス)で結果を比較していきます。 実行結果は以下のようになります。

1. 実行結果の比較

走れメロス

  • AST
メロスは激怒した。必ずかの「ジャッジ」忘却の王を除かねばならぬと決意した。
メロスには政治がわからぬ。
「メロスは村の牧人」である。
「笛吹き羊」と遊んで暮らしてきた。
けれども「弱」に対しては、人一倍に敏感であった。
今日未明、メロスは村を出発し、「脳越山お声が」離れた。このしらくすの位置にやってきた。
  • GST
メロスは激怒した 必ずかの「邪智」暴虐の王を除かねばならぬと決意した 
メロスには政治がわからぬ 
「メロスは村の巻一」である 
「笛を吹き」羊と遊んで暮らしてきた 
けれども「邪悪」に対しては人一倍に敏感であった 
今日未明メロスは村を出発し「の声山を越え十里」離れたこのシラクスの市に行ってきた

場内アナウンス

  • AST
「本日は」ご来場いただきまして、誠にありがとうございます。
開演に先立ちましてお客様にお願い申し上げます。
携帯電話など音の出るものの、電源はお切りください。
また許可のない録音撮影はご遠慮ください。
皆様のご協力をよろしくお願いいたします。
  • GST
「実は」ご来場頂きまして誠にありがとうございます
開演に先立ちましてお客様にお願い申し上げます
携帯電話など音の出るものの電源はお切りください
また許可のない録音撮影はご遠慮ください
皆様のご協力をよろしくお願いいたします

このままだとよく精度がわからないのでこちらのサイト(IT-4005 日音声認識エンジン性能評価方法のガイドラインの6.8.3.2 単語認識率、6.8.3.3 単語正解率、6.8.2.2 単語レベルでの正解認識・誤認識の判定)を元に比較を行っていきます。

認識の誤りには3つの種類があります。

  • 置換誤り - 異なる単語と認識された誤り
  • 脱落誤り - 認識結果に発声された単語が現れなかった誤り
  • 挿入誤り - 発声にない単語が認識結果に現れた誤り

これらの誤りから単語認識率と単語正解率を求めます。

単語認識率 = \frac{正解単語数}{全単語数} \times 100 \%

単語正解率 = \frac{正解単語数 - 挿入誤り単語数}{全単語数} \times 100 \%

(全単語数 = 正解単語数 + 置換誤り単語数 + 脱落誤り単語数)

単語への分割は自然言語処理オープンソースライブラリの「GINZA」を用いて分割を行いました。2つの音声ファイルの結果を集計した表は以下のようになります。

正解数 脱落 置換 挿入 単語認識率(%) 単語正解率(%)
AST 127 5 6 2 92.0 90.6
GST 136 2 5 1 95.1 94.4

f:id:optim-tech:20200228162642p:plain

f:id:optim-tech:20200302140506p:plain

音声認識精度は右上に点があればあるほど良い音声認識とされているみたいです。自分が試した音声ではGSTの方が良いという結果になりました。

2. 処理速度の比較

処理速度をそれぞれ比較した結果は以下の通りになります(単位はそれぞれ秒)。

回数 メロスAST メロスGST アナウンスAST アナウンスGST
1 13.59 6.71 10.56 5.37
2 13.55 5.57 11.07 6.81
3 13.58 5.99 10.57 5.32
4 13.58 5.91 10.57 5.24
5 13.56 7.10 10.57 5.06
平均 13.57 6.25 10.66 5.56

速度もGSTの方が早いですね。

3. 料金面での比較

両者の料金を簡単にまとめると以下の通りになります。(1ドル=110円換算、表の料金は1時間辺りの料金)

~1h ~5h 5h~ 備考
AST - Free ¥0 ¥0 利用不可 カスタムモデルも同じ
AST - Standard ¥112 ¥112 ¥112 カスタムモデル ¥156.8、マルチチャンネル ¥235.20
GST - データロギングなし ¥0 ¥158.4(¥0.66/15s) ¥158.4(¥0.66/15s) データ量は月で更新。100万分以上からはSpeech-to-Text 割り当てリクエストで問い合わせください。
GST - データロギングあり ¥0 ¥105.6(¥0.44/15s) ¥105.6(¥0.44/15s) データ量は月で更新。100万分以上からはSpeech-to-Text 割り当てリクエストで問い合わせください。

サービスを実際に使用したシミュレーションをグラフにすると以下のようになります。(ASTはStandardのデフォルトのモデル、GSTはデータロギングなしで計算しています。1ドル=110円で換算しています。)

f:id:optim-tech:20200228163521p:plain

大体3時間ちょっとくらいでASTの方がやすくなります。大量に使う場合だとASTの方が安く済みそうです。

まとめ

全体的なまとめとしては性能面ではGSTが速度、認識能力ともに優秀でした。しかしASTの方はデフォルトで認識結果に句読点がつき、テキストのクオリティは高いです。認識能力自体も両者に大きな差はないので、音声を大量に取り扱うのだったら、ASTも検討してもいいかもしれないですね!

オプティムでは、他社の新しいサービスも調査し活用しています。このような技術に興味のある方は、こちらをご覧ください。