つまりなにしたの?
前回画面上に5*7点の注視点を用意してそれぞれをガン見しているオタクこと私のキャプチャをノートPC据え付けのWebカメラで撮影した。
今回はこれを使ってGoogLeNetにどこを見ている画像なのかを判別してもらおうと思う。
ただ、今回は動作確認用に各ポイント20枚ずつというかなり少ないデータセットで動かしてみたのが今日のはなし。
一昨日やり始めたらこんな記事が出ていた
shiropen.com
しゅごい。こういうのやりたい…
どんな手順でやるの?(前回から再掲)
1, データセット作成アプリを作る
2, 自分の顔でデータセットを作る→(苦行すぎるので一旦すくなめで実行)
ensekitt.hatenablog.com
3, 性能の良い画像解析系のCNNを流用(転移学習)して構築する→(今日はこころ転移学習無しでやった)
4, 色んな所を見ている顔のデータを学習する→(辛抱強く待つ)
5, 実際に稼働させて目線の座標がざっくり分かったら嬉しい
ディレクトリごとにわけられた多くの画像を読み込む方法
qiita.com
が同じような方法でデータセットを作っていたので、参考に写経させていただきつつ
LabeledImageDatasetを使うことにした
chainer.datasets.LabeledImageDataset — Chainer 3.2.0 documentation
from chainer.datasets import LabeledImageDataset from itertools import chain # 画像フォルダ IMG_DIR = 'datas' # 各注視点ごとのフォルダ dnames = glob.glob('{}/*'.format(IMG_DIR)) # キャプチャのパス fnames = [glob.glob('{}/*.jpg'.format(d)) for d in dnames if not os.path.exists('{}/ignore'.format(d))] fnames = list(chain.from_iterable(fnames)) labels = [os.path.basename(os.path.dirname(fn)) for fn in fnames] dnames = [os.path.basename(d) for d in dnames if not os.path.exists('{}/ignore'.format(d))] labels = [dnames.index(l) for l in labels] d = LabeledImageDataset(list(zip(fnames, labels)))
データセットの加工
さっきの記事を参考にデータセットを加工してみることにした。
今度はTransformDatasetを使った。
chainer.datasets.TransformDataset — Chainer 3.2.0 documentation
from chainer.datasets import TransformDataset from PIL import Image width, height = 224, 224 # 平均画像を用意する(これはCaffe Model Zooのモデルのときと変えてないの失敗した… mean_image = np.ndarray((3, 224, 224), dtype=np.float32) mean_image[0] = 103.939 mean_image[1] = 116.779 mean_image[2] = 123.68 # 各データに行う変換 def transform(inputs): img, label = inputs img = img[:3, ...] img = img.astype(np.uint8) img = Image.fromarray(img.transpose(1, 2, 0)) img = img.resize((width, height), Image.BICUBIC) img = np.asarray(img).transpose(2, 0, 1) img = img - mean_image return img, label # 変換付きデータセットにする td = TransformDataset(d, transform)
学習の設定
バッチサイズ50で5000epoch回してみた。
TrainとValidは8対2で分けた。
もちろん全然データセットとしては少ないけど、進むことまでは確認したかったのでとりあえずこれで実施する。
def train(train, test): model = L.Classifier(GoogLeNet()) dev = 0 if dev >= 0: chainer.cuda.get_device(dev).use() model.to_gpu() optimizer = chainer.optimizers.Adam() optimizer.setup(model) train_iter = chainer.iterators.SerialIterator(train, 50) test_iter = chainer.iterators.SerialIterator(test, 50,repeat=False, shuffle=False) epoch = 5000 updater = training.StandardUpdater(train_iter, optimizer, device=dev) trainer = training.Trainer(updater, (epoch, 'epoch'), out="result") # Evaluator trainer.extend(extensions.Evaluator(test_iter, model, device=dev)) # LogReport trainer.extend(extensions.LogReport()) # PrintReport trainer.extend(extensions.PrintReport( entries=['epoch', 'main/loss', 'main/accuracy','validation/main/loss', 'validation/main/accuracy', 'elapsed_time' ])) print("run") trainer.run()
コードはこちら
一旦結果
epoch main/loss main/accuracy validation/main/loss validation/main/accuracy elapsed_time 4995 0.108707 0.973333 6.63872 0.299291 15884.8 4996 0.096381 0.978182 5.98058 0.374752 15887.8 4997 0.0417148 0.991667 6.02118 0.36766 15891.1 4998 0.0102915 0.998333 6.42415 0.333475 15894.3 4999 0.00949544 0.996667 6.19799 0.381418 15897.6 5000 0.00411291 0.998182 6.61703 0.368085 15900.7
完全に過学習気味なので、とりあえずデータセットを増やしていけば良さそう。
もう少しデータを増やしたら平均画像もこれ用に更新しようと思う。