可変長のミニバッチ、softmax_cross_entropyに-1、EmbedIDの謎挙動など
ほとんどChainer専用ブログになってきたのでタイトルにChainerメモって付けるのやめました。
https://groups.google.com/forum/#!topic/chainer/VFbZCgccs6I
ここで少し言及されていたので。
[明日 晴]
[今日 は 雨]
[本当 に 凄い 雪]
こういう可変長をミニバッチで学習させる時に長さが違うので困る。
[0 1]
[2 3 4]
[5 6 7 8]
次元が合わない。
なので-1で埋めて長さを合わせる。
[0 1 -1 -1]
[2 3 4 -1]
[5 6 7 8]
これをひっくり返して
[0 2 5]
[ 1 3 6]
[-1 4 7]
[ -1 -1 8]
こうしてからRNNに投げる
最初は
[0 2 5] これがx
[ 1 3 6] これがt(正解)
これは問題ない。
次は一つずらして
[ 1 3 6] これがx
[-1 4 7] これがt(正解)
ここで正解データに-1が登場する。
chainer1.4からはsoftmax_cross_entropyの正解(t)に-1を投げるとそれを「無視」してくれるようになった。
http://docs.chainer.org/en/stable/reference/functions.html?#chainer.functions.softmax_cross_entropy
t (Variable) – Variable holding an int32 vector of groundtruth labels. If t[i] == -1, correspondig x[i] is ignored.
Chainer1.4.0がリリースされました - studylog/北の雲 (一番最後)
「無視」というのが正確にどうなってるのか中のコードを読んでないのでわからないけど、ようする計算しない?と解釈してます。ここまでは問題ない。
そんで次は色々と問題が出てくる。
[-1 4 7] x
[ -1 -1 8] t
xに-1が含まれてしまう。
これやっちゃうとどうなるかというと、EmbedIDに-1を投げてることになる。存在しないはずの-1なんだけど、なぜか普通にWなどの値が返ってきたりする。たまにnanの時もある。CPUだと何らかの値が返ってくる事が多いけどGPUだとnan率が高いなどと、まちまち。いずれにせよ-1は存在しないはずなのにエラーが出ないので見かけ上はそのまま学習が進む。
でもGPUだとすぐ破綻してlossがnanになる。CPUだとなぜかnanにはならない。よくわからない。
とにかくxに-1を含めちゃいけない。めちゃくちゃになる。
(EmbedIDに-1投げたらエラーが出るべきなのかなと思ってますが…。)
この回避策としてxに-1が含まれてたら自分はEOSに該当するidに変えるようにしている。これだと弊害が少ないはず。EOSのvocab_idが100だとしたら
[-1 4 7] x
[ -1 -1 8] t
を
[100 4 7] x
[ -1 -1 8] t
に変えてから学習してる。これでちゃんと学習できるようになったけどモヤモヤする。本当はこうしたい。
あおのたす on Twitter: "任意長のデータをchainerのLSTMでミニバッチでエンコードしたい場合、どうすればいいのだろうか…0埋めするとエンコードした場合最終的なhがzero vectorになってしまう。" (会話の下の方)
https://groups.google.com/forum/#!topic/chainer/M7ea5yAjdWM
でも意味がよくわからないので保留してる。
追記:解決しました
ついでにEmbedIDの謎挙動
n_vocab=10でEmbedID作って、
- 10を超えた場合
CPU すぐエラーが出る。(IndexError: index 10 is out of bounds for size 10)
GPU 超えてもかなり大丈夫、いつかこれでとまる (cupy.cuda.runtime.CUDARuntimeError: cudaErrorIllegalAddress: an illegal memory access was encountered)
- マイナス値
CPU、GPUともにエラーでない 全部nanで埋まってたりすることもある
これが正しい挙動なのかバグなのかはよくわからないけど、気をつけないと危険。