import cv2 import numpy as np def rotateImage(image, angle): center = tuple(np.array(image.shape)[:2]/2) # 2d ! rot_mat = cv2.getRotationMatrix2D(center,angle,1.0) result = cv2.warpAffine(image, rot_mat, tuple(np.array(image.shape)[:2]) ,flags=cv2.INTER_LINEAR) return result def rotateImageAndSave(path, label): files = glob.glob(path) files.sort() for i, filename in enumerate(files): print i, img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) for deg in range(90,360,90): img = rotateImage(img, deg) str_deg = str(deg) output = "../train_data/"+label+"/"+str(i)+"rotate"+str_deg+'.png' cv2.imwrite(output, img) flipX = cv2.flip(img, 0) output = "../train_data/"+label+"/"+str(i)+"rotate"+str_deg+"flipX"+'.png' cv2.imwrite(output, flipX) flipY = cv2.flip(img, 1) output = "../train_data/"+label+"/"+str(i)+"rotate"+str_deg+"flipY"+'.png' cv2.imwrite(output, flipY) flipXY = cv2.flip(img, -1) output = "../train_data/"+label+"/"+str(i)+"rotate"+str_deg+"flipXY"+'.png' cv2.imwrite(output, flipXY)
水増し関数.py
rotateImageAndSave(r"../train_data/1/*.png","1") rotateImageAndSave(r"../train_data/0/*.png","0")
水増し.py
画像パスとラベルの対応関係を記述する
inputfolder = r"../train_data" import sys import os.path import shutil import glob import random # 書き込むテキストファイル train_list = open("train.txt", "w") test_list = open("test.txt", "w") classno = 0 count = 0 for label in range(0,2): label=str(label) imagefolder = inputfolder+"/"+label+"/" images = [r.split('/')[-1] for r in glob.glob(imagefolder+"*.png")] startcount = count length = len(images) for image in images: # 各クラスのデータの75%を学習に25%をテストに使う if random.random() < 0.75: train_list.write(imagefolder+image+" %d\n" %classno) else: test_list.write(imagefolder+image+" %d\n" %classno) count+=1 classno+=1 train_list.close() test_list.close() print "Complete!"
ラベル対応.py
学習モデル
from chainer import cuda, Function, FunctionSet, gradient_check, Variable, optimizers, serializers from chainer.training import extensions import chainer.functions as F class CNN(): #cuda.get_device(0).use() # GPU用コード def __init__(self): self.model = FunctionSet( conv1 = F.Convolution2D(1,32,3,pad=1), conv2 = F.Convolution2D(32,32,3,pad=1), conv3 = F.Convolution2D(32,16,3,pad=1), conv4 = F.Convolution2D(16,16,3,pad=1), l1 = F.Linear(256,50),#1つ目の値は計算方法があるが適当でもChainerが実行時に正しい値を教えてくれる l2 = F.Linear(50,3), ).to_cpu() def forward(self, x_data, y_data, train=True): x, t = Variable(x_data), Variable(y_data) c = F.max_pooling_2d(F.relu(self.model.conv1(x)), 2) c = F.max_pooling_2d(F.relu(self.model.conv2(c)), 2) c = F.max_pooling_2d(F.relu(self.model.conv3(c)), 2) c = F.max_pooling_2d(F.relu(self.model.conv4(c)), 2) h = F.dropout(F.relu(self.model.l1(c)), train=train) y = self.model.l2(h) if train: # 学習時 return F.softmax_cross_entropy(y, t) else: return y # 評価時
モデル.py
いよいよ学習!
学習の前に元データの画像サイズを確認しておきます。
今回は64と出力されました。1片64の正方形画像です。
import cv2 img = cv2.imread(r"../train_data/0/0.png", 0) print img.shape imagesize = img.shape[0]
画像サイズ.py
学習のためのコードです。今回は100回学習を繰り返します。
import numpy as np import chainer from chainer import Function, FunctionSet, gradient_check, Variable, optimizers, serializers from chainer.training import extensions import argparse import random import chainer.functions as F import cv2 import time #cuda.get_device(0).use() # GPU用コード # 学習モデル設定 model = CNN() optimizer = optimizers.Adam() optimizer.setup(model.model) # 学習データリストファイルから一行ずつ読み込む train_list = [] for line in open(r"train.txt"): pair = line.strip().split() train_list.append((pair[0], np.float32(pair[1]))) # 画像データとラベルデータを取得する x_train = [] # 画像データ格納 y_train = [] # ラベルデータ格納 for filepath, label in train_list: img = cv2.imread(filepath, 0) # グレースケールで読み込む x_train.append(img) y_train.append(label) # 学習で使用するsoftmax_cross_entropyは # 学習データはfloat32,ラベルはint32にする必要がある。 x_train = np.array(x_train).astype(np.float32) y_train = np.array(y_train).astype(np.int32) # 画像を(学習枚数、チャンネル数、高さ、幅)の4次元に変換する x_train = x_train.reshape(len(x_train), 1, imagesize, imagesize) / 255 N = len(y_train) batchsize = 60 datasize = len(x_train) n_epoch = 100 # 繰り返し学習回数 # 学習開始 train_start = time.time() print "start" for epoch in range(1, n_epoch+1): sum_loss = 0 perm = np.random.permutation(N) # データセットの順番をシャッフル train_start_one = time.time() for i in range(0,datasize, batchsize): x_batch = x_train[perm[i:i+batchsize]] # バッチサイズ分のデータを取り出す y_batch = y_train[perm[i:i+batchsize]] # 初期化 optimizer.zero_grads() # 誤差伝播 loss = model.forward(x_batch, y_batch, train=True) # 誤差逆伝播 loss.backward() # ネットワークパラメータ更新 optimizer.update() sum_loss += loss.data print "epoch:{} loss={} time:{}".format(epoch, sum_loss / (datasize/batchsize), time.time()-train_start_one) if epoch%10==0: serializers.save_npz("model_{}".format(n_epoch), model.model) serializers.save_npz("state_{}".format(n_epoch), optimizer) print "train time:{}".format(time.time()-train_start) # 学習したモデルを出力する serializers.save_npz("model_{}".format(n_epoch), model.model) serializers.save_npz("state_{}".format(n_epoch), optimizer)
学習.py
学習完了!
私のMacbook Air ではtrain time:1088.80467081とでました。約15分くらいですね。続いて精度の検証を行ってみたいと思います。