talosのプログラミング教室

【Deep Learning】KerasでMNIST

スポンサーリンク

はじめに

こんにちは。talosです。

前回はTensorFlowのインストールなど、Deep Learningを行う準備をしました。

talosta.hatenablog.com

今回はMNISTという手書きの数字の画像データを用いて、クラス分けをしていきます。


スポンサーリンク



MNISTとは

MNISTは機械学習チュートリアルとしてよく用いられるデータセットです。

このように手書きの0~9の画像がトレーニング用6万枚、テスト用1万枚集められ、それぞれにラベルが付いています。

f:id:talosta:20190530225240p:plain

レーニング用というのが学習に使うデータ、テスト用がモデルの精度を検証するためのデータです。

また、下の記事でも述べましたが、教師あり学習は問題と答えの組を学習します。

talosta.hatenablog.com

この答えがラベルに当てはまります。

MNISTで言うと「0」が書かれた画像には「0」というラベル、「1」が書かれた画像には「1」というラベルが付いています。

「そのままじゃん」って聞こえてきそうですが、例えば犬と猫の画像を分ける場合にも0と1のような整数値のラベルを付けるのが普通です。

KerasでMNIST

では早速コーディングをしていきましょう。

以下のプログラムを書いてください。

import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

これはTensorFlowの公式ページにあるチュートリアルです。

上から順に解説します。

import tensorflow as tf

はTensorFlowをインポート、つまり使う準備をしています。

そして毎回tesnsorflowと書くのが面倒なのでtfという名前を付けています。

略さなくてもいいのですが、tensorflowをtfとするのが一般的なので覚えておくとよいでしょう。

mnist = tf.keras.datasets.mnist

はmnistのデータセットを取得しています。

(x_train, y_train),(x_test, y_test) = mnist.load_data()

は取得したデータをトレーニング用、テスト用に分け、さらにそれを説明変数目的変数に分けています。

説明変数とは今まで入力と言っていた部分です。

今回は画像データがこれにあたります。

目的変数とは今まで出力やラベルと言っていた部分です。

今回は0~9の整数値がこれにあたります。

データ分析では説明変数にはx、目的変数にはyを使うのが一般的です。

x_train, x_test = x_train / 255.0, x_test / 255.0

画像というのは画素とが縦横に並んでいます。

今回扱う画像はグレースケールなので、それぞれの画素は0~255の画素値で表すことができます。

それを255.0で割ることで0~1の間に正規化しています。

これはデータのばらつきを減らすことを目的としています。

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])

ここでは、どのようなモデルを作るかを設定しています。

1行目にSequentialとありますが、これはSequentialモデルという単純に層を積み重ねたモデルを作ることを意味しています。

2行目のFlattenは入力を平滑化しています。

今回の画像はグレースケールで28×28の2次元のテンソルなので、それを1次元にしています。

「input_shape=(28, 28)」というのは28×28の2次元テンソルですよって伝えています。


3行目と5行目のDenseは全結合層のことです。

すべてのニューロンが次の層のすべてのニューロンに結合しているため、全結合層といいます。

1つ目の引数の512や10というのは出力空間の次元数を表しています。

2つ目の引数のactivationというのは活性化関数です。

3行目ではReLU関数、5行目ではSoftmax関数を使用しています。


4行目のDropoutはDeep Learning過学習を防ぐ手法です。

ニューロンをある割合で無効にして学習します。

引数は0.2なので20%のニューロンを無効にしています。

ちなみに出来上がるモデルを図で表すとこんな感じです。(なぜか入力層が数字になっていますが。。。)

f:id:talosta:20190531171415p:plain

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

モデルの設定をしています。

optimizerは使用する勾配法で、Adamを使用しています。

lossは損失関数で、クロスエントロピーの1種を使用しています。

sparseとは”まだらな”という意味で、ラベルが1、2、3などの整数値のときに使用するそうです。

一方で、ラベルが(1, 0, 0)、(0, 1, 0)、(0, 0, 1)のようなOne-Hotベクトルのときはcategorical_crossentropyを使用するそうです。

参考:https://jovianlin.io/cat-crossentropy-vs-sparse-cat-crossentropy/

metricsは評価関数で、accuracyは予測と正解の一致率です。

model.fit(x_train, y_train, epochs=5)

訓練(学習)します。

上で述べた通り、x_trainはトレーニング用データの説明変数、y_trainはトレーニング用データの目的変数です。

epochsは反復回数です。

model.evaluate(x_test, y_test)

損失値と正解率を計算します。

x_testはトレーニング用データの目的変数、y_testはテスト用データの目的変数です。


以上で解説は終わりです。

実行すると、

Epoch 1/5
60000/60000 [==============================] - 20s 327us/sample - loss: 0.2251 - acc: 0.9328
Epoch 2/5
60000/60000 [==============================] - 22s 374us/sample - loss: 0.0984 - acc: 0.9699
Epoch 3/5
60000/60000 [==============================] - 17s 288us/sample - loss: 0.0699 - acc: 0.9784
Epoch 4/5
60000/60000 [==============================] - 18s 303us/sample - loss: 0.0537 - acc: 0.9828
Epoch 5/5
60000/60000 [==============================] - 18s 299us/sample - loss: 0.0440 - acc: 0.9854
10000/10000 [==============================] - 1s 131us/sample - loss: 0.0703 - acc: 0.9794

[0.07028627284257673, 0.9794]

といった出力が出てくると思います。

一番下の[]の中が左から損失値、正解率です。

正解率が97.9%と、今のままでもかなり精度が高いです。

精度向上のためのワンポイント

ラベルをOne-Hotベクトル化します。

import tensorflow as tf
from tensorflow.keras.utils import to_categorical # 追加

mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# One-Hotベクトル化
y_train_new = to_categorical(y_train)  # 追加
y_test_new = to_categorical(y_test)  # 追加

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='categorical_crossentropy',  # sparse_categorical_crossentropy → categorical_crossentropyに変更
              metrics=['accuracy'])

model.fit(x_train, y_train_new,  # y_train → y_train_newに変更
          epochs=5)
model.evaluate(x_test, y_test_new)  # y_test → y_test_newに変更

としてください。

実行してみると、

[0.0638532468331512, 0.9812]

精度が少し上がりました。

おわりに

今回はKerasでMNISTを扱いました。

まだまだ精度向上の余地はあると思うので、いろいろ試してみてください。