先生
ねえ。

管理人
はい?

先生
このブログのタイトル何?

管理人
趣味で始める機械学習ですが。。。

先生
機械学習に関する記事なくね?

管理人
いや、あの。。。

先生
言い訳はいいからサッサと書け

管理人
はい

前回は、データを探そうと思ったらネットに落ちてなくて本を買った所までを書かせていただきました。今回は、買った本から教師用データを集めて学習をさせていこうと思います。

教師用データを集める

まずは、実際に購入した本からウォーリーを探しては写真に収めていく作業を行って教師用データを集めていきました。

管理人
あ、これが機械学習のエンジニアがその道のプロになるという所以かな

とかが頭をよぎりつつ、以下の作業を3時間ほど行いました。

  • ウォーリーを探す
  • 携帯で写真を撮る
  • 撮った画像をPCに送る
  • ウォーリーの所だけを切り抜く
  • 適当なサイズに保存する

おかげで、ウォーリーの画像が携帯の写真フォルダを埋め尽くし、後悔が自分の気持ちをどんどん下げていきます。負けられませんが。ともかく順調に作業をすすめていたのですが、ウォーリーの画像が集まる携帯を見ているうちに二つほど問題があるのではないかという疑念がわいてきました。

問題その1:画質粗い問題

たくさんの教師データがあった方がイイだろうという事と財布との相談の結果、今まで販売されている全ての本を一冊にまとめた本で原本とおなじぐらいの値段だという事で、この本を購入しました。

これ見開きで大体、原本の1/4ぐらいのサイズに縮小されているんです。
つまり、画質がとっても悪い!

はい。ケチった私が悪いんです。(でも、遊びの為に1500円の本5-6冊も買えない)これは教師データとしてはやってしまったな感が既に否めませんが、買ってしまったものは仕方ないのでこれで強行していきます。

苦肉の策としてプーリング層の処理を省くなどして、学習側で飲み込んでいくしかない。どうなるかはわからないけども。

問題その2:あれウォーリー顔違くね?問題

どちらかというとこっちの方が大きな問題です。よく漫画とかで初期のころと最後の方で絵のタッチとかが変わることってあると思うんですが、それと似たような現象がウォーリーを探せにも起こっています。

機械学習をさせる側にしては大きな問題ですよ、これ。ちなみに抜き出したデータをいくつか貼りますがこんな感じ。

f:id:ct-innovation01:20171027150642p:plain f:id:ct-innovation01:20171027150657p:plain f:id:ct-innovation01:20171027153714p:plain

管理人
思った以上に顔変わってません??

しかもネットで見つけたのと比べるとわかるんですが、ほとんど正面見てやがらないんだ、こいつ・・・・

f:id:ct-innovation01:20171026090425p:plain

まだデータを集めただけなのに早々に心を折ってくるとは、ウォーリーさん流石です。しかし、2000円使っちゃったので泣き言も言ってられません。頑張ります。

どのライブラリを使うか

機械学習を行うにあたってPythonを使うことは決めていましたが、まだライブラリを選択していませんでした。機械学習を行うためによく使われているライブラリでCNNをやろうと思っているので以下からどれかを選択しようと思います。

  • TensorFlow
  • Chainer
  • Caffe
  • Pylearn2

今回は、Chainerを選択することにしました。

なぜ、Chainerにしたか

どのライブラリも非常に強力で素晴らしいのですが、私のスキルとPCの都合なども鑑みて考慮した結果、以下の2つを理由にChainerに決めました。

1.サクッと始められる

ライブラリの多くは、依存するライブラリがいくつもあるなどがあり、機械学習を始めるまでにいろんなハードルを越えなきゃいけないのに対し、Chainerはインストールにそこまで煩わしさもなくすぐに作業が始められると聞いた。

2.記法が直観的でわかりやすい

どのようにネットワークを構築していくのか(入力層と出力層の設定)などが非常にシンプルにわかりやすく書けるので、プログラマ2年生の私でも書けそう。

ということで、とりあえずChainerを使うことに決めたのでインストールを手短に済ませて(本当に簡単に終わった。)作業に入っていきます。

何層のCNNにするか

以下のサイトから少し画像をお借りして、どうするか考えてみます。一般的かどうかは分からないがよくこんな形で畳み込み層とプーリング(サブサンプリング)層を組合せてから全結合してクラス分類をする画像がよく見つかりますね。


PARsE | Education | GPU Cluster | Efficient mapping of the training of Convolutional Neural Networks to a CUDA-based cluster

私も倣いこの形で行こうかと思ったいましたが教師用データの画像の粗さを見るとこれ以上プーリングを行うのって大丈夫なのか?ってことで今回はプーリング層をなしにしてみてうまくいくかどうか試してみます。

教師用データはどれぐらい用意したか

正解データであるウォーリーの画像の切り抜きは約40枚、不正解のデータは適当にネットから約100枚用意しました。結構少ないですね。ダメだったら増やしていきます。

実際のプログラム

クラスの作成

ニューラルネットワークのクラスを作り込むことにします。

# coding=utf-8
from chainer import Chain
import chainer.links as L
import chainer.functions as F

class MyCNN(Chain):
    def __init__(self,  n_out):
        super(MyCNN, self).__init__(
            conv1=L.Convolution2D(in_channels=1, out_channels=10,
                    ksize=5, stride=1, pad=2),
            conv2=L.Convolution2D(in_channels=None, out_channels=20,
                    ksize=5, stride=1, pad=2),
            l1=L.Linear(None, 500),
            l2=L.Linear(500, 500),
            l3=L.Linear(500, n_out)
        )

    def forward(self, x):
        h1 = self.conv1(x)
        h2 = self.conv2(h1)
        h3 = F.relu(self.l1(h2))
        h4 = F.relu(self.l2(h3))
        out = self.l3(h4)
        return out

入力層と出力層を合わせて6層のディープラーニングを行うことにします。それぞれの層でどういう事をしてほしいか書くだけなので結構分かりやすい。

ただ、conv1conv2ってわざわざわける意味ない気がとてもする。プーリングしてないんだからこれまとめてもいいかなぁ?わかんないのでこのままいきます。

あと、forwardかけるときのh1h2を何も考えず、恒等関数として処理したけどいいのかな?ダメだったら、考え直すことにします。

学習をさせる

大体、Chainerで学習させるとなればこういう書き方すればいいみたいなので、そのままインスパイアしました。Trainerを使う方法も考えましたが、今回は愚直にプログラム書くことにしました。

model = cnn.MyCNN(2)
optimizer = optimizers.Adam()
optimizer.setup(model)

n_epoch = 40
batch_size = 30
for epoch in range(n_epoch):
    sum_loss = 0
    sum_accuracy = 0
    perm = np.random.permutation(N)
    for i in range(0, N, batch_size):
        x = Variable(data[perm[i:i+batch_size]])
        t = Variable(label_data[perm[i:i+batch_size]])
        y = model.forward(x)
        model.zerograds()
        loss = F.softmax_cross_entropy(y, t)
        acc = F.accuracy(y, t)
        loss.backward()
        optimizer.update()

serializers.save_npz("wally.npz", model)

実際は、このほかに画像をデータにする部分や正規化する部分などあるが割愛してます。このプログラムを稼働させてAccuracyのプロットをした結果が以下の通りでした。

結構早い段階で収束してました。次回はこれで、実際に判別できるかテストしてみます。

1件のコメント

  1. ピンバック: CNNでウォーリーを探してみた【その3】 | 趣味で始める機械学習

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です