Google Colaboratory で CIFAR-10 をやってみた メモ

20210606 google colaboratory で CIFAR-10 メモ

ググったサイトや本のプログラムが一発で動く事は殆どない。
そこを直していく中で知識が増えていく(時間はかかるが・・・)
そして理解できたあたりで期待していたサイトが見つかる事がよくある。


今回うまく行かなかった、主な原因は、kerasのver違い。
今、Cifar-10をやる人はいないのか参考サイトはkeras 1.xが殆ど。Colabはkeras2.x。
参考サイトのプログラムを2.0に合わせるよう修正したら動いた。


#CIFAR-10
CIFAR-10は32x32ピクセルのカラー画像のデータセット。クラスラベルはairplane, automobile, bird, cat, deer, dog,frog,horse, ship, truckの10種類で訓練用データ5万枚、テスト用データ1万枚から成る。
keras.datasets.cifar10モジュールを使えば勝手にダウンロードして使いやすい形で提供してくれる。


#X_train , y_trainの中身
X_trainは (50000, 32, 32, 3) の4次元テンソルで与えられる
配列には0-255の画素値が入っているため255で割って0-1に正規化。
 ※入る数値はこんなかんじか?
  画像が50000枚:0-49999
  行数が32:0-255を255で割って正規化するので>0-1
  列数が32:0-255を255で割って正規化するので>0-1
  チャンネルが3(RGB) :0-2
y_trainは (50000, 1) の配列で与えられる。
クラスラベルは0-9の値が入っているのでNNで使いやすいように
one-hotエンコーディング形式に変換する。
  画像が50000枚:0-49999
  10種のどれかをone-hotなので:0,1


#CNNの構築
少し層が深いCNNを構成
INPUT -> ((CONV->RELU) * 2 -> POOL) * 2 -> FC

畳み込み層(CONV), ReLU活性化関数(RELU) を2回繰り返して
プーリング層(POOL)を1セットとしてそれを2セット繰り返し
後に全結合層(FC)
を通して分類するという構成。

#!/usr/local/bin/python3
#!-*- coding: utf-8 -*-

import os
import numpy as np
# from scipy.misc import toimage
from PIL.Image import fromarray as toimage
import matplotlib.pyplot as plt

from keras.datasets import cifar10
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
# from keras.layers import Convolution2D, MaxPooling2D
from keras.layers import Conv2D, MaxPooling2D
# from keras.utils.visualize_util import plot
from keras.utils.vis_utils import plot_model


def cnn_model(X_train, nb_classes):

    model = Sequential()

    # model.add(Convolution2D(32, 3, 3, border_mode='same', input_shape=X_train.shape[1:]))
    model.add(Conv2D(32, (3, 3), padding="same", input_shape=X_train.shape[1:]))

    model.add(Activation('relu'))
    model.add(Conv2D(32, (3, 3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))

    # model.add(Convolution2D(64, 3, 3, border_mode='same'))
    model.add(Conv2D(64, (3, 3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(64, (3, 3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.25))

    model.add(Flatten())
    model.add(Dense(512))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))

    model.add(Dense(nb_classes))
    model.add(Activation('softmax'))

    model.compile(
        loss='categorical_crossentropy',
        optimizer='adam',
        metrics=['accuracy']
    )

    return model

def plot_cifar10(X, y, result_dir):
    plt.figure()

    # 画像を描画
    nclasses = 10
    pos = 1

    for targetClass in range(nclasses):
        targetIdx = []

        # クラスclassIDの画像のインデックスリストを取得
        for i in range(len(y)):
            if y[i][0] == targetClass:
                targetIdx.append(i)

        # 各クラスからランダムに選んだ最初の10個の画像を描画
        np.random.shuffle(targetIdx)

        for idx in targetIdx[:10]:
            img = toimage(X[idx])
            plt.subplot(10, 10, pos)
            plt.imshow(img)
            plt.axis('off')
            pos += 1

    plt.savefig(os.path.join(result_dir, 'plot.png'))

def save_history(history, result_file):
    loss = history.history['loss']
    acc = history.history['acc']
    val_loss = history.history['val_loss']
    val_acc = history.history['val_acc']
    epochs = len(acc)

    with open(result_file, "w") as fp:
        fp.write("epoch\tloss\tacc\tval_loss\tval_acc\n")
        for i in range(epochs):
            fp.write("%d\t%f\t%f\t%f\t%f\n" % (i, loss[i], acc[i], val_loss[i], val_acc[i]))
if __name__ == '__main__':

    # データ学習訓練の試行回数
    epochs = 100

    # 学習結果の保存ディレクトリ
    result_dir = '/content/drive/MyDrive/CIFAR-10'

    # 1回の学習で何枚の画像を使うか
    batch_size = 128

    # 識別ラベル数
    nb_classes = 10

    # 入力画像の次元
    img_rows, img_cols = 32, 32

    # チャネル数(RGBなので3)
    img_channels = 3

    # CIFAR-10データをロード
    # (nb_samples, nb_rows, nb_cols, nb_channel) = tf
    (X_train, y_train), (X_test, y_test) = cifar10.load_data()

    # ランダムに画像をプロット
    plot_cifar10(X_train, y_train, result_dir)

    # 画素値を0-1に変換
    X_train = X_train.astype('float32')
    X_test = X_test.astype('float32')
    X_train /= 255.0
    X_test /= 255.0

    # クラスラベル(0-9)をone-hotエンコーディング形式に変換
    Y_train = np_utils.to_categorical(y_train, nb_classes)
    Y_test = np_utils.to_categorical(y_test, nb_classes)

    # モデル
    model = cnn_model(X_train, nb_classes)

    # モデルのサマリを表示
    model.summary()
    plot_model(model, show_shapes=True, to_file=os.path.join(result_dir, 'model.png'))

    # 学習
    history = model.fit(
        X_train,
        Y_train,
        batch_size=batch_size,
        epochs=epochs,
        verbose=1,
        validation_data=(X_test, Y_test),
        shuffle=True
    )

    # 学習したモデルと重みと履歴の保存
    model_json = model.to_json()

    with open(os.path.join(result_dir, 'model.json'), 'w') as json_file:
        json_file.write(model_json)

    model.save_weights(os.path.join(result_dir, 'model.h5'))
    save_history(history, os.path.join(result_dir, 'history.txt'))

    # モデルの評価
    loss, acc = model.evaluate(X_test, Y_test, verbose=0)

    print('Test loss:', loss)
    print('Test acc:', acc)


kerasのバージョン確認方法

import keras
print(keras.__version__) # 2.5.0  colaboratory の keras version


参考とさせて頂いたサイト。ありがとうございます
qiita.com
qiita.com
qiita.com
nahareport.blogspot.com
qiita.com
child-programmer.com

参考とさせて頂いた本。