奥さんが自分のメディアを持っていて日々サステナビリティや育児について発信しており、その一環で色々な方にインタビューをしています。
インタビューは録音した音源をもとに対話形式で書き起こすわけなのですが、これが毎回結構な手間らしい。既存のサービスもいくつかあるのですが、それなりにお金がかかる*1とわかりました。
で、ちょっと調べてみたところGoogle Cloud APIの一つであるSpeech To Textが使えそうだとわかったので、簡単なツールを作ってみることにしました。
実装
書き起こしはそのまま使うわけでなく記事を書くために参考にするものなので、要件としては発言者、だいたいの発言内容と発言時間がわかれば問題なさそうです。それに基づいて実装していきます。
実装だけ見たい人は以下のレポジトリにコードがあります。
Speech To Textの導入
Speech To Textの導入は非常に簡単です。今回はNode.jsを選択しましたが、以下のコードだけでも動きます。
const client = new speech.SpeechClient(); const [operation] = await client.longRunningRecognize(req); const result = operation.promise();
resultには書き下したテキストに加えて単語単位のデータも返ってきます。こちらがその一例です。
音声データはローカルに置くかGoogle Storageに置くか選択できます。 なお、推奨音声データというものがこちらにまとめられています。16kHz以上の音源にする、FLAC形式にするといった具合です。
ひとまず、こちらの音声*2をテキストに起こしてみますと、以下のように出力されます。
はい僕はゆうすけですメールでソフトエンジニアをしてます今最もサンフランシスコにあるという感じする開発する会社で働いていますいやいやさん自己紹介お願いしますはいこんにちはゆうやですサンフランシスコベイエリアのフードストラップラーメンヒーローのて苦労しています2019年からバンクーバーに住んでいますよろしくお願いしますお願いします今井さんという屋さんはどういう出会いだったんですかこれ直接実はまだ会ったことないんですよねそうですねはいただうちの会社自分の今働いてる会社の神様とラーメンヒーローの神様が間な感じと言うかなんでしょうねそういう感じの仕様のキヨさんがラーメンヒーローの使用の日さんの師匠的な存在なんですよね
ここから仕様に合わせて手を加えていきます。
句読点
まずは句読点を打って読みやすくしていきます。Speech To Textでは enableAutomaticPunctuation
というオプションがあり、これをつけることで句読点がつきます。しかし実際のところ(おそらく日本語だと)非常に精度が悪く、ほぼ機能してないと言っても差し支えありません。ここでは他の手法を検討してみます。
口語文を眺めてみると、句読点がつく文字列にはパターンがあります。例えば"ですよね"、"なります"といった具合です。
都合の良いことにAPIのレスポンスは文章データの他に分かち書きのデータが返ってきます。
Word: です|デス Word: よ|ヨ Word: ね|ネ
このことから文節のマッチングをすることで良い具合に句読点が付けられそうです。
効率よくマッチングを行うために句読点のつくパターンでトライ木を作り、マッチングをしました。計算量としてはO(M)(Mは与える文章量)になります。実装はここにあります。これを実行した結果が以下です。いい感じに句読点がついています。
はい僕はゆうすけです。メールでソフトエンジニアをしてます。今最もサンフランシスコにあるという感じする開発する会社で働いています。いやいやさん自己紹介お願いします。はい。こんにちはゆうやです。サンフランシスコベイエリアのフードストラップラーメンヒーローのて苦労しています。2019年からバンクーバーに住んでいます。よろしくお願いします。お願いします。今井さんという屋さんはどういう出会いだったんですか。これ直接実はまだ会ったことないんですよね。そうですね。はい。ただうちの会社自分の今働いている会社の神様とラーメンヒーローの神様がまあ仲良いと言うかなんでしょうね。おそらくあのチョンプの使用のキヨさんがラーメンヒーローの使用のヒロさんの師匠的な存在なんですよね。
話者の切り分け
さて、次は話者の切り分けです。話者の切り分けは、Speech To Text APIのベータ機能として提供されています。
機能を使うためには v1p1beta1 を使い、enableSpeakerDiarization
を設定する必要があります。
const client = new speech.v1p1beta1.SpeechClient(); { ... "enableSpeakerDiarization": true, "diarizationSpeakerCount": 3, // 話者数 }
結果はWordInfo
の speakerTag
というフィールドに格納されます。
実装はこのへんです。実行結果は以下です。残念ながらそこまで精度は高くないようです。声質を比較してると思われるので、声が似ていない話者であればもう少し綺麗にとれるかも。
(p-2),はい。僕はゆうすけです。メールでソフトエンジニアをしてます。
(p-1),今最もサンフランシスコにあるという感じする開発する会社で働いています。いやいやさん自己紹介お願いします。
(p-3),はい。こんにちはゆうやです。サンフランシスコベイエリアのフードストラップラーメンヒーローのて苦労しています。2019年からバンクーバーに住んでいます。よろしくお願いします。お願いします。今井さんという屋さんはどういう出会いだったんですか。
(p-1),これ直接実はまだ会ったことないんですよね。そうですね。はい。ただうちの会社自分の今働いてる会社の神様とラーメンヒーローの神様が間な感じと言うかなんでしょうね。
(p-3),そういう感じの仕様のキヨさんがラーメンヒーローの使用の日さんの師匠的な存在なんです。
発言時間
発言時間は enableWordTimeOffsets
オプションを有効にすることで取得できます。各文節ごとに startTime
, endTime
がナノセコンド単位でとれます。今回は録音の振り返りがしやすいように、話者の切り替えごとに録音開始からの発言時間を追加しました。
0:00:04,(p-2),はい。僕はゆうすけです。メールでソフトエンジニアをしてます。
0:00:15,(p-1),今最もサンフランシスコにあるという感じする開発する会社で働いています。いやいやさん自己紹介お願いします。
0:00:34,(p-3),はい。こんにちはゆうやです。サンフランシスコベイエリアのフードストラップラーメンヒーローのて苦労しています。2019年からバンクーバーに住んでいます。よろしくお願いします。お願いします。今井さんという屋さんはどういう出会いだったんですか。
0:00:53,(p-1),これ直接実はまだ会ったことないんですよね。そうですね。はい。ただうちの会社自分の今働いてる会社の神様とラーメンヒーローの神様が間な感じと言うかなんでしょうね。
0:01:01,(p-3),そういう感じの仕様のキヨさんがラーメンヒーローの使用の日さんの師匠的な存在なんです。
チューニング
ここからはオプショナルですが、もう少し語彙認識の精度があげられないかみてみます。APIの機能にspeech adaptation
というものがあり、特定の単語の認識度を向上させることができます。
特に数字や住所などパターン化された語彙には強いようです。ただこちらもこのままだと書き起こしには有効ではないので、さらに adaptation boost
を使います。こちらは特定の単語に重みつけを与えることで、より精度よく認識できるようになります。
たとえば前の文章でご認識されていた単語をピックアップし、正しい文言で重みつけしてみます。
speechContexts: [ { phrases: ['今井', 'ベイエリア', 'Today I Learned', 'ゆうやさん', 'CEO', 'テックリード', 'スタートアップ'], boost: 20 }, { phrases: ['今最も', 'いやいやさん', 'いう屋さん', '神様'], boost: 1 } ]
実装はこちらのブランチにあります。
結果
0:00:04,(p-1),はい。僕はゆうすけです。ベイエリアでソフトエンジニアをしてます。
0:00:15,(p-2),サンフランシスコにあるという体験を共有するサービスを開発する会社で働いています。ゆうやさん自己紹介お願いします。
0:00:34,(p-3),はい。こんにちはゆうやです。サンフランシスコベイエリアのフードスタートアップラーメンヒーローのテックリードしています。2019年からバンクーバーに住んでいます。よろしくお願いします。お願いします。今井さんとゆうやさんはどういう出会いだったんですか。
0:00:53,(p-2),これ直接実はまだ会ったことないんですよね。そうですね。はい。ただうちの会社自分の今井働いてる会社のceoとラーメンヒーローのceoが仲良いと言うかなんでしょうね。
0:01:01,(p-3),おそらくあのceoのキヨさんがラーメンヒーローのceoの日さんの師匠的な存在なんです。
会社の神様
=> 会社のCEO
、メール
=> ベイエリア
など音声認識がかなり改善しました。
最初と比べてかなり読みやすくなったんではないでしょうか!
検証
さて、このツールを使い、実際のインタビューデータを書き起こしてみました。
時間: 1時間30分 Hz: 32000 Hz ファイル形式: Flac
処理時間
およそ15分程度。Google側の処理がほとんどで、クライアント側の処理は30秒ほどでした。
評価
まず最初に3分ほど音声を切り出して頻出する単語や固有名詞などを抽出し、adaptation boostを適用しました。比較データが用意できなかったので定性的な評価しかできないのですが、まあなんとなく話がわかる程度には書き起こしできました。インタビュワーが振り返るぶんには使えるんじゃないでしょうか。
その他の気づきをざっくばらんにあげると、
- 人間は話すときフィラー(「えっと」などのつなぎ言葉)が多いので、そのまま書き起こすとだいぶ雑音が多い
- おもみつけを強くしすぎるとその単語に引っ張られてもともと正しかった単語も誤認識される
- 文脈を認識しているわけでないので、支離滅裂な文章になりがち
といったところです。adaptation boostの適用にも限界があるので、ある一定以上の精度を期待するのであれば、マシンラーニングで自前の学習モデルを持つなどSpeech To Text以外の選択肢を検討したほうがよさそうです。
金額
1時間30分でわずか5セントでした。これなら調整しながらバンバン処理をまわしまくっても問題ないですね。
まとめ
今回Speech To Textを触ってみての感想は、"使いやすいけど向き不向きはある"というところでしょうか。 向いているのは比較的文章のパターンや文脈が決まっている音声データです。カスタマーサービスの電話応答なんかうってつけでしょう。boost adaptationを使えば頻出する単語に重み付けをして精度を高めることができます。逆に向いていないのはまさに書き起こしのような一度きりの文字起こしが必要な、パターンが定まっていない音声です。これも重み付けをすることである程度精度は挙げられますが、トライアンドエラーが必要なので割にあわないかなーと思いました。ではでは。