5 Deep Learning 手書き数字認識 MNIST

MNIST データセット

MNISTデータセットは機械学習の分野で有名なデータセットである。
MINISTの画像は28×28のグレー画像で、各ピクセルは0~255の値をとる。それぞれの画像データに対しては、0~9の対応するラベルが与えられている。
load_mnist関数の引数 flattenフラグは 配列を1次元配列にするか否か、 normalizeは入力画像を0.0~1.0の値に正規化するかどうかを設定する。
normalizeをFalseにすれば、入力画像のピクセルは0~255になる。3つ目の引数のone_hot_labelはラベルをone_hot表現として格納するかどうかを設定する。
one-hot表現とは[0,0,1,0,0,0,0,0,0,0]のように、正解となるインデックスの配列の内容だけが1で、それ以外は0の配列である。
実装を下図のようになり、


出力は下図のようになる。

4.9 Deep Learning 3層ニューラルネットワークの実装 5

4.9.5 ソフトマックス関数の特徴


前回の実装を簡略化して、関数化すると上記のようになるが、
ここで、以前触れた演算誤差の問題が出てくる。
eの10乗(e^10)は20,000を超え、
eの100乗(e^100)は0が40個以上ならぶ巨大な数字になり、
eの1000乗(e^1000)の結果はPythonでは(他の言語も)無限大を表すinfが返ってくる。(infinity)
巨大な数字同士の割り算を行うと、数値が不定になり、nan(not a number)が返る。

これを改善する方法として、
\[y_k = \frac{exp(a_k)}{\displaystyle \sum_{i=1}^n exp(a_i)} = \frac{Cexp(a_k)}{C \displaystyle \sum_{i=1}^n exp(a_i)} \\
= \frac{exp(a_k + \log C)}{\displaystyle \sum_{i=1}^n exp(a_i + \log C)}
= \frac{exp(a_k + C’)}{\displaystyle \sum_{i=1}^n exp(a_i + C’)} \tag{4.9.4-1} \]
のような変形ができる。
\[ C * e^{a_k} = e^{(a_k + \log C)} \]
に注意。(対数の公式)

実際に改善前のソフトマックス関数を使用して、実装すると、下記のようになる。

改善後のソフトマックス関数を使用して、実装すると、下記のようになる。

このようにソフトマックス関数の出力は0~1の間に収まり、ソフトマックス関数の総和は1になる。
よって、ソフトマックス関数の出力を「確率」として解釈することができる。
上の例ではy[0] = 0.018(1.8%) y[1] = 0.245(24.5%) y[2] = 0.737(73.7%)のように解釈でき、2番目(0,1,2の2)の要素が一番確率が高いので2番目を返すということができる。

ここまでやっておいてなんだが、通常ソフトマックス関数は省略されるらしい。
なぜなら、指数関数(e^x)は単調増加する関数であり、入力の大小と出力の大小は必ず一致するからである。
また、一般的にニューラルネットワークは出力の一番大きい要素だけを認識結果とするため、ソフトマックス関数の実装によって、コンピュータの演算を増やす必要はないとして、ソフトマックス関数は省略されるという。

4.9.6 出力層のニューロンの数

出力層のニューロンの数は、解くべき問題に応じて、適宜決める必要がある。
例えばアラビア数字0~9のどれか一つを予測する問題は、10クラス分類問題として、出力層のニューロンは10個に設定する。

ここでは出力層のニューロンの値の大きさをグレーの濃淡で表している。この例ではy2が一番濃く描画されており、y2のニューロンが一番高い値を出力している。
これは、y2に該当するクラス、つまり「2」であることを、このニューラルネットワークが予測したことを示す。

4.9 Deep Learning 3層ニューラルネットワークの実装 4

4.9.4 恒等関数とソフトマックス関数

恒等関数は前回記述した通り、入ってきたものに対して、何も手を加えずに出力する関数である。恒等関数によって、変換されるプロセスは、隠れ層(中間層)での活性化関数と同じで、1本の矢印で描画する。

画像推論等の分類に使われるソフトマックス関数は、次の式で表される。

\[y_k = \frac{exp(a_k)}{\displaystyle \sum_{i=1}^n exp(a_i)}\tag{4.9.4-1} \]
exp(x)はe^x を表す指数関数で、(eは2.7182…のネイピア数と呼ばれる実数)

出力層が全部でn個あるとして、k番目のy_kを求める計算式である。
式(4.9.4-1)に示すように、ソフトマックス関数の分子は入力信号のa_kの指数関数、分母は全ての入力信号の指数関数の和から構成される。

なお、ソフトマックス関数を図で表すと、次の図のようになる。ソフトマックスの出力は、すべての入力信号から矢印による結びつきがある。式(4.9.4-1)から分かるように、出力の各ニューロンがすべての入力信号から影響をうけることになるからである。

ソフトマックス関数を実装すると下記の通りになる。

4.9 Deep Learning 3層ニューラルネットワークの実装 3


続いて、第1層から第2層、及び出力層までの実装を行う。最後の出力層の活性化関数だけ異なる。σ()で表される。(σはギリシャ文字のシグマ)ここでは入力をそのまま返す”恒等関数”を使用する。
identify_function()という大層な名前がついているが 入力xに対してxをただ返すだけの水道管のパイプのような関数である。 y = x;
今更だが、import numpy as np という構文は、
これからnumpyライブラリをnpとして使うよという宣言である。
np.dot()やnp.array()はJavaでいうところの、hogehogeClass.show()という表記と同様である。dot()は行列の内積、array()は配列の定義、sigmoid()はシグモイド関数であるかは説明した。

関数にして、単純化した実装は下記の通り。

変数networkの配列としての初期化や代入、連想配列の使用などが難解かもしれないが、こう書けば動くと考えていれば、現状問題はない。

4.9 Deep Learning 3層ニューラルネットワークの実装 2

上図4.9-3が示す通り、バイアスのためのニューロン①が追加されている。ここで、バイアスの右下のインデックスが一つしかないことに注意されたい。前層のバイアスニューロンが一つしかないため、前層のニューロンを書く必要がないのである。

これまでの確認も含めて、(と本に書いてある)a1^(1)を数式で表すと、重み付き信号とバイアスの和で次のように計算される。

\[a_1^{(1)} = w_{11}^{(1)} + w_{12}^{(1)}x_2 + b_1^{(1)}\tag{4.9.1}\]

行列の内積を用いると、次のように表せる。
ただし、
\[A^{(1)} = XW^{(1)} + B^{(1)}\tag{4.9.2}\]
\[
A^{(1)} = \left(
\begin{array}{ccc}
a_1^{(1)} & a_2^{(1)} & a_3^{(1)}
\end{array}
\right) , X = \left(\begin{array}{cc} x_1 & x_2 \end{array}\right), B = \left(\begin{array}{ccc} b_1^{(1)} & b_2^{(1)} & b_3^{(1)} \end{array}\right) \]

\begin{equation}
W^{(1)} = \left(
\begin{array}{ccc}
w_{11}^{(1)} & w_{21}^{(1)} & w_{31}^{(1)} \\
w_{12}^{(1)} & w_{22}^{(1)} & w_{32}^{(1)}
\end{array}
\right)
\end{equation}

実装は以下の通り、Z1については次回説明する。sigmoid()関数は以前、紹介した活性化関数の一つである。