追記(2017-06-20)
再帰的ニューラルネットワークも実装してみて、再度まとめました。
明けました。
本年もどうぞ、よろしくお願いいたします。
機械学習系のライブラリは去年から何かしら使ってみたいなーと思っていました。
今回、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で実装しました。
今回はやりませんでしたが、個人的には、再帰的ニューラルネットワークも今度やってみたいなーと思っています。
時系列データか自然言語処理に適用してみたいですね。
コメント