備忘録とか日常とか

学んだこととかを書きます。

Deeplearningライブラリ「Keras」でつまずいたこと

DeeplearningライブラリのKerasを使っているときにはまったことをいくつかメモ。
ほぼ自分用かもしれない


今までTheanoを使ってアルゴリズムの勉強かついろいろ実験していたのだが、
勉強にはなるものの一から新しいアルゴリズムを実装するのはなかなかしんどいので
Theanoのラッパーとして使えるKerasを使ってみた

他にも色々あるっぽいけど評判良さそうなので。。
そのうち浮気するかもしれん


ちょっと使って見たところ、何個か細かい点でつまずいたのでメモしておく。
バックエンドはTheanoしか使っていないのでTensorflowについてはわかりません

ラベルはバイナリベクトルで扱う

まずこれ。
keras.datasetsからmnistなどのデータセットを取ってこれる。
mnistの場合だと以下

import keras.datasets import mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()

mnist.load_data()の戻り値はタプル*2

Xは(n_samples, row, column)という形のnp.arrayで、
yは0~9のint型の数値を持つ(n_samples,)という形のnp.arrayとなっている
Kerasはラベルを数値ではなく、0or1を要素に持つベクトルで扱うらしい
つまりあるサンプルに対するターゲットを「3」だとすると

[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

みたいな感じにしなければならない。

これは以下のように解決できる。

from keras.utils import np_utils
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)

(n_samples, n_classes)というnp.arrayがそれぞれのyに代入される。

入力データは[0,1]の範囲に正規化しなければならない

これが一番わかりにくかった
mnistの場合だと,まず入力データはint型になっているので変換する
その後画素値の最大である255で割り算しておく

X_train = X_train.reshape(X_train.shape[0], 28, 28).astype("float32")
X_train /= 255.0

こうしないと一向に学習が進まない。
Theano使ってるときは特にこういった処理はしなくても学習できたので
判明するまで丸二日くらいかかった

ドキュメントのわかりやすいとこに書いといてほしいです。。

poolingのフィルタがはみ出る場合は端っこのピクセルを無視する

細かい点だけど。
Theanoでプーリングを行う場合はtheano.tensor.signal.poolを使うのだが
フィルタサイズやストライドに加えてignore_borderという引数をとる。
これは例えばフィルタサイズ(3,3)、ストライド(2,2)みたいな設定にしたときに、
特徴マップの端でフィルタがはみ出した場合の扱いを決定する引数である。
図の例↓

f:id:may46onez:20151221223401p:plain

ignore_border=Trueとすると、はみ出た分のプーリングは行わない
つまり上図の例だと出力の特徴マップは(2,2)となる

この引数が、TheanoのデフォルトではFalseになっているのが
KerasだとTrueになっている

あまり性能に影響は出ないと思われるが、特徴マップのサイズがあまりにも小さくなりすぎると
認識率が落ちることが(自分の経験では)多々あったので
自分でネットワーク構造を考える場合は気に留めといたほうがいいかもしれない。

シークバー処理中にValueErrorを吐かれる

Kerasのいいところの一つに、学習状況などをシークバーでお知らせしてくれる機能がある
こんなの↓

Epoch 1/20
60816/60816 [==============================] - 19s - loss: 0.1665 - acc: 0.9597 
Epoch 2/20
31200/60816 [==============>...............] - ETA: 8s - loss: 0.1583 - acc: 0.9612

あとどれぐらいで学習が終わるか、lossがどれぐらい減少しているか、
学習データに対する認識率はどうか、
validationセットを指定した場合はそれに対する認識率もリアルタイムで表示される。

非常に便利な機能なのだが、
たまに以下のようなエラーを吐くことがある

ValueError: I/O operation on closed file

これはipythonでのバグらしいのだが、
今のところこれを根本的に解決する方法がないらしい・・・
丸一日かけて学習していたモデルが途中で止まったらかなりげんなりするだろう。
現に自分はした。

とりあえずの解決策としては、model.fit()の引数にverbose=0とする
これでシークバーが表示されなくなるのでエラーは回避できるが、
せっかくの便利機能が使えなくなる。。


公式の対応に期待か。