会議の文字起こしをGoogle Cloud Speech to Text APIの音声文字変換でやってみたい(研究中)

Google Cloud Platformの機械学習系サービスの Speech to Text を使って、会議を録音した音声を用意して、ブラウザでいくつかコマンドを打つだけのお手軽作業で(特にSDKなどのインストールやコーディングナシで)文字起こしさせてみよう、という話です。

 

 

前書き

私は某「女子中学生みたいな略称の団体」に所属しておりまして、そちらでは毎月行われる理事会の議事録を取る業務があります。

だいたいは総務係の人がやるので私の仕事ではないのですが、毎月総務の人らは数時間分の会議の議事録を会議の何倍もの時間を必死こいて文字起こしされているので、ここは本業の知識を生かして面倒くさい文字起こしを自動化することができれば売りつけて小遣い稼ぎに…もとい本業と団体活動で多忙を極める総務の人たちも助かり、恩を売れる…もとい文字起こしという生産性がない業務以外の活動に注力してもらえるのではないかと考えました。

全体の流れ

全体のプロセスとしては

  1. 会議をできる限り高品質に録音をする
  2. クラウドAPIに録音データを食わせて文字列を得る
  3. 文字列の校正、手直し

という流れになろうかと思います。

目指すところと目指さないところ

専門用語も多いんで完璧な文字起こしは無理でしょうが、「人間がイチから起こすよりは早い」くらいになるといいなぁ、といったところ。

上の2と3を合わせた長さが元の会議の時間より短くできると理想。

※「一人の人間が会議音声を聞きながら再度はっきりと発音したモノを認識させる」アプローチがわりと有効のようですが、本記事ではそっちはあえて扱いません。

それぞれのプロセスについて

1.録音について

さて、まずは録音ですが、

GoogleAPIは録音された音声データを元に文字列に変換するわけですから、「いかに高品質に録音したモノを食わせるか」がほぼ全てです。機械学習だのAIだのの進歩以前に、機械から観て聞き取りやすい良いデータか用意できるかどうかがキモですので、まずは録音自体を頑張りましょう。

 

それはともかく、会議の状況としては以下になります。

  • 発言する可能性がある人数はおよそ10人~20人程度
  • それらが入る会議室での開催
  • それぞれPAマイクまたは会議マイクシステムで発言する
  • 所要時間は2~6時間くらい

 小規模な会議の時のPAマイクとはこういうやつで、ワイヤレスのマイクを3本くらい回しながらやります。

https://www.amazon.co.jp/%E3%83%91%E3%83%8A%E3%82%BD%E3%83%8B%E3%83%83%E3%82%AF-Panasonic-300MHz%E5%B8%AF%E3%83%9D%E3%83%BC%E3%82%BF%E3%83%96%E3%83%AB%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%AC%E3%82%B9%E3%82%A2%E3%83%B3%E3%83%97-WX-PW31/dp/B002NS2L5Y/

中規模の会議の時はもうちょっと本格的な会議マイクシステムがあります。

CCSシリーズ -CCS900 Ultro-|会議用マイクを選ぶなら「BOSCH会議システム」|ソリューション・サービス一覧|東和エンジニアリング

 こういうやつですね。

 

 とりあえず、小規模な会議の場合はPAマイクになりますのでそっちの録音をしてみます。

ウチの備品のPAマイクはLINE-OUT(AUX-OUT)が付いていないのでボイスレコーダーPAマイクの前に置いて録らなければなりません。

 Google SpeechAPIでは

・モノラルで
・MP3等で圧縮されていないもの

が推奨されているので、モノラルのWAV形式で録ります。

録音した後は音声データをSpeech APIに食わせます。

 

2.Google Speech to Text APIで変換をする

(意識の低い)文字起こし処理の手順概要

GoogleのSpeech to Textはいろいろなサイトで解説されているのですが、しっかりとした手順(ちょっと試すには面倒くさい)で解説するページが多く、とりあえずどんな塩梅よ、と試すレベルであればCloud Shellでやりましょう。

これだとコードを書かずにいくつかの比較的簡単なコマンドを打つだけでいいのでお手軽です。SDKのインストールも不要でブラウザだけでいいです。繰り返しが面倒くさくなってきた頃にコードやUIの整備を考えるくらいでいいのではないでしょうか。

まずは準備として、

という準備。

毎回の変換の手順は以下の通り。使うコマンドは最低限3つ+αなので簡単ですね。

  • Cloud Storageのバケットに音声ファイルをアップロードする(ブラウザにドラッグしたらいいです)
  • Cloud Shellを開く(Cloud Platform Console画面の右上にボタンがあります)
  • 以下のコマンドで認識処理を実行(これはWAVで16bitで44.1kHzの場合の設定です)
  • $ gcloud ml speech recognize-long-running '(バケットにアップロードした音声ファイルのURL ※)' --language-code='ja-JP' --encoding='linear16' --sample-rate=44100 --async
    ※音声ファイルのURLは gs://(バケット名)/(ファイル名) の形式になります。
  • 処理のIDが発行されるので適当にメモする(応答の中のname:に続く数字がIDです)
  • しばらくバックグラウンドで処理が実行されるので、終了し次第結果を保存するように以下のコマンドを実行する。
  • gcloud ml speech operations wait (ID) > (ファイル名).json
  • 終わり次第JSONで結果が保存されるのでそれまでほっとく(30分くらいしか待ってくれないので、長いファイルの場合タイムアウトでエラーになります。その場合はもう一回実行しましょう)
  • そのままだと人間では読めないので適当な方法でデコードする。以下はjqコマンドを使う例(Cloud Consoleでは最初から使えるようになっています)
  • $ cat (ファイル名).json | jq '.' > (任意のファイル名).txt
  • どうせconfidenceとかダブルクォートとかいらないので、発言部分だけ抜くならこう(でもなぜかエラーになる場合が)
  • $ cat (ファイル名).json | jq -r '.results.alternatives.transcript' > (任意のファイル名).txt
  • 必要に応じてsedなりなんなりで改行コードを変えてもいいですね。nkfは入ってないのですが。
  • または以下のサイトとかで。
    JSON整形 | URLエンコード・デコード - tatenosystem.com
  • 保存したファイルをダウンロードする
  • dl (ダウンロードしたいファイル名)

 

注意点としては

  • ステレオでしか録れないボイスレコーダーだと何らかの方法でモノラル(1ch)に変換しないとエラーになります。
  • 食わせられるデータは1GBまでです(WAV 16bit 44.1kHz モノラルですと約3時間強分)
  • リファレンスによると最大180分とありますので、長い会議では何らかの方法で分割します。
  • PAの前にボイスレコーダーを置く方法ですとどうしても雑音や反響を拾ってしまうのでAUX-OUTがある機種だとそれで録った方がいいでしょうね。

最初に適当なボイスレコーダーで適当に試したところ結果としては散々だったので、もうちょっと録音品質を上げる方法を詰めてみようかと思います。(下の「もう少し録音に凝ってみた」の節を参照。)

3.校正や手直し

固有名詞や人名とかへの対応など

当然ながら音声というのはいわばカナだけの文章であるわけで、それにどんな漢字を割り当てるかはAI次第です。ある程度係り受け等の文脈を意識した漢字変換がされるようではありますが、固有名詞や人名はどうしても同音異義語が混ざってしまい精度に限度があります。

この場合、頻度の高い単語や人名(特に出席者)をまとめて変換時にヒントを追加すると精度の向上が期待されます。

ヒントの追加は gcloud ml speech recognize-long-running のコマンドに --hints オプションをつけます。

書き方は --hints=[単語1,単語2,単語3,…] となります。並べた単語に近い音が現れたときに優先的にこれらの単語が選択されるようです。

とはいえ、英語であればアルファベットなので発音と文字が概ね一致するので効果が高そうなのですが、日本語の漢字は読みとは直結しないためあまり効果は見込めなさそうです。

従って現在はヒントで使う単語の漢字とカタカナの対応表を作って、一旦ヒント単語を漢字ではなくカタカナで指定して変換するようにしています。このようにすると固有名詞がすべてカタカナで出てくるので、できあがったものを別途テキストエディタで置換します。同音異義語が多い現場では辛くなってきますが、不規則な誤変換をされるよりはマシです。

単語が多くなると置換操作も多くなるので、適当なエディタのマクロ機能とか使うと早いでしょう。

口語体への対応

会議は人間同士のやりとりになりますので口語体がどうしても混ざります。

逐語型の議事録の場合でも、口語体そのままではなく一部書き直す場合もあるので、口語体の語尾等を文語体の形に置換しておけば手直しが楽になります。

同じく「えー」「まあ」「あのー」など、議事録には載せない単語も一括で消しておけば作業が楽になりますね。

エロ単語やスラングへの対応

わりと無視できない頻度で下品なスラングや隠語が紛れ込んできます。

Googleがどういう単語のライブラリを作っているのかはよくわかりませんが、おそらく本業の検索で集めた膨大な文字列からライブラリを作っているのでしょう。そのため真面目な単語だけでなくネット上に存在する多種多様な単語が変換結果に表れます。

これに関しては、よく出てくる単語をまとめて固有名詞の置換と同じ要領で置換してしまうようにしています。こっちで試した限りでは、セックス、フェラ、エロ、おまんこ、輪姦などがわりと頻出する気がしました。

また、変換時に「--filter-profanity」オプションを追加することである程度変換時に伏せ字に変換させることができるようです。fuck等が伏せられるようですが、日本語でどれくらい有効なのかは試していないのでわかりません。

 


もう少し録音に凝ってみた

適当なボイスレコーダーで適当に録音したところあまり良い結果にならなかったので、もう少し録音に凝ってみたところ、わりと変換精度の向上が見られました。

機材について

とりあえず以下の機種で試しています。

何回か試した限りでは指向性マイクであるDR-07で録ったのが最も誤変換が少ない気がします。

ボイスレコーダーだと人間の声の周波数帯域を強調する傾向があるので結果として元の音から歪んでしまい変換品質の低下につながっている傾向があるように思えます。結果としてリニアPCMレコーダーのほうが変換の品質がよいような気がします。(たまたまかもしれませんし、単に私の持ってるボイスレコーダーがへっぽこだからかもしれませんが)

Googleの変換コマンドは1GBまでしか食ってくれないので、長ーい会議の場合はたまに止めて分割するといいのですが、DR-05やDR-07には録音中に設定した容量になると分割してくれる機能がありますので、1GBか512MBで分割するよう設定しておくといいですね。(Googleクラウド基盤のほうが忙しいときは1GBですとエラーになる可能性が高かったので512MBがバランスが良さそうでした。)

※DR-07の後継機にWiFiなどの便利機能が付いたDR-22WLというのがあるのですが、容量で分割する機能がなくなってしまったようです。代わりに時間で分割する機能が付きましたが最大で60分。180分で分割できれば良かったんですが…。この機種、リーズナブルなのにWAVとMP3で同時に記録する素敵な機能が付いたのに残念…。

こういうの、「機械学習の素材録りに向いてますよ」みたいな売り方すると新しいニーズを掘り起こせるんではないかと思うんですよね。どうですかTASCAMさん。

指向性マイクと無指向性マイク

一見、無指向性マイクのほうが全方位の音を拾ってくれるので会議録音に向いてそう似思えたりもしますが、PAスピーカーの音を録るのであれば指向性モデルでスピーカーに向けて録ったほうがよさそうです。無指向性マイクですと、会議室の壁への反響もしっかり録ってしまって結果としてノイズになっている気がします。

最も重要なポイント

いろいろ試した結果変換精度向上に最も重要なのは「PA機器のLINE-OUT端子でレコーダーと直結して録る」ことで、PA機器にLINE-OUTが無いときは「PAスピーカーのすぐ前にレコーダーを置いて録る」で、会議室の真ん中にレコーダーを置いて録ったデータでは品質に限界がありました。

思うに、口から発せられる音は空気を伝わるうちに減衰しますが、Google機械学習の元データはおそらくスマホなどのマイクで録られた音声を元にしていて、数十センチ以内で録られているためほとんど減衰していません。会議室の真ん中に置いたレコーダーでは話者から数メートル離れてしまい、認識精度が著しく落ちてしまうのではないかと思いました。話者の口からレコーダーまで、「空気中を通る部分が1m以下」になるようにするのが良さそうです。

(それはそれとして、LINE-OUTで録る場合は、マイクでの発言しか録音されませんので、マイクをオンにし忘れた発言もちゃんと文字起こしする必要があるのであれば、あとで人間が確認する用に部屋の真ん中に置いて録った録音は予備としてあったほうがよさそうです)

その他録音について

1つのマイクで一人の話者がしゃべるのが最も理想的な環境と言えるでしょうから、それにできるだけ近づける努力をすることになります。

  • 録音レベルが十分かつオーバーしないようにする
  • 発言者ごとに音量をできるだけ合わせる工夫をする(大きな差があると欠落する率が上がる気がします)

その他細かいこと

変換結果のJSONファイルの内容について

{
"@type": "type.googleapis.com/google.cloud.speech.v1.LongRunningRecognizeResponse",
"results": [
{
"alternatives": [
{
"confidence": 0.88359386,
"transcript": "\u305d\u308c\u306e\u65b9\u306b\u884c\u304d\u307e\u305b\u3093\u304b29\u5e74\u5ea6\u7b2c1\u56de\u4ee5\u4e0a\u3067\u793e\u4f1a\u306b\u3092\u59cb\u3081\u305f"
}
]
},
{
"alternatives": [
{
"confidence": 0.6885556,
"transcript": "\u5343\u8449\u5e02\u30e9\u30a4\u30d6\u30ab\u30e1\u30e9"
}
]
},
{
"alternatives": [
{
"confidence": 0.6807716,
"transcript": "\u30d5\u30b8\u81ea\u8ee2\u8eca\u9e7f\u5150\u5cf6"
}
]
},

のように適当に分割されて並びます。confidenceが信頼度で、1に近いほど結果に自信がある(正確とは限らない)。transcriptが変換された文章です。日本語はそのままでは読めないのでデコードしないとイケません。

よく使うコマンドについて

gcloud ml speech recognize-long-running (オプションやファイル名)
長いファイルの音声認識を実行。
gcloud ml speech operations describe (ID)
音声認識ジョブの現在の進行状況やその他情報を表示(ジョブが実行中の場合)。または認識結果を返す(ジョブが完了済みの場合)。
gcloud ml speech operations wait (ID)
音声認識ジョブの終了を待って、終了し次第認識結果を返す。※30分程度でタイムアウトする。
dl (ファイル名)
指定したファイルをブラウザでダウンロード
jq (オプションいろいろ)
Googleクラウドプラットフォームとは直接関係ありませんが、jsonファイルを成形したり特定の内容を取り出したりするコマンド。 
sed (オプションいろいろ)
こちらもGoogleクラウドプラットフォームとは直接関係ありませんが、テキストファイルを加工するのに使います。
jqとsedを組み合わせて、
$ cat (jsonファイル名) | jq -r '.results.alternatives.transcript' | sed -e 's/$/\r/g' > (出力ファイル名) 
のようにして、変換結果から文章だけ抜き出しつつデコードして改行コードも変換してエディタで扱いやすくしています。

詳しくはリファレンスを見ましょう。

https://cloud.google.com/sdk/gcloud/reference/ml/speech/recognize-long-running?hl=ja

https://cloud.google.com/sdk/gcloud/reference/ml/speech/operations/?hl=ja

課金について

「60分以上、15秒ごとに0.006USD」とありますので、最初の1時間は無視するとして、1時間あたり170円程度となります。

 


今後確認したい内容

  • ml speechコマンドにもベータコマンドとアルファコマンドがあるようだが、これらはどういう位置づけになるのか?。(今の正式コマンドになる前のバージョンのコマンドなのか、次期マイルストーンを先取りした、正式コマンドより新しいバージョンなのか。後者なら正式コマンドより変換品質が上がる場合があるのか。)
    →betaでもオプションが同じなら変換精度は同じように見えます。
  • alpha版にはダイアライゼーション機能(話者ごとにIDを振る機能)があるので、将来的には議事録における「誰の発言か」の識別がしやすくなるかも。
  • 会議前後の雑談タイムの有無で変換品質に差は出るのか(前後をカットする意味はあるのか)→なさそう。
  • GoogleのSpeech to Text API機械学習のデータセットGoogleが用意したものなので、かなり汎用的なデータセットになっているはずで、会議のような特定用途向けに変換精度を上げるのには限度がありそうです。Googleのサービスは自前のデータセットは使えないようなので(たぶん)、この辺をなんとかするにはAzureの似たようなサービスを使うといいのかも?(仮)

エラーについて

recognize-long-runningコマンドを実行する際にエラーが出るときがあります。

大体英語で何かしら出てくるので、読めば原因もだいたい判るとは思いますが、いくつか挙げておきます。

INVALID_ARGUMENT: Async input too long. Maximum input audio length is 3 h.

音声ファイルの時間が長すぎ(3時間超え)。

適当な波形編集ソフトで分割しましょう。

フリーソフトだと https://www.audacityteam.org/ とか?。

レコーダーの設定で自動分割にしている場合は短めにすると良いでしょう。WAV 16bit 44.1kHz モノラルで1GB分割にしていると、1ファイルあたり3時間をちょっとだけ超えてしまいます。

RESOURCE_EXHAUSTED: Resource has been exhausted (e.g. check quota).

リソースの上限を超えた要求をしたときに出ます。主に同時にいくつも発行したりしたときに出る気がしますが、自分のアカウントだけではなく、他のユーザーの処理も含んでいるのか、時間を変えれば全く同じファイルを同じオプションで実行していても出るときと出ないときがあります。

単独で実行している場合であっても音声ファイルが長い時にも出るようです。これは上限の3時間を超えていなくても状況によっては出る時があります。ファイルをいくつかに分割して短くすると通ったりします。