読者です 読者をやめる 読者になる 読者になる

データ分析エンジニアが気まぐれに更新するブログ

勉強してきた技術などを適当に書いていければと思います。

Chainerでニューラルネットワーク及び畳み込みニューラルネットワークを実装してみた

Python ディープラーニング Chainer 機械学習

明けました。

本年もどうぞ、よろしくお願いいたします。


機械学習系のライブラリは去年から何かしら使ってみたいなーと思っていました。

今回、Chainerを触ってみまして、MNISTの画像認識アルゴリズムを、ニューラルネットワークと畳み込みニューラルネットワークで実装してみました。

ちなみに、他にもTensorFlowも使ってみたのですが、自分としてはひとまずChainerの方がコード感覚としてしっくりきましたので、こちらを使ってみました。


Chainer

Chainerはニューラルネットワークを実装するためのライブラリです。


Chainer : http://chainer.org/


コーディングが直感的でかつ柔軟性があり、基本的なニューラルネットワークディープラーニングの他にも、リカレントニューラルネットワークや畳み込みニューラルネットワークなど、様々なタイプのニューラルネットワークを実装することができます。

ただし、柔軟である分、ある程度、ニューラルネットワークの知識が求められる部分があるのかなーと思います。

ちなみにインストールが超楽チンです。


ニューラルネットワークを実装する

今回はMNIST画像を分類するモデルをニューラルネットワークで作ってみます。

有名な問題なので、説明はほぼ省略しますが、手書きの数字の画像を画像認識して何の数字が書かれているかを予測する問題です。

画像サイズは28ピクセルで、グレースケールですので、そのまま1次元配列化して、入力層数を28*28=784とします。

これを0〜9の数字を予測しますので、出力層数は10とします。

Pythonで書いたコードが以下になります。

import numpy as np
%matplotlib inline
import matplotlib.pylab as plt
from sklearn.datasets import fetch_mldata
import chainer
import chainer.links as L
import chainer.functions as F
from chainer import Chain, optimizers, Variable, serializers

mnist = fetch_mldata('MNIST original', data_home='.')
mnist.data = mnist.data.astype(np.float32) # image data 784*70000 [[0-255, 0-255, ...], [0-255, 0-255, ...], ... ]
mnist.data /= 255 # to 0-1
mnist.target = mnist.target.astype(np.int32) # label data 70000
N = 60000
x_train, x_test = np.split(mnist.data,   [N])
t_train, t_test = np.split(mnist.target, [N])

class NN(Chain):
    def __init__(self, n_in, n_out):
        super(NN, self).__init__(
            l1 = L.Linear(n_in, 1000),
            l2 = L.Linear(1000, 1000),
            l3 = L.Linear(1000, 1000),
            l4 = L.Linear(1000, n_out, initialW=np.zeros((n_out, 1000), dtype=np.float32))
        )
    def forward(self, x):
        h = F.relu(self.l1(x))
        h = F.relu(self.l2(h))
        h = F.relu(self.l3(h))
        h = self.l4(h)
        return h
    
model = NN(784, 10)
optimizer = optimizers.Adam()
optimizer.setup(model)

n_epoch = 5
batch_size = 1000
for epoch in range(n_epoch):
    sum_loss = 0
    sum_accuracy = 0
    perm = np.random.permutation(N)
    for i in range(0, N, batch_size):
        x = Variable(x_train[perm[i:i+batch_size]])
        t = Variable(t_train[perm[i:i+batch_size]])
        y = model.forward(x)        
        model.zerograds()
        loss = F.softmax_cross_entropy(y, t)
        acc = F.accuracy(y, t)
        loss.backward()
        optimizer.update()
        sum_loss += loss.data*batch_size
        sum_accuracy += acc.data*batch_size
    print("epoch: {}, mean loss: {}, mean accuracy: {}".format(epoch, sum_loss/N, sum_accuracy/N))
    
cnt = 0
for i in range(10000):
    x = Variable(np.array([x_test[i]], dtype=np.float32))
    t = t_test[i]
    y = model.forward(x)
    y = np.argmax(y.data[0])
    if t == y:
        cnt += 1

print("accuracy: {}".format(cnt/10000))
epoch: 0, mean loss: 0.5703720599412918, mean accuracy: 0.8343000013381243
epoch: 1, mean loss: 0.14626061742504437, mean accuracy: 0.9571833292643229
epoch: 2, mean loss: 0.08734064015249411, mean accuracy: 0.9738500038782756
epoch: 3, mean loss: 0.05790263672048847, mean accuracy: 0.9827499995628993
epoch: 4, mean loss: 0.03985198233276606, mean accuracy: 0.9882166624069214
accuracy: 0.9778


交差検証により、学習用の教師ラベル付きデータを60000件、学習したモデルの予測率をテストするデータを10000件として、学習・予測をさせた結果、正解率97.78%となりました。


畳み込みニューラルネットワークを実装する

次に畳み込みニューラルネットワークで解いてみます。

畳み込みの場合は、問題の場合に応じて、フィルター、パディング、ストライドといった畳み込みニューラルネットワーク特有の設定値に基づいて入力数を設定します。

今回はフィルターは5ピクセル、パディングとストライドは特に設定せずに実装しました。

import numpy as np
%matplotlib inline
import matplotlib.pylab as plt
from sklearn.datasets import fetch_mldata
import chainer
import chainer.links as L
import chainer.functions as F
from chainer import Chain, optimizers, Variable, serializers

mnist = fetch_mldata('MNIST original', data_home='.')
mnist.data = mnist.data.astype(np.float32) # image data 784*70000 [[0-255, 0-255, ...], [0-255, 0-255, ...], ... ]
mnist.data /= 255 # to 0-1
mnist.target = mnist.target.astype(np.int32) # label data 70000
N = 60000
x_train, x_test = np.split(mnist.data,   [N])
t_train, t_test = np.split(mnist.target, [N])

# to (n_sample, channel, height, width)
x_train = x_train.reshape((len(x_train), 1, 28, 28))
x_test = x_test.reshape((len(x_test), 1, 28, 28))

class CNN(Chain):
    def __init__(self):
        super(CNN, self).__init__(
            conv1 = L.Convolution2D(1, 20, 5), # filter 5
            conv2 = L.Convolution2D(20, 50, 5), # filter 5
            l1 = L.Linear(800, 500),
            l2 = L.Linear(500, 500),
            l3 = L.Linear(500, 10, initialW=np.zeros((10, 500), dtype=np.float32))
        )
    def forward(self, x):
        h = F.max_pooling_2d(F.relu(self.conv1(x)), 2)
        h = F.max_pooling_2d(F.relu(self.conv2(h)), 2)
        h = F.relu(self.l1(h))
        h = F.relu(self.l2(h))
        h = self.l3(h)
        return h

model = CNN()
optimizer = optimizers.Adam()
optimizer.setup(model)

n_epoch = 5
batch_size = 1000
for epoch in range(n_epoch):
    sum_loss = 0
    sum_accuracy = 0
    perm = np.random.permutation(N)
    for i in range(0, N, batch_size):
        x = Variable(x_train[perm[i:i+batch_size]])
        t = Variable(t_train[perm[i:i+batch_size]])
        y = model.forward(x)
        model.zerograds()
        loss = F.softmax_cross_entropy(y, t)
        acc = F.accuracy(y, t)
        loss.backward()
        optimizer.update()
        sum_loss += loss.data*batch_size
        sum_accuracy += acc.data*batch_size
    print("epoch: {}, mean loss: {}, mean accuracy: {}".format(epoch, sum_loss/N, sum_accuracy/N))

cnt = 0
for i in range(10000):
    x = Variable(np.array([x_test[i]], dtype=np.float32))
    t = t_test[i]
    y = model.forward(x)
    y = np.argmax(y.data[0])
    if t == y:
        cnt += 1

print("accuracy: {}".format(cnt/10000))
epoch: 0, mean loss: 0.6474141379197439, mean accuracy: 0.8123833332210779
epoch: 1, mean loss: 0.12804378295938174, mean accuracy: 0.9615333338578542
epoch: 2, mean loss: 0.08095948826521635, mean accuracy: 0.9747333298126857
epoch: 3, mean loss: 0.059256415938337643, mean accuracy: 0.9818999985853831
epoch: 4, mean loss: 0.047269358299672604, mean accuracy: 0.9852833330631257
accuracy: 0.986


今回はコーディング感覚について勉強しておきたかったため、さすがにこの問題例では精度が飛躍的に上がるというわけではないですが(元々良いですし)、若干精度向上しました。


以上、ニューラルネットワークと畳み込みニューラルネットワークをChainerで実装しました。

今回はやりませんでしたが、個人的には、リカレントニューラルネットワークも今度やってみたいなーと思っています。

時系列データか自然言語処理に適用してみたいですね。


最後に、今回勉強で参考にした書籍を挙げておきます。



「ゼロから作るDeep Learning」は、Chainerではないのですが、ニューラルネットワークや畳み込みニューラルネットワークの仕組みを理解するには、とても解りやすい書籍なので、オススメです。

Chinerは、ある程度ニューラルネットワークの仕組みを理解していれば結構動かせちゃいますので、ニューロンや入力層・隠れ層・出力層の構成、誤差逆伝播で重みを更新していくことなどの仕組みを抑えておくと良いと思います。