としおの読書生活

田舎に住む社会人の読書記録を綴ります。 主に小説や新書の内容紹介と感想を書きます。 読書の他にもワイン、紅茶、パソコン関係などの趣味を詰め込んだブログにしたいです。

タグ:画像分類

DeepLearningのブームのきっかけとなったAlexNetを使用してcifar10の画像分類をしてみたので忘備録として記録を残します。

cifar10について知りたい人は以下の記事で使用方法などを書いているのでそちらをご覧ください。







AlexNetとは


AlexNetは2012年のILSVRCにおいて従来の画像分類手法に対して大差をつけて優勝した手法である。

AlexNetにより画像分類における深層学習の有効性が示され、深層学習のブームがおきた。

現在でも画像分類モデルのベースラインとして利用されることが多々ある。

1


AlexNetのモデルの構造は上手のようになっている、5層の畳み込み層、3層のプーリング層、3層の全結合層からできている。


AlexNetでは活性化関数が従来使用されてきたtanhではなくReLUが使用されている。ReLUを使用することでtanhに比べて学習を高速化することができている。

また、過学習を抑制するために隠れ層のニューロンを無効化するDropoutもAlexNetでは使用されている。



実装




# AlexNetの論文を参考して作成したモデル def CreateAlexNet(input_shape, num_classes): model=Sequential() model.add(Conv2D(filters=96, kernel_size=3, strides=(1, 1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='zeros')) model.add(MaxPool2D(pool_size=(2, 2))) model.add(BatchNormalization()) model.add(Conv2D(filters=256, kernel_size=3, strides=(1,1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='ones')) model.add(MaxPool2D(pool_size=(2, 2))) model.add(BatchNormalization()) model.add(Conv2D(filters=384, kernel_size=3, strides=(1,1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='zeros')) model.add(Conv2D(filters=384, kernel_size=3, strides=(1,1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='ones')) model.add(Conv2D(filters=256, kernel_size=3, strides=(1,1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='ones')) model.add(MaxPool2D(pool_size=(2, 2))) model.add(BatchNormalization()) model.add(Flatten()) model.add(Dense(4096, activation='relu', bias_initializer='ones')) model.add(Dropout(0.5)) model.add(Dense(4096, activation='relu', bias_initializer='ones')) model.add(Dropout(0.5)) model.add(Dense(num_classes, activation='softmax')) return model

モデルは先ほどのAlexNetの図を参考に作成しました。

畳み込み層 ー>プーリング層 ー>畳み込み層 ー>プーリング層 ー>畳み込み層 ー>畳み込み層 ー>畳み込み層 ー>プーリング層 ー>全結合層 ー>全結合層という構成になっています。






学習結果


100epoch学習させてみた結果以下のような結果になりました。

2

テストデータに対する精度は80%ほどまで向上しました。パラメータのチューニングをせずにここまでの精度が出るなんてさすがという感じです。

前回行ったLeNetでは精度が65%ほどでしたので、それと比べてもAlexNetの性能の良さが分かります。

最後に、今回作成したソースコードを以下にのせておきます。


from keras.models import Sequential from keras.layers.convolutional import Conv2D from keras.layers.pooling import MaxPool2D from keras.layers.core import Dense, Flatten, Dropout from keras.layers.normalization import BatchNormalization from keras.datasets import cifar10 from keras.utils import np_utils from keras import optimizers import matplotlib.pyplot as plt # AlexNetの論文を参考して作成したモデル def CreateAlexNet(input_shape, num_classes): model=Sequential() model.add(Conv2D(filters=96, kernel_size=3, strides=(1, 1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='zeros')) model.add(MaxPool2D(pool_size=(2, 2))) model.add(BatchNormalization()) model.add(Conv2D(filters=256, kernel_size=3, strides=(1,1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='ones')) model.add(MaxPool2D(pool_size=(2, 2))) model.add(BatchNormalization()) model.add(Conv2D(filters=384, kernel_size=3, strides=(1,1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='zeros')) model.add(Conv2D(filters=384, kernel_size=3, strides=(1,1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='ones')) model.add(Conv2D(filters=256, kernel_size=3, strides=(1,1), padding='same', input_shape=input_shape, activation='relu', bias_initializer='ones')) model.add(MaxPool2D(pool_size=(2, 2))) model.add(BatchNormalization()) model.add(Flatten()) model.add(Dense(4096, activation='relu', bias_initializer='ones')) model.add(Dropout(0.5)) model.add(Dense(4096, activation='relu', bias_initializer='ones')) model.add(Dropout(0.5)) model.add(Dense(num_classes, activation='softmax')) return model # 学習の様子を可視化 def ShowTrainData(history): plt.figure(figsize=(10,5)) plt.subplot(1,2,1) plt.plot(history.history['accuracy']) plt.plot(history.history['val_accuracy']) plt.title('Model accuracy') plt.ylabel('Accuracy') plt.xlabel('Epoch') plt.legend(['Train', 'Test'], loc='upper left') plt.subplot(1,2,2) plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('Model loss') plt.ylabel('Loss') plt.xlabel('Epoch') plt.legend(['Train', 'Test'], loc='upper left') plt.show() def main(): # cifer10をダウンロード (x_train,y_train),(x_test,y_test)=cifar10.load_data() # 32×32×3の配列 # 画像を0から1の範囲で正規化 x_train = x_train.astype('float32') # float32に変換 x_train = x_train/255; # 0~1の値に変換するために255で割る(cifer10は0-255のRGBで表現されている) x_test = x_test.astype('float32') x_test = x_test/255; # 正解ラベルをone-hot表現に変換 y_train = np_utils.to_categorical(y_train, 10) y_test = np_utils.to_categorical(y_test, 10) #モデルを構築 model = CreateAlexNet(x_train[0].shape, 10) sgd = optimizers.SGD(lr=0.01) model.compile(optimizer='SGD',loss='categorical_crossentropy',metrics=['accuracy']) batch_size = 128; epoch = 100; history=model.fit(x_train,y_train,batch_size=batch_size,nb_epoch=epoch,verbose=1,validation_split=0.1) ShowTrainData(history) if __name__ == '__main__': main()




CNNの元祖となるLeNetを用いてcifar10の画像分類を行いました。





cifar10とは


cifar10とは飛行機、自動車、鳥、猫、トナカイ、犬、蛙、馬、船、トラックの10種の画像のデータセットです。

各画像は32×32のカラー画像で全体画像数は60000件あります。そのうち50000件が訓練データ、10000件がテストデータとなっています。

cifar10の画像の例を以下に示します。

Figure_1


LeNetとは


LeNetとは1998年に発表された畳み込みニューラルネットワーク(CNN)の元祖とも呼ばれているニューラルネットワークです。

ディープラーニングの火つけ役となったAlexNetもLeNetを参考にしたネットワーク構成となっています。

Figure_2

LeNetのネットワーク構成は、2層の畳み込み層、2層のプーリング層、2層の全結合層からできており、近年のモデルと比べると層が浅いのが特徴的です。

また、近年よく用いられているDropoutやBatch Normalaizationなども用いられていないためシンプルな構成となっています。


実装



cifar10の準備


# cifer10をダウンロード
    (x_train,y_train),(x_test,y_test)=cifar10.load_data() # 32×32×3の配列

    # 画像を0から1の範囲で正規化
    x_train = x_train.astype('float32') # float32に変換
    x_train = x_train/255; # 0~1の値に変換するために255で割る(cifer10は0-255のRGBで表現されている)
    x_test = x_test.astype('float32')
    x_test = x_test/255;

    # 正解ラベルをone-hot表現に変換
    y_train = np_utils.to_categorical(y_train, 10)
    y_test = np_utils.to_categorical(y_test, 10)

cifar10の画像は0-255のRGBで表現されているため255で割って0~1の範囲で正規化しています。

正解ラベルはone-hot表現に変換しています。
4なら[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
6なら[0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
といった感じに。


LeNetの構築


# LeNetの論文を参考して作成したモデル
def CreateLeNet(input_shape, num_classes):
    model=Sequential()
    
    model.add(Conv2D(filters=6, kernel_size=5, padding='same', input_shape=input_shape, activation='tanh'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Conv2D(filters=16, kernel_size=5, padding='same', activation='tanh'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Flatten())
    model.add(Dense(120, activation='tanh'))
    model.add(Dense(84, activation='tanh'))
    model.add(Dense(num_classes, activation='softmax'))
    
    return model

モデルは先ほどのLeNetの図を参考に作成しました。

畳み込み層 ー>プーリング層 ー>畳み込み層 ー>プーリング層 ー>全結合層 ー>全結合層という構成になっています。

LeNetのオリジナルの論文をモデルに作ったので活性化関数がreluではなくtanhなのに違和感を感じます…。


学習結果


100epoch学習させてみた結果以下のような結果になりました。

Figure_3

テストデータに対する精度は65%ほどまで向上し自分が予想していたよりも良い結果になりました。

128 -> 256 ー> 128といった全結合層のみを使用して学習した結果は以下のようになっていたことからLeNetの画像分類に対する有用性が分かりますね。

Figure_4


ただ、30epochを超えたあたりから過学習を起こしているのが少し気になります。Dropoutの処理とかをいれたらましになるのかな。


次はLeNetベースで精度を改善するか、他のモデルを使ってcifar10の学習をしてみたいと思います。

AlexNetを使用してcifar10の画像分類を行ってみました。




最後に、今回使用したソースコードを以下にのせておきます。

from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.layers.core import Dense, Flatten
from keras.datasets import cifar10
from keras.utils import np_utils
import matplotlib.pyplot as plt


# LeNetの論文を参考して作成したモデル
def CreateLeNet(input_shape, num_classes):
    model=Sequential()
    
    model.add(Conv2D(filters=6, kernel_size=5, padding='same', input_shape=input_shape, activation='tanh'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Conv2D(filters=16, kernel_size=5, padding='same', activation='tanh'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Flatten())
    model.add(Dense(120, activation='tanh'))
    model.add(Dense(84, activation='tanh'))
    model.add(Dense(num_classes, activation='softmax'))
    
    return model


# 学習の様子を可視化
def ShowTrainData(history):
    
    plt.figure(figsize=(10,5))
    
    plt.subplot(1,2,1)
    plt.plot(history.history['accuracy'])
    plt.plot(history.history['val_accuracy'])
    plt.title('Model accuracy')
    plt.ylabel('Accuracy')
    plt.xlabel('Epoch')
    plt.legend(['Train', 'Test'], loc='upper left')

    plt.subplot(1,2,2)
    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('Model loss')
    plt.ylabel('Loss')
    plt.xlabel('Epoch')
    plt.legend(['Train', 'Test'], loc='upper left')
    
    plt.show()


def main():
    # cifer10をダウンロード
    (x_train,y_train),(x_test,y_test)=cifar10.load_data() # 32×32×3の配列

    # 画像を0から1の範囲で正規化
    x_train = x_train.astype('float32') # float32に変換
    x_train = x_train/255; # 0~1の値に変換するために255で割る(cifer10は0-255のRGBで表現されている)
    x_test = x_test.astype('float32')
    x_test = x_test/255;

    # 正解ラベルをone-hot表現に変換
    y_train = np_utils.to_categorical(y_train, 10)
    y_test = np_utils.to_categorical(y_test, 10)

    #モデルを構築
    model = CreateLeNet(x_train[0].shape, 10)
    model.compile(optimizer='SGD',loss='categorical_crossentropy',metrics=['accuracy'])
    batch_size = 128;
    epoch = 100;

    history=model.fit(x_train,y_train,batch_size=batch_size,nb_epoch=epoch,verbose=1,validation_split=0.1)
    ShowTrainData(history)
    
if __name__ == '__main__':
    main()




↑このページのトップヘ