CIFAR-10にチャレンジしてみた【Keras】
なかなかハイペースに進めています。この記事はシリーズ物なのですが、わずか一日でCIFAR-10にまでやってきました。
CIFER-10とは何か
10種類のカラー画像をまとめたデータセットのことです。MNISTと同じ10クラスですが、こちらはカラー画像であるという点が大きな違いです。もちろん数字ではなく飛行機、自動車などのオブジェクトの括りになっています。基本的には応用なのですが、これを分類するネットワークを作って、今日は終わりにしておきましょう。
import os import keras from keras.models import Sequential from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.layers.core import Activation from keras.layers.core import Flatten, Dropout from keras.layers.core import Dense from keras.datasets import cifar10 from keras.optimizers import RMSprop from keras.callbacks import TensorBoard, ModelCheckpoint def network(input_shape, num_classes): model = Sequential() # extract image features by convolution and max pooling layers model.add(Conv2D( 32, kernel_size=3, padding="same", input_shape=input_shape, activation="relu" )) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Conv2D(64, kernel_size=3, padding="same", activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2))) # classify the class by fully-connected layers model.add(Flatten()) model.add(Dense(512, activation="relu")) model.add(Dropout(0.5)) model.add(Dense(num_classes)) model.add(Activation("softmax")) return model class CIFAR10Dataset(): def __init__(self): self.image_shape = (32, 32, 3) self.num_classes = 10 def get_batch(self): (x_train, y_train), (x_test, y_test) = cifar10.load_data() x_train, x_test = [self.preprocess(d) for d in [x_train, x_test]] y_train, y_test = [self.preprocess(d, label_data=True) for d in [y_train, y_test]] return x_train, y_train, x_test, y_test def preprocess(self, data, label_data=False): if label_data: # convert class vectors to binary class matrices data = keras.utils.to_categorical(data, self.num_classes) else: data = data.astype("float32") data /= 255 # convert the value to 0~1 scale shape = (data.shape[0],) + self.image_shape # add dataset length data = data.reshape(shape) return data class Trainer(): def __init__(self, model, loss, optimizer): self._target = model self._target.compile( loss=loss, optimizer=optimizer, metrics=["accuracy"] ) self.verbose = 1 logdir = "logdir_cifar10_net" self.log_dir = os.path.join(os.path.dirname(__file__), logdir) self.model_file_name = "model_file.hdf5" def train(self, x_train, y_train, batch_size, epochs, validation_split): if os.path.exists(self.log_dir): import shutil shutil.rmtree(self.log_dir) # remove previous execution os.mkdir(self.log_dir) model_path = os.path.join(self.log_dir, self.model_file_name) self._target.fit( x_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=validation_split, callbacks=[ TensorBoard(log_dir=self.log_dir), ModelCheckpoint(model_path, save_best_only=True) ], verbose=self.verbose ) dataset = CIFAR10Dataset() # make model model = network(dataset.image_shape, dataset.num_classes) # train the model x_train, y_train, x_test, y_test = dataset.get_batch() trainer = Trainer(model, loss="categorical_crossentropy", optimizer=RMSprop()) trainer.train( x_train, y_train, batch_size=128, epochs=12, validation_split=0.2 ) # show result score = model.evaluate(x_test, y_test, verbose=0) print("Test loss:", score[0]) print("Test accuracy:", score[1])
意外にも、本に掲載された内容そのままで実行することができました。画像ファイルも事前に準備するのかと思いましたが、プログラム自体が勝手にダウンロードしてくれました。便利な時代になったものですね。
動かしてみたよ
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 170500096/170498071 [==============================] - 191s 1us/step Train on 40000 samples, validate on 10000 samples Epoch 1/12 40000/40000 [==============================] - 83s 2ms/step - loss: 1.7585 - acc: 0.3689 - val_loss: 1.4300 - val_acc: 0.4941 Epoch 2/12 40000/40000 [==============================] - 83s 2ms/step - loss: 1.3339 - acc: 0.5281 - val_loss: 1.2361 - val_acc: 0.5749 Epoch 3/12 40000/40000 [==============================] - 90s 2ms/step - loss: 1.1653 - acc: 0.5911 - val_loss: 1.1378 - val_acc: 0.6001 Epoch 4/12 40000/40000 [==============================] - 82s 2ms/step - loss: 1.0476 - acc: 0.6321 - val_loss: 1.0420 - val_acc: 0.6337 Epoch 5/12 40000/40000 [==============================] - 80s 2ms/step - loss: 0.9616 - acc: 0.6615 - val_loss: 0.9585 - val_acc: 0.6602 Epoch 6/12 40000/40000 [==============================] - 80s 2ms/step - loss: 0.8937 - acc: 0.6882 - val_loss: 0.9359 - val_acc: 0.6781 Epoch 7/12 40000/40000 [==============================] - 76s 2ms/step - loss: 0.8425 - acc: 0.7058 - val_loss: 0.8910 - val_acc: 0.7006 Epoch 8/12 40000/40000 [==============================] - 74s 2ms/step - loss: 0.7818 - acc: 0.7270 - val_loss: 0.8884 - val_acc: 0.7000 Epoch 9/12 40000/40000 [==============================] - 74s 2ms/step - loss: 0.7397 - acc: 0.7434 - val_loss: 0.8670 - val_acc: 0.7085 Epoch 10/12 40000/40000 [==============================] - 74s 2ms/step - loss: 0.6927 - acc: 0.7605 - val_loss: 0.8795 - val_acc: 0.7043 Epoch 11/12 40000/40000 [==============================] - 75s 2ms/step - loss: 0.6524 - acc: 0.7751 - val_loss: 0.8307 - val_acc: 0.7244 Epoch 12/12 40000/40000 [==============================] - 78s 2ms/step - loss: 0.6230 - acc: 0.7878 - val_loss: 0.8078 - val_acc: 0.7294 Test loss: 0.8138949976921082 Test accuracy: 0.7255
まとめ
結果としては72.55%の正答率ということになりました。MINSTに比べると格段に性能が悪いことが判ります。書籍の実行例も同じようになっていたので、これはこういうものだと理解しましょう。4つに3つは見分けられるという点を評価すべきなのでしょうね。
Conv2Dの階層を増やす事例も書籍には掲載されていましたが、精度が75%くらいになるのがせいぜいのようです。他にも、データ水増しの事例も載っていましたが、76%くらいにしかならないようです。学習時間に比べて割りに合わないように見えるのは気のせいでしょうか。
ただ、論文上では最新の精度は96%を超えるところまで到達しているそうです。どうやって、そんな精度を実現することができたのか、興味深いです。