Sunday, February 03, 2008

Software::JINKOU-MUNOU - MIU開発(1)

パトリンさんとこでMINAエンジンの人工無能さんと戯れたのがきっかけで,
ちょっと新しい人工無能を作るモチベーションが出てきました

土曜日にさくっと作ろうとか思っていたのですが,
システム全体図をまず練って,ここはこういう技術使おうとか考えて.
さくっと作れるようなもんじゃなくなりました(笑
まず設置場所が公共のサーバとなると次のような制約をもとで開発しなければいけません.

  • PerlのCPANやPPMでインストールできるようなモジュール,
    つまり標準モジュール以外のモジュールを利用するのは避けないといけない.
  • サーバリソースを食いまくるような処理は避けないといけない.
    たとえば以下のような処理.
    • 形態素解析を利用する
    • サーバ上で初めて辞書などを解析する,つまり前処理をまったくローカルで行わない 
辞書の問題はMINAのころから凄い気になっていて,
辞書4など文字列置換用辞書なんかもうちょい前もってどないか処理できないか,
と考えたこともありました.
ただ,入力としてユーザの発言を受け取り,
しかもその発言内容をMINAの発言内容として利用できるような仕様にしていたため,
MINAの発言は静的に決定できるものでもありませんでした.
ま,それでもある程度は辞書に対して前処理をある程度ほどこせたような気もします.


今回開発する人工無能,というか今までの人工無能とずいぶん違う気がするので
その名称は使わず,ロボットチャットでいいかなぁと思っています.
で,今回のロボットチャットMIUさん(漢字表記だと美羽.
MIUを漢字変換したらこれしか出てこなかったから美羽という安直な由来です).
辞書改めシナリオデータをバイナリに変換しちゃいます.
で,そのバイナリをサーバ上に設置したMIUサーバが読み取り,
クライアントプログラムであるブラウザとAjaxによる非同期通信で会話を進めていきます.

一個一個詳細を書きますと,
  • なぜ辞書じゃなくてシナリオデータとかいう呼称になっているのか
    • 会話の主導権をMIUに渡すとなると,MIU側である程度話の流れを作ることができるし作らないといけない.MINAなど辞書型でも過去発言検索機能により話の流れを作ることができたが,ユーザの自由な発言によりいくらでもその流れは壊すことはできた.MIUではユーザができる発言の自由度は限定されるので,MIUでは辞書というよりもシナリオを作っていく作業になる.
  • なぜバイナリに変換するのか
    • 上述した前処理の話と関連するが,シナリオデータになにがしかの前処理を加えてサーバ上でシナリオデータを読み込み,会話文を返すためにはメモリ節約の面からみてバイナリへの変換が有効.数値データを文字列として保存しておくのは阿呆.
    • またシナリオデータはxml形式にするが,xmlのパースのためには別途パースに必要なモジュールが必要であり,またパースする処理をサーバで行う必要がある.別途モジュールをサーバへインストールする必要がなく,かつサーバ上で最小限の処理でシナリオデータを読み込めるようにするためには,プログラムが解釈しやすい形へシナリオデータを変換する必要がある.
    • メモリ節約,プログラムが解釈しやすいフォーマットという面から,シナリオデータをバイナリへの変換することを選んだ
  • なぜAjaxなのか
    • 非同期通信+イベント・タイマー処理により,MINAよりも表現の幅が広がる.リッチインターフェースの実現や,ページ遷移がない円滑な会話処理などの実現が考えられる.またMIUがあたかもリアルタイムに考え,メッセージを入力しているという演出が可能になる.
という考えの下,MIUの構成を練っていました.
今日は,とりあえずIO部分ができないとテストしずらい!ってことで
Perlの配列をバイナリに落とす,つまりシリアライズ処理を書いていました.
シリアライズするんだったらSotrableや,データベースであるSDBMとかGDBM,DB_File使えよって話なんですが,
シナリオデータ読み取りの効率性を考えると,
独自フォーマットのシリアライズを実装したほうがいいんですよね.
やりたい処理というのが,StorableやDB_Fileとかじゃいまひとつ達成できないのです.
MLDBMなら達成できるんだけどなーと思ったりもしますが.
MLDBMにしちゃうとローカルで前処理,というのが実現しにくくなります.
確かDB_Fileとか,データベースファイルのバージョン互換性がなくて,
ローカルで作ったデータベースファイルがサーバ側では読めない,というケースがありえる.
ちなみに大学の実験ではMLDBM使ってます.
便利ですよねーあれ.

で,今日はとりあえずpack, unpack使って配列データをバイナリに落とし込んだり読み込んだりする処理を書いてました.
シリアライズ対象となるデータ構造が,配列と木構造,あとは構造体かなぁ.
構造体といっても,スカラーや配列をメンバに持つようなデータ構造です.
配列ができてしまえばちゃちゃっと作れちゃいそうな感はあります.

自前シリアライズを使う理由は,MLDBMとかじゃちょっと使うのに気が引ける,という理由以外にもあります.
仕様さえ決めておけば,他の言語でもシリアライズ可能だからです.
今回開発するMIUは,別にPerlをローカルマシンにインストールしなくてもよいかもしれないのです.
MINAは辞書のテストを行うためにローカルにPerlをインストールしなければなりませんでした.
このテストは,ほとんど辞書の書き方があっているかどうか,を確認するためのものです.
まぁ,学習データを作る,という目的でローカル上で走らせる,ということもあるでしょうけど.

MIUの場合,シナリオデータをバイナリへ変換する過程を踏みますから,
そこで文法チェックができます.
ま,xmlファイルをパースするってのが文法チェックということになるんですが,
そのほかデータがでかすぎだとかそのIDの振り方は変だとかいうチェックもできます.
ちなみにデータサイズの制限もあるんですよね,バイナリ変換すると.
走らせるマシンが,まぁ今はほとんど32ビットマシンです.
long型へpackしてもビット長は32ビットです.
どこにシナリオ文字列があるのかという,つまり文字列の位置を指し示すアドレスをlong値で保存するんで,
シナリオ文字列合計の上限が4GB(packできるlong値はなんか知りませんけど4byteなんで,
2の32乗byteが上限)になってしまうとかあります.
テキストデータで4G超えはなかなかないと思うんで,その制限はあってないようなもんだと思いますけど.

他の言語でもシリアライズ(つまりバイナリ変換)が可能と書きましたが,
つまるところ他の言語でのシリアライズを想定しています.
きっと誰かが他の言語でシリアライズしたがるだろうとかそんな理由じゃないです.
理由として,
  • Perlをローカルマシンにインストールしなくてもよいようにしたい
  • バイナリ変換プログラムをウインドウアプリケーションにしたい
    • Perl/Tkとかじゃなしに,たとえばC#とかでウインドウアプリケーションを書きたい
というところです.
バイナリ変換する手前のフォーマットがxmlである時点で,
手作業でシナリオデータ作成->xmlへのなにがしかの変換処理->xml->バイナリ
を考えていました.
xmlを簡単に作成するつったら,.NETでxmlへのシリアライズライブラリがありますよね.
人手でシナリオデータを作成するとき,そのシナリオデータの仕様をどうするのか,
エディタを自前で作る必要があるのかという話になりますが,とりあえずそこは深く練らず.
人手によるシナリオデータからバイナリファイルまでのパスができあがったので,
とかくxmlをバイナリへおとす処理を書けば簡単なテストはできるし,開発着手してっても大丈夫かなと思い,
今日は配列シリアライズプログラムを書いていました.

操作する対象が配列なんで,ついでにTIEARRAY使って
バイナリファイル読み込んでいる雰囲気を隠蔽してみました.
隠蔽すれば,いろんなアルゴリズム,サブルーチンへ応用できますしね.
たとえば,
fetch($index)
とかやって要素を取得するとかよりも,配列のようにアクセスできればforeach文も使えます.

なんだかさくっと,というレベルの話じゃないんですが,
夢のような話をしているわけでもなく,
毎晩帰宅後に開発していけば大丈夫そうなレベルです.

Ajaxを使ったインターフェース開発や,テスト用のシナリオデータ作成とか,
可能ならシナリオエディタ,そのほかなにがしかのエディタ向けシナリオ作成プラグインとか
作らないといけないんですが.
とりあえず明日は木構造シリアライズモジュール作成ですね.

No comments: