ゼロから作るDeep Learning(7日目)

こんにちは、筋肉めがねです。

 

つい先日、オセロの世界大会で日本人が優勝、そして最年少優勝記録を更新した、というニュースがありましたね。小さい頃から将棋に慣れ親しんできた身としては、こういったマインドスポーツで日本人が優勝する、というのは嬉しいものですね。 特に囲碁やオセロ、チェスのように、文字盤のないマインドスポーツは違う国の相手と対戦する事ができ、そして相手の思考を感じる事のできる面白い体験ができますよね。久しぶりに将棋を指したくなってきました。

 

f:id:KinnikuMegane:20181109030728p:plain

 

それでは、本日も「ゼロから作るDeep Learning」を進めていきましょう。

本日も第3章でございます。

 

前回の記事ではソフトマックス関数について書きました。ソフトマックス関数は分類問題に使う活性化関数であり、そしてソフトマックス関数から出力されるoutputの総和が1となる事が重要でしたね。つまり、各要素を確率として捉える事ができる、という事でした。

 

本日は、実践です。手書き数値画像の分類を行います。機械学習では、モデルが学習を行うフェーズ、そして推論を行うフェーズの二つのフェーズがある、と以前の記事で書きましたね。ここで行う手書き数値の画像分類は推論のみ、つまり学習フェーズの実装は行いません。学習済みの重みパラメータを使用します。

 

では、どういうニューラルネットワークを作るか、と言いますと、例えば以下のような画像を入力し、ニューラルネットワークがこの画像が示す数値を判断します。その数値と予め準備された答え(この場合は5)を突き合わせて、どれぐらいの精度でニューラルネットワークが正しい答えを導き出したか、という事を行います。

f:id:KinnikuMegane:20181006081037p:plain

テストに使う画像の数は10,000枚、各画像のサイズは28x28:784個のピクセルがあり、各ピクセルは0から255までの値を取ります。今回作るニューラルネットワークは3層構造であり、入力層は784個、出力層は10個のニューロンで構成します。つまり一回の処理で読み込ませる画像は1枚であり、そして、784個のピクセルの情報(0から255の値)を一つ一つ各入力ニューロンに読み込ませます。784個の各のピクセル情報を複数層で処理し、最終的に10個の出力を出します。例えば配列[0, 0, 1, 0, 0, 0, 0, 0, 0, 0]という出力を出します。これは各要素番号が数値に該当していると考えて良くて、この場合の出力は要素番号2、つまりニューラルネットワークが数値の2と判断した、と考えます。(配列は要素番号が0から始まりますね。)

 

それでは、10,000枚の画像をニューラルネットワークに読み込ませ、そのoutputがどれぐらいの精度なのか、いつも通り結果を書きましょう。

Accuracy: 0.9352

 

93.52%の精度で、今回作ったニューラルネットワークは読み込んだ手書き数値を正しく判断する事が出来ました。

 

続いてコードです。

#先ずは本書で紹介されているMNISTという手書き数字画像セットを準備します。
#Terminal上で
git clone https://github.com/oreilly-japan/deep-learning-from-scratch.git

#そして、本書で紹介されている通り、ディレクトリch01からch08のうちの1つに入ります。例えばch03のディレクトリに入ります。
cd deep-learning-from-scratch/ch03

#ch03のディレクトリ直下で、python環境下に入る。
python

import sys, os
sys.path.append(os.pardir)
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax

(x_train, t_train), (x_test, t_test) = \
      load_mnist(flatten=True, normalize=False)

def get_data():
      (x_train, t_train), (x_test, t_test) = \
            load_mnist(normalize=True, flatten=True, one_hot_label=False)
      return x_test, t_test

def init_network():
      with open("sample_weight.pkl", 'rb') as f:
            network = pickle.load(f)
      return network

def predict(network, x):
      W1, W2, W3 = network['W1'], network['W2'], network['W3']
      b1, b2, b3 = network['b1'], network['b2'], network['b3']
      a1 = np.dot(x, W1) + b1
      z1 = sigmoid(a1)
      a2 = np.dot(z1, W2) + b2
      z2 = sigmoid(a2)
      a3 = np.dot(z2, W3) + b3
      y = softmax(a3)
      return y

x, t = get_data()
network = init_network()

accuracy_cnt = 0
for i in range(len(x)):
     y = predict(network, x[i])
     p = np.argmax(y)
     if  p == t[i]:
           accuracy_cnt += 1

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))

 

いろいろと書いてありますが、大事な事は2点のみです。

 

1つは、このニューラルネットワークは学習済みのパラメータを使用している、という事です。具体的にはコード内のW1, W2, W3, b1, b2, b3です。784個の入力ニューロンへ各ピクセルの情報(0から255の値を取り得る)を入れ、それに何らかの処理を加えて、0から9の数値が書かれた各々の箱に入る確率を出す、という事をやってるんですが、それを93.52%の確率でできているのは、既に求められている課題を解決できる最適解をW1, W2, W3, b1, b2, b3が持っているからなんですね。では逆にどうして認識精度が100%ではないのか、という疑問がでてきますが、それは分かりません。

 

そしてもう一つ大事な事は、このニューラルネットワークでは入力の値、各ピクセルの0から255という情報に対して正規化、という前処理を行っている、とう事です。以下の部分です。

load_mnist(normalize=True

これは、各ピクセルの情報値を255で割り、全ての数値を0から1の間に収束させる、という関数です。単純に0から255の数値の分布よりも、0から1の数値の分布の方が扱いやすいですよね。

 

次回は3章最後の記事です。バッチ処理について書きます。 

それでは、本日は以上でございます。