PythonMania

普段はロボットとAIを組み合わせて色々作ってます。Python関係以外も色々投稿していくと思います。

【Python】画像認識 - CNNを実装してみる【Python】



今回はKerasを使ってConvolutional Neaural Network(CNN)を構築し、実際に学習を行ってみたいと思います。


今回も今までと同様、植物の画像分類コンペを取り上げて勉強していきます。

www.kaggle.com


#必要なライブラリの読み込み
import glob
import os
from PIL import Image, ImageOps
import numpy as np
from scipy.misc import imresize
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelBinarizer


#globを使いトレーニングデータを読み込む
z = glob.glob("E:/Kaggle/plant-seedlings-classification/train/*/*.png")
ori_label = []
ori_imgs = []
for fn in z:
    if fn[-3:] != 'png':
        continue
    ori_label.append(fn.split('/')[-2])
    new_img = Image.open(fn)
    ori_imgs.append(ImageOps.fit(new_img, (48, 48), Image.ANTIALIAS).convert('RGB'))


#画像を1枚表示してみる
ori_imgs[1]

#画像の配列化、正則化、カテゴリラベルの数値化
imgs = np.array([np.array(im) for im in ori_imgs])
imgs = imgs.reshape(imgs.shape[0], 48, 48, 3) / 255
lb = LabelBinarizer().fit(ori_label)
label = lb.transform(ori_label)


#トレーニングデータとテストデータの分割
trainX, validX, trainY, validY = train_test_split(imgs, label, test_size=0.05, random_state=42)



#CNNモデル構築に必要なライブラリのインポート
from keras.layers import Dropout, Input, Dense, Activation,GlobalMaxPooling2D, BatchNormalization, Flatten, Conv2D, MaxPooling2D
from keras.models import Model, load_model
from keras.optimizers import Adam


#CNNモデルの構築
#インプットレイヤー 今回は画像サイズ(48 × 48) のRGB(3チャンネル)画像を読み込み
IM_input = Input((48,48,3))
#2次元の畳み込みレイヤー 入力画像(48×48×3)の画像を(3×3)のフィルターを通して畳み込み、(46×46×16)に変換
IM = Conv2D(16,(3,3))(IM_input)
#データ値の平滑化 過学習の抑制や学習の進行速度向上の効果あり
IM = BatchNormalization(axis = 3)(IM)
#活性化関数 今回は「relu」
IM = Activation("relu")(IM)
IM = Conv2D(16, (3, 3))(IM)
IM = BatchNormalization(axis = 3)(IM)
IM = Activation('relu')(IM)
#(2×2)のフィルターを(2×2)ずつずらしていき、特徴を圧縮(強調)する
IM = MaxPooling2D((2,2),strides = (2,2))(IM)
IM = Conv2D(32, (3, 3))(IM)
IM = BatchNormalization(axis = 3)(IM)
IM = Activation('relu')(IM)
IM = Conv2D(32, (3, 3))(IM)
IM = BatchNormalization(axis = 3)(IM)
IM = Activation('relu')(IM)
IM = GlobalMaxPooling2D()(IM)
#全結合層 reluを使って64次元のベクトルに変換
IM = Dense(64, activation='relu')(IM)
IM = Dropout(0.5)(IM)
IM = Dense(32, activation='relu')(IM)
IM = Dropout(0.5)(IM)
IM = Dense(12, activation='softmax')(IM)
model = Model(inputs=IM_input, outputs=IM)
model.summary()
model.compile(loss='categorical_crossentropy',optimizer=Adam(lr=1e-4), metrics=['acc'])

#学習に必要なライブラリのインポート
from keras.callbacks import LearningRateScheduler, EarlyStopping
from keras.callbacks import ModelCheckpoint

#学習の実行
batch_size = 64
annealer = LearningRateScheduler(lambda x: 1e-3 * 0.9 ** x)
earlystop = EarlyStopping(patience=10)
modelsave = ModelCheckpoint(
    filepath='model.h5', save_best_only=True, verbose=1)
model.fit(
    trainX, trainY, batch_size=batch_size,
    epochs=200,
    validation_data=(validX, validY),
    callbacks=[annealer, earlystop, modelsave]
)


#テストデータの読み込み
z = glob.glob("E:/Kaggle/plant-seedlings-classification/test/*/*.png")
test_imgs = []
names = []
for fn in z:
    if fn[-3:] != 'png':
        continue
    names.append(fn.split('/')[-1])
    new_img = Image.open(fn)
    test_img = ImageOps.fit(new_img, (48, 48), Image.ANTIALIAS).convert('RGB')
    test_imgs.append(test_img)
model = load_model('model.h5')

#テストデータの配列化、正則化
timgs = np.array([np.array(im) for im in test_imgs])
testX = timgs.reshape(timgs.shape[0], 48, 48, 3) / 255



#推論実行
yhat = model.predict(testX)
test_y = lb.inverse_transform(yhat)

#提出用データ作成
#import pandas as pd
#df = pd.DataFrame(data={'file': names, 'species': test_y})
#df_sort = df.sort_values(by=['file'])
#df_sort.to_csv('results.csv', index=False)