エコーロボット。サリーのマイクからとらえた音声データをストリーミングにしてPC経由でGoogle Cloud APIに送って、返送された日本語テキストをまた喋らせてみた。
カテゴリー: Google Cloud Platform
エコーロボットの枠組み
ロボットのマイクに話しかけ、その音声をPCを経由してGoogle Cloud APIに送り、帰ってきた言葉をリアルタイムでロボットに再生させるというエコーロボット、ほぼできた。Googleからの返送がストリーミングで、ほぼリアルタイムなので、違和感なくロボットはしゃべり返せる。さしあたって、ALTextToSpeechで喋らせている。
ただ、PC側の処理の中で、返された文字列を、ロボットに喋るぶぶだけに処理すると、返送されてくる言葉が壊れる状況が発生する。いまのところ、理由がわからない。これさえなければ、ほぼ、終わりなのだが。
Google Cloud Speech APIとNaoqiのストリーミング接合について
記憶から消える前に、どうやってつなげたかという基本的なメソッドだけを書いておく。pythonのソースをあげても良いのだが、著作権問題がよくわからないので、避けよう。
(1)Google APIの基本は以下のソースを利用する。これを(G)としよう。
https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/speech/grpc/transcribe_streaming.py
(2)ALAudioDevice側のストリーミング処理の基本ソースは、
http://www.baku-dreameater.net/archives/9331
を利用させていただいた。(R)とする
(3)基本は、(G)のpyaudioの部分をALAudioDeviceに置き換えることである。まず、main関数の冒頭に、(R)のロボットのIPとポート処理、qimessasingのオブジェクト生成部分を書き加える。ここは、それらを理解していれば簡単にできるだろう。それらに関連するライブラリをimportすることもおわすれなく。わすれたら、エラーになるのでその時直しても良い。その後、Google APIを利用する権限を持ったserviceオブジェクトの生成に入っている。
(4)record_audio関数の書き換え。
0、Queueからqueueオブジェクトを作る、ときに、chunkの制限を加えたが、これの必要性はチェックしていない。まあ、やったことはやったので、書いておく。次のように変更した。
buff = queue.Queue(chunk)
バッファが一杯になる値を加えたのだが。必要なのか?
1、audio_interfaceとaudio_streamのオブジェクト生成に関する部分は、pyaudioのものなので、削除する。したがってそのクローズ処理も不要である。
2、record_audioの引数の最後にappを加える。
3、削除した行の代わりに、次の3行を加える
player = EchoRobotHumanSpeech(app, buff, rate)
app.session.registerService("MyEchoRobotHumanSpeech", player)
alaudio = player.start("MyEchoRobotHumanSpeech")
EchoRobotHumanSpeechは、次に説明するALAudioDevice利用のためのクラスであり、MyEchoRobotHumanSpeechは、モジュール名でNaoqiがモジュールの識別子とするものである。
4、yield _audio_data_generator(buff)の直後に、
alaudio.robot_audio.unsubscribe("MyEchoRobotHumanSpeech")
を加える。モジュールの終了処理である。
(5)クラスEchoRobotHumanSpeechの定義。基本は、(R)のSoundDownloadPlayerクラスである。ただ、このクラスは、pyaudioでパソコンから出力するようになっているのだが、それは不要であるので削除する。代わりに、Google APIへのストリーミングアップロード処理を加える。
1、コンストラクタの引数に、buff, rateを加える。rateはグローバル変数のRATEを使っても良いが、プログラムの質的にはここに引数を与えた方が良い。
2、コンストラクタに、次の2行を加える。record_audioのなかでQueueから作られるbuffは全体として、決定的に重要な役割を果たしている。
self.buff = buff
self.rate = rate
3、startメソドには、次の2行だけを残して、全て削除する
self.robot_audio.setClientPreferences(serviceName, self.rate, 3, 0)
self.robot_audio.subscribe(serviceName)
最初のものはデバイスのプリファレンスで、3は、前方マイクから音を取得するもの。次のものは、ストリーミングの開始メソッド、その後、コールバックがprocessRemoteに設定され、音声データが次々にそのコルバックに送られる。
(6)コールバックの設定:ここで色々詰まった。一番わからなかったが、次のようにすれば良い。
1、オリジナルのコールバック、
def _fill_buffer(buff, in_data, frame_count, time_info, status_flags):
は不要なので削除する。
2、次の新しいコールバックを、クラスEchoRobotHumanSpeechの中に設定する。
def processRemote(self, nbOfChannels, nbOfSamplesByChannel, timeStamp, in_data):
self.buff.put(str(in_data))
#print("processRemote No." + str(self.count) + " / in_data = " + str(len(in_data))
# + " サイズ = " + str(self.buff.qsize()))
return None
コメントを外して動かすと、コールバックがどのように呼び出されるか少しわかるだろう。
バッファにデータを文字列化して付け加えるというのも一つのポイントだが、これは、そうしないとエラーになるのですぐわかる。
(7)request_streamの日本語化などは、少し前の記事に詳細に書いたのでそれと同じである。
他は大きく変えなかったが、最終出力がラインフィードで同じ行を書き換える操作をしているので、何をしているかがわかりにくくなるから、常に改行してGoogleから送られてくるデータがどんなものかをわかるようにしたくらいだ。
できてしまえば簡単な感じなのだが、途中で分からなくて投げ出しそうになった。
ロボットマイクからストリーミングでGoogle APIに送って変換動画
変換している様子を動画に撮ったのでお見せする。
サリーを「寒い」と聞き間違った以外は、ほぼ正確。そのサリーも、最初は正しく聞き取っている。季節感を重視した変換になってしまったのかもしれない。そこが、人工知能らしいところか。
ついに動いた!!NAOの音声デバイスとGoogle Cloud APIのストリーミング連動
この間、NAOのマイクからの音声データをPC側でストリーミングで取得し、それをGoogle Cloud APIにそのままストリーミングで送り込み、ストリーミングでテキストに変換されたデータを受け取るという作業を行なっていたが、なんとか動いた。
NAOからデータを受け取るのは、ALAudioDeviceをpythonのqimessagingセッションだ。コールバックに入ってくるストリーミング音声データをQueueでうけとめ、一定量になったらGoogleに送り込み、テキスト化する。
二つをどう繋げるのか相当困惑したが、Google APIのサンプルのpyaudioを、ALAudioDeviceの機能に置き換えるのを基本にすれば動くことがわかった。
あとは、このテキストを整形して、ロボットに喋らせれば良いだけである。こちらは、ALTextToSpeechでもつかえば簡単にできる。エコーロボットになる。
パソコンは経由する。ネットで調べると、直接ロボットにpyaudioをインストールするという試みもあるようだが、結局、人工知能的な様々な処理はPC側でやらせた方が良いと思っている。ロボットのコンピュータの能力に制限されないから。
まだいま、出来たばっかりで、きちんと整理されていないので、それがそんだら詳しい報告をあげる。
言葉が通じないときの人工知能
ほぼ、雑談に近いが、Google Cloud APIで、ストリーミングとして言語解析する時、APIに今から喋ることは英語だと伝えて(設定して)、日本語を話した。すると、APIは、必死でその日本語の音声を英語として解釈、解析しようとする。当然、英語にはできない。それでも、なんとかその発音に近い英語の文章を返してくる。まさにこれだ、これが実に人工知能なのだ。とても面白い。人間が、理解できない外国語に出会った時にやっていることを再現しているようだ。
エコーロボット(echo robot)の考察
人間的知能の最もプリミティブな形態は、音を言葉に変えることだと思う。たとえば、見知らぬ外国語は言葉ではなく単なる音でしかない。しかし、それが言葉に変わった時、すべての人間的知能の基礎ができる。言葉は、まさにロゴスなのだ。
この間、Googoleのcloud apiのストリーミングの音声解析をやってきたが、結局それは、知能なのだ。非常に単純で、簡単なことをやっているように思われるかもしれないが、そこにこそ人工知能の基礎がある。音を連続的に言葉に変えること、それは素晴らしいことだと思う。確かに、その言葉を意味化することはできていない。しかし、決定的に重要な一歩だと思う。
そこで、エコーロボットというのを考えてみる。いや、実際に作ってみようと思う。人が話しかけた言葉を、そのまま鸚鵡返しに、自分で繰り返すのだ。音声を単にロボットの発音に変換するのではない。一旦、「言葉」してから、ロボットの音声としてそれを発するのだ。赤ちゃんが、お母さんの言葉を真似しながら、言葉を覚えていくことに似ている。マネができれば、その意味を少し理解して返せば、ごく簡単な人間的応答ができてしまうはずだ。お笑いで言えば、いつかそれがボケにつながる。
エコーロボットは、人工知能型ロボットの最も初歩的なもので、プログラミングで言えば、"Hello World" に対応するものだ。
そのための技術としては、まず、ロボットの音声データをストリーミングで受け取る必要がある。これは、ALAudioDeviceでできることがわかった。それを、GoogleのCloud APIに送って、これまたストリーミングで言葉化する。返ってきた言葉を、ロボットに送り込んでALTextSpeechで発生させる。
プログラミングのツボはだいたいわかったので、数日中にはできると思う。
ロボットのマイクを利用して音声ストリーミング認識
ここまでくると、次の課題は、NAOのマイクから入ってくる音声をGoogleのクラウドAPIに送って、ストリーミングで認識、テキストデータ化させることである。
これについては、Pepperで色々試された結果がウェッブにあるので、それを学んでなんとか二つを接合させれないかと考えている。
http://www.baku-dreameater.net/archives/9331
とか、
http://qiita.com/hanzo/items/bb89d021e170133b9d41
とかがとても参考になりそうです。
それができれば、ロボットが聞いた言葉をパソコン経由でGoogleにストリーミング送信し、返ってきたデータをパソコン上で解析して、結論をロボットに送り込んで喋らせれば良い。
Google Cloud の音声ストリーミング認識状況の動画
グーグルの音声認識のストリーミング版を利用している状況を動画に撮った。
文字列の表示うまくいっていないが、音声認識そのものはかなり正確に行われていることがわかっていただけると思う。
これをロボットに組み込みたい。
Googleのspeech recognitionのストリーミング版の試み
Googleのspeech recognitionのストリーミング版を試した。そのすごさにおどろかされた。
まず、それをやった手続きをいかに記録しておく。基本的に、
https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/speech/grpc
解説されていることをそのままやったのだが。しかし、手間はかかるし、混乱する。
以下、MACの場合を想定している。
(1)先の、スタティックな音声ファイルの認識で書いたように、Google Cloud Platformへの登録手続きは済ませておかなければならない。
(2)Google Cloud SDKをインストールする。
https://cloud.google.com/sdk/
から、自分の環境に適合したのものをインストールする。
./install.sh
で開始される。OSに合ったクイックスタートページをチェックしておく。
gcloud initをやると、色々聞かれてくるので、答える。プロジェクトの選択が大事。
gcloud infoなどのコマンドを試し確認しておく。
PATHの設定変更なども自動でするので、その後、
source ~/.bash_profile
は、やっておくこと。
(3)権限ファイルがまた必要になるので、先の音声ファイルの時にもやった、権限ファイルの位置を示す次のコマンドを先にやっておいた。ガイドでは後でやるようになっているが、この辺りは自信はない。ただ、私は先にやっておいた。しかしこれはやらなくても良い感じだ。
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account.json
(4)以下のコマンドで権限(authentication)の設定をする。
gcloud beta auth application-default login
このgcloudをじっこうすると、まず、gcloud Beta Commandsなどのコンポーネントがインストールされていないので、先にそれをやりますねというメッセージが出て、それを完了した時点で、あらためて上記のコマンドを自動で再起動しているようだ。
(5)途中、プラットフォームへのペジが開いて、ログインを求められるので、それを実行すると、権限ファイルが自動的に "default location"に保存されるようだ。
Credentials saved to file: [/Users/xxxxx/.config/gcloud/application_default_credentials.json]
というわけだ。
(6)PortAudioのインストール:brewがインストールされていれば
brew install portaudio
をやる。インストールされていなければ、インストールする。ただ、最後の実行段階で、audio系のエラーが出たので、結局、
pip install --global-option='build_ext' \
--global-option='-I/usr/local/include' \
--global-option='-L/usr/local/lib' \
pyaudio
をその後実行したら、エラーが出なくなった。クイックスタートのページでは、インストールの時点でエラーが出たらとなっていたが、その段階ではエラーがでなかった。
(9)virtualenvをインストールする。これがごちゃごちゃして、めどうだったが、そのウェッブサイトによれば、
$ [sudo] pip install virtualenv
でインストールできるようだ。sudoをつけて、root権限でインストールした方が良いと思う。
(10)virtualenvの実行と設定:以下のコマンドを実行する。
$ virtualenv env
$ source env/bin/activate
(11)サンプルを実行するための依存ファイルをインストールする。そのために、サイトに置かれているrequirements.txtの内容をコピーして、その名前のファイルとして、ローカルに作成しておく。そして、以下のコマンドを実行する。
$ sudo pip install -r requirements.txt
(12)pythonの実行ファイルのコピーと変更
サイトのtranscribe_streaming.pyをコピーして、ローカルのフォルダのファイルにする。コピーの際、インデントなどが崩れるとエラーになるので気をつけること。
唯一変更すべきところは、
language_code='en-US', # a BCP-47 language tag
の箇所を、
language_code='ja-JP', # a BCP-47 language tag
に変更する。変更しないと、こちらで喋ったことを全て、英語で返してくる。日本語として解釈するために必要な変更だ。
(12)ストリーミングによる認識、テキスト化の実行
$ python transcribe_streaming.py
を実行する。
パソコンのマイクに向かって、喋ると、ほとんどリアルタイムで、翻訳を返してくる!!!