深層学習

深層学習(ディープラーニング)は,4層以上のニューラルネットワークモデルを使った機械学習の手法。

このページにはKerasで深層パーセプトロンと畳込みニューラルネットワークを作ってMNISTデータを学習するサンプルプログラムがあります。

畳込みニューラルネットワーク

畳み込みニューラルネットワーク(Convolutional Network)について参考になるサイト

MNISTデータベース

MNISTデータベースは,手書き数字画像とそのラベル(正解データ)のデータベース

  • 28x28画素
  • 訓練用データ: 60,000個
  • テスト用データ: 10,000個
  • クラス数: 10 (数字の0から9)

Kerasでは,MNISTデータベースの他,いくつかのデータセットをコマンド1行で読み込むことができる(参考URL)。

サンプルプログラム

KerasでMNISTデータセットの学習

以下のプログラムは, jupyter noteboookにペタペタと貼ればすぐ実行できます。

注意

3/1 17:00に不具合の修正をしました。(下の深層パーセプトロンのプログラム例でRMSpropを利用できなかったのを修正)

ヘッダ部分

以下の2つのプログラムの実行に必要なヘッダ部分です。

  • モジュールの読み込み
  • MNISTデータ分類用プログラムの学習履歴表示関数の定義
!pip install keras # jupyter notebookで実行する時に必要
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.optimizers import RMSprop
from keras import backend as K
import matplotlib.pyplot as plt
# グラフ表示
def hist_plot(hist):
## 訓練データおよび評価データの目的関数(loss,val_loss)の変化
plt.plot(hist.history['loss'], marker='.', label='loss')
plt.plot(hist.history['val_loss'], marker='.', label='val_loss')
plt.grid()
plt.title('objective function')
plt.legend(loc='best', fontsize=12)
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()
## 訓練データおよび評価データに対する正確性(acc, val_acc)のグラフ
## - compile時のmetricで定義した指標
plt.plot(hist.history['acc'], marker='.', label='acc')
plt.plot(hist.history['val_acc'], marker='.', label='val_acc')
plt.grid()
plt.title('model accuracy')
plt.legend(loc='best', fontsize=12)
plt.xlabel('epoch')
plt.ylabel('acc')
plt.show()

深層パーセプトロンによる分類

Kerasのdeep MLPサンプルプログラムkeras/examples/mnist_mlp.pyを少し変更したものです。4層構造になっています。

 - コメントの追加

  • MNISTサンプルの一部を表示
  • 誤差変化のグラフ描画を追加(上記Header部で関数定義)
'''
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.
'''
batch_size = 128
num_classes = 10 # 手書き数字を10クラスの数字に分類
epochs = 3 # 20にすると精度は98.4%に
# データをランダムに教師データとテストデータに分ける
# xが画像データ(28x28ピクセルの行列, uint8[28][28]の配列)
# yはカテゴリラベルデータ(0から9のinteger, uint8の配列)
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 画像データ(訓練データ)を少し表示してみる
fig=plt.figure(figsize=(10, 5))
fig.subplots_adjust(left=0, bottom=0, right=0.5, top=0.5, wspace=0.1, hspace=0.1)
for i in range(50):
ax=fig.add_subplot(5, 10, i+1, xticks=[], yticks=[])
ax.imshow(x_train[i].reshape((28, 28)), cmap='gray')
plt.show()
# 28x28=784要素の2次元データを, 要素数784個の1次元データに変換
# (2次元データのまま処理をすすめる方法もある)
# 訓練データは60,000個。テストデータは10,000個
x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)
# データをfloat32型に変換し, [0,255]の値を[0,1.0]に規格化
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')
# カテゴリの値[0,9]をバイナリ値(10bitのいずれかのみが1)に変換
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
# 入力層(784)=>中間層1(512)=>中間層2(512)=>出力層(10)
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(784,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation='softmax'))
# モデルの情報を表示
model.summary()
# NNモデル構築
# - loss: 目的関数
# - optimizer: 学習方法
# - RMSpropは勾配降下法の修正版。これを使うにはヘッダ部で宣言必要
# - metrics: モデルの正確性の評価に使う指標(学習には使わないが履歴を残せる)
model.compile(loss='categorical_crossentropy',
optimizer=RMSprop(),
metrics=['accuracy'])
# 学習
hist = model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test))
# 評価
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
# 学習経過のグラフ表示
hist_plot(hist)

畳み込みニューラルネットワークによる分類

KerasのCNNサンプルプログラムkeras/examples/mnist_cnn.pyのソースを少し変更したもの - コメント追加 - 誤差変化のグラフ描画を追加(上記Header部で関数定義)

'''
Trains a simple convnet on the MNIST dataset.
Gets to 99.25% test accuracy after 12 epochs
(there is still a lot of margin for parameter tuning).
16 seconds per epoch on a GRID K520 GPU.
'''
batch_size = 128
num_classes = 10
epochs = 5
# input image dimensions
img_rows, img_cols = 28, 28
# データをランダムに教師データとテストデータに分ける
# xが画像データ(28x28ピクセルの行列, uint8[28][28]の配列)
# yはカテゴリラベルデータ(0から9のinteger, uint8の配列)
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# KerasのバックエンドがTheanoか, tensorflowかで,画像の書式が異なる。
# 28x28のグレイスケール画像の場合は1チャンネルなので (カラー画像なら3チャンネル),
# Theanoならchannels_firstで,(1,28,28)
# Tensorflowならchannels_lastで(28,28,1)
# channels_first か channels_last かは$HOME/.keras/keras.json に設定されている
# この設定情報を image_data_format()でアクセスして,対応する形式にデータ変換
if K.image_data_format() == 'channels_first':
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
else:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
# データをfloat32型に変換し, [0,255]の値を[0,1.0]に規格化
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
# 各サンプルの個数を確認
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# カテゴリの値[0,9]をバイナリ値(10bitのいずれかのみが1)に変換
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
# 入力層(28,28)=>Convolution 1(2^5x28x28)=>Convolution 2(2^6x28x28)
# =>MaxPooling2D(2^6x7x7)=>Dense(128)=>出力層(10)
# Conv2D: 2次元入力をフィルターする畳み込み層
# - はじめの引数:
# - 使用するカーネルの数
# - 各カーネルの出力画像サイズは端の処理によるが,デフォルトでは入力画像と同じ
# - 細胞数="カーネル数x入力サイズ"
# - kernel_size: カーネルの大きさ。
# - activation : 活性化関数
# - relu (Rectified Linear Unit) f(x)=max(x,0)
# -softmax:
# MaxPooling2D
# - 画像を指定したサイズに区切り,その要素の最大値を区画の値とする
# - pool_size=(2,2)とすると, 出力画像サイズは1/4になる
# - データサイズを落としつつ, 各カーネルの表現する特徴の有無の情報を維持
# Flatten
# - 畳み込み層の出力を1次元ベクトルに変換(Denseに入力するため)
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
hist=model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
# 学習経過のグラフ表示
hist_plot(hist)
view raw 3-1-MNISTbyCNN hosted with ❤ by GitHub

畳み込みニューラルネットワークによる文字認識デモはKeras-jsにあります。