以下のプログラムは, jupyter noteboookにペタペタと貼ればすぐ実行できます。
3/1 17:00に不具合の修正をしました。(下の深層パーセプトロンのプログラム例でRMSpropを利用できなかったのを修正)
深層学習(ディープラーニング)は,4層以上のニューラルネットワークモデルを使った機械学習の手法。
このページにはKerasで深層パーセプトロンと畳込みニューラルネットワークを作ってMNISTデータを学習するサンプルプログラムがあります。
畳み込みニューラルネットワーク(Convolutional Network)について参考になるサイト
MNISTデータベースは,手書き数字画像とそのラベル(正解データ)のデータベース
Kerasでは,MNISTデータベースの他,いくつかのデータセットをコマンド1行で読み込むことができる(参考URL)。
!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層構造になっています。
- コメントの追加
''' | |
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) |
畳み込みニューラルネットワークによる文字認識デモはKeras-jsにあります。