TensorFlowのseq2seqを自前のデータセットで試す

[seq2seqで利用可能な日本語対話データセットをダウンロードするツール](http://qiita.com/knok/items/df7a155d17e3c9a12e94)の続きです。TensorFlowのseq2seqサンプルを、このデータで学習できるようにしてみました。

オリジナルのTensorFlowサンプルseq2seqは、WMTの配布する巨大な英仏翻訳のデータセットをダウンロード、展開して処理するコードが入っています。考えなしに動かせる点ではとてもお手軽で良いのですが、自分で用意したデータセットを与えるには向いていません。そこで、指定したディレクトリ上にあるinput.txt(encoder用データ)とoutput.txt(decoder用データ)を読みに行くよう修正したバージョンをgithubに置きました。オリジナルのコードに準じてApache 2.0ライセンスです。

[knok/tf-seq2seq-mod: Modified seq2seq on TensorFlow](https://github.com/knok/tf-seq2seq-mod)

これを動かす点順を以下に示します。TensorFlowが既に入っているものとします。UTF-8テキストを対象とした処理はpython2でしかうまく動かない点に気をつけてください。

# データの準備

```shell-session
$ git clone https://github.com/knok/make-meidai-dialogue
$ cd make-meidai-dialogue
$ make
$ nkf -w -X -Z0 sequence.txt | \ # 全角英数字、かなの正規化
sed -ne '/^input/s/^input: //p' | mecab -Owakati > input.txt
$ nkf -w -X -Z0 sequence.txt | \
sed -ne '/^output/s/^output: //p' | mecab -Owakati > output.txt
$ cd ..
```

# seq2seqの学習

```shell-session
$ mkdir train
$ git clone https://github.com/knok/tf-seq2seq-mod
$ cd tf-seq2seq-mod
$ python translate.py --data_dir ../make-meidai-daialogue --train_dir ../train \
 --size 400 \ # 中間層のユニットサイズ
 --en_vocab_size 10000 \ # 入力(Encoder)側の語彙数
 --fr_vocab_size 10000 \ # 出力(Decoder)側の語彙数
 --num_layers 1 \ # GRU/LSTM中間層の数
 --batch_size 5 # バッチサイズ
Creating vocabulary ../make-meidai-daialogue/output.vocab10000.fr from data ../tmp-data/output.txt
Creating vocabulary ../make-meidai-daialogue/input.vocab10000.en from data ../tmp-data/input.txt
Tokenizing data in ../make-meidai-daialogue/output.txt
Tokenizing data in ../make-meidai-daialogue/input.txt
Creating 1 layers of 400 units.
Created model with fresh parameters.
Reading training data (limit: 0).
global step 200 learning rate 0.5000 step-time 0.55 perplexity 480.04
  trg = もう 、 し 、 下 が
  hyp = うん 、 、 、 、 、 、 、 、 、 、 、 、 、 、
global step 400 learning rate 0.5000 step-time 0.63 perplexity 72.16
  trg = あ 、 そのまま で 、 まず 、 今 は 。
  hyp = うーん 。 0 。 。 0 。 0 。 。
(中略)
global step 3600 learning rate 0.5000 step-time 0.56 perplexity 25.57
  trg = でも 私 も 今日 来 て ない けど 、 0 人 、 出し た 人 から 。
  hyp = でも 、 、 は が た ない よ 、 ( 人 、 0 た よ ? 、
```

例示しているハイパーパラメーターは、GPUメモリ1GB程度で動かせる程度の規模です。余裕があるならvocab数やミニバッチサイズを増やしても良いでしょう。
オリジナルのソースを若干修正し、学習途中のdecoderの入出力を表示するようにしています。学習が進めば、入力と出力がだいたい同じようになってきます。

```
global step 8800 learning rate 0.4803 step-time 0.78 perplexity 17.91
  trg = あたし 、 何 か こう いう のに 録 る と 、 ( はい ) 全然 声 が 違う の  。
  hyp = うん が うん か ー 、 か 。 ない ん 思う ( うん ) うん うん が ない ん ?
global step 10200 learning rate 0.4803 step-time 0.91 perplexity 17.19
  trg = そこ ずーっと 開け て っ て 下 、 そこ の それ 。
  hyp = そう ? ない ない ない て ない ? ( ? ? は
global step 45600 learning rate 0.3553 step-time 0.54 perplexity 7.40
  trg = 本格 的 に 知ら ない ねえ 。
  hyp = 本格 的 に 知ら ない ん 。
global step 93600 learning rate 0.2215 step-time 0.53 perplexity 2.93
  trg = まず 行ける か どう か も 問題 な ん だ けど さ ー 。
  hyp = うん 行ける か な か なー さ じゃ ん じゃ けど さ ー 、
global step 126600 learning rate 0.1512 step-time 0.57 perplexity 1.77
  trg = うん 、 それで 、 ( うん ) わたし も びっくり し ちゃっ た 。
  hyp = なん 、 それで 、 ( うん ) あの は そう し た た 。
global step 467000 learning rate 0.0027 step-time 0.57 perplexity 1.02
  trg = デザート ・ ランチ バイキング 、 000 円 。
  hyp = デザート ・ ランチ バイキング 、 000 円 。
```

学習が進むにつれて、間違っている単語もそれほど外れていないものがだんだん選択されるようになってきています。Ctrl-C等で止めない限り学習は終了しないので、perplexityが十分下がったら強制終了させてください。

# デコード

引数--decodeを指定すると、対話的に入力するモードになります。適当な文章を入力しましょう。ただし、このプログラムでは内部で分かち書きを行わないので、mecab -Owakati等で処理した文字列を予め用意しておきましょう。

```shell-session
$ python translate.py --data_dir ../make-meidai-daialogue --train_dir ../train \
 --size 400 --en_vocab_size 10000 --fr_vocab_size 10000 --decode
Reading model parameters from /abs/path/to/trainn/translate.ckpt-1439600
> こんにちは
ー 。
> なん すか これ
なんか 、 この 言葉 が あっ た と 。
> こん ちゃ
うーん 。
> なん だ よ お め え
なん だろ う 。
> なん だって こと は 無い だろ 
ほんと 、 それ は いけ ない の かしら 。
> 
```

必ずしも同じ出力が出るとは限りませんが、くだけた文章だとそれなりの結果を返してくれる感じです。元のコーパスがくだけた文章ばかりなので、かしこまった文章だと応答がいまいちのようです。