word2vecでロボットに言葉の演算をやらせた

この間、ずっとはまっていたのは、word2vecを使い、wikipediaに登場する単語を演算可能にすることだった。そこに、ボケの匂いを感じたのだ。word2vecは、ニューラルネットを使って、言葉を数量ベクトル化する手法だ。すると、言葉の演算がベクトル演算に変化できて、面白い結果が出てくる。
http://www.blog.umentu.work/ubuntu-word2vec%E3%81%A7%E6%97%A5%E6%9C%AC%E8%AA%9E%E7%89%88wikipedia%E3%82%92%E8%87%AA%E7%84%B6%E8%A8%80%E8%AA%9E%E5%87%A6%E7%90%86%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/

http://qiita.com/tsuruchan/items/7d3af5c5e9182230db4e
を参考にした。
wikipediaデータをmecabで分かち書きした膨大な単語について、演算が可能になった。たとえば、
ギター+キーボード
という演算をやらせると「セッション」になるとか。面白い。ネタになる。
隠れユニット200個で、学習結果のウェイトマトリクスデータが、900メガバイトを超える。
このデータは、ロボットNAOのストレージには入らない。そこで、NAOのUSBポートからデータをロードしようとしたら、当然のことなのだが、mallocで確保しようとしたヒープのメモリが、確保できない。仕方がないので、このデータを処理するライブラリを、パソコン上において、naoqiのリモートライブラリとすることで解決した。
人工知能など、およそ、その機能をロボットに全部組み込む事は不可能なので、PC上のリモートライブラリにするのはある意味自然なのだが、ロボットを立ち上げ、さらにリモートでライブラリを立ち上げるのは面倒だ。
しかも、言葉の聞き取りは、これも実に面倒なのだが、qichatを使って、トリがを与え、ロボットに喋りかけた言葉をwav音声データにして、パソコン上のサーバーに送って、それをさらにrawデータに変換したりして、Google cloud APIの音声認識システムに送って、テキスト化し、それをまたパソコン上で、形態素分析して、必要なデータを取り出し、またロボットのqichatのスクリプトの中にイベントとして取り組むと言う、質面倒臭いことをやる。それで、10秒くらい使ってしまうのが痛い。
しかし、まあ、これで、結構な人工知能をロボットに組み込んだことになる。

Google Cloud APIのストリーミングを継続して使う

Google Cloud APIのストリーミング音声認識を、ロボットとの継続した対話に使おうとすると、60秒の制限があって、それ以上使えずに、例外が発生してアボートしてしまう。これでは使えない。
そこで、gracefull(優美)に一つの会話を終了させながら、次の会話に入っていくということがどうしても必要になる。その基本的なやり方を以下に記しておく。
(1)ロボットからの音声データのストリーミング入力は、それとして生かしておくという戦略。
(2)Google Cloudからは、送られたーデータの解析結果が中間的に、最終的にの二つのバージョンで送られて来るが、最終バージョンが送られて来たら、それを一旦出力(エコーロボットとしてロボットに喋らせる、あるいは、人間入力の言葉を解析して応答を用意したりして)
(3)これで例外を発生させずに終わるが、これだと一回の聞き取りしかできなくなってしまう。そこで、
requests = request_stream(buffered_audio_data, RATE)
のスレッドの作成から、再度はじめ直す必要がある。そこでここからを関数化して、先の終了後に、再帰的にこの関数を呼び出すようにすればいい。すると、また60秒制限の新しいスレッドが立ち上がる。無限続けるのは良くないので、いったい何度ロボットやり取りするかを事前に与えておいて、その回数の会話をしたら全てを終了させるようにすれば良い。
(4)一つ問題は、(2)で、会話が入れば、一つのスレッドはグレースフルに終わるが、無言の時間が続くと終わるタイミングを逃して例外を発生させてしまう。そこで、60秒以内の一定時間無言が続くと、一旦gracefullに終わらせる。
そこで、次のようなタイマーイベントを、先に分離した関数部分の中に置いておく、
###############
def stopAPI():
print "ループを止めます"
recognize_stream.cancel()
#ここまでが関数、以下でタイマーでこのハンドラーを呼び出す
t=threading.Timer(MAX_SILENT_LENGTH,stopAPI)
t.start()
###############
関数の中にstopAPIという関数を定義して、MAX_SILENT_LENGTHの秒数が経過すると、
recognize_stream.cancel()
というイベントを発生させる。すると、CANCELLという例外が発生して、綺麗に終わるように例外処理手続きが組み込まれているのでうまくいく。そしてこの例外処理が終わった後、さいど、先に作成した関数、request_streamから始める関数をスタートさせれば良い。
これで、指定回数の会話が終わるまで、継続的にGoogle Cloud APIでストリーミング処理を続けることができる。
これで、人工無脳の会話ボットと、ロボットNAO、そしてGoogle Cloud APIの三つをつなぐ準備が80%ほど、整った。

ibotのライブラリにタイマーコマンドを加える

ロボットと何かパフォーマンスをやっているときに、尺が気になる。時間切れで失格ということが実際にあるからだ。そこで、対話システム用のコマンドに、タイマーコマンドを作成した。
トピックファイルの中に、
$wscom_starttimer_1=タイマー秒数
をいれると、それが実行された段階で、指定秒数のタイマーがスタートする。時間が来ると割り込みイベントが発生するので、それを、トピックファイルのイベント関数で、たとえば、
u:(e:TIMEOUT) 時間が来ました
のように、しておけばよい。
途中でタイマーを止める時は、
$wscom_stoptimer_1=1
をトピックファイルに埋め込んでおけば良い。

ロボット植え込みiBotは、ほぼできた

途中、ロボットのウェッブサーバーをapache2にしようかという迷いがあったが、結局、originalのnginxを使った。これからは、本番は、スマホだけで全て処理できる。
こちらに何か支障があれば、今まで通りノートブックのサーバー上のiBotでもコントロールできるので、セキュリティが高まった。
ロボット植え込みiBotの弱点は、パソコンからのファイル転送をftpなどに頼らなければならないところだ。これも、nginx用のfcgiを使えるようになればなんとかなるので、しばらくそれに取り組みたい。
それが終わったら、 クラウドの人工知能機能を利用する段取りに入りたい。

ロボットnaoにapache2ウェッブサーバーをインストール

前に書いた理由で、新たにnaoにapache2をインストールすることにした。手順をメモがわりに書いておく。
(1)apache2の最新版をダウンロードする。ここでは、apache2-2.4.25を使った。
(2)opennaoバーチャルロボットにpsftpなどで転送し、解凍する
(3)解凍したフォルダで、./configure --prefix=ロボット上のインストールしたいフォルダの指定する。私は、rootじゃなく、naoで実行したいので、/home/nao 以下のフォルダを指定した。
(4)普通にmakeとmake installを実行する。エラーは出ない。
(5)インストールしたフォルダごとアーカイブし、naoの実機に転送する。
(6)httpd.confを編集する。私の場合は、portを80から8080に変更。変更しないと、通常のrobotページとバッティングするので。cgiを動かす設定、ドメイン名がコメントアウトされているのをそのまま外す。関係のないドメイン名になっているが、コメントアウトするとスタート時に警告が出るを避けるだけの目的。
(7)ただ、これだけでは、apachectl startとやるとライブラリがらみのエラーが出て、実行できない。そこで以下の操作をやる。
opennaoの/usr/libディレクトリから、次の二つのファイルを取ってくる。
libaprutil-1.so.0
libapr-1.so.0
これをapache2のあるフォルダ以下libフォルダを作成してその下に入れておく。今そのフォルダを、
/home/nao/hoge/lib
だったとしよう。/etc/ld.so.conf.d/にnanoを使って、apache.confファイルを作り、そこに、上記フォルダのパスを書いて保存する。
ロボットのrootになって、ldconfigを実行する。その後、
ldconfig -p | grep libapr
をrootで実行すると、
libaprutil-1.so.0 (libc6) => /home/nao/ibot/www/lib/libaprutil-1.so.0
libapr-1.so.0 (libc6) => /home/nao/ibot/www/lib/libapr-1.so.0
となり、これでOKである。
あとは、ポートを8080にしている限り、rootにならなくても、naoユーザーのままで、apachectl
./bin/apachectl start
を起動すれば、サーバーが立ち上がり、ロボットのipとポートを指定すると、
と、無事立ち上がった。

ロボットにapache2を入れようと

naoには、nginxというウェッブサーバーが入っている。それはそれでいい。しかし、c++で作った実行ファイルをcgiにしたいのだが、nginxにはcgiを直接動かす機能がないので、fastcgiなどを追加しなきゃいけないらしい。それもまた入っているようなのだが、pythonしか動かないような設定になっているように見える。nginxやfastcgiに不慣れなので、不確かなのだが。
これ以上、いじると、元のロボットページなどに影響が出るかもしれないので、別にウェッブサーバーを動かそうと思う。ポートを、80じゃなくて、8080あたりにしておけば、nginxとバッティングしないだろう。
apache2は長年使い慣れている。ちょっと重たいが、まあ、それほどディスクを食うわけではない。
ただ、前にも書いたように、ロボットには、g++などの開発ツールは入っていないので、opennaoというvirtual-naoを使う必要がある。ここで開発すれば、まあ、naoに持ち込めると踏んでいる。そこで、opennaoでapache2をコンパイルするところまではやった。
あとは、ロボットに持ち込んで、動かすだけだが、今日はこれ以上それをやっている余裕はないので、やめておく。明日は時間が取れると思う。

埋め込み用ibotサイト

ロボットをコントロールするためのWEBシステムibotをロボット自身のサーバー上で動かすための改変をしていたが、それは終えた。いざ、通常のロボットサイトの下にibotというフォルダを作りそこに入れようとしたら、そもそも、ロボットのLinuxでphpが動いていないことに気づいた。
phpでサーバーサイドの処理を行うhtml5システムなので、困った。phpを入れようとすると、gccやらgmakeなどをインストールしなければならず、それが限りなく重たい。そこで、naoqiの指摘ライブラリの中で、ファイルを操作などを行うようにしようと思った。つまり、javascriptからqimessaging.jsでC++で作成したnaoqiのライブラリを呼び出して、サーバー内のファイル操作をやらせるのだ。ただ、パソコンからのファイルのアップロードの受け取り処理をphpにやらせていたのだが、それをライブラリでやる方法が今ひとつわからない。

ibotをバージョンアップする

一つ大きな仕事があって、安定したibotシステムで対応しなければならなかったので、本格的な変更を全くしなかった。それが終わって、これからもっといいシステムにする。当面の改良すべき点は、
(1)複数ロボットを扱っている時Qimessaging.jsからsessionオブジェクトを、毎回作り直していたが、これが無駄なので、sessionを連想配列の中に入れて、使い回せるようにする。
(2)telepathyがやはり不安定なので、現在のような複数ロボットの起動時に、他のすべてのロボットの状態をすべて認識するというのはそのままに生かして、それをたとえやらなくても、あるいは既にやっていたとしても、ibotクライアント側が持っているすべてのロボット情報を事後的にロボットに送り込んで、telepathy通信に用いられるようにする。
さらに抜本的には、先に書いたロボットの聞いた言葉をクライアント側で、文字列に起こして人工知能的処理ができるようにしたい。

Juliusにwav音声ファイルをテキスト化させる

先の投稿の手続きの段階の、chromeのweb speech apiの代わりに、juliusを使えないかと試したところ、ほぼ、問題ないレベルで答えを出すことがわかった。
Juliusにwavファイルで、音声データを与えて、それをテキストに変換させてみた。

 
 
これで、プロセスとプログラムが、単純化される。

音声認識でweb speech api を使う

今日考えていたことをメモがわりに書いておこう。
(1)ロボットNAOが受け取った人の言葉を音声ファイルに出力することは制御できるだろう。C++でライブラリ化することができる。
(2)そのファイルをPC、つまりMACbookに、無線ネットワーク経由で送ることもできる。
(3)MacでChromeを開いていて、ibotサイトを表示しているとすると、Chromeのweb speech api が使えるだろう。
(4)受け取った音声ファイルをJAVAで、実際の音として出力することはできるだろう。
(5)その音を、物理的コードを使って、マイク入力として直接入力することができるだろう。
(6)その入力に反応して、音声をweb speech apiがテキスト化することができるだろう。
(7)javascriptからjavaを呼びだして、そのテキストを、JAVAで解析して、求める答えを構成させることができたとする。
(8)それをロボットに送り込み、qichatの変数に組み込み、それを読み出させるイベントを発生させることができるだろう。
(9)ロボットは、その内容を喋るだろう。
※PCはインターネットに接続していなければならない。
以上