はじめに
皆さんはじめまして。
この記事はmnist_mlp.pyを1行ずつ解説していくだけの記事です。
AIに興味があるけどまだ触ったことはない人などが対象です。これを読めばディープラーニングの基本的な学習の流れが理解できるはず、と思って書いていきます。(もともとは社内で研修用に使おうと思って作成していた内容です)
全3回予定です。
- 【AI初心者向け】mnist_mlp.pyを1行ずつ解説していく(KerasでMNISTを学習させる)
- 【AI初心者向け】mnist_cnn.pyを1行ずつ解説していく(KerasでMNISTを学習させる)
- 【AI初心者向け】mnist_transfer_cnn.pyを1行ずつ解説していく(KerasでMNISTを学習させる)
動作確認方法について
MNISTは画像なので、このコードを動かすにはGPUがあったほうがいいです(CPUだとちょっと辛いです)。
おすすめの方法はGoogle Colaboratoryを使う方法です。
やることは2つだけ。
・Python3の新しいノートブックを開く
・ランタイムからGPUを有効にする
これでGPUが使えるようになりました。
セルにコードを貼り付けて実行(ショートカットはCTRL+ENTER)するだけで動きます。
mnistについて
手書き文字画像のデータセットで、機械学習のチュートリアルでよく使用されます。
内容:0~9の手書き文字
画像サイズ:28pix*28pix
カラー:白黒
データサイズ:7万枚(訓練データ6万、テストデータ1万の画像とラベルが用意されています)
mlpとは
Multilayer perceptron、多層パーセプトロンのことです。
mnistは画像データですが、画像データの形を(28, 28)から(784,)に変更することでmlpとして学習させることができます。(精度は第2回でやるCNNのほうが上です。)
mnist_mlp.pyについて
mnistの手書き文字の判定を行うモデルをKerasとTensorFlowを使って作成するコードです。
0~9の10種類の手書き文字を入力として受け取り、0~9のいずれであるか10種類に分類するモデルを作成します。
コードの解説
準備
'''Trains a simple deep NN on the MNIST dataset.
Gets to 98.40% test accuracy after 20 epochs
(there is *a lot* of margin for parameter tuning).
2 seconds per epoch on a K520 GPU.
'''
# 特に必要ないコードです(Pythonのバージョンが3だが、コードがPython2で書かれている場合に必要になる)
from __future__ import print_function
# 必要なライブラリをインポートしていく
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import RMSprop
# 定数を最初にまとめて指定する
batch_size = 128 # バッチサイズ。1度に学習するデータサイズ
num_classes = 10 # 分類するラベル数。今回は手書き画像を0~9の10種類に分類する
epochs = 20 # エポック数。全データを何回学習するか
データの前処理
# mnistのデータを読み込み、訓練データ(6万件)とテストデータ(1万件)に分割する
(x_train, y_train), (x_test, y_test) = mnist.load_data()
'''mlpでインプットデータとして使用できるようにするため、reshapeしてデータの形式を合わせる
x_train:(60000, 28, 28) ->(60000, 784) 28pix*28pixの画像を1列にする
x_test:(10000, 28, 28) ->(10000, 784) 28pix*28pixの画像を1列にする'''
x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)
# 画像データは0~255の値をとるので255で割ることでデータを標準化する
# .astype('float32')でデータ型を変換する。(しないと割ったときにエラーが出るはず)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
# データの数を出力して確認
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# ラベルデータをone-hot-vector化する
'''one-hot-vectorのイメージはこんな感じ
label 0 1 2 3 4 5 6 7 8 9
0: [1,0,0,0,0,0,0,0,0,0]
8: [0,0,0,0,0,0,0,0,1,0]'''
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
標準化について:画像の各ピクセルの値は0~255になっています。これを0~1に変換するイメージです。画像で機械学習するときは大体この255で割る処理をして、値を標準化します。
one-hot-vectorについて:今回、ラベルは0~9の10種類があり、それぞれ0~9の数字で表しています。しかし、10種類に分類したいだけなので、ラベルの数字自体には意味がありません。そこで、one-hot-vectorすることにより0と1のみでどのラベルなのかを表せるように変換します。
モデルの定義
# Sequentialクラスをインスタンス化
model = Sequential()
# 中間層
# 全結合層(512ユニット、活性化関数:Relu、受け取る入力サイズ:784)を追加
model.add(Dense(512, activation='relu', input_shape=(784,)))
# 0.2の確率でドロップアウト
model.add(Dropout(0.2))
# 全結合層(512ユニット、活性化関数:Relu、受け取る入力サイズは自動で判断)を追加
model.add(Dense(512, activation='relu'))
# 0.2の確率でドロップアウト
model.add(Dropout(0.2))
# 出力層
# 全結合層(10ユニット、活性化関数:SoftMax、受け取る入力サイズは自動で判断)を追加
model.add(Dense(num_classes, activation='softmax'))
# モデルの構造を可視化
model.summary()
SequentialモデルはDNNの層を積み重ねて作るモデルです。一番最初の層にだけ、input_shapeを指定してやる必要があります。
出力層の活性化関数は、今回は多値分類するモデルなのでsoftmaxを使います。
学習
# 学習プロセスを設定する
model.compile(
# 損失関数を設定。今回は分類なのでcategorical_crossentropy
loss='categorical_crossentropy',
# 最適化アルゴリズムを指定。学習率などをいじれる
optimizer=RMSprop(),
# 評価関数を指定
metrics=['accuracy'])
# 学習させる
history = model.fit(
# 学習データ、ラベル
x_train, y_train,
# バッチサイズ(128)
batch_size=batch_size,
# エポック数(20)
epochs=epochs,
# 学習の進捗をリアルタムに棒グラフで表示(0で非表示)
verbose=1,
# テストデータ(エポックごとにテストを行い誤差を計算するため)
validation_data=(x_test, y_test))
モデルの定義が終わったら、損失関数や最適化アルゴリズムを指定してコンパイルします。その後、モデルにデータを渡して学習させます。より良いモデルを作るためには、最適化アルゴリズムやバッチサイズ、エポック数などをいろいろ変更して試してやる必要があります。
評価
# テストデータを渡す(verbose=0で進行状況メッセージを出さない)
score = model.evaluate(x_test, y_test, verbose=0)
# 汎化誤差を出力
print('Test loss:', score[0])
# 汎化性能を出力
print('Test accuracy:', score[1])
学習が終わったら、テストデータを使ってどの程度の性能になったのかを評価します。lossが低く、accuracyが高いほど良いモデルといえます。