機械学習でサイコロの目をカウントするモデルを作成する
最近機械学習が楽しい。時代の波に乗っているものというのは遊んでも仕事に使っても楽しいものだ。
先日サイコロをOpenCVでカウントするプログラムを作ってみたが、これを機械学習で実現してみたいと思ったのでやってみる。
機械学習で実装すると、認識が堅牢になることが期待される。
サイコロがひとつ写った画像を認識するモデルを作成
Chainer(Preferred Networks社謹製)でさくっとかいた。
(勉強には時間がかかった。さくっとかけるのはChainerが素晴らしいだけだ。肝に銘じよう)
モデルはたった5層のCNN(Convolutional Neural Network)。
最近流行りの深層学習からすると、だいぶシンプルなモデルで十分な性能を得ることができる。
https://github.com/yudai09/count_saikoro/blob/master/cnn/single/models/CNN.pygithub.com
入力画像の例
この入力画像に対するラベル(教師)は1となる。
処理概要
- サイズが(32, 32, 3)の小さな画像を入力(撮影したあとで圧縮した)
- 畳み込み層を3層、全結合層を2層に設定
- 最後の層(出力に最も近い層)の活性化関数をsoftmaxに設定しクラス分類
単一のサイコロの写真を2つ写し合計を計算するモデルを作成
仕事で多入力、1出力のモデルを開発する必要があったので、 実験として作ってみた。
画像は上と同じ(サイコロがひとつ写った)画像を流用した。
異なるのは
- 写真を2つを同時にネットワークに入力していること
- その2つの写真のサイコロの目を足し合わせたものを正解のラベルとして扱っていること
フレームワークはいろいろ試してみたかったのでPytorchを使ってみた。 Kerasも使ってみたが、簡単に使える反面で柔軟性にかけるし、生のTensorflowは触る気が起きなかった。 そしてChainerと同じぐらい柔軟で、海外でも流行っているというPytorchに魅力を感じた。 Caffeがよい、と言う話も見かけたが、どうなんだろう。後日試してみたいと思う。
ちなみに、このレベルの実装だと、Chainerとの違いは全結合層の手前でview()を呼ぶことぐらいかなぁという感じだ。
もっと実装を重ねていけば見えてくるものもあるだろう。
モデルはこんな感じ。
class MyModel(torch.nn.Module): def __init__(self, nb_class): super(MyModel, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(3, 64, 5), nn.Conv2d(64, 64, 5), nn.Conv2d(64, 128, 5)) self.conv2 = nn.Sequential( nn.Conv2d(3, 64, 5), nn.Conv2d(64, 64, 5), nn.Conv2d(64, 128, 5)) self.fc = nn.Sequential( nn.Linear(128 * 20 * 20 * 2, 120), nn.Linear(120, 84), nn.Linear(84, nb_class), ) def forward(self, x, y): x1 = self.conv1(x) x2 = self.conv2(y) x1 = x1.view(-1, 128 * 20 * 20) x2 = x2.view(-1, 128 * 20 * 20) x1x2 = torch.cat((x1, x2), 1) return self.fc(x1x2)
2つの同じ形状の畳み込み層にそれぞれサイコロの写真を入力し、その出力をtorch.cat
で結合し全結合層へ入力している。
早々にValidationデータに対する正答率が100%に近づく。気持ちいいぐらいに。
OpenCVとおなじことを実現するのはサボった
2つのサイコロの写真の合計の目を出力するモデルの作成は割愛した。 同じことをすれば多少なりとも比較ができてよいのだが、興味がなくなってしまったのだ。
また、必要がでてきたら実装したいと思う。