読者です 読者をやめる 読者になる 読者になる

福岡は今日も雨

情報系大学生のブログ。主に技術,音楽について。

顔画像を載せるだけで髪型をおすすめしてくれるLineBotを開発しました!

こんにちは。
とある勉強会で呼ばれて,「DeepLearningと髪型推薦への応用」という話で発表させていただきました。

(slideshareにアップロードしたら一部分の記号が欠けてしまった..)
内容としてはOpenCVで顔を切り抜き,あらかじめ学習させたDeepLearning器にかけてその人にあったおすすめの髪型をレコメンドするというものです。
これをちょうどLineBotAwardというものをやっているそうで。ちょうどいいのでサーバを用意して締め切りギリギリに急遽製作

現在はまだ女性限定ですね...。
美容院に行く前だとか,友達と身内で遊んで使ったりとかしてみてください!

@wtl5693l

f:id:taichitary:20170301075343p:plain

遊んでくれるとすごい嬉しいです。感想とかくれると更に嬉しいです。宜しくお願いします。

画像をopenCVで顔部分を切り抜いたりしながら,pickle形式で保存するまで

顔から髪型をおすすめするDeepLearning器を作りたい,んで今日はデータの前処理やらラベル張りやらをやった。
1000枚以上ラベル張りが必要なデータがあって死にそうだったが,なんとかおしまい,データ前処理部分でopenCVで顔を切り抜いたり,
pickleで保存するまでをやったりした. openCVが全然できないので全然アレなコードですが,メモ用に書き残しておく

# 顔を切り抜くコード
def cut_out_face():
	directories = os.listdir('2_8_images')
	for directory in directories:
		if directory.find('.DS_Store') > -1:
			continue

		img_ary = os.listdir('2_8_images/' + directory)
		for image in img_ary:
			if image.find('.DS_Store') > -1:
				continue

			img = cv2.imread('2_8_images/' + directory + '/' + image, cv2.IMREAD_COLOR)
			gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
			face = faceCascade.detectMultiScale(gray, 1.1, 3)
			if len(face) > 0:
				for rect in face:
					x = rect[0]
					y = rect[1]
					width = rect[2]
					height = rect[3]
					dst = img[y:y+height, x:x+width]
					fixed_dst = cv2.resize(dst, (32,32))

					if not os.path.exists('hair_pickle/' + directory):
						os.mkdir('hair_pickle/' + directory)

					np_path = 'hair_pickle/' + directory + '/' + image
					cv2.imwrite(cv_path, fixed_dst)

パスとかは無視してください。必要なのはimg = cv2.imread(~~)からの部分で,ここからはじまります
rectで顔の部分を切り抜いてる感じですね,今回はalexnetの構造を一から作るのが面倒だったので32*32でresizeしていますが,
必要に応じて縦×横を変更してください

def img2pickle():
	directories = os.listdir('hair_pickle')
	for directory in directories:
		if directory.find('.DS_Store') > -1:
			continue

		img_ary = os.listdir('hair_pickle/' + directory)
		for image in img_ary:
			if image.find('.DS_Store') > -1:
				continue

			np_img = np.asarray(Image.open('hair_pickle/' + directory + '/' +image).convert('RGB'), dtype=np.uint8)

			if image.find('jpg') > -1:
				new_name = image.replace('.jpg', '')
			elif image.find('png') > -1:
				new_name = image.replace('.png', '')
			elif image.find('jpeg') > -1:
				new_name = image.replace('.jpeg', '')
			else:
				new_name = image

			if not os.path.exists('hair_pickles/' + directory):
				os.mkdir('hair_pickles/' + directory)

			np_path = 'hair_pickles/' + directory + '/' + new_name
			np.save(np_path, np_img)

jpg,pngやらを取り除くうまい方法考えるより力技にしてしまった..., convert('RGB')としておくと,(3*32*32)のものがもらえます
なにもしなかったら(32*32*3)になっちゃうので,alexnetに合わせて先に(3*32*32)にしておきました。正規化とかは全くしていないので,
GCNやらLCNやら255で割ったりしてください. 明日は実際に学習させながら,SSDHモデルを作っていこうと思います

AlexNetをCPUモードで動かす(2:自分でダウンロードしたcifar10を利用する編)

元々のcifar-10のpickleからダウンロードしたものが,どうやら(3024*)のデータであったようだ。
ということで,これをまず(1024*3)に変更。どうやら1024ごとにr,g,bに分かれているようである。
参考
[Python]CIFAR-10, CIFAR-100のデータを読み込む方法 - Qiita

ということで,次にそれで実行しても次元が違うとchainerに怒られたのでよーくchainerでchainer.datasets.get_cifar10()したときのものと照らし合わせて確認

# chainer.datasets.get_cifar10()によるもの
(array([[[ 0.23137257,  0.16862746,  0.19607845, ...,  0.61960787,
           0.59607846,  0.58039218],
         [ 0.0627451 ,  0.        ,  0.07058824, ...,  0.48235297,
           0.4666667 ,  0.4784314 ],
         [ 0.09803922,  0.0627451 ,  0.19215688, ...,  0.46274513,
           0.47058827,  0.42745101],
         ...,
         [ 0.81568635,  0.78823537,  0.77647066, ...,  0.627451  ,
           0.21960786,  0.20784315],
         [ 0.70588237,  0.67843139,  0.72941178, ...,  0.72156864,
           0.38039219,  0.32549021],
         [ 0.69411767,  0.65882355,  0.7019608 , ...,  0.84705889,
           0.59215689,  0.48235297]],

        [[ 0.24313727,  0.18039216,  0.18823531, ...,  0.51764709,
           0.49019611,  0.48627454],
         [ 0.07843138,  0.        ,  0.03137255, ...,  0.34509805,
           0.32549021,  0.34117648],
         [ 0.09411766,  0.02745098,  0.10588236, ...,  0.32941177,
           0.32941177,  0.28627452],
         ...,
         [ 0.66666669,  0.60000002,  0.63137257, ...,  0.52156866,
           0.12156864,  0.13333334],
         [ 0.54509807,  0.48235297,  0.56470591, ...,  0.58039218,
           0.24313727,  0.20784315],
         [ 0.56470591,  0.50588238,  0.55686277, ...,  0.72156864,
           0.46274513,  0.36078432]],

        [[ 0.24705884,  0.17647059,  0.16862746, ...,  0.42352945,
           0.40000004,  0.4039216 ],
         [ 0.07843138,  0.        ,  0.        , ...,  0.21568629,
           0.19607845,  0.22352943],
         [ 0.08235294,  0.        ,  0.03137255, ...,  0.19607845,
           0.19607845,  0.16470589],
         ...,
         [ 0.37647063,  0.13333334,  0.10196079, ...,  0.27450982,
           0.02745098,  0.07843138],
         [ 0.37647063,  0.16470589,  0.11764707, ...,  0.36862746,
           0.13333334,  0.13333334],
         [ 0.45490199,  0.36862746,  0.34117648, ...,  0.54901963,
           0.32941177,  0.28235295]]], dtype=float32), 6)

ふむ
次に(3*1024)にした画像

(array([[ 0.23137255,  0.16862746,  0.19607843, ...,  0.84705883,
          0.59215689,  0.48235294],
        [ 0.24313726,  0.18039216,  0.1882353 , ...,  0.72156864,
          0.4627451 ,  0.36078432],
        [ 0.24705882,  0.17647059,  0.16862746, ...,  0.54901963,
          0.32941177,  0.28235295]], dtype=float32), 6)

なんかすくないな...と思って見ていると,どうやら(3*32*32)のデータを読み込ませていたらしく。
ということでコードを変更

def divive_l_t():
    ary = unpickle()
    data_ary = []
    label_ary = []
    for dict in ary:
        for data, label in zip(dict['data'], dict['labels']):
            rsh_data = data.reshape(3, 1024)
            data_ary.append(rsh_data)
            label_ary.append(label)

    return data_ary, label_ary

def divive_tr_t():
    data_ary, label_ary = divive_l_t()
    imageData = []
    labelData = []
    for data,label in zip(data_ary, label_ary):
        r, g, b = data[0], data[1], data[2]
        rImg = np.asarray(np.float32(r) / 255.0).reshape(32, 32)
        gImg = np.asarray(np.float32(g) / 255.0).reshape(32, 32)
        bImg = np.asarray(np.float32(b) / 255.0).reshape(32, 32)
        img = np.asarray([rImg, gImg, bImg])
        imageData.append(img)
        labelData.append(np.int32(label))

    return imageData, labelData

これで思う形になったので,あとは

train = tuple_dataset.TupleDataset(imageData[0:threshold], labelData[0:threshold])
test = tuple_dataset.TupleDataset(imageData[threshold:], labelData[threshold:])

としておしまいっ。thresholdは閾値で,trainデータとtestデータを分けております。
全コードは以下。GPUモードは帰宅してからとりかかります。

import chainer
import chainer.functions as F
import chainer.links as L
from chainer import training
from chainer.training import extensions
from chainer.datasets import tuple_dataset
import numpy as np
import _pickle as cpickle
import os

def unpickle():
    base_path = os.path.dirname(os.path.abspath(__file__))
    cifar_path = os.path.normpath(os.path.join(base_path, '../cifar-10-batches-py'))
    ary = []
    for i in range(1, 6):
        file_path = cifar_path +'/data_batch_' + str(i)
        fo = open(file_path, 'rb')
        tmp_dic = cpickle.load(fo, encoding='latin1')
        ary.append(tmp_dic)
        fo.close()

    return ary

def divive_l_t():
    ary = unpickle()
    data_ary = []
    label_ary = []
    for dict in ary:
        for data, label in zip(dict['data'], dict['labels']):
            rsh_data = data.reshape(3, 1024)
            data_ary.append(rsh_data)
            label_ary.append(label)

    return data_ary, label_ary

def divive_tr_t():
    data_ary, label_ary = divive_l_t()
    imageData = []
    labelData = []
    for data,label in zip(data_ary, label_ary):
        r, g, b = data[0], data[1], data[2]
        rImg = np.asarray(np.float32(r) / 255.0).reshape(32, 32)
        gImg = np.asarray(np.float32(g) / 255.0).reshape(32, 32)
        bImg = np.asarray(np.float32(b) / 255.0).reshape(32, 32)
        img = np.asarray([rImg, gImg, bImg])
        imageData.append(img)
        labelData.append(np.int32(label))

    return imageData, labelData

class AlexNet(chainer.Chain):

    input_size = 227

    def __init__(self):
        super(AlexNet, self).__init__(
            conv1 = L.Convolution2D(None, 96, 11, stride=4),
            conv2 = L.Convolution2D(None, 256, 3, pad=2),
            conv3 = L.Convolution2D(None, 384, 3, pad=1),
            conv4 = L.Convolution2D(None, 384, 3, pad=1),
            conv5 = L.Convolution2D(None, 256, 3, pad=1),
            fc6 = L.Linear(None, 4096),
            fc7 = L.Linear(None, 4096),
            fc8 = L.Linear(None, 10))

    def __call__(self, x):
        h = F.max_pooling_2d(F.local_response_normalization(F.relu(self.conv1(x))), 3, stride=2)
        h = F.max_pooling_2d(F.local_response_normalization(F.relu(self.conv2(h))), 3, stride=2)
        h = F.relu(self.conv3(h))
        h = F.relu(self.conv4(h))
        h = F.max_pooling_2d(F.relu(self.conv5(h)), 3, stride=2)
        h = F.dropout(F.relu(self.fc6(h)))
        h = F.dropout(F.relu(self.fc7(h)))
        h = F.relu(self.fc8(h))

        return h

# モデルのインスタンス化
model = L.Classifier(AlexNet())
optimizer = chainer.optimizers.Adam()
optimizer.setup(model)

# 訓練データとテストデータに分割
# train, test = chainer.datasets.get_cifar10()
# chainer.datasets.get_cifar10()で渡されるデータの次元は(3,32,32)
# 自分がとってきたデータは(3*1024)
imageData, labelData = divive_tr_t()
threshold = np.int32(len(imageData)/8*7)
train = tuple_dataset.TupleDataset(imageData[0:threshold], labelData[0:threshold])
test = tuple_dataset.TupleDataset(imageData[threshold:], labelData[threshold:])

train_iter = chainer.iterators.SerialIterator(train, 100)
test_iter = chainer.iterators.SerialIterator(test, 100, repeat=False, shuffle=False)

updater = training.StandardUpdater(train_iter, optimizer, device=-1)
trainer = training.Trainer(updater, (100, 'epoch'), out='result')
trainer.extend(extensions.Evaluator(test_iter, model, device=-1))
trainer.extend(extensions.LogReport())
trainer.extend(extensions.PrintReport(['epoch', 'main/loss', 'validation/main/loss', 'main/accuracy', 'validation/main/accuracy']))
trainer.extend(extensions.ProgressBar())

trainer.run()

AlexNetを(とりあえず)CPUモードで動かす

numpyとかへの慣れの少なさか,データセットを用意してchainerに流すところで詰まっている感じ
というかここが一番面倒くさいかも
chainerからとってこれるメソッドで呼び出すと以下

class AlexNet(chainer.Chain):

    input_size = 227

    def __init__(self):
        super(AlexNet, self).__init__(
            conv1 = L.Convolution2D(None, 96, 11, stride=4),
            conv2 = L.Convolution2D(None, 256, 3, pad=2),
            conv3 = L.Convolution2D(None, 384, 3, pad=1),
            conv4 = L.Convolution2D(None, 384, 3, pad=1),
            conv5 = L.Convolution2D(None, 256, 3, pad=1),
            fc6 = L.Linear(None, 4096),
            fc7 = L.Linear(None, 4096),
            fc8 = L.Linear(None, 10))

    def __call__(self, x):
        h = F.max_pooling_2d(F.local_response_normalization(F.relu(self.conv1(x))), 3, stride=2)
        h = F.max_pooling_2d(F.local_response_normalization(F.relu(self.conv2(h))), 3, stride=2)
        h = F.relu(self.conv3(h))
        h = F.relu(self.conv4(h))
        h = F.max_pooling_2d(F.relu(self.conv5(h)), 3, stride=2)
        h = F.dropout(F.relu(self.fc6(h)))
        h = F.dropout(F.relu(self.fc7(h)))
        h = F.relu(self.fc8(h))

        return h

# モデルのインスタンス化
model = L.Classifier(AlexNet())
optimizer = chainer.optimizers.Adam()
optimizer.setup(model)

# 訓練データとテストデータに分割
train, test = chainer.datasets.get_cifar10()
# print(len(imageData[0][1]))
# threshold = np.int32(len(imageData)/8*7)
# train = tuple_dataset.TupleDataset(imageData[0:threshold], labelData[0:threshold])
# test = tuple_dataset.TupleDataset(imageData[threshold:], labelData[threshold:])

# print(len(train[0][0]))

train_iter = chainer.iterators.SerialIterator(train, 100)
test_iter = chainer.iterators.SerialIterator(test, 100, repeat=False, shuffle=False)

updater = training.StandardUpdater(train_iter, optimizer, device=-1)
trainer = training.Trainer(updater, (100, 'epoch'), out='result')
trainer.extend(extensions.Evaluator(test_iter, model, device=-1))
trainer.extend(extensions.LogReport())
trainer.extend(extensions.PrintReport(['epoch', 'main/loss', 'validation/main/loss', 'main/accuracy', 'validation/main/accuracy']))
trainer.extend(extensions.ProgressBar())

trainer.run()

頑張った跡が見られる
ちょっと今から普通の画像でもなんとかできるようになんとかします。

(2/17)AlexNetを作ってcifar-10をしていてtupleDatasetにできなくてハマっている

曲者だじぇ
Cifar-10をAlexnetで分類するコードを書いているのだが,どうもなんだか動かない
Chainerではcifar-10を手にいれるchainer.datasets.tuple_dataset.TupleDataset型で手にいれるメソッドがあるのは知ってるけれど
今回は次に書くプログラムのためにそれを使わずにすることにした。

train_tup, test_tup = chainer.datasets.get_mnist()
# get_mnistでdataset.TupleDataset型のものを持ってくるメソッド

(array([ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.01176471,  0.07058824,  0.07058824,
         0.07058824,  0.49411768,  0.53333336,  0.68627453,  0.10196079,
         0.65098041,  1.        ,  0.96862751,  0.49803925,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.11764707,  0.14117648,  0.36862746,  0.60392159,
         0.66666669,  0.99215692,  0.99215692,  0.99215692,  0.99215692,
         0.99215692,  0.88235301,  0.67450982,  0.99215692,  0.94901967,
         0.76470596,  0.25098041,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.19215688,  0.9333334 ,
         0.99215692,  0.99215692,  0.99215692,  0.99215692,  0.99215692,
         0.99215692,  0.99215692,  0.99215692,  0.98431379,  0.36470589,
         0.32156864,  0.32156864,  0.21960786,  0.15294118,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.07058824,  0.8588236 ,  0.99215692,  0.99215692,
         0.99215692,  0.99215692,  0.99215692,  0.77647066,  0.71372551,
         0.96862751,  0.9450981 ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.3137255 ,  0.61176473,  0.41960788,  0.99215692,  0.99215692,
         0.80392164,  0.04313726,  0.        ,  0.16862746,  0.60392159,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.05490196,
         0.00392157,  0.60392159,  0.99215692,  0.35294119,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.54509807,
         0.99215692,  0.74509805,  0.00784314,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.04313726,  0.74509805,  0.99215692,
         0.27450982,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.13725491,  0.9450981 ,  0.88235301,  0.627451  ,
         0.42352945,  0.00392157,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.31764707,  0.94117653,  0.99215692,  0.99215692,  0.4666667 ,
         0.09803922,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.17647059,
         0.72941178,  0.99215692,  0.99215692,  0.58823532,  0.10588236,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.0627451 ,  0.36470589,
         0.98823535,  0.99215692,  0.73333335,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.97647065,  0.99215692,
         0.97647065,  0.25098041,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.18039216,  0.50980395,
         0.71764708,  0.99215692,  0.99215692,  0.81176478,  0.00784314,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.15294118,
         0.58039218,  0.89803928,  0.99215692,  0.99215692,  0.99215692,
         0.98039222,  0.71372551,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.09411766,  0.44705886,  0.86666673,  0.99215692,  0.99215692,
         0.99215692,  0.99215692,  0.78823537,  0.30588236,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.09019608,  0.25882354,  0.83529419,  0.99215692,
         0.99215692,  0.99215692,  0.99215692,  0.77647066,  0.31764707,
         0.00784314,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.07058824,  0.67058825,  0.8588236 ,
         0.99215692,  0.99215692,  0.99215692,  0.99215692,  0.76470596,
         0.3137255 ,  0.03529412,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.21568629,  0.67450982,
         0.88627458,  0.99215692,  0.99215692,  0.99215692,  0.99215692,
         0.95686281,  0.52156866,  0.04313726,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.53333336,  0.99215692,  0.99215692,  0.99215692,
         0.83137262,  0.52941179,  0.51764709,  0.0627451 ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ], dtype=float32), 5)

これがおそらくiteratorとして受け付ける形で,データとラベルのタプル。
んでこれを作ればいいんでしょ、って方向性で元々のデータをいじってみたのだが

def divive_l_t():
    ary = unpickle()
    data_ary = []
    label_ary = []
    for dict in ary:
        for data, label in zip(dict['data'], dict['labels']):
            data_ary.append((data / 255).astype(np.float32))
            label_ary.append(label)

    return data_ary, label_ary

def divive_tr_t():
    data_ary, label_ary = divive_l_t()
    train = []
    test = []
    for i in range(50000):
        if i < 39999:
            # ひとつひとつのデータについて,型をchainerで決められたtupleの型に合わせていく。
            tup = (data_ary[i], label_ary[i])
            # print(len(tup))
            train.append(tup)
        else:
            tup = (data_ary[i], label_ary[i])
            test.append(tup)

    train_tup = chainer.datasets.tuple_dataset.TupleDataset(train)
    test_tup = chainer.datasets.tuple_dataset.TupleDataset(test)

    return train_tup, test_tup

こうしてみても、

((array([ 0.23137255,  0.16862746,  0.19607843, ...,  0.54901963,
          0.32941177,  0.28235295], dtype=float32), 6),)

という奇妙なデータ構造になっちゃうんだよね。
この辺りをどう解決すればいいのか...もう少しchainer.datasets.tuple_dataset.TupleDataset()について調べておくべきか..
以下全コード。ちょっと違うけれど実験中なので許して。出来次第しっかり書く予定

import chainer
import chainer.functions as F
import chainer.links as L
from chainer import training
from chainer.training import extensions
import numpy as np
import _pickle as cpickle
import os

def unpickle():
    base_path = os.path.dirname(os.path.abspath(__file__))
    cifar_path = os.path.normpath(os.path.join(base_path, '../cifar-10-batches-py'))
    ary = []
    for i in range(1, 6):
        file_path = cifar_path +'/data_batch_' + str(i)
        fo = open(file_path, 'rb')
        tmp_dic = cpickle.load(fo, encoding='latin1')
        ary.append(tmp_dic)
        fo.close()

    return ary

def divive_l_t():
    ary = unpickle()
    data_ary = []
    label_ary = []
    for dict in ary:
        for data, label in zip(dict['data'], dict['labels']):
            data_ary.append((data / 255).astype(np.float32))
            label_ary.append(label)

    return data_ary, label_ary

def divive_tr_t():
    data_ary, label_ary = divive_l_t()
    train = []
    test = []
    for i in range(50000):
        if i < 39999:
            # ひとつひとつのデータについて,型をchainerで決められたtupleの型に合わせていく。
            tup = (data_ary[i], label_ary[i])
            # print(len(tup))
            train.append(tup)
        else:
            tup = (data_ary[i], label_ary[i])
            test.append(tup)

    train_tup = chainer.datasets.tuple_dataset.TupleDataset(train)
    test_tup = chainer.datasets.tuple_dataset.TupleDataset(test)

    return train_tup, test_tup

class AlexNet(chainer.Chain):

    input_size = 227

    def __init__(self):
        super(AlexNet, self).__init__(
            conv1 = L.Convolution2D(None, 96, 11, stride=4),
            conv2 = L.Convolution2D(None, 256, 5, pad=2),
            conv3 = L.Convolution2D(None, 384, 3, pad=1),
            conv4 = L.Convolution2D(None, 384, 3, pad=1),
            conv5 = L.Convolution2D(None, 256, 3, pad=1),
            fc6 = L.Linear(None, 4096),
            fc7 = L.Linear(None, 4096),
            fc8 = L.Linear(None, 10))

    def __call__(self, x):
        h = F.max_pooling_2d(F.local_response_normalization(F.relu(self.conv1(x))), 3, stride=2)
        h = F.max_pooling_2d(F.local_response_normalization(F.relu(self.conv2(h))), 3, stride=2)
        h = F.relu(self.conv3(h))
        h = F.relu(self.conv4(h))
        h = F.max_pooling_2d(F.relu(self.conv5(h)), 3, stride=2)
        h = F.dropout(F.relu(self.fc6(h)))
        h = F.dropout(F.relu(self.fc7(h)))
        h = F.relu(self.fc8(h))

        return h

# モデルのインスタンス化
model = L.Classifier(AlexNet())
optimizer = chainer.optimizers.Adam()
optimizer.setup(model)

# 訓練データとテストデータに分割
# 今回はchainerのTupleDatasetのメソッドを使っているが,うまくキャストしているのかが心配
# TODO: ここのtupleのデータ構造(型)と,もともとのデータ構造(型)を合わせないとうまくいかないと思う
train, test = divive_tr_t()
# train_tup, test_tup = chainer.datasets.get_mnist()
# mnistとデータを合わせればうまくいくはず

train_iter = chainer.iterators.SerialIterator(train, 100)
test_iter = chainer.iterators.SerialIterator(test, 100, repeat=False, shuffle=False)

updater = training.StandardUpdater(train_iter, optimizer, device=-1)
trainer = training.Trainer(updater, (100, 'epoch'), out='result')
trainer.extend(extensions.Evaluator(test_iter, model, device=-1))
trainer.extend(extensions.LogReport())
trainer.extend(extensions.PrintReport(['epoch', 'main/loss', 'validation/main/loss', 'main/accuracy', 'validation/main/accuracy']))
trainer.extend(extensions.ProgressBar())

trainer.run()

MNIST DatasetをChainerで,GPUを利用して学習するまで

もう少ししたら発表があることに気づいて必死でモデルを組み始めた。
ちょっとChainerを思い出しながら書いて,GPUも手に入って環境も整ったこともあり,一回MNISTを分類してみようかと。

いろんなブログやらqiitaを参考にしながらもう一度書いてみた。
CPUモードからGPUモードに変更するときは

# GPUの設定
cuda.get_device(0).use()
model.to_gpu()
# modelの設定後(この場合インスタンス化のあと)に行うこと。

これと

xp = cuda.cupy

これでnumpyの配列をすべてxpで変えていく。
注意として,numpyにはあったメソッドがxpでなかったりするので,そこらへんはちょろちょろ自分で書いたりしなきゃいけないかも.
今回少しだけはまった点としては

 def forward(self, x_data, y_data, train=True):
        x, t = Variable(cuda.to_gpu(x_data)), Variable(cuda.to_gpu(y_data))
        h1 = F.dropout(F.relu(self.l1(x)), train=train)
        h2 = F.dropout(F.relu(self.l2(h1)), train=train)
        y = self.l3(h2)

ここのforwardだが,x_data,y_dataの引数部分をcuda.to_gpuでcupyモードにしなければならない
同様に,matplotlibはcupyに対応していないので,numpyに戻す必要があり。この時は逆のcuda.to_cpuを利用しよう。
以下に全ソースコード

# -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import fetch_mldata
from chainer import cuda, Variable, optimizers, Chain
import chainer.functions as F
import sys

plt.style.use("ggplot")

batchsize = 100
n_epoch = 20
n_units = 1000  # 中間層
pixel_size = 28
xp = cuda.cupy

# Chainerのクラス作成
class MNISTChain(Chain):
    def __init__(self):
        super(MNISTChain, self).__init__(
            l1=F.Linear(784, n_units),
            l2=F.Linear(n_units, n_units),
            l3=F.Linear(n_units, 10)
        )

    def forward(self, x_data, y_data, train=True):
        x, t = Variable(cuda.to_gpu(x_data)), Variable(cuda.to_gpu(y_data))
        h1 = F.dropout(F.relu(self.l1(x)), train=train)
        h2 = F.dropout(F.relu(self.l2(h1)), train=train)
        y = self.l3(h2)

        # 交差エントロピー関数を誤差関数とする
        return F.softmax_cross_entropy(y, t), F.accuracy(y, t)


# MNISTの画像データDL
print("fetch MNIST dataset")
mnist = fetch_mldata('MNIST original', data_home=".")
# mnist.data : 70,000件の28x28=784次元ベクトルデータ
mnist.data = mnist.data.astype(xp.float32)
mnist.data /= 255  # 正規化

# mnist.target : 正解データ
mnist.target = mnist.target.astype(xp.int32)

# 学習用データN個,検証用データを残りの個数に設定
N = 60000
x_train, x_test = xp.split(mnist.data, [N])
y_train, y_test = xp.split(mnist.target, [N])
N_test = y_test.size

# modelを書く
model = MNISTChain()
# GPUの設定
cuda.get_device(0).use()
model.to_gpu()
# optimizerの設定
optimizer = optimizers.Adam()
optimizer.setup(model)

# train and show results
train_loss = []
train_acc = []
test_loss = []
test_acc = []

# Learning loop
for epoch in range(1, n_epoch + 1):
    print("epoch", epoch)

    # training
    # Nこの順番をランダムに並び替える
    perm = np.random.permutation(N)
    sum_accuracy = 0
    sum_loss = 0

    # 0~Nまでのデータをバッチサイズごとに使って学習
    for i in range(0, N, batchsize):
        x_batch = x_train[perm[i:i + batchsize]]
        y_batch = y_train[perm[i:i + batchsize]]

        # 勾配を初期化
        optimizer.zero_grads()
        # 順伝播させて誤差と精度を算出
        loss, acc = model.forward(x_batch, y_batch)
        # 誤差逆伝播で勾配を計算
        loss.backward()
        optimizer.update()

        train_loss.append(cuda.to_cpu(loss.data))
        train_acc.append(cuda.to_cpu(acc.data))
        sum_loss += float(cuda.to_cpu(loss.data)) * batchsize
        sum_accuracy += float(cuda.to_cpu(acc.data)) * batchsize

    # 訓練データの誤差と正解精度を表示
    print("train mean loss = {0}, accuracy = {1}".format(sum_loss / N, sum_accuracy / N))

    # evaluation
    # テストデータで誤差と正解精度を算出し汎化性能を確認
    sum_accuracy = 0
    sum_loss = 0
    for i in range(0, N_test, batchsize):
        x_batch = x_test[i:i + batchsize]
        y_batch = y_test[i:i + batchsize]

        # 順伝播させて誤差と精度を算出
        loss, acc = model.forward(x_batch, y_batch, train=False)

        test_loss.append(cuda.to_cpu(loss.data))
        test_acc.append(cuda.to_cpu(acc.data))
        sum_loss += float(cuda.to_cpu(loss.data)) * batchsize
        sum_accuracy += float(cuda.to_cpu(acc.data)) * batchsize

    # テストデータの誤差と正解精度を表示
    print("test  mean loss = {0}, accuracy = {1}".format(sum_loss / N_test, sum_accuracy / N_test))


# 精度と誤差をグラフ描画
plt.figure(figsize=(8, 6))
print(train_acc)
plt.plot(range(len(train_acc)), train_acc)
plt.plot(range(len(test_acc)), test_acc)
plt.legend(["train_acc", "test_acc"], loc=4)
plt.title("Accuracy of MNIST recognition.")
plt.plot()
plt.show()

結果
epoch 1
train mean loss = 0.279147822180142, accuracy = 0.9147833364456892
test mean loss = 0.1345167052175384, accuracy = 0.9583000040054321
epoch 2
train mean loss = 0.13670490186351042, accuracy = 0.9580500034491221
test mean loss = 0.09032138824637513, accuracy = 0.9720000040531158
epoch 3
train mean loss = 0.10736077687082192, accuracy = 0.9674000060558319
test mean loss = 0.07859976113279117, accuracy = 0.9760000038146973
epoch 4
train mean loss = 0.09530005491416281, accuracy = 0.9700833410024643
test mean loss = 0.07128305285063107, accuracy = 0.9774000066518783
epoch 5
train mean loss = 0.084215888553299, accuracy = 0.9739500084519386
test mean loss = 0.06781253896362614, accuracy = 0.9797000044584274
epoch 6
train mean loss = 0.07421663962226982, accuracy = 0.9765500106414159
test mean loss = 0.06678849312360398, accuracy = 0.9806000036001206
epoch 7
train mean loss = 0.07206320945755579, accuracy = 0.9780166767040889
test mean loss = 0.07613256934724631, accuracy = 0.9780000054836273
epoch 8
train mean loss = 0.06645605529270446, accuracy = 0.9794666781028112
test mean loss = 0.0694200206313326, accuracy = 0.9796000057458878
epoch 9
train mean loss = 0.06027518025541213, accuracy = 0.9811333427826564
test mean loss = 0.06582227945725208, accuracy = 0.981700006723404
epoch 10
train mean loss = 0.06272635982527087, accuracy = 0.9803333427508673
test mean loss = 0.06362627781827541, accuracy = 0.9824000054597855
epoch 11
train mean loss = 0.05525149108822613, accuracy = 0.9822166780630748
test mean loss = 0.059438277111039495, accuracy = 0.984400006532669
epoch 12
train mean loss = 0.05769200769641126, accuracy = 0.9823666775226593
test mean loss = 0.06064008094675955, accuracy = 0.9821000069379806
epoch 13
train mean loss = 0.05246836805231093, accuracy = 0.9837333444754283
test mean loss = 0.06008758193208678, accuracy = 0.9841000068187714
epoch 14
train mean loss = 0.05325017308399159, accuracy = 0.983550010919571
test mean loss = 0.06348420954424, accuracy = 0.9837000048160554
epoch 15
train mean loss = 0.04687451647075553, accuracy = 0.9857833432157834
test mean loss = 0.06079861531910865, accuracy = 0.9840000057220459
epoch 16
train mean loss = 0.05024066871997396, accuracy = 0.9843666763106982
test mean loss = 0.06952258783453544, accuracy = 0.9837000060081482
epoch 17
train mean loss = 0.04789641752979757, accuracy = 0.985533343354861
test mean loss = 0.0688758676241605, accuracy = 0.9830000072717666
epoch 18
train mean loss = 0.04523991203939658, accuracy = 0.9865000093976657
test mean loss = 0.06825290421969839, accuracy = 0.9847000086307526
epoch 19
train mean loss = 0.04624386687396812, accuracy = 0.9864333433906237
test mean loss = 0.06506712173536017, accuracy = 0.9841000074148178
epoch 20
train mean loss = 0.04339798055817179, accuracy = 0.9869333428144454
test mean loss = 0.07073728352328346, accuracy = 0.9837000060081482

pltの結果
f:id:taichitary:20170216215346p:plain

誤差が減り,正答率が上がった。うまく学習が進んだとわかる。

Common Lispとテキストゲーム

Lisp

Land of Lispの5章の復習。飽きないように作られていて良い。

連想リスト
リスト構造というLispの基本の形に,他の言語でよくある辞書型(Python風)なもの。キーと値が紐付いている形は,Lispではこう書くようで。

(defparameter *nodes* '((living-room (you are in the living-room. a wizard is snoring loudly on the couch))
(garden (you are in a beautiful garden. there is a well in front of you))
(attic (you are in the attic. there is a giant welding torch in the corner))))

簡潔で解りやすい。この連想リストの形から,キーと一緒に抜き出す方法はこちら / 値が取りたい時も書く

(assoc 'garden *nodes*)
; (garden (you are in a beautiful garden. there is a well in front of you))
(cadr (assoc 'garden *nodes*))
; (you are in a beautiful garden. there is a well in front of you)

準クォート
Lispでは,コードモードとデータモードを使い分けることによってコードを実行する。
データモードの時はデータの塊として処理されるのであるが,一部分だけコードを埋め込みたいときがある。そんな時にこれ。

(defun describe-path(edge)
`(there is a ,(caddr edge) going, (cadr edge) from here.))

注意すべきは,[`]であって[']ではないこと。ここでエラーが起きて首をかしげて少し時間をとった。

眠たいので高階関数については明日。