Wed May 25 22:24:37 JST 2016

対話事例を取ってくる

「今起きた」「おそよう^^」

cat 2Dcat | awk '$0=$2' | grep -v null | while read id; do
  if [ ! -f "inreplyto/$id" ]; then
    twurl "/1.1/statuses/show.json?id=${id}" | jq -r .text > inreplyto/$id;
    sleep 10;
  fi;
done

LSTM 言語生成 [検索]

いわゆるNNs の型は [float; m] -> [float; n] である.
ここで [float; m] は長さ m で要素がすべて float とある配列を表現する型.
RNN (recurrent-NNs) の一つであるLSTMは [float; m] -> [float; m] である.
ただし、この機械は状態を持つ.
状態は一回の入出力によって変化する.
その状態で入出力が変化するので ([float; m], State) -> ([float; m], State) と書くのが正確である.
また初期状態という状態が定まっている.

応答文生成や自動翻訳にRNNが期待されている.
どちらともに、長さが不明な文1を入力に与えると、長さがやはり不明な文2が出力されるという機械にほかならない.

RNNの枠組みでこの機械を再現する素朴な方法は単純である.
文1を [float; m] に変換する.
これを x1 x2 .. xm とする.
これは例えば文字やトークンの列に相当する.

機械 RNN に x1 x2 .. xm を順に与える.
出力は初め気にしないが、xm を与えて出てきた出力を y1 として記録する.
次からは y1 を与えて出力を y2 とする
y2 を与えて出力を y3 とする
これを繰り返すことで無限長の出力列を得るが、
特殊な制御文字 </s> を考える.
これは決して他とは被らないという意味で特殊である.
出力 yn</s> になったとき、機械をとめ、それまでを出力とする.

初めの入力の最後 xm をやはり制御文字 </s> とする方法もあるし、別の制御文字を敢えて使うことも考えられる.
双方向RNNというのもある.
これは初め、x1 x2 .. xm と読むのではなく
xm .. x2 x1 x1 x2 .. xm と、まずはじめに逆順に読んで、その後に順に読むのである.
LSTMは昔読んだ入力を徐々に忘れていく.
繰り返し読むことでうまい具合に記憶しているっていう、技巧である.

実験 (小さいサンプル)

   ./gen.py test.model
> おはよう
おはようございます
> おはようございます
おやすみ
> おっはー
おやすみ
> 起きた
はい、おはよう
> 寝る
おはようございます
> もう寝よう
もう寝るの?!
> 寝ます
おやすみなさい
>

実験 (少し大きいサンプル)

平面ねこさんからは結局、1035の対話事例が得られた. 決して多くはないが、平面ろぼさんからコレ以上取るのは難しそうだ. 他のソースも考えよう.

とりあえずこれで演ってみる.

./train.py -i 2Dcat.txt -o 2Dcat.model --iteration 10000

実は公平に事例を選んでるわけではないのだが、平均的に10epoch学習したことになる.

ちなみに CPU 1個で22分かかった.

$ ./gen.py 2Dcat.model
> あ
うんんんだ
> ねえ
その話
> 元気?
うんんんんだ
> 元気してる?
そう
> ねえねえ
その話
> 大丈夫ですか
そう
> おい
そうだね
> しっかりして
そうだね
> ごめんね
なんだ
> おはよー
ふうん
> 今まで寝てた
その話しない
> 寝てた
その話しない
> …
そう
> ……
そうなの
> やたのしい
そんなの
> 楽しい
そう
> やだ
そう
> よし死のう
そうだね
> なにそれ
なんだ
> @@;
ふふむ
> ふふふ…
そう
> wwwwwwwwwwwwwwwwwwwwww
ふふふ
> テンション高いねー
なんだ
>

絶望