kerasでirisの分類をやってみたメモ
(注意)ただ、私が自分自身のkerasの学習のために書いたメモです。このエントリには、何も新しいことはありません。
kerasとは
kerasは有名なので、そんなに説明はいらないかと思うけれども、Pythonの深層学習ライブラリ。TensorflowやTheanoのラッパー的な位置づけで、ネットワークのモデルを簡単に記述できるフレームワーク。Caffeとか、Chainerとか、動かしたことあったけど、Kerasはなかったので、最近評判がいいと噂のkerasを触ってみることに。触った感じもめちゃくちゃ分かりやすいので、研究用途でなく、私みたいな深層学習との向き合い方をしている人には、keras最高じゃないかなと思います。
最近、ドキュメントが日本語に翻訳されているので、とても読みやすい。
Chainerとか、他のフレームワークとの比較は下記のSlideshareが何となく分かりやすい。
Deep Learningライブラリ 色々つかってみた感想まとめ // Speaker Deck
簡単なコードの説明
有名なirisの分類問題をkerasでやってみました。 ちなみに、バックエンドはtensor flowで実行しています。コードの全部は、gistに貼ってあります。
データの準備:irisデータ読み込み
from sklearn import datasets iris = datasets.load_iris() features = iris.data #特徴ベクトル targets = iris.target #分類ラベル
- ちなみに、featuresとtargetsのデータ構造像はこんな感じです
features
array([[ 5.1, 3.5, 1.4, 0.2], [ 4.9, 3. , 1.4, 0.2], [ 4.7, 3.2, 1.3, 0.2]・・・
targets
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
kerasに必要なものをインポート
from keras.models import Sequential from keras.layers import Dense, Activation
モデルの設定
model = Sequential() model.add(Dense(12, input_dim=4)) model.add(Activation('relu')) model.add(Dense(3, input_dim=12)) model.add(Activation('softmax')) model.compile(optimizer='SGD',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
上記で書いたモデルはこういう感じになります
- 入力層:4次元
- 隠れ層:12次元
- 出力層:3次元(3クラス分類問題のため)
- 各層の間の結合:Dense(全結合)
- 入力層→隠れ層の活性化関数:relu
- 隠れ層→出力層の活性化関数:softmax
- 最適化:SGD
- 損失関数:sparse_categorical_crossentropy
図に表すとこんな感じ
学習
model.fit(features, targets, nb_epoch=20, batch_size=5)
- kerasでは、こんな感じで標準出力に学習途中の結果を出してくれます
- さらにkerasのバックエンドをtensor flowにした場合は、結果をtensorboardでみることができます
- modelとかにcallbackを指定してあげる必要はあります
Epoch 1/20 150/150 [==============================] - 0s - loss: 1.2433 - acc: 0.5067 Epoch 2/20 150/150 [==============================] - 0s - loss: 0.6935 - acc: 0.6733 Epoch 3/20 150/150 [==============================] - 0s - loss: 0.6501 - acc: 0.7000 Epoch 4/20 150/150 [==============================] - 0s - loss: 0.6012 - acc: 0.6733 ・・・(以下略)・・・
学習モデルで予測
model.predict(features, batch_size=10, verbose=1)
- 上記で学習したモデルにデータを入れたときに、どういう予測をするのかを返えす
だた、今回は、kerasの動きを見たかっただけなので、全部学習データとしてつかっているので。なので、あまり意味はなくなっています。本来であれば、データを学習用とテスト用に分けておきます。
ちなみに、こんな感じで出力されます。今回は3クラス分類問題なので、3次元で出力されます。
array([[ 9.78549898e-01, 2.12393254e-02, 2.10749422e-04], [ 9.49374020e-01, 4.98638190e-02, 7.62094394e-04], [ 9.69367325e-01, 3.02073583e-02, 4.25341772e-04], [ 9.45379853e-01, 5.37167825e-02, 9.03351058e-04], ・・・(以下略)・・・
学習モデルの評価
model.metrics_names model.evaluate(features, targets, batch_size=10)
- 本来であれば、交差検定をやるべきなんですが、kerasの動きを見たかったので、交差検定やってません。
- なので、これは今回は動きを見る程度です
その他:いろいろやってみて思ったこと
損失関数の設定をまちがってやってみると・・・?
モデルの記述のところに、 sparse_categorical_crossentropy
ではなく、 categorical_crossentropy
と記述してみるとこんな感じに例外となった。
model = Sequential() model.add(Dense(12, input_dim=4)) model.add(Activation('relu')) model.add(Dense(3, input_dim=12)) model.add(Activation('softmax')) model.compile(optimizer='SGD',loss='categorical_crossentropy',metrics=['accuracy']) model.fit(features, targets, nb_epoch=20, batch_size=5)
- 例外部分
Exception: Error when checking model target: expected activation_22 to have shape (None, 3) but got array with shape (150, 1)
モデルのチェックでおかしいよと例外が飛んでいるのがわかったが、損失関数の設定がマズいと気づくのに少し時間がかかってしまった。もう少し、丁寧なメッセージだとありがたいが・・・。ちなみに、 categorical_crossentropy
は、数字ではなく、文字でのラベリングデータに使用するみたい(kearas_available-objectives)。
モデルのテストどうするんだ問題
上の損失関数の設定ミスでは、例外が飛んでミスとわかったが、ネットワークのモデリングについては、間違えても例外が飛ばず、自分のモデルの記述ミスに気がつかないケースもあって注意が必要だなと思った。
たとえば、irisは3クラス分類なのに、なぜか私は最初4クラス問題だと思い込んでしまっていて、最後の出力層の次元を4次元と設定していた。accuracyがちょっと上がりにくいなーと見直してようやく、自分のミスに気がついた。このようにミスがあっても、それでも何となくは動いてしまうので、テスト(品質保証の方)が難しいなーと思った。
活性化関数とか、モデルどうするんだ問題
初めのirisぐらいなら、雑に組んでも学習できるでしょと舐めきっていて(ごめんなさい)、単純にコードとしてkerasで組むことだけを考えていたので、ネットワーク設計は微塵も考えずに、relu使っておけばいいやと、隠れ層・出力層の活性化関数ともにコピペでreluに設定していた。
けれども、reluだと全然学習がうまくいかなかった。 このようにモデルを設定して、学習させたらacc: 0.3600 までしかいかなかった・・・。
model = Sequential() model.add(Dense(12, input_dim=4)) model.add(Activation('relu')) model.add(Dense(3, input_dim=12)) model.add(Activation('relu')) model.compile(optimizer='SGD',loss='sparse_categorical_crossentropy',metrics=['accuracy']) model.fit(features, targets, nb_epoch=20, batch_size=5)
ちなみに、出力層がsoftmaxとreluではこのぐらい違った。
- 出力層がsoftmax
- loss: 0.2591 - acc: 0.9667
- 出力層がrelu
- loss: 0.6949 - acc: 0.3600
多クラス分類の出力層にになんで、relu使っているんだ!?という疑問はおっしゃる通りなのですが、雑にネットワークモデルを組んで動かしても、精度がでないということは今後注意しておきたい(今までこの現象にあたってこなかったのは、単純に私の経験値不足かもしれないが)。
今回、kerasの実装を追いたいということで、モデルを考えずにreluをつかったけれど、DNNをやるときはそれではダメで、実装とネットワークモデルはセットにして考えないといけない(むしろ、ネットワークを先に設計してから、実装する方がいい)ということを再認識させられた。
ちなみに、2クラス分類、多クラス分類、回帰などの使い分けは機械学習プロフェッショナルシリーズの深層学習に載っていたりするが、下記を参考にしてもといいと思います。
www.slideshare.net
それにしてもKerasは直感的に記述できて、分かりやすい。研究でなく、動かしてみたいというのであれば、ほぼkerasでいいのではないかと思う。