Cloud Speech-to-Textの単語レベルの変換信頼度が本当に信頼できるのか検証してみた

[Google Cloud Platform その２ Advent Calendar 2018の14日目](https://qiita.com/ao_log/items/47ae92641bbdc0cf8fb1)の投稿です。

## Cloud Speech-to-Textの紹介
Googleがクラウドサービスとして提供しているサービスの１つに、音声をテキストに書き起こすことができるCloud Speech-to-Textがあります。

当然の事ながら、100%の精度で書き起こす事は難しいのものの、かなりの正確度で発話ファイルを文字に起こすことができる、大きな可能性を秘めたサービスだと思っています。

◇Cloud Speech-to-Textについて知りたい方はこれらの先人の皆様の記事が役立ちそうです
https://gigazine.net/news/20180824-speech-to-text-gcp-cloud-mojiokoshi/
http://note103.hateblo.jp/entry/2018/07/23/115930
https://gigazine.net/news/20180824-speech-to-text-gcp-cloud-mojiokoshi/

## レスポンスに単語レベルの正確度を追加できるようになっていました
直近のドキュメントを読むと、レスポンスに対して、"単語レベルの信頼度"が追加可能になっていました。今年の2018年5月頃はそんな機能無かったと記憶していて、2018年の10月頃に追加された機能でしょうか?? "信頼度"とは、いわばどれくらいの確信度を持ってレスポンスを返しているのか?を表す指標ですね。

単語レベルの信頼度の有効化
https://cloud.google.com/speech-to-text/docs/word-confidence

```text:信頼度の定義
Cloud Speech-to-Text では、音声クリップの音声文字変換を行うときに、
精度も測定してレスポンスします。
Speech-to-Text から送信されるレスポンスでは、
音声文字変換リクエスト全体の信頼度レベルが 0.0 から 1.0 の範囲の数値で示されます
```

通常の本文単位でのレスポンスですと、どこが誤った箇所で、どこが正しく変換されている箇所なのか、判別する事は困難です。しかし、単語レベルで正確度が分かれば、"信頼度95%以上のワードだけ抽出する"などして、音声からのトピック抽出に使えそうだなと考えました。ノイズとなる低品質な変換を排除する事で、的確な意味抽出ができるのでは?という考え方です。

<img width="619" alt="スクリーンショット 2018-12-13 23.35.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/56466/5a0fd317-000c-102a-3e5d-610154565649.png">


0.0-1.0で信頼度を表示しますよ〜！とは言うものの、実際に挙動を確認してみないと、実用性があるのかどうか何とも言えませんね。この単語レベルの信頼度が本当に信頼できる指標となっているのか、手元の発話データで早速試してみました。

## 検証方法
①音声ファイルをGoogleSpeech-to-Textで変換
②誤って変換している単語の信頼度を確認し本当に低い値となっているか?正しく変換された文字は高い信頼度となっているか?検証してみる

## まとめと所感
試した内容の結果だけ、先に書いておきます。

- 今回の音源ファイルでは、大多数の単語が信頼度0.961に集中していた。もっと他の音源でも試して挙動を正確に理解する必要がありそう
- 外れ値とも言える、信頼度が低い単語については確かに実際に誤認識しているものが多く含まれていた。低いものを除外するフィルタ形式は有効に機能しそうな肌感
- 単語レベルでは、助詞などキーワード抽出の文脈では不要なワードも出現するので、実活用の際はフィルタ処理が必要になりそう
- 音声ファイルからトピックを抽出する試みには十分に活用できそうな程にそもそも高精度。もっと遊んでみたくなった。

### ①音声ファイルをGoogleSpeech-to-Textで変換

※検証に使用する音声ファイル(筆者が外の環境で録音しているニュース記事です..w)

元記事
Apple、関税率次第では中国外でiPhoneを製造するかも
https://jp.techcrunch.com/2018/12/13/2018-12-12-apple-could-end-up-manufacturing-iphones-in-another-country-due-to-tariffs/

読み上げた音声ファイル
https://d.kuku.lu/ecbbd4ceae

実行コード([詳細はドキュメントをご確認下さい](https://cloud.google.com/speech-to-text/docs/quickstart?hl=ja))

```python
from google.cloud import speech_v1p1beta1 as speech
def transcribe_with_word_confidence(gcs_uri):
    client = speech.SpeechClient()
    audio = speech.types.RecognitionAudio(uri=gcs_uri)
    ## 読み込む音声ファイルの設定を記述
    config = speech.types.RecognitionConfig(
        encoding=speech.enums.RecognitionConfig.AudioEncoding.FLAC,
        sample_rate_hertz=48000,
        language_code='ja-JP',
        ## enable_word_confidenceで単語単位の信頼度抽出をTrueにする
        enable_word_confidence=True
        )

    operation = client.long_running_recognize(config, audio)

    print('Waiting for operation to complete...')
    result = operation.result(timeout=300)
    return result

## 変換の実行
result = transcribe_gcs_with_word_time_offsets("【音声ファイルのパス】")
```

↓__Speech-to-Textの翻訳結果(読みやすいように句読点を打っています)__

```
ブルームバーグの新たな報道によると Apple は関税と iPhone 制度についていくつかのシナリオを描いている。
現段階では iPhone は米国と中国の間で展開されている貿易戦争の直接的な影響は受けていない。しかし、米国大統領ドナルドトランプがスマホへの関税を引き上げると決断すれば後にとっては大問題となる。

夜 Apple は現在 iPhone の大半を中国で製造していて、最終組み立てはフォックスコンと共に行っている。

間でも高いいくつかの国ではアップルは中国外のサプライヤーと共同している。例えば台湾の製造業者ウィストロンは、インドのバンガロールに組み立て施設を建設した当初計画でiPhone SE はインドで製造するはずだった。

似たような例として国ジャポンは2011年にブラジルに施設解除した。しかし、その結果は期待外れでブラジルでのデバイスの価格は米国よりもかなり高いものになってしまった

```
こちとら誤った変換の結果を見たいと意気込んでいるのですが、かなり正確に日本語に変換されている事がわかります。しゅごい。。変換結果を元記事と比較してdiffにかけてみましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/56466/777e01c9-241a-d976-31b7-a311b4aea195.png)

大体合っているようにも見えますが、間違えて変換してしまっている語句を抜き出してみます。

|    No.   |    正しい単語    |    誤った変換結果    |
|:-----------------|:------------------|:------------------|
| 1             |              Bloomberg |        ブルームバーグ        |
| 2           |            製造 |       制度       |
| 3             |               |        夜        |
| 4             |              Apple |        後        |
| 5               |                関税の |         間でも         |
| 6             |             協働 |       協同       |
| 7          |           開所 |      解除       |

これらの誤って変換してしまった単語と、正しく変換できている単語との間で、信頼度の差分が見られるのか?検証してみます。


### ②誤って変換している単語の信頼度を確認し本当に低い値となっているか?正しく変換された文字は高い信頼度となっているか?検証してみる

レスポンス結果から、単語と信頼度を抽出->PandasのDataFrameに変換し、各信頼度毎の分布を見てみましょう。

↓こんな感じで、単語と信頼度列を持ったデータフレームを作ります

```python:
word_list = []
confidence_list = []
result_dict = {}

#レスポンスから単語と信頼度のリストを抽出
for result in result1.results:
    for word in result.alternatives[0].words:
        word_list.append(word.word)
        confidence_list.append(word.confidence)

#PandasのDataFrameに変換
result_dict["word"] = word_list
result_dict["confidence"] = confidence_list
df = pd.DataFrame.from_dict(result_dict)

```

↓結果を表示してみます。信頼度と単語のペアが表示され、発音情報もデータとして保持されている事が分かりますね。

```python
df.head(5)
```
<img width="318" alt="スクリーンショット 2018-12-14 0.59.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/56466/f19b2407-4a60-cda2-2598-2f3db56c5268.png">
↓単語数は205で、平均の信頼度は0.94/最低で0.72/25パーセントタイルが0.96149という事でかなり偏りのある分布になっている??

```python
df.describe()
```
<img width="158" alt="スクリーンショット 2018-12-14 1.00.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/56466/664a75f7-db2a-8bdf-815f-3eaca1e179af.png">
↓ヒストグラムにするとこんな感じ。

```python
import vega
import altair as alt
alt.renderers.enable('notebook')

#信頼度のヒストグラムを描画する
#本記事の趣旨とはそれますが、Altair使い易くておすすめです( ・∇・)
# https://altair-viz.github.io/
alt.Chart(df).mark_bar().encode(
    alt.X("confidence:Q"),
    y='count()',
)
```

<img width="468" alt="スクリーンショット 2018-12-14 0.53.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/56466/21860b50-0d08-4e7e-a814-1ddb51d6ccb5.png">

うーん、特定の信頼度に偏るという結果はあまり予想していなかったのですが、音源との相性もあるのでしょうか？
今回の実験だけではN数が足りず、原因の調査までは踏み込めていませんが、とりあえずこんな結果になりました_:(´ཀ`」 ∠):

0.96付近の単語の正解度がどれくらいあるのかも気になりますが、信頼度0.90以下の、"Google的に自信無いっすわ..."と判断された単語に絞り込んで深掘りしてみます。

```python

#信頼度が0.9以下の単語に絞り込み
df_under_09_confidence = df[df["confidence"]<0.90]
#信頼度を昇順に並び替えて表示。14個の単語に絞り込まれた
df_under_09_confidence.sort_values("confidence",ascending = True)

```
↓__信頼度0.9以下の単語を信頼度昇順に並べた結果。__
<img width="612" alt="スクリーンショット 2018-12-14 1.23.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/56466/922de5fe-2ff2-a53b-12bc-8fc9778ea755.png">


紫で囲ってある部分は、実際に間違えて変換していた箇所です。開所と解除/ 何も無いところに入った夜 / appleやブルームバーグなどのカタカナ語が信頼度の低い結果として抽出されています。"解除"や"夜"が含まれていたのは流石ですね。

形態素解析を行う際には、た/は/で、などの助詞も1単語として認識されているようですので、実際のアプリケーションで利用する際には、意味のある単語に絞り込めるように処理を加える必要がありそうです。

最後に、元々の単語リストに信頼度スコアを振っておきます。

|    No.   |    正しい単語    |    誤った変換結果    |信頼度|
|:-----------------|:------------------|:------------------|:------------------|
| 1             |              Bloomberg |        ブルームバーグ        |0.891
| 2           |            製造 |       制度       | 0.961
| 3             |               |        夜        | 0.776
| 4             |              Apple |        後        | 0.961
| 5               |                関税の |         間でも         |0.961
| 6             |             協働 |       共同       |0.961
| 7          |           開所 |      解除       |0.780

__結果を見て思った事①:__ 
解除は拾えているものの、協働->共同の同音異義語は高い信頼度で表示されています。文脈まで考慮した信頼度算出は難しいのかも

__結果を見て思った事②:__ 
関税の->間でもでは、"間"を音読みの"カン"の音で拾っていると思われます。実際にレスポンスでは、"間|アイダ,カン"として読み方も合わせて返ってきています

もっと他の音源でも試してみたいところですが、今回の分析はここまでとします！
最後まで読んで頂いてありがとうございました！

## 検証に使用したソースコード
参考になる部分があれば使ってください

```python:word_confidence.py
import pandas as pd
import altair as alt

from google.cloud import speech_v1p1beta1 as speech
def transcribe_with_word_confidence(gcs_uri):
    client = speech.SpeechClient()
    audio = speech.types.RecognitionAudio(uri=gcs_uri)
    ## 読み込む音声ファイルの設定を記述
    config = speech.types.RecognitionConfig(
        encoding=speech.enums.RecognitionConfig.AudioEncoding.FLAC,
        sample_rate_hertz=48000,
        language_code='ja-JP',
        ## enable_word_confidenceで単語単位の信頼度抽出をTrueにする
        enable_word_confidence=True
        )

    operation = client.long_running_recognize(config, audio)

    print('Waiting for operation to complete...')
    result = operation.result(timeout=300)
    return result

result = transcribe_gcs_with_word_time_offsets("ファイルパスを入れます")

word_list = []
confidence_list = []
result_dict = {}

#レスポンスか単語と信頼度のリストを抽出
for result in result1.results:
    for word in result.alternatives[0].words:
        word_list.append(word.word)
        confidence_list.append(word.confidence)



result_dict["word"] = word_list
result_dict["confidence"] = confidence_list
df = pd.DataFrame.from_dict(result_dict)
df.describe()

import vega
import altair as alt
alt.renderers.enable('notebook')

alt.Chart(df).mark_bar().encode(
    alt.X("confidence:Q"),
    y='count()',
)

```