対象読者:CNNを用いた画像分類の基本知識があり、Kerasを用いて実装をしたいと思っている人
CIFAR-10データセットとは
CIFAR-10データセットは、32x32のカラー画像6万枚からなり、10クラス、各クラス6千枚の画像から構成されています。また、学習画像は5万枚、テスト画像は1万枚あります。
(参考:CIFAR-10 and CIFAR-100 datasets)
実装環境
Google Colaboratoryの無料版を用いています。
Google ColaboratoryはGoogleが提供するJupyter notebook環境です。
また、Pythonのバージョンは3.7
Kerasのバージョンは2.1です。
実装
必要なモジュールのインポート
import numpy as np
import matplotlib.pyplot as plt
from keras.datasets import cifar10
from keras.utils.np_utils import to_categorical
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPool2D
from keras.layers import Dense,Activation,Dropout,Flatten
from keras.layers import BatchNormalization
データセットの読込と前処理
# CIFAR-10データセットをダウンロード
(x_train,y_train), (x_test,y_test) = cifar10.load_data()
# 画像を0~1の範囲で正規化
x_train = x_train.astype('float32')/255.0
x_test = x_test.astype('float32')/255.0
# 正解ラベルをOne-Hotベクトルに変換
y_train = to_categorical(y_train,10)
y_test = to_categorical(y_test,10)
print(x_train.shape, y_train.shape)
(50000, 32, 32, 3) (50000, 10)
モデルの構築
Kerasではモデルの記述方法として、いくつかありますが、今回は一番簡単なSequentialで記述します。
今回のモデルのアーキテクチャ(構成)は、CNN-BN-ReLU-CNN-BN-ReLU-Poolをブロックとしたものを2つ繋げ、その後全結合層に接続しています。
モデルの損失関数には、多クラス分類であるため、交差エントロピーを採用しています。
また、最適化関数にはAdamを採用しています。最適化関数には他にSGDやRMSpropなどがありますが、経験的にAdamがおすすめです。
#モデルの構築
model = Sequential()
model.add(Conv2D(32,(3,3),padding='same',input_shape=(32,32,3)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32,(3,3),padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(64,(3,3),padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(64,(3,3),padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(10,activation='softmax'))
model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])
#モデルの表示
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 32, 32, 32) 896
batch_normalization (BatchN (None, 32, 32, 32) 128
ormalization)
activation (Activation) (None, 32, 32, 32) 0
conv2d_1 (Conv2D) (None, 32, 32, 32) 9248
batch_normalization_1 (Batc (None, 32, 32, 32) 128
hNormalization)
activation_1 (Activation) (None, 32, 32, 32) 0
max_pooling2d (MaxPooling2D (None, 16, 16, 32) 0
)
conv2d_2 (Conv2D) (None, 16, 16, 64) 18496
batch_normalization_2 (Batc (None, 16, 16, 64) 256
hNormalization)
activation_2 (Activation) (None, 16, 16, 64) 0
conv2d_3 (Conv2D) (None, 16, 16, 64) 36928
batch_normalization_3 (Batc (None, 16, 16, 64) 256
hNormalization)
activation_3 (Activation) (None, 16, 16, 64) 0
max_pooling2d_1 (MaxPooling (None, 8, 8, 64) 0
2D)
flatten (Flatten) (None, 4096) 0
dense (Dense) (None, 512) 2097664
activation_4 (Activation) (None, 512) 0
dropout (Dropout) (None, 512) 0
dense_1 (Dense) (None, 10) 5130
=================================================================
Total params: 2,169,130
Trainable params: 2,168,746
Non-trainable params: 384
_________________________________________________________________
モデルの学習
# モデルの学習
history = model.fit(x_train,y_train,
batch_size=128, # バッチサイズを128に設定
epochs=10, # エポック数を10に設定
verbose=1, #進捗状況をプログレスバーで表示
validation_split=0.1) # 訓練データの1割を検証データとして扱う
Epoch 1/10
352/352 [==============================] - 17s 16ms/step - loss: 1.8556 - accuracy: 0.3420 - val_loss: 2.1067 - val_accuracy: 0.2288
Epoch 2/10
352/352 [==============================] - 5s 14ms/step - loss: 1.3924 - accuracy: 0.4909 - val_loss: 1.2452 - val_accuracy: 0.5358
Epoch 3/10
352/352 [==============================] - 5s 15ms/step - loss: 1.2152 - accuracy: 0.5603 - val_loss: 1.1623 - val_accuracy: 0.5936
Epoch 4/10
352/352 [==============================] - 5s 15ms/step - loss: 1.0994 - accuracy: 0.6016 - val_loss: 0.9856 - val_accuracy: 0.6396
Epoch 5/10
352/352 [==============================] - 5s 15ms/step - loss: 1.0258 - accuracy: 0.6324 - val_loss: 0.8176 - val_accuracy: 0.7106
Epoch 6/10
352/352 [==============================] - 6s 17ms/step - loss: 0.9742 - accuracy: 0.6509 - val_loss: 0.8058 - val_accuracy: 0.7172
Epoch 7/10
352/352 [==============================] - 5s 14ms/step - loss: 0.9245 - accuracy: 0.6684 - val_loss: 0.8620 - val_accuracy: 0.7020
Epoch 8/10
352/352 [==============================] - 5s 14ms/step - loss: 0.8831 - accuracy: 0.6843 - val_loss: 1.0213 - val_accuracy: 0.6504
Epoch 9/10
352/352 [==============================] - 5s 14ms/step - loss: 0.8554 - accuracy: 0.6920 - val_loss: 0.8039 - val_accuracy: 0.7184
Epoch 10/10
352/352 [==============================] - 5s 14ms/step - loss: 0.8128 - accuracy: 0.7072 - val_loss: 0.7428 - val_accuracy: 0.7446
学習結果の表示
# エポックごとの正解率とlossの取得
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
# エポック数の取得
epochs = range(len(acc))
# 正解率の表示
plt.plot(epochs, acc, label='acc')
plt.plot(epochs, val_acc, label='val_acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.show()
# lossの表示
plt.plot(epochs, loss, label='loss')
plt.plot(epochs, val_loss, label='val_loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
エポック数が増えるにつれ、正解率は上がり、lossの値は小さくなっています。
今回は学習のエポック数10に設定しましたが、もっと学習させればより性能が上がることが期待できます。
テストデータを用いたモデルの評価
# 評価
loss,acc = model.evaluate(x_test,y_test,verbose=0)
print('Test loss:',loss)
print('Test accuracy:',acc)
Test loss: 0.7661172151565552
Test accuracy: 0.7469000220298767
分類精度は正解率77%となりました。
ソースコード全体
import numpy as np
import matplotlib.pyplot as plt
from keras.datasets import cifar10
from keras.utils.np_utils import to_categorical
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPool2D
from keras.layers import Dense,Activation,Dropout,Flatten
from keras.layers import BatchNormalization
# CIFAR-10データセットをダウンロード
(x_train,y_train), (x_test,y_test) = cifar10.load_data()
# 画像を0~1の範囲で正規化
x_train = x_train.astype('float32')/255.0
x_test = x_test.astype('float32')/255.0
# 正解ラベルをOne-Hot表現に変換
y_train = to_categorical(y_train,10)
y_test = to_categorical(y_test,10)
#モデルを構築
model = Sequential()
model.add(Conv2D(32,(3,3),padding='same',input_shape=(32,32,3)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32,(3,3),padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(64,(3,3),padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(64,(3,3),padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(10,activation='softmax'))
model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])
#モデルの表示
model.summary()
# モデルの学習
history = model.fit(x_train,y_train,
batch_size=128, # バッチサイズを128に設定
epochs=10, # エポック数を10に設定
verbose=1, #進捗状況をプログレスバーで表示
validation_split=0.1) # 訓練データの1割を検証データとして扱う
# エポックごとの正解率とlossの取得
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
# エポック数の取得
epochs = range(len(acc))
# 正解率の表示
plt.plot(epochs, acc, label='acc')
plt.plot(epochs, val_acc, label='val_acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.show()
# lossの表示
plt.plot(epochs, loss, label='loss')
plt.plot(epochs, val_loss, label='val_loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
# 評価
loss,acc = model.evaluate(x_test,y_test,verbose=0)
print('Test loss:',loss)
print('Test accuracy:',acc)
関連記事
- KerasでCIFAR-10の画像分類をやる【②モデルの保存と読み込み】