前回に引き続いて、kerasでの初学者向けディープランニング実装を行っていきたいと思います。前回はあらましを述べただけなので少々物足りないと思った方も少なくはないのでしょうか、今回はさわりを述べていきたいとか思います。

前回の記事はこちらです。

karasを用いたディープランニング

5.CNNによる犬と猫の分類

→Keras特設サイトはこちら

結果を分かりやすくするために、コンピュータビジョンで古くから問題になっているCNNを使って、画像に犬と猫のどちらが含まれているかを分類するという簡単なケースを取り上げます。画像データセットをKaggleからダウンロードしました。データセットはリンクからダウンロードすると、ZIPファイル形式になっています。

from google.colab import drive
drive.mount(‘/content/gdri
ve/’)!mkdir -p dataset!unzip /
content/gdrive/My\ Drive/Colab
\ Notebooks/blogs_medium/
cat_dog.zip -d dataset/

数行のコードを使って、Google Colabで直接ファイルを解凍することができます。

ここでは、22年前のニューラルネットワークであるLeNet-5を、通常は学習用サンプルとして使用しています。

ここからは、KerasでLeNet-5を構築するためのコードを紹介します。Kerasで再現性のある結果を得るためには、ランダムシードの設定が必要です。

import os

import tensorflow as tf

import numpy as np

python_random as random

np.random.seed(42)

python_random.seed(42)

tf.random.set_random_seed(42)

続いて、画像データに注目します。画像データをkeras.preprocessing.imageでtrainとvalidationの配列に読み込ませます。すべての画像には、(100,100,3)のように、統一されたサイズが必要です。データセットに含まれる犬や猫の画像は、大きかったり小さかったりと大きさが異なりますが、リサイズすることで同じ大きさにすることができます。

import keras

import glob

import os

from keras.preprocessing.image import ImageDataGenerator,load_img,img_to_array, array_to_img

from keras.layer import Dense, Conv2D, MaxPool2D, Flatten,Dropout

from keras import optimizers

from keras.models import Sequential

import numpy as np

image_size=(100,100)

train_cats = glob.glob(‘dataset/training_set/training_set/cats/*.jpg’)

train_dogs = glob.glob(‘dataset/training_set/training_set/dogs/*.jpg’)

train_files = [fn for fn in train_cats]+[fn for fn in train_dogs].

print(len(train_files))

train_imgs = [img_to_array(load_img(img, target_size=image_size)) for img in train_files].

train_imgs = np.array(train_imgs)

print(train_imgs.shape)

train_labels= [0 for i in range(len(train_cats))]+[1 for i in range(len(train_dogs))].

val_cats = glob.glob(‘dataset/test_set/test_set/cats/*.jpg’)

val_dogs = glob.glob(‘dataset/test_set/test_set/dogs/*.jpg’)

val_files = [fn for fn in val_cats]+[fn for fn in val_dogs].

val_imgs = [img_to_array(load_img(img, target_size=image_size)) for img in val_files].

val_imgs = np.array(val_imgs)

print(val_imgs.shape)

val_labels= [0 for i in range(len(val_cats))]+[1 for i in range(len(val_dogs))].

上記のコードでは,訓練セットと検証セットのどちらにも,すべての「犬」と「猫」が配列されています。また、犬には数字の1を、猫には数字の0をつけます。

次に、カテゴライズされた整数の特徴0と1をワンショットエンコーディングで符号化します。

num_classes = 2

epocs = 10

imput_shape = (100,100,3)

# テキストのカテゴリーラベルをエンコード

from sklearn.preprocessing import OneHotEncoder, LabelEncoder

train_labels_array = np.array(train_labels)

le = LabelEncoder()

train_integer_encoded = le.fit_transform(train_labels_array)

ohe = OneHotEncoder(sparse=False)

train_integer_encoded = train_integer_encoded.reshape(len(train_integer_encoded), 1)

train_labels_ohe = ohe.fit_transform(train_integer_encoded)

validation_labels_array = np.array(val_labels)

validation_integer_encoded = le.fit_transform(validation_labels_array)

ohe = OneHotEncoder(sparse=False)

validation_integer_encoded = validation_integer_encoded.reshape(len(validation_integer_encoded), 1)

validation_labels_ohe = ohe.fit_transform(validation_integer_encoded)

モデルを早く収束させるために、データを正規化する必要があります。

train_imgs_scaled = train_imgs.asstype(‘float32’)

validation_imgs_scaled = val_imgs.asstype(‘float32’)

train_imgs_scaled /= 255

validation_imgs_scaled /= 255

次に、モデル構造を構築します。

from keras import layers

from keras.layer import Conv2D, MaxPooling2D, Flatten, Dense, Dropout

from keras.models import model

from keras import optimizers

def lenet_5(in_shape=(100,100,3), n_classes=2):

in_layer = layers.Input(in_shape)

conv1 = layers.Conv2D(filters=20, kernel_size=5,

padding=’same’, activation=’relu’)(in_layer)

pool1 = layers.MaxPool2D()(conv1)

conv2 = layers.Conv2D(filters=50, kernel_size=5,

padding=’same’, activation=’relu’)(pool1)

pool2 = layers.MaxPool2D()(conv2)

flatten = layers.Flatten()(pool2)

dense1 = layers.Dense(500, activation=’relu’,kernel_initializer=’glorot_uniform’)(flatten)

preds = layers.Dense(2, activation=’softmax’,kernel_initializer=’glorot_uniform’)(dense1)

opt = keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, amsgrad=False)

model = Model(in_layer, preds)

model.compile(loss=”categorical_crossentropy”, optimizer=opt, metrics=[“accuracy”])

return model

if __name__ == ‘__main__’:

model = lenet_5()

print(model.summary())

モデルの概要

ここでは、10エポックでモデルを学習し、batch_sizeを200と定義しました。

from keras.callbacks import ModelCheckpoint

checkpoint = ModelCheckpoint(“lenet.h5”,monitor=’val_acc’,verbose=1,save_best_only=True, save_weights_only= False, mode =’auto’,period=1)

history = model.fit(x=train_imgs_scaled, y=train_labels_ohe, validation_data=(validation_imgs_scaled, validation_labels_ohe), batch_size=200, epochs=10, callbacks=[checkpoint], shuffle=True)

長い待ち時間の後、トレーニング/バリデーションのダイアグラムを得ることができました。

 

上の図は、5エポック後にモデルがあまり改善されていないことを示しています。しかし、オーバーフィットしていません。そのため、得られたモデルはまだ使用することができます。

私たちは、犬猫分類器のためのより良いLeNet-5モデルを訓練するために、より多くの努力をしたいので、モデルのハイパーパラメータに焦点を当てて、モデルを改善します。

6.コードによるLetNet-5でのTalos

ここでは,LeNet-5と同じ構造を持つ新しい関数を定義します.ただし,モデルのハイパーパラメータの一部は可変です.これらの可変ハイパーパラメータを辞書 “p “に保存します。

p = {‘first_hidden_layer’: [500],

‘opt’: Adam, sgd],

‘dropout’: [0,0.5],

‘weight_regulizer’:[None],

‘lr’: [1],

‘emb_output_dims’: [None],

‘kernel_initializer’:[“glorot_uniform”]}

コンピュータの計算やプログラムの実行時間を短縮するために、辞書には「opt」と「dropout」という変数だけを設定しています。オプティマイザには2つのオプション(Adamまたはsgd)、ドロップアウトには2つの可能な値を設定しています。全部で4つの組み合わせがあります。

from keras.optimizers import Adam,sgd

from keras.models import load_model

from keras.utils import CustomObjectScope

from keras.initializers import glorot_uniform

import talos

from talos.model.normalizers import lr_normalizer

def lenet_model(x_train, y_train,x_val, y_val, params):

in_layer = layers.Input((100,100,3))

conv1 = layers.Conv2D(filters=20, kernel_size=5,

padding=’same’, activation=’relu’)(in_layer)

pool1 = layers.MaxPool2D()(conv1)

conv2 = layers.Conv2D(filters=50, kernel_size=5,

padding=’same’, activation=’relu’)(pool1)

pool2 = layers.MaxPool2D()(conv2)

flatten = layers.Flatten()(pool2)

dense1 = layers.Dense(params[‘first_hidden_layer’], activation=’relu’)(flatten)

dropout1 = layers.Dropout(params[‘dropout’])(dense1)

preds = layers.Dense(2, activation=’softmax’)(dropout1)

model = Model(in_layer, preds)

model.compile(loss=”categorical_crossentropy”, optimizer=params[‘opt’](lr=lr_normalizer(params[‘lr’],params[‘opt’])), metrics=[“acc”])

steps_per_epoch = int(np.ceil(train_imgs.shape[0] / 20)) – 1

history = model.fit(x=train_imgs_scaled, y=train_labels_ohe, validation_data=(validation_imgs_scaled, validation_labels_ohe), batch_size=200, epochs=10, callbacks=[talos.utils.ExperimentLogCallback(‘kgt’, params)], verbose=1)

return history, model

t = talos.Scan(x=train_imgs_scaled, y=train_labels_ohe, model=lenet_model, experiment_name= ‘kgt’, params=p)

Scanコマンド(talos.Scan)を使って、実験の設定を開始します。これは、最後の基本的なLeNet-5モデルのトレーニングよりも長い時間をかけて行われます。

 

全てを考慮すると、Adamを使用しているがドロップアウトがないモデル0が最も良いパフォーマンスを示します。

7.おわりに

今回のお話では、Kerasで構築したCNNのハイパーパラメータをtalosを使ってチューニングする方法を紹介しました。序盤は、パラメータやハイパーパラメータに関する基礎知識と、ハイパーパラメータを最適化するための通常の手法のおさらいをしました。残りの部分では、LeNet-5ベースの猫と犬の分類器を構築し、興味のあるすべてのハイパーパラメータの組み合わせをスキャンしました。検証の指標を観察することで、どのハイパーパラメータが最も影響力があり、どの組み合わせが最良の結果を与えるかを知ることができます。

 

いかがでしたでしょうか。Kerasの畳み込みニューラルネットワークについての実装入門をご紹介させていただきました。少々わかりずらいところもあるかもしれませんが、自己補填することでより理解が深まるので冒頭でも話しましたが検索して調べることが自己育成に繋がると思います。