Layerの出力の結合

mnistを用いた全結合NNを用いてLayerの出力の結合を行います.

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

  • Layerの出力の結合方法

必要なライブラリ

  • 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)

ニューラルネットワークモデルの定義と出力の結合

近年,複雑なネットワーク構造を持つモデルが増えてきており,入ってくるデータをそれぞれ別のレイヤーに分けるsplit構造や複数レイヤーから出てきた複数の出力を一つのレイヤーに入力するconcatenate構造が時々出てきます.
以下のようにReNomでもconcatenateを使うことができます.
In [3]:
class Mnist(rm.Model):

    def __init__(self):
        super(Mnist, self).__init__()
        self._layer1 = rm.Dense(100)
        self._layer2 = rm.Dense(20)
        self._layer3 = rm.Dense(100)
        self._layer4 = rm.Dense(20)
        self._layer5 = rm.Dense(10)

    def forward(self, x):
        t1 = self._layer2(rm.relu(self._layer1(x)))
        t2 = self._layer4(rm.relu(self._layer3(x)))
        concatenated = rm.concat(t1,t2)
        out = self._layer5(concatenated)
        return out

インスタンス化

In [4]:
network = Mnist()

学習ループ

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

In [5]:
# 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.267641 test_loss:0.141645
epoch 001 train_loss:0.113229 test_loss:0.103424
epoch 002 train_loss:0.076932 test_loss:0.086349
epoch 003 train_loss:0.057434 test_loss:0.082932
epoch 004 train_loss:0.044242 test_loss:0.090178
epoch 005 train_loss:0.034046 test_loss:0.084983
epoch 006 train_loss:0.026465 test_loss:0.081169
epoch 007 train_loss:0.021621 test_loss:0.073292
epoch 008 train_loss:0.016413 test_loss:0.073131
epoch 009 train_loss:0.012462 test_loss:0.079027

モデルの評価

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

In [6]:
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()
[[676   0   0   0   0   1   4   0   1   0]
 [  0 832   1   0   0   0   1   7   1   0]
 [  3   2 706   3   2   0   0   4   5   0]
 [  1   2   1 695   0   5   0   0   2   1]
 [  1   0   0   1 708   1   7   0   1   3]
 [  0   0   1   3   0 589   3   1   2   1]
 [  2   0   1   0   1   2 683   0   1   0]
 [  0   0   2   1   2   0   1 683   0   4]
 [  1   3   2   5   3   4   1   1 652   1]
 [  2   1   0   7  14   4   0   5   1 632]]
             precision    recall  f1-score   support

        0.0       0.99      0.99      0.99       682
        1.0       0.99      0.99      0.99       842
        2.0       0.99      0.97      0.98       725
        3.0       0.97      0.98      0.98       707
        4.0       0.97      0.98      0.98       722
        5.0       0.97      0.98      0.98       600
        6.0       0.98      0.99      0.98       690
        7.0       0.97      0.99      0.98       693
        8.0       0.98      0.97      0.97       673
        9.0       0.98      0.95      0.97       666

avg / total       0.98      0.98      0.98      7000

../../../_images/notebooks_renom_dl_concatenate_notebook_12_1.png