Softmax-with-Lossレイヤの実装|Excel VBAでIris分類問題
本ページは「ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装」を参考にニューラルネットワークを作成していきます。参考書籍では「Affineレイヤ」「ReLUレイヤ」「Softmax-with-Lossレイヤ」という3つのレイヤを作成し、それらを組み合わせることでニューラルネットワークを構築していきます。本サイトでも同じように3つのレイヤをVBAで作成し実装していきます。
本ページではその中の「Softmax-with-Lossレイヤ」をVBAで実装していきます。
Softmax-with-Lossレイヤの機能
Softmax-with-Lossレイヤは
「入力された値にSoftmax関数を適用し活性化させる機能」と
「損失関数(交差エントロピー誤差)を求める機能」の2つの機能まとめたレイヤです。
Softmax関数の機能と交差エントロピー誤差を求める機能は「Functions」モジュールで実装しているので、このレイヤの順伝播ではそれら機能を呼び出すだけです。逆伝播も計算だけ見れば非常にシンプルな内容になので簡単に実装することができます。(なぜその計算になるかを理解するのは少し難易度が高いです)
機械学習の流れ
今回作成していくニューラルネットワークをレイヤで表すと下図の通りです。
このレイヤの流れは以下のようになっています。(以下では上図の各レイヤを左から「Affine1」「Sigmoid」「Affine2」「Softmax-with-Loss」として説明していきます)
1. 入力値(4つの数字)を「Affine1」に入れ、入力値と重みの総和を計算する。
2.「Affine1」の出力を「Sigmoid」に入れて活性化させる。(ReLUにも変更可能)
3.「ReLU」の出力を「Affine2」に入れ、入力値と重みの総和を計算する。
4.「Affine2」の出力を「Softmax-with-Loss」に入れ、活性化の結果/損失関数を求める。
5.「Softmax-with-Loss」から「Affine2」に逆伝播(Affine2のパラメータを更新)
6.「Affine2」から「Sigmoid」に逆伝播
7.「ReLU」から「Affine1」に逆伝播(Affine1のパラメータを更新)
上記の1~7を数百回ループすることで「Affine1」と「Affine2」が持つパラメータ(重み/バイアス)が正解に近づくように徐々に更新されていきます。あとは損失関数をもとにループを止めれば学習終了といった流れになってます。
Softmax-with-Lossレイヤレイヤの実装
まずはクラスモジュールで「SoftmaxWithLoss_Layer」というモジュールを作成します。
このレイヤはインスタンスを作るわけでもなければ、値を保存する必要もないのですが、他のレイヤと揃えるためにクラスモジュールで実装していきます。
また「Option Base 1」を使い配列を「1」スタートにします。
これは要素数とインデックスを合わせ配列同士の計算をわかりやすくするためです。
以下はSoftmax-with-Lossレイヤの全コードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
Option Explicit Option Base 1 Dim loss As Double Dim y() As Double Dim t() As Long '―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― Public Function forward(ByRef x() As Double, ByRef input_t() As Long) As Double Dim i As Long ReDim t(UBound(input_t)) For i = 1 To UBound(input_t) t(i) = input_t(i) Next i ReDim y(UBound(x)) y = Functions.Softmax(x) loss = Functions.cross_entropy_error(y, t) forward = loss End Function '―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― Public Function backward(ByRef dout As Double) As Double() Dim dx() As Double Dim i As Long ReDim dx(UBound(t)) For i = 1 To UBound(t) dx(i) = (y(i) - t(i)) Next backward = dx End Function |
Function forward
関数「forward」は名前のとおり順伝播を行う関数です。
このレイヤで行う順伝播は、Softmax関数の適用し交差エントロピー誤差を求めるまでです。
Softmax関数は入力される値の割合に応じて合計が「1」になるような値に変換するという関数です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Dim loss As Double Dim y() As Double Dim t() As Long '―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― Public Function forward(ByRef x() As Double, ByRef input_t() As Long) As Double Dim i As Long ReDim t(UBound(input_t)) For i = 1 To UBound(input_t) t(i) = input_t(i) Next i ReDim y(UBound(x)) y = Functions.softmax(x) loss = Functions.cross_entropy_error(y, t) forward = loss End Function |
この関数の引数としては「x()」と「input_t()」があります。
「x()」は前の層(今回の場合はAffine2)の出力値
「input_t()」はone-hot表現に変換した入力画像データの正解ラベルです。
この関数では下記のような処理を行っています。
②「x()」に対してSoftmax関数を適用し、「y()」に格納
③「y()」と「t()」を使って交差エントロピー誤差を求め、その値を返す
交差エントロピー誤差は損失関数、いわゆる”Loss値”と呼ばれ学習が進むにつれてこの値が0に近づいていきます。学習精度の目安の1つとしてこの値は非常に重要な存在です。
Function backward
関数「backward」は名前のとおり逆伝播を行う関数です。
Softmax-with-Lossレイヤの逆伝播は順伝播時の入力値が0以下の場合は0を、0より大きい場合は前の層から逆伝播してきた「微分の値」をそのまま返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Public Function backward(ByRef dout As Double) As Double() Dim dx() As Double Dim i As Long ReDim dx(UBound(t)) For i = 1 To UBound(t) dx(i) = (y(i) - t(i)) Next backward = dx End Function |
この関数の引数としては「dout」がありますが、コードの内容を見るとわかる通り「dout」は使いません。(Pythonコードでも同じように引数として「dout=1」を設定しているためここでも同じように表現しています)
そのため引数については無視して下さい。
このレイヤではSoftmax関数の出力値「y()」と正解ラベル「t()」の差を逆伝播します。
「y()」「t()」の値は順伝播で保存しているので、
そのまま各要素の差を求め1次元配列として返します。
たとえば「y(1,2,3)」「t(0,1,0)」の場合は
dx(1 – 0 , 2 – 1 , 3 – 0) → dx(1 , 1 , 3)が返り値となります。
この返り値が「微分の値」として逆伝播されていきます。
(なぜ引き算をすると「微分の値」になるのかの説明は参考書籍を参照下さい)
これにより2つのAffineレイヤが持つ重み/バイアスパラメータの値を更新することができます。
まとめ
ここでは「ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装」を参考にVBAでSoftmax-with-Lossレイヤの実装を行いました。
今回実装したSoftmax-with-Lossレイヤの機能をまとめると以下の通りです。
Function forward:順伝播(Softmax関数の適用し損失関数を求める)
Function backward:逆伝播(「微分の値」を求めて逆伝播)
Softmax-with-Lossレイヤは「Functions」モジュールで実装した
「Softmax関数」「交差エントロピー誤差」を呼び出しているだけのレイヤです。
順伝播でいうと1番最後で、逆伝播でいうと1番最初になる学習の折り返し地点となるレイヤです。
また最終的にニューラルネットワークが導き出した値を出力するレイヤでもあるので、どのような計算が行われているのかはしっかりと理解しておきましょう。
次回はニューラルネットワークの本体となるTwoLayerNetクラスの実装です。
これまでに実装したAffineレイヤ、ReLU(Sigmoid)レイヤ、そしてSoftmax-with-Lossレイヤを呼び出しニューラルネットワークを構築していきます。
【次回】TwoLayerNetクラスの実装
【次回】Sigmoidレイヤの実装
メインページ