8月末頃に, TwitterだったかFacebookだったかで, Fashion-MNIST[1][2]なるデータセットの存在を知った.
以前に, ファッション画像における洋服の「色」分類にチャレンジ[3]したこともあり, 少し試してみた.
関連記事:
・Fashion-MNISTやってみた(1)
・Fashion-MNISTやってみた(2)
今回は, 予備実験的に前処理を中心に少し試してみた.
2. 予備実験(前処理編)
2.1 ベースシステム
Keras[4]のexamples/mnist_cnn.pyは, 畳み込み層が2層のCNNモデルであるが, ベースモデルとして畳み込み層が4層のCNNモデルを考えてみた.
モデル構造:
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_1 (Conv2D) (None, 28, 28, 64) 640 _________________________________________________________________ conv2d_2 (Conv2D) (None, 28, 28, 64) 36928 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 14, 14, 64) 0 _________________________________________________________________ conv2d_3 (Conv2D) (None, 14, 14, 128) 73856 _________________________________________________________________ conv2d_4 (Conv2D) (None, 14, 14, 128) 147584 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 7, 7, 128) 0 _________________________________________________________________ flatten_1 (Flatten) (None, 6272) 0 _________________________________________________________________ dense_1 (Dense) (None, 256) 1605888 _________________________________________________________________ dense_2 (Dense) (None, 256) 65792 _________________________________________________________________ dense_3 (Dense) (None, 10) 2570 =================================================================
コード:
from __future__ import print_function import os import gzip import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pylab as plt from utils import mnist_reader from keras.utils import to_categorical from keras.preprocessing import image from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential from keras.layers import Input, Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D from keras.callbacks import EarlyStopping from keras import optimizers TRAIN_DIR = './data/fashion/train' VAL_DIR = './data/fashion/val' TEST_DIR = './data/fashion/test' MODEL_DIR = './model' MODEL_FILE = 'cnn_v2_base.hdf5' HIST_FILE = 'cnn_v2_base.png' TRAIN_SAMPLES = 60000 VAL_SAMPLES = 2000 TEST_SAMPLES = 10000 IMG_ROWS = 56 IMG_COLS = 56 IMG_CHANNELS = 1 classes = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] BATCH_SIZE = 100 EPOCHS = 100 # 学習データ準備 def train_generator(): train_data_generator = ImageDataGenerator( rescale = 1.0 / 255) train_data = train_data_generator.flow_from_directory( TRAIN_DIR, target_size = (IMG_ROWS, IMG_COLS), color_mode = 'grayscale', classes = classes, class_mode = 'categorical', batch_size = BATCH_SIZE, seed = 1, shuffle = True) return train_data # 評価データ準備 def val_generator(): val_data_generator = ImageDataGenerator( rescale = 1.0 / 255) val_data = val_data_generator.flow_from_directory( VAL_DIR, target_size = (IMG_ROWS, IMG_COLS), color_mode = 'grayscale', classes = classes, class_mode = 'categorical', shuffle = False) return val_data def set_model(): input_shape = (IMG_ROWS, IMG_COLS, IMG_CHANNELS) model = Sequential() model.add(Conv2D(64, kernel_size=(3, 3), padding='same', activation='relu', input_shape=input_shape)) model.add(Conv2D(64, (3, 3), padding='same', activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(128, (3, 3), padding='same', activation='relu')) model.add(Conv2D(128, (3, 3), padding='same', activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) model.add(Dense(256, activation='relu')) model.add(Dense(256, activation='relu')) model.add(Dense(len(classes), activation='softmax')) model.summary() model.compile(loss='categorical_crossentropy', optimizer=optimizers.Adam(lr=0.0005, beta_1=0.9, beta_2=0.999), metrics=['accuracy']) return model def draw_history(hist): val_acc = hist.history['val_acc'] val_loss = hist.history['val_loss'] fig = plt.figure() ax_acc = fig.add_subplot(111) ax_acc.plot(val_acc, label='acc', linestyle='solid', color='blue') ax_loss = ax_acc.twinx() ax_loss.plot(val_loss, label='loss', linestyle='dashed', color='red') ax_acc.set_xlabel('epochs') plt.savefig(HIST_FILE) def training(train_data, val_data, model): early_stopping = EarlyStopping(monitor='val_loss', patience=10, verbose=1) hist = model.fit_generator( train_data, steps_per_epoch = int(TRAIN_SAMPLES/BATCH_SIZE), epochs = EPOCHS, validation_data = val_data, validation_steps = VAL_SAMPLES, callbacks = [early_stopping]) model.save_weights(os.path.join(MODEL_DIR, MODEL_FILE)) draw_history(hist) return model def evaluate(model, path='./data/fashion'): labels_path = os.path.join(path, 't10k-labels-idx1-ubyte.gz') with gzip.open(labels_path, 'rb') as lbpath: y_test = np.frombuffer(lbpath.read(), dtype=np.uint8, offset=8) y_test = to_categorical(y_test, len(classes)) x_test = np.empty((TEST_SAMPLES, IMG_ROWS, IMG_COLS, IMG_CHANNELS)) for i in range(len(y_test)): fname = 't10k_{0:05d}.bmp'.format(i) img = image.load_img(os.path.join(TEST_DIR, fname), grayscale=True, target_size=(IMG_ROWS, IMG_COLS)) x = image.img_to_array(img) / 255.0 x_test[i,:,:,:] = x score = model.evaluate(x_test, y_test, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1]) if __name__ == '__main__': model = set_model() train_data = train_generator() val_data = val_generator() model = training(train_data, val_data, model) evaluate(model)
2.2 Data Augmentation
keras.preprocessing.image.ImageDataGeneratorを活用して, 学習時に以下の4つの処理により画像を変形し, ロバストなモデルを作成してみた.
・width_shift_range: 横幅に対する割合0.1 --- ランダムに水平シフトする範囲
・height_shift_range: 縦幅に対する割合0.1 --- ランダムに垂直シフトする範囲
・zoom_range: 0.1 --- ランダムにズームする範囲. [lower, upper] = [1-zoom_range, 1+zoom_range]
・horizontal_flip: True --- 水平方向に入力をランダムに反転
変更箇所:
# 学習データ準備 def train_generator(): train_data_generator = ImageDataGenerator( rescale = 1.0 / 255, width_shift_range = 0.2, height_shift_range = 0.2, zoom_range = 0.1, horizontal_flip = True)
2.3 画像サイズ拡大
画像サイズを拡大して学習すると, 精度が向上する場合があるといった話を聞いたことがあったので, これも試してみた.
変更箇所:
IMG_ROWS = 56 IMG_COLS = 56 IMG_CHANNELS = 1
2.4 結果
以下の条件で, 比較実験を行ってみた.
学習/評価条件
データセット :Fashion-MNIST
学習データ :60,000サンプル
ミニバッチサイズ:100サンプル
テストデータ :10,000サンプル
実験結果
前処理 | エポック数 | 精度 |
ベースモデル | 15 | 0.9266 |
Data Augmentation | 66 | 0.9427 |
Data Augmentation+画像サイズ拡大 | 45 | 0.9338 |
精度0.94程度までは, 簡単なモデル構造と前処理で達成できることを確認した.
ここから, 現時点(2017/9/20)のTopスコア0.967に近付けるにはかなりの工夫が必要そう.
引き続き, 時間のある時に試してみようと思う.
----
参照URL:
[1] GitHub - zalandoresearch/fashion-mnist: A MNIST-like fashion product database. Benchmark
[2] http://tensorflow.classcat.com/category/fashion-mnist/
[3] 第1回FR FRONTIER:ファッション画像における洋服の「色」分類にチャレンジ!!(1)
[4] GitHub - keras-team/keras: Deep Learning for humans
| 退屈なことはPythonにやらせよう ―ノンプログラマーにもできる自動化処理プログラミング
| ゲームを作りながら楽しく学べるPythonプログラミング (Future Coders(NextPublishing))
| Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎
|