MATHGRAM

主に数学とプログラミング、時々趣味について。

python: chainerを使って化物語キャラを認識させるよ! 〜part5 主要キャラで多値分類(未知データに適用編)〜

はい、part5でございます。

-- 目次 --

まずは2値分類してみる。

ここから主要キャラの分類

今回は前回の2値分類に少し手を加えて、多値分類をします。

ネトワークなどの根本的な部分は変更ありません。

最終的な出力が10通りになるように変更したくらいです。
あと撫子とか月火とか画像がすごい少なかったので、ガウスノイズとペッパーノイズを加えることにより、
2000枚程度まで、水増ししました。

学習枚数は、
負例: 15000枚
主要キャラたち: 1800枚
です。
ちょっと画像が少ないかな〜。

学習の過程はこんな感じ。

epoch: 1
2016-03-22 00:39:43.913570
train mean loss=1.18005131154, accuracy=0.610652140454
test  mean loss=1.80967427409, accuracy=0.540751492506
epoch: 2
2016-03-22 00:46:17.604887
train mean loss=0.766596870978, accuracy=0.741430833116
test  mean loss=2.25404204469, accuracy=0.588366806568
epoch: 3
2016-03-22 00:52:58.503691
train mean loss=0.640313144716, accuracy=0.784847951602
test  mean loss=1.97074703021, accuracy=0.581267653004

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

epoch: 28
2016-03-22 07:30:14.651147
train mean loss=0.105090085609, accuracy=0.966426435842
test  mean loss=4.66628507105, accuracy=0.63786476721
epoch: 29
2016-03-22 07:36:30.702969
train mean loss=0.0999042894729, accuracy=0.968184216734
test  mean loss=5.14881660291, accuracy=0.640139633662
epoch: 30
2016-03-22 07:42:46.231465
train mean loss=0.0866300846959, accuracy=0.970117772395
test  mean loss=4.49815036958, accuracy=0.648925326096

三時間でスリープに入るよう設定してたら、午前5時くらいに止まってやがった。

そんなことは置いといて・・・
う〜ん。微妙ですね・・・。やはり4層のネットワークではこれくらいが限界なのかな?

とりあえず学習済みモデルを使って未知データに適用させてみます。

f:id:ket-30:20160322082716p:plain

おっ!?

前回、暦扱いされていたひたぎさんがちゃんと識別されています!

ちょっと今回はここまでにしといて、part5.5を設けます。
そっちでもっとディープに書き換えたネットワークで学習させる!
なんなら、そっちがメインってことで!目指せAccuracy90%!

3/24追記:
ちょっと待ってくれ!!コード見返したらtrainとtestの枚数が逆になってやがった・・・。
なんだよこのくそみたいなミス。情けない・・・

ってことでそこを修正し、どうせならってことで画像を増やして再学習させます。
負例:訓練用=18000枚、テスト用=4000枚
主要キャラたち:訓練用=3600枚、テスト用=400枚

いつか指摘がいただけるようコードも載せますね。

#coding: utf-8

#必要なライブラリのインポート
import cv2
import os
import six
import datetime

import chainer
from chainer import optimizers
import chainer.functions as F
import chainer.links as L
import chainer.serializers as S
from clf_bake_model import clf_bake

import numpy as np


#その1 ------データセット作成------

#フォルダは整数で名前が付いています。
#今回0が負例で、1が暦フォルダになっております。
def getDataSet():
    #リストの作成
    X_train = []
    X_test = []
    y_train = []
    y_test = []

    for i in range(0,10):
        path = "/Users/kentowatanabe/Desktop/bake_detection/img/train/"
        if i == 0:
            #othersは15000枚用意します。テスト用には3000枚
            cutNum = 22000
            cutNum2 = 18000
        else:
            #主要キャラたちは1800枚ずつ。テスト用には300枚
            cutNum = 4000
            cutNum2 = 3600
        imgList = os.listdir(path+str(i))
        imgNum = len(imgList)
        for j in range(cutNum):
            imgSrc = cv2.imread(path+str(i)+"/"+imgList[j])
            #imreadはゴミを吸い込んでも、エラーで止まらずNoneを返してくれます。
            #ですので読み込み結果がNoneでしたらスキップしてもらいます。
            if imgSrc is None:continue
            if j < cutNum2:
                X_train.append(imgSrc)
                y_train.append(i)
            else:
                X_test.append(imgSrc)
                y_test.append(i)

    return X_train,y_train,X_test,y_test



#その3 ---------学習させる-------

def train():
    #上で作った関数でデータセットを用意します。
    X_train,y_train,X_test,y_test = getDataSet()
    #このままだとchainerで読み込んでもらえないので、array型にします。
    X_train = np.array(X_train).astype(np.float32).reshape((len(X_train),3, 50, 50)) / 255
    y_train = np.array(y_train).astype(np.int32)
    X_test = np.array(X_test).astype(np.float32).reshape((len(X_test),3, 50, 50)) / 255
    y_test = np.array(y_test).astype(np.int32)
    # 諸々の初期設定
    model = clf_bake()
    optimizer = optimizers.Adam()
    optimizer.setup(model)

    epochNum = 30
    batchNum = 50
    epoch = 1

    # 学習とテスト
    while epoch <= epochNum:
        print("epoch: {}".format(epoch))
        print(datetime.datetime.now())

        trainImgNum = len(y_train)
        testImgNum = len(y_test)

        #---学習---
        sumAcr = 0
        sumLoss = 0

        perm = np.random.permutation(trainImgNum)

        for i in six.moves.range(0, trainImgNum, batchNum):
            #ランダムにbatchNumの数だけ抽出する
            X_batch = X_train[perm[i:i+batchNum]]
            y_batch = y_train[perm[i:i+batchNum]]

            optimizer.zero_grads()
            loss, acc = model.forward(X_batch, y_batch)
            loss.backward()
            optimizer.update()

            sumLoss += float(loss.data) * len(y_batch)
            sumAcr += float(acc.data) * len(y_batch)
        print('train mean loss={}, accuracy={}'.format(sumLoss / trainImgNum, sumAcr / trainImgNum))

        #---テスト---
        sumAcr = 0
        sumLoss = 0

        perm = np.random.permutation(testImgNum)

        for i in six.moves.range(0, testImgNum, batchNum):
            X_batch = X_test[perm[i:i+batchNum]]
            y_batch = y_test[perm[i:i+batchNum]]
            loss, acc = model.forward(X_batch, y_batch, train=False)

            sumLoss += float(loss.data) * len(y_batch)
            sumAcr += float(acc.data) * len(y_batch)
        print('test  mean loss={}, accuracy={}'.format(
            sumLoss / testImgNum, sumAcr / testImgNum))
        epoch += 1
        #モデルの保存
        S.save_hdf5('model'+str(epoch+1), model)

train()

枚数増やしたからかなり時間かかりそうです。
学習終わったら、また記事更新します。

-- 目次 --

まずは2値分類してみる。

ここから主要キャラの分類

p.s. ってことでしばしお待ちを。