Google Cloud Speech API における音声前処理と文字起こし精度の関係調査

## 文字起こし精度が思ったより低いぞ

前回の[Google Speech APIの使い方](https://qiita.com/ysdyt/items/bc22eb04d90eb074cf9d)をまとめた記事の最後でも言及しましたが、文字認識精度が思った以上に低いという問題にぶち当たりました。

rebuild.fmでは8割くらい文字起こしできているらしいですが、自分の場合は[体感で半分も認識されていない](https://github.com/ysdyt/podcast_app/blob/master/text/google_speech_api/001.txt)印象です。完璧ではないまでも、文字起こしされた文章を読んだらおおよそ会話内容がわかることを期待していたのに結構壊滅的な感じでした。

「Speech APIは悪くない、自分の前処理が悪いのだ」という前提に立ち、前処理の有無やパラメータの組み合わせを色々試して精度比較してみました。Google Speech APIにおけるベストな前処理方法を探すことが今回の目的です。



## 検証対象音源データ

自身が収録・配信しているPodcast「白金鉱業.FM」の[第一回目の音源](https://shirokane-kougyou.fm/episode/1)を対象にしました。uploadされているものは編集済みのクリアな音源ですが、静かな部屋で収録するなど、収録にはそこそこ気を使っているので音質としてはrawデータでもさほど違いがないほどクリアです。

音源の長さはちょうど1hです。編集によってスタートから1hの位置でカットしました。1hである意味はそれほどありませんが、長尺の音源に対して試してみたかったのと、実験対象としてキリが良いようにしただけです。

## 検証項目

[前回の記事](https://qiita.com/ysdyt/items/bc22eb04d90eb074cf9d)の最後で立てた仮設を確認するため、今回は **「ノイズ低減処理の有無」「音量調整の有無」「sample rate hertzの違い」** の3項目について検証を行います。

- **ノイズ低減処理**・・・Audacityで行うホワイトノイズ処理。実行方法は[こちら](https://qiita.com/ysdyt/items/9a95857aed85a19766b0)

- **音量調節処理**・・・Leveratorで行う自動音量調節を行う処理。実行方法は[こちら](https://qiita.com/ysdyt/items/9a95857aed85a19766b0)

- **sample rate hertz**・・・音声のサンプリング率。Speech APIでは16kHZでのサンプリングが推奨されているが、元々16kHZ以上で収録された音源は16kHZでリサンプリングせず収録そのままのサンプリング率でSpeech APIにインプットすることが注意書きされている。内容と実行方法は[こちら]((https://qiita.com/ysdyt/items/9a95857aed85a19766b0))。収録に用いたマイクのデフォルトのサンプリング率が44kHzのため今回は 16kHz or 44kHzの2パターンを試す。

上記3項目についてパラメータの総組み合わせを作りました。以下表のように全8種類となります。

| No.  | ファイル名                                | ノイズ低減処理 | 音量調節 | sample rate hertz | ファイルサイズ |
| ---- | ----------------------------------------- | -------------- | -------- | ----------------- | -------------- |
| 1    | 01_001_NoiRed-true_lev-true_samp16k.flac  | True           | True     | 16k               | 73.1MB         |
| 2    | 02_001_NoiRed-true_lev-true_samp44k.flac  | True           | True     | 44k               | 169.8MB        |
| 3    | 03_001_NoiRed-true_lev-false_samp16k.flac | True           | False    | 16k               | 64.7KB         |
| 4    | 04_001_NoiRed-true_lev-false_samp44k.flac | True           | False    | 44k               | 147.4KB        |
| 5    | 05_001_NiRed-false_lev-true_samp16k.flac  | False          | True     | 16k               | 75.8KB         |
| 6    | 06_001_NiRed-false_lev-true_samp44k.flac  | False          | True     | 44k               | 180.9KB        |
| 7    | 07_001_NiRed-false_lev-false_samp16k.flac | False          | False    | 16k               | 68.1KB         |
| 8    | 08_001_NiRed-false_lev-false_samp44k.flac | False          | False    | 44k               | 160.2KB        |

ファイルサイズを見る限り、「sample rate hertz」は16kにするとファイルサイズがガクンと下がります。これは普通ですね。「ノイズ低減処理」「音量調節」は有無がどのようにファイルサイズに影響するかはパターンが不明でした。

ちなみに、白金鉱業.FMで毎回公開している音源は

- ノイズ低減処理 → True,
- 音量調節 → True
- sampling rate → 16k

の No.1 と同じ処理に当たるものです。



## 検証方法

### 実行方法

Google Speech APIの実行方法は[前回の記事](https://qiita.com/ysdyt/items/bc22eb04d90eb074cf9d)の通りに行いました。

### 評価方法

1文字つづ正確に文字起こしされているのか確認するのはさすがにダルいので、ここでは定性的にざっくりとどのパラメータでもっとも精度の良い文字起こしができているかを確認します。

ただ、それだけだとさすがに評価が難しいので、いちおう定量結果っぽいものとして

- 文字起こし全文字数
- mecabで抽出した全単語数（重複あり）
- mecabで抽出した名詞数（重複あり）
- mecabで抽出した全単語数（重複なし）
- mecabで抽出した名詞数（重複なし）

くらいを評価項目として出しておきます。



## 結果

### 定量結果

定量結果の値は以下となります。

| No.  | ファイル名                                | ノイズ低減処理 | 音量調節 | sample rate hertz | 文字起こし文字数 | 重複有りの全単語数 | 重複有りの名詞単語数 | 重複なしの全単語数 | 重複なしの名詞単語数 |
| ---- | ----------------------------------------- | -------------- | -------- | ----------------- | ---------------- | ------------------ | -------------------- | ------------------ | -------------------- |
| 1    | 01_001_NoiRed-true_lev-true_samp16k.flac  | True           | True     | 16k               | 16849            | 9007               | 2723                 | 1664               | 1034                 |
| 2    | 02_001_NoiRed-true_lev-true_samp44k.flac  | True           | True     | 44k               | 16818            | 8991               | 2697                 | 1666               | 1030                 |
| 3    | 03_001_NoiRed-true_lev-false_samp16k.flac | True           | False    | 16k               | 16537            | 8836               | 2662                 | 1635               | 1026                 |
| 4    | 04_001_NoiRed-true_lev-false_samp44k.flac | True           | False    | 44k               | 16561            | 8880               | 2651                 | 1659               | 1019                 |
| 5    | 05_001_NiRed-false_lev-true_samp16k.flac  | False          | True     | 16k               | 17219            | 9191               | 2758                 | 1706               | 1076                 |
| 6    | 06_001_NiRed-false_lev-true_samp44k.flac  | False          | True     | 44k               | 17065            | 9118               | 2727                 | 1675               | 1055                 |
| 7    | 07_001_NiRed-false_lev-false_samp16k.flac | False          | False    | 16k               | 16979            | 9045               | 2734                 | 1679               | 1047                 |
| 8    | 08_001_NiRed-false_lev-false_samp44k.flac | False          | False    | 44k               | 17028            | 9120               | 2727                 | 1664               | 1040                 |

表だとちょっと分かりづらいのでグラフにしました。

<img width="596" alt="スクリーンショット 2020-01-02 21.13.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100780/0f36ee77-34d4-640e-f15f-b1987a2c4cf5.png">

<img width="710" alt="スクリーンショット 2020-01-02 21.13.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100780/ce0739e0-17bd-6f4a-0fc8-223bd71e852f.png">

<img width="692" alt="スクリーンショット 2020-01-02 21.13.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100780/c13a13b3-e63e-2ddf-7c44-0a4b82a38744.png">


- 全ての項目を考慮して**最も良い結果だったのはNo.5**（ノイズ低減処理なし・音量調整あり・sampling 16kHz）
- **悪かったのは No.3 or No.4** （どちらも同着くらいで悪い）



定量結果から言えそうなことは、

- ノイズ低減処理は **無いほう（False）** が良い
- 音量調整の処理は**あったほう（True）**が良い

- samplingは、「ノイズ低減処理」「音量調整処理」の有無の方が影響が大きいので、16kHz or 44kHz の差は殆ど無いと言っていいくらいですが、厳密に言うと「重複なしの名詞単語数」項目では常に 16kHzの方が微妙に良い結果なので、**16kHzがベター** といえそう。



### 定性結果

最も良かった No.5 と、悪かったNo.3（No.4でもよかったがとりとりあえずこっち）の文字起こし結果を定性的に確認します。

#### 文字起こし結果

文字起こし全体のうちの1部分の範囲について、見比べやすいように画像を左右に並べました。左がNo.5、右がNo.3です。

<img width="725" alt="スクリーンショット 2020-01-02 10.35.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100780/377a88a8-60ff-031d-1107-8565a560700c.png">

まぁやっぱりよくわからない。

#### 頻出名詞

よくわからないので、No.5とNo.3からそれぞれ出力された「重複なしの名詞単語」と「そのカウント数」を見比べてみます。出現数が11回以上あった単語を試しに表示してみます。

<img width="459" alt="スクリーンショット 2020-01-02 20.38.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100780/0656b516-c9d8-835b-7d94-022e320141c1.png">

出現頻度が高い単語はほぼ同じように見えます。

#### ワードクラウド

ついでに、特に情報は増えませんがワードクラウドも出してなんとなく眺めてみます。左がNo.5、右がNo.3。

ちなみに、「焼酎」というのは「常駐」の文字起こしミスですね。

<img width="716" alt="スクリーンショット 2020-01-02 20.44.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100780/c1f9f5d2-cf72-6b0c-966b-06a7808c6a04.png">


# まとめ

検証した3項目の内、定量的にもっとも良い成績を出した組み合わせは、

- ノイズ低減処理 → なし
- 音量調整処理 → あり
- sample rate hertz → 16kHz

となりました。API公式にも書かれていた通り、ノイズ低減処理は無い方が良いようです。一方、音量調整処理はあったほうが良いので音量ははっきりしている（小さくない）方がAPIにとっては良いみたいです。最後に、16kHz以上で収録されたものはリサンプリングするなとありましたが、44kHzで収録した場合もAPI的には16kHzにリサンプリングしたほうが良いようでした（ただ、大局には影響しないようですが。）

最も成績の良かった項目の組み合わせ（No.5）が出力した文字起こし結果と、最も成績の悪かった項目の組み合わせ（No.3）が出力した文字起こし結果を定性的に比較した場合、文字起こしが成功している頻出単語にはほぼ差はないように見え、パラメータの違いが文字起こしの内容自体に大きな差を生み出すものではないことがわかりました。出現がレアな単語ではもしかするとうまく新規に文字起こしが成功している場合があるかもしれませんが、今回の検証のスコープから外れるため（そこまで確認する元気がないため）確認していません。

「rebuild.fmでは8割くらい文字起こしできてる」への謎は深まりますが、私の収録可能音源クオリティーでは、Google Speech APIの文字起こし精度はこれくらいが限界なのだろうと思っています。まだまだ自動文字起こしへの道は険しいですね。



## Future Work

今回得られたベスト精度のGoogle Speech API文字起こし結果 vs. Amazon Transcribeをやってみたいと思います。

自分が見た範囲の「比較してみた」系記事では、数行（もしくは数分）レベルの文字起こしを行いgood/badを述べているものが多いです。もしくはニュース動画のような"クリアすぎる音源"に対して行っているものも多いです。

Transcribeについて[バズっていたブログ](https://note.com/sangmin/n/nf404e9945f48)でも英語での文字起こしで精度が高い話をしています。自然言語処理分野では英語の精度が高いのは知られているところですが日本語だとどうかというところが肝心です。

自分が知りたいのは、日本語の音源、Podcastのように素人収録されたノイズの多い音源、1hくらいの長尺音源、複数人がクロストークしている音源 に対してどこまでAPIだけで戦えるのかなので検証してみたいと思います。