やりたかったこと
コスプレイヤーの画像から、その元ネタを当てる、というものを作りたかった。
タイトルの通り。
機械学習で何か作りたいけどアイデアがない、といったことを彼女に相談してみたところ、コスプレイヤーである彼女が「こういうのはどう?」と提案してくれた。
しかし学習のために画像を集めているときに大変気持ち悪がられてしまうという予想外の事態になってしまったので、このへんで終了して別のものを作ろうと思う。
コンセプトはなかなか面白いし役にたつ可能性もあるので誰かに意思を継いでもらえれば嬉しい。
モデル
畳み込み(24 x 3 x 3)
↓
畳み込み(42 x 3 x 3)
↓
ドロップアウト: 50%
↓
maxプーリング(2 x 2)
↓
(Flattenしておく)
全結合: 出力500
↓
ドロップアウト: 20%
↓
全結合: 出力200
↓
全結合: 出力は分類するクラスの数
中間層の活性化関数はすべてReLU。
model.summary() の結果
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 128, 128, 24) 672 _________________________________________________________________ activation (Activation) (None, 128, 128, 24) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 126, 126, 42) 9114 _________________________________________________________________ dropout (Dropout) (None, 126, 126, 42) 0 _________________________________________________________________ activation_1 (Activation) (None, 126, 126, 42) 0 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 63, 63, 42) 0 _________________________________________________________________ flatten (Flatten) (None, 166698) 0 _________________________________________________________________ dense (Dense) (None, 500) 83349500 _________________________________________________________________ dropout_1 (Dropout) (None, 500) 0 _________________________________________________________________ dense_1 (Dense) (None, 200) 100200 _________________________________________________________________ dense_2 (Dense) (None, 6) 1206 ================================================================= Total params: 83,460,692 Trainable params: 83,460,692 Non-trainable params: 0 _________________________________________________________________
用意したクラス
の6クラスを用意してみた。
画像のラベル付けは(作りが悪くなければ)フォルダにぶち込むだけで済むのでテキストの分類に比べると楽だなー等と思いつつ、インターネットで適当に各120枚くらい集めた。
各100ちょっとでは学習データとしてあまりにも心もとないので、 コントラストや明度などをいじった水増しデータも用意して2000枚くらいに増やしてみたが、過学習を起こしまくって逆に精度が下がってしまった(ので学習に使ったデータはオリジナルのみ)
精度は?
テストデータはもちろん分けたうえで
586/586 [==============================] - 8s 13ms/step - loss: 11.1606 - acc: 0.1928 Epoch 2/10 586/586 [==============================] - 2s 3ms/step - loss: 2.0719 - acc: 0.4761 Epoch 3/10 586/586 [==============================] - 2s 3ms/step - loss: 0.5985 - acc: 0.8225 Epoch 4/10 586/586 [==============================] - 2s 3ms/step - loss: 0.2646 - acc: 0.9403 Epoch 5/10 586/586 [==============================] - 2s 3ms/step - loss: 0.0915 - acc: 0.9812 Epoch 6/10 586/586 [==============================] - 2s 3ms/step - loss: 0.0432 - acc: 0.9966 Epoch 7/10 586/586 [==============================] - 2s 3ms/step - loss: 0.0106 - acc: 0.9966 Epoch 8/10 586/586 [==============================] - 2s 3ms/step - loss: 0.0065 - acc: 1.0000 Epoch 9/10 586/586 [==============================] - 2s 3ms/step - loss: 0.0019 - acc: 1.0000 Epoch 10/10 586/586 [==============================] - 2s 3ms/step - loss: 9.6496e-04 - acc: 1.0000 91/91 [==============================] - 0s 2ms/step 0.8021977949928452
最後の 0.8021977949928452
がテストデータを使った検証(model.evaluate)の結果。
8エポック目からaccuracyが1に達してしまい、明らかに過学習を起こしてしまっているが、学習に使ったのがたった100枚程度の画像だということを加味すれば正解率80%は悪くはない。
データをもう少し綺麗にする、丁寧に水増しする、新しいデータを調達する等すればもっと上がるだろうと思う。
おまけ
Webで動かしてみたかったのでDjangoでウェブアプリケーションにして組み込んでみたがいろいろと大変で学びがあった
h5ファイルがでかい
学習はあらかじめ開発環境で済ませておいてh5ファイルとして保存しておく。
そのh5ファイルが学習したパラメータを持っているだけにとにかくでかい(今回は1GB少し)。
これをメモリにロードすることになるので、学習させる必要はなくてもある程度のスペックが求められる。
Linodeの8GBでどうにか動いたが$40/month。つらい。
Djangoアプリに組み込む場合の定石 is 何
Djangoの知見がなくどうしたらいいかよくわからなかったが、もしRailsならinitializersでモデルを読み込むだろうと考えてapps.pyで読み込んだ。合ってるんだろうか。。。
しばらく公開しておく
2018/10/19までは動かしておくので興味があれば。
nginxまともに設定してないのでいろいろとエラーが見えるかも
http://xxx.xxx.xxx.xxx/classifier/
注: 2018/10/20にインスタンスごと抹消予定
2018/10/27 追記
消しました