広告
広告

Keras で MNIST の手書き文字の分類

カテゴリ:programming

Keras には MNIST の手書き文字データをダウンロードするライブラリが含まれている。そのデータを使って単純な全結合ネットワークの学習を行う。

環境は Keras 2.2 と Tensorflow 1.5。GPU を使わない環境構築はUbuntu on WSL に Keras をインストールするを参照。

学習データとテストデータのダウンロード

from keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

train_images が学習用画像で train_labels が正解のラベルだ。test_images は汎化性能の試験をするための画像で、test_labels はその正解ラベルだ。

データの前処理

画像データの正規化

画像データの型は縦28px, 横28px の UINT8 だ。今回は全結合ネットワークなのでこれを一次元配列へ変換する。加えて [0, 255] の範囲の値を [0, 1] の範囲に収まるようにデータを正規化する。

train_images = train_images.reshape((len(train_images), 28 * 28))
train_images = train_images.astype('float16') / 255
test_images = test_images.reshape((len(test_images), 28 * 28))
test_images = test_images.astype('float16') / 255

ラベルを one-hot 表現へ変換

mnist.load_date() が返す正解ラベルは整数で表現されている。これを one-hot 表現に変換する。例えば [0, 9] の整数のうちの5を one-hot 表現にすると、(0,0,0,0,0,1,0,0,0,0) というベクトルになる。8の確率が 80 %で5の確率が 20 %というベクトルを one-hot で表現すると (0,0,0,0,0,0.2,0,0,0.8,0) になる。

from keras.utils import to_categorical
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

モデルの構築

model
構築する層のモデル

入力は一次元化された 28 * 28 のサイズのグレースケール画像だ。これは一番最初の層の引数で指定する。ここでは活性化関数として ReLU を指定する。活性化関数の種類は活性化関数のまとめ(ステップ、シグモイド、ReLU、ソフトマックス、恒等関数)を参照。

十種類の数値の分類を行うので出力層のノード数は 10 で、活性化関数として softmax を指定する。これは解く問題によって変わる。例えばレビュー内容がポジティブかネガティブかの分類のような2値分類問題ならば、活性化関数に sigmoid を使い、損失関数に binary_crossentropy を使う。

from keras.models import Sequential
from keras.layers import Dense

model = Sequential([
    Dense(512, activation='relu', input_shape=(28*28,)),
    Dense(10, activation='softmax')
])

モデルのコンパイル

コンパイル時に最適化アルゴリズムと損失関数、学習とテストとを監視する指標を指定する。最適化アルゴリズムは学習が進むたびに学習率を少なくするために使われる。最適化アルゴリズムの種類は深層学習の最適化アルゴリズムを参照。

損失関数は正解ラベルからの距離、つまり正解から遠いか近いかを定義する。

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

学習

学習時にはエポックとバッチサイズを指定する。バッチサイズは一度に処理するデータ数だ。この例では 128 枚の画像が一度に処理される。エポック数は学習回数だ。この例では全データを5回ずつ使って学習される。

model.fit(train_images, train_labels, epochs=5, batch_size=128)

汎化性能試験

print(model.evaluate(test_images, test_labels))

model.evaluate を実行すると [0.0638885846251389, 0.9808] のような結果が表示される。左側は損失値で右側が正解率だ。この例の正解率は 98.08 %だ。

ソースコード

from keras.datasets import mnist
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense

# 画像の取得
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

# 画像の正規化
train_images = train_images.reshape((len(train_images), 28 * 28))
train_images = train_images.astype('float16') / 255
test_images = test_images.reshape((len(test_images), 28 * 28))
test_images = test_images.astype('float16') / 255

# 正解ラベルの one-hot 変換
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

# モデルの構築
model = Sequential([
    Dense(512, activation='relu', input_shape=(28*28,)),
    Dense(10, activation='softmax')
])

# モデルのコンパイル
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])

# 学習
model.fit(train_images, train_labels, epochs=5, batch_size=128)

# 汎化試験
print(model.evaluate(test_images, test_labels))

# Tensorflow のエラー消し
from keras import backend as K
K.clear_session()

広告
広告