数値画像認識

全結合ニューラルネットワークモデルを用いた数字画像分類.

このチュートリアルでは全結合ニューラルネットワークを用いて数字認識モデルを構築します. チュートリアルを通して以下の点を紹介します.

  • Sequential, Functional modelを用いたニューラルネットワーク構築方法
  • modelの学習方法

必要なライブラリ

  • matplotlib 2.0.2
  • numpy 1.12.1
  • scikit-learn 0.18.2
In [1]:
from __future__ import division, print_function
import matplotlib.pyplot as plt
import numpy as np

from sklearn.datasets import fetch_mldata
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelBinarizer
from sklearn.metrics import confusion_matrix, classification_report

import renom as rm
from renom.optimizer import Sgd

MNISTデータのロード

最初にMNISTデータ・セットをダウンロードし、学習ができるように前処理を施します.今回はsckit-learnの fetch_mldata 関数を使用します.

MNISTデータセットは70000枚の数字画像からなります.まずは、データセットを学習用とテスト様に分割します.次にデータ255で割ることで、画像を0-1の間にスケーリングします.更に、教師データを二値化します.このようにして、データの前処理が完了しました.

In [2]:
# Datapath must point to the directory containing the mldata folder.
data_path = "../dataset"
mnist = fetch_mldata('MNIST original', data_home=data_path)

X = mnist.data
y = mnist.target

# Rescale the image data to 0 ~ 1.
X = X.astype(np.float32)
X /= X.max()

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1)
labels_train = LabelBinarizer().fit_transform(y_train).astype(np.float32)
labels_test = LabelBinarizer().fit_transform(y_test).astype(np.float32)

# Training data size.
N = len(X_train)

ニューラルネットワークの定義

次にニューラルネットワークを定義します.このチュートリアルでは、二層ニューラルネットワークを定義します.具体的には全結合層を2つ持つニューラルネットワークになります.次に活性化関数を選びます.ここでは relu 関数を選びました.

ReNomでは、演算にVariableオブジェクトが含まれると演算の履歴を残し、計算グラフを作り続けます. もし誤差逆伝播を実行する必要が無いのであれば、計算グラフを保持することはメモリの無駄遣いとなるので、 Nodeオブジェクトの detach_graph() メソッドを呼び計算グラフを削除することが出来ます. もしくはTutrial0.2で説明しているように、withブロックを用いて計算グラフの生成を管理することができます.

In [3]:
class Mnist1(rm.Model):

    def __init__(self):
        super(Mnist1, self).__init__()
        self._layer1 = rm.Dense(100)
        self._layer2 = rm.Dense(10)

    def forward(self, x):
        out = self._layer2(rm.relu(self._layer1(x)))
        return out

L2ノルム正則化を加えたニューラルネットワークモデル

In [4]:
class Mnist2(rm.Model):

    def __init__(self):
        super(Mnist2, self).__init__()
        self._layer1 = rm.Dense(100)
        self._layer2 = rm.Dense(10)

    def forward(self, x):
        out = self._layer2(rm.relu(self._layer1(x)))
        return out

    def weight_decay(self):
        weight_decay = rm.sum(self._layer1.params.w**2) + rm.sum(self._layer2.params.w**2)
        return weight_decay

Sequentialモデルを用いたニューラルネットワークの定義

In [5]:
sequential = rm.Sequential([
        rm.Dense(100),
        rm.Relu(),
        rm.Dense(10),
    ])

インスタンス化

In [6]:
# Choose neural network.
# network = Mnist1()
# network = Mnist2()
network = sequential

学習ループ

ここまでで、ニューラルネットワークを構築することが出来ました. 次に学習ループを定義します. ここではミニバッチを用いた確率的勾配降下法(SGD)による学習を行います. 学習のたびに学習データから重複なしにデータをランダムに取り出しそのデータを用いて重みを更新します. このような確率的な重み更新方法を取ることで学習曲線はスムーズではなくなりますが、結果的に学習の結果が改善します.

In [7]:
# Hyper parameters
batch = 64
epoch = 10

optimizer = Sgd(lr = 0.1)

learning_curve = []
test_learning_curve = []

for i in range(epoch):
    perm = np.random.permutation(N)
    loss = 0
    for j in range(0, N // batch):
        train_batch = X_train[perm[j * batch:(j + 1) * batch]]
        responce_batch = labels_train[perm[j * batch:(j + 1) * batch]]

        # The computational graph is only generated for this block:
        with network.train():
            l = rm.softmax_cross_entropy(network(train_batch), responce_batch)
            if hasattr(network, "weight_decay"):
                l += 0.0001 * network.weight_decay()

        # Back propagation
        grad = l.grad()

        # Update
        grad.update(optimizer)

        # Changing type to ndarray is recommended.
        loss += l.as_ndarray()

    train_loss = loss / (N // batch)

    # Validation
    test_loss = rm.softmax_cross_entropy(network(X_test), labels_test).as_ndarray()
    test_learning_curve.append(test_loss)
    learning_curve.append(train_loss)
    print("epoch %03d train_loss:%f test_loss:%f"%(i, train_loss, test_loss))
epoch 000 train_loss:0.333865 test_loss:0.206294
epoch 001 train_loss:0.169508 test_loss:0.157213
epoch 002 train_loss:0.125200 test_loss:0.123576
epoch 003 train_loss:0.100399 test_loss:0.104024
epoch 004 train_loss:0.083224 test_loss:0.098977
epoch 005 train_loss:0.072607 test_loss:0.092286
epoch 006 train_loss:0.062846 test_loss:0.083760
epoch 007 train_loss:0.055399 test_loss:0.080172
epoch 008 train_loss:0.049468 test_loss:0.089180
epoch 009 train_loss:0.044689 test_loss:0.074930

モデルの評価

学習が終了したモデルを評価します. ここでは混同行列を用いて、各クラスに属するテストデータの正解割合を表示しました. また、テストデータに対する、再現率、適合率、F1スコアについても同様に表示しています. 今回のモデルでは、テストデータを95%の正解率で識別できるモデルを構築することができました.

In [8]:
predictions = np.argmax(network(X_test).as_ndarray(), axis=1)

# Confusion matrix and classification report.
print(confusion_matrix(y_test, predictions))
print(classification_report(y_test, predictions))

# Learning curve.
plt.plot(learning_curve, linewidth=3, label="train")
plt.plot(test_learning_curve, linewidth=3, label="test")
plt.title("Learning curve")
plt.ylabel("error")
plt.xlabel("epoch")
plt.legend()
plt.grid()
plt.show()
[[678   0   1   1   1   2   2   2   4   1]
 [  0 749   2   1   3   0   0   1   2   0]
 [  1   5 686   3   2   0   0   3   2   1]
 [  0   0   2 719   0  10   0   3   2   3]
 [  0   1   0   0 639   0   3   2   0  13]
 [  1   1   0   5   0 657   1   0   1   1]
 [  6   0   1   0   3   3 664   0   2   0]
 [  2   1   1   1   7   1   0 681   0   3]
 [  2   5   1   4   2   4   1   0 683   3]
 [  0   1   0   2   4   3   1   6   1 684]]
             precision    recall  f1-score   support

        0.0       0.98      0.98      0.98       692
        1.0       0.98      0.99      0.98       758
        2.0       0.99      0.98      0.98       703
        3.0       0.98      0.97      0.97       739
        4.0       0.97      0.97      0.97       658
        5.0       0.97      0.99      0.98       667
        6.0       0.99      0.98      0.98       679
        7.0       0.98      0.98      0.98       697
        8.0       0.98      0.97      0.97       705
        9.0       0.96      0.97      0.97       702

avg / total       0.98      0.98      0.98      7000

../../../_images/notebooks_image_processing_digit-image-classifier_notebook_16_1.png