Google Cloud Speech APIでストリーミング音声認識してみる

あすかです。

今日はJavaのおはなしです。

クラウド音声認識というと、最近はいろいろなものがあります。
Bing、Watson、それからGoogle
今回は、Google Cloud Speechを使って、ストリーミング音声認識に挑戦してみます!

cloud.google.com

今回は、その導入にあたって不満はまったことがたくさんありましたので、
その愚痴解決法とかを書いてみます。

※4/10追記:実行時のコマンドラインパラメータを書き忘れてたので追記しました

用語解説

音声認識とは

音声認識は、みなさん御存知の通り、音声をテキストに変換する技術です。
例えば、「おはよう」とマイクとかに話しかけて録音したやつを音声認識すると、「おはよう」という文字が出てくるわけです。
プログラムは、音声を文字として変換できます。

うひょおハイテク!と、言葉だけ聞くとだれもがそう思うのでしょうが、音声認識慣れが必要です。
音声認識に慣れていない人が話した音声を認識しようとしても、うまく変換できません。
意味不明な日本語になります。

私は耳が聴こえないので、音声認識で話す時のコツはよくわかりませんが、
大学の教授が言うには、アナウンサーみたいな話し方をすれば認識精度が向上するらしいです。

なぜGoogle Speech API

精度がいいと評判だったので、何が何でも試してみたくてもってきました。
他にBingとかもありますが、私が調べた限り、精度に関してはお察しです。
Watsonも、Google Cloud Speechより微妙に精度が低いという比較の記事がありましたので、今回はGoogle Cloud Speechを使ってみます。

ストリーミング音声認識

音声認識には、2つのタイプがあります。

  • あらかじめ用意した音声ファイルをクラウドに投げる
  • マイクで話した内容をリアルタイムでクラウドに投げる(ストリーミング)

今回は、後者をやってみます。

Google Speech APIは、ストリーミング音声認識をサポートしています。
しかし、ストリーミングは、JavaPythonなど一部の言語でしかサンプルが提供されていません。

C#ではサンプルは提供されていませんが、gRPCがnugetで提供されておりGoogle SpeechのgRPCの仕様と組み合わせれば、時間はかかるでしょうが理論上は可能です。
追記:C#でStreamingするソースができあがりました

めんどいので今回はJavaを使います。

今回やること

Googleが公開しているJavaサンプルをビルドしてみます。
まず、ここからリポジトリを落とします。

github.com

speech / grpc フォルダにあるのが、今回実行したいプログラムになります。
grpcフォルダをプロジェクトフォルダとして開きます。java-docs-samplesのルートをプロジェクトとして開くわけではありませんので注意してください。

これはmavenになっていますので、githubの説明を参照の上、適切な方法でビルドする必要があります。私はNetBeansでやりました。

pom.xmlで指定されており、ローカルにないライブラリをダウンロードする

IDEの機能を使うなり、コマンドライン使うなり、お好みでどうぞ。

Google Cloudプロジェクトを作成

Google Cloudコンソールを開き、画面上のバーから現在開いているプロジェクト名をクリックします。

f:id:kmynews:20170409110043p:plain

するとプロジェクト選択画面が出てきますので、右上の「+」を押します。

f:id:kmynews:20170409110155p:plain

プロジェクト名を入力し、画面の指示に従って進めます。

f:id:kmynews:20170409110323p:plain

デフォルトではダッシュボードの中央に「APIの概要」が出てきますので、これをクリックして、

f:id:kmynews:20170409110432p:plain

画面右側から「ライブラリ」をクリックし、検索ボックスに「speech」と入れます。

f:id:kmynews:20170409110505p:plain

Google Cloud Speech API」を選択します。
紛らわしいですが、下の「Speech API」はクローズドベータテスト中のものです。

一部に「Google Speech APIは商用利用不可」という記述を見かけますが、それはこのクローズドβテスト中のもののことで、今回利用するものは大丈夫です。多分。ここの記事の「すでに公開済のアルファ版は~」の段落参照)

f:id:kmynews:20170409110722p:plain

APIをプロジェクトに追加したら、「認証情報」より、認証情報を作成します。

f:id:kmynews:20170409110805p:plain

「サービスアカウントキー」を選択します。
サービスマンではありません。

f:id:kmynews:20170409110826p:plain

サービスアカウントを適当に選ぶなり作るなりしてからJSONを選択して、作成します。

作成すると、JSONファイルがダウンロードされますので、それをどこかに保存します。

認証キーをプログラムから読み込む

UNIXmac含む)の場合は別の方法がありますが、Windowsでの設定方法がわからなかったので、今回は代替として以下のようにします。
StreamingRecognizeClient.javacreateChannelメソッドからこういう行を見つけます。

GoogleCredentials creds = GoogleCredentials.getApplicationDefault();

これをこうします。

GoogleCredentials creds = GoogleCredentials.fromStream(new FileInputStream("C:\\credential.json"));

パスのところは、さっき保存したjsonファイルを指定しておきます。

利用言語を日本語に設定する

デフォルトではen-US、つまり音声認識結果が英語で出力されます。
なので、言語を日本語に変える必要があります。

recognizeメソッド内で、

RecognitionConfig config =
		RecognitionConfig.newBuilder()
				.setEncoding(RecognitionConfig.AudioEncoding.LINEAR16)
				.setSampleRate(recorder.getSamplingRate())
				.build();

こういう行を見つけて、

RecognitionConfig config =
		RecognitionConfig.newBuilder()
				.setEncoding(RecognitionConfig.AudioEncoding.LINEAR16)
				.setSampleRate(recorder.getSamplingRate())
				.setLanguageCode("ja-JP")
				.build();

といった感じで、「ja-JP」の設定をはさみます。

pom.xmlを編集する

ここでサンプルを修正することで、利用するクラスが増減しました。
このままビルドするとmavenのcheckerでエラーが出ます。

そこで、ちょっと荒業ですが、
C:\Users\(ユーザ名)\.m2\repository\com\google\cloud\samples\shared-configuration\1.0.2\shared-configuration-1.0.2.pom
このファイルをテキストエディタで開きます。

こういう記述がありますので、そっくりそのまま消してしまいます。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-checkstyle-plugin</artifactId>
  <version>${maven-checkstyle-plugin-version}</version>
  <configuration>
    <configLocation>google-checks.xml</configLocation>
    <consoleOutput>true</consoleOutput>
    <failOnViolation>true</failOnViolation>
    <failsOnError>true</failsOnError>
    <includeTestSourceDirectory>true</includeTestSourceDirectory>
    <suppressionsLocation>suppressions.xml</suppressionsLocation>
  </configuration>
  <dependencies>
    <!--
     Add a dependency to use bundled resources.
                   See: http://stackoverflow.com/a/19690484/101923 
    -->
    <dependency>
      <groupId>com.google.cloud.samples</groupId>
      <artifactId>checkstyle-configuration</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>
  <executions>
    <execution>
      <goals>
        <goal>check</goal>
      </goals>
    </execution>
  </executions>
</plugin>

これでリビルドしてください。

実行!

※画面は、このサンプルとプロセス間通信を利用して連携させたWPFアプリのものです。実際にサンプルをビルドすると、結果はコマンドラインIDEの出力欄に表示されます。
※実行時にALPNなんとかのエラーが出る場合は、この記事を下へ読み進めてください。

サンプルアプリを起動するには、プロジェクトフォルダを開いて、コマンドプロンプトに、以下のように入力します。
java -cp target\grpc-sample-1.0-jar-with-dependencies.jar com.examples.cloud.speech.StreamingRecognizeClient --sampling 16000

f:id:kmynews:20170409114143p:plain

音声認識がちゃんと出ます!わーいわーい
誤変換もところどころにありますが、日本語として理解できなくはないレベルです。

音声認識精度を、他のサービスと比べてみましょう。
Bing Speech APIのサンプルを走らせて、同じ動画を読ませたところ、こういう結果が返ってきます。

f:id:kmynews:20170409115435p:plain

理解できなくはないですが、ところどころ難しい表現が入っています。

今回は、音声認識エンジンの弱点である「違う人が同時に話す」音声データを読み込ませたため、
ところどころセリフがとんでいたりしていますが、
それを引きにすると、精度の面ではGoogle Speechのほうがわかりやすいと思います。

いつか、Google Speechくらいの精度が普通になればいいですね。

実行時に「Jetty ALPN/NPN has not been properly configured.」が出る場合は

ALPNライブラリのページで「あまりおすすめできない」と書かれてはいるのですが、現状この解決法しか見つかりません。
まず、以下の2つのページから、最新verをクリックして、「******.jar」をダウンロードします。

次に、プログラムを起動する時のコマンドラインオプションに、

-Xbootclasspath/p:jars\alpn-boot-8.1.9.v20160720.jar
-javaagent:jars\jetty-alpn-agent-2.0.6.jar

を加えます。今回の場合は2つのファイルをjarsフォルダに入れましたが、みなさんの環境に合わせて適切な名前に置き換えてください。

なお、プログラム起動時のオプション設定ですが、NetBeansの場合はプロジェクトのプロパティから設定できます。

f:id:kmynews:20170409112652p:plain

参考:Googleドキュメントの誤りについて

Google Speech APIに関するGoogleドキュメントに、少なくとも2つの誤りがあります。

サンプルアプリケーションにおける「Java 非ストリーミングおよびストリーミング音声認識サンプル」ですが、このリンクからとぶのはNatual Language APIという別のAPIのサンプルです。
正しくはこっちです。

また、クライアントライブラリのページで、Javamavenコードが示されていますが、0.11.0-betaというバージョンは存在しません。(17/4/8時点)
0.11.0-alphaに置き換える必要があります。

公式がんばれ・・・!

まとめ

争え・・・!もっと争え・・・!