誤差逆伝播法を行列演算でExcelに実装してXavierの初期値の有効性を実験してみた

2024年5月18日

Excelによるニューラルネットワークを行列演算で効率化する

行列演算は大量のデータの線形和を一遍に計算するのに便利です。

過去の記事で9画素の〇✕画像を見分けるニューラルネットワークをExcelに実装しました。

ニューラルネットワークをExcelに実装して画像処理させてみた。

 

この時は行列演算を使わなかったので、使ったらどれだけ簡単になるか試してみました。

また、重みの初期値がどれだけ学習速度に影響するかもシミュレーションしてみました。

【勾配消失しない重みの初期値】Excelでモンテカルロシミュレーションしてみた

 

行列を定義する

行列サイズを決定する

前回作ったニューラルネットワークは、入力層9ニューロン、隠れ層3ニューロン、出力層2ニューロンでした。

クリックすると拡大します

 

入力が3×3画素の画像データだったため、分かりやすくするために上図のようにExcelに入力していました。

これを今回は9個の画素データを並べて1次元のデータにします。

クリックすると拡大します

 

その上で入力データ、隠れ層の重み、出力層の重み、出力データを下記の行列サイズにします。

クリックすると拡大します

 

2つの行列の掛け算をする時には、前の行列と列数と後の行列の行数が一致していないといけないことに注意です。

それに注意すると、自ずと行列のサイズはこのように決定されます。

 

行列成分を決定する

すると、行列の成分も自ずと下記のように決定します。

クリックすると拡大します

 

重み行列WHやWOがどのニューロンにかかる重みに対応しているかは、図示した通りです。

また前回は44組の教師データを1つずつ読み込んで逐次学習させましたが、今回は44組のデータをまとめてバッチ処理します。

これにより行列演算の威力が更に発揮され、処理の高速化が期待できます。

クリックすると拡大します

 

Excelに実装する

順伝播の計算式

それではExcelに入力していきます。

最初の順伝播の計算は簡単なので、サラッと行きます。

クリックすると拡大します

 

クリックすると拡大します

 

クリックすると拡大します

 

逆伝播の計算式

ここから逆伝播の計算が入ってきます。

まず簡単な出力層の重みの勾配は次のように計算します。

クリックすると拡大します

 

例えばwO11の勾配を求めるには、uO1の計算式にwO11が入っていて、zO1の計算式にuO1が入っているので、連鎖律により上式のように3つの微分に分解できます。

それぞれの微分は簡単に計算できます。

 

次に、少し難しい隠れ層の重みの勾配は次のように計算できます。

クリックすると拡大します

 

図が込み入っていますが、考え方自体は出力層の重みの微分と同じです。

例えばwH11の勾配を求めるにはuH1の計算式にwH11が入っています。

そしてuH1が関係してくるのはuO1、zO1、uO2、zO2の計算式です。

ですから、それに沿って連鎖律を適用していくと上図のように計算できます。

クリックすると拡大します

 

収束するまでバッチ計算を繰り返す

さて、これで44組の入力データによる1バッチ分の計算が終わりました。

最後に計算された隠れ層の重みの勾配と出力層の重みの勾配に学習率を掛けて、初期値の重みから引いて更新します。

そして、この更新された重みを使って同じ44組のデータを入力として2バッチ目の計算を行います。

上図では1バッチ目が終了した損失関数の値は10.95でしたが、この値が十分に小さくなるまでバッチ計算を繰り返します。

学習率を0.5にした場合の結果は次のようになりました。

 

Xavierの初期値の有効性を実験する

Xavierの初期値を使うときれいに収束

上記のシミュレーションでは、隠れ層と出力層の各重みの初期値を平均ゼロ、標準偏差0.の正規分布に従う乱数で設定していました。

Xavierの初期値では、前の層のニューロン数をとすると、平均ゼロ、標準偏差1/√n正規分布乱数で設定すると良いとされています。

これに従うと、隠れ層の初期値は標準偏差1/3、出力層の初期値は標準偏差1/√3になります。

これに従って初期値を設定した場合の結果は次のようになりました。

 

初期値は乱数で設定していますので毎回結果は異なるのですが、ほぼ毎回きれいな放物線で収束しXavierの初期値の有効性が確認できました。

 

初期値が小さすぎても学習率を上げることで改善

次に、標準偏差を.01に変えてシミュレーションしてみました。

結果は次の通りです。

 

振幅は少ないのですが、最初の10バッチくらいはほとんど学習が進みませんでした。

Excelシートで計算結果を見ると原因がよく分かります。

まず、勾配の計算式を見てみましょう。

出力層、隠れ層共に出力の誤差が計算式に掛け算で含まれています。

出力の誤差は出力値-教師データの値です。

クリックすると拡大します

 

重みの初期値を平均ゼロ、標準偏差0.01にしていますので、初期値はほぼゼロです。

ということは、入力値に重みを掛けて合計した線形和もほぼゼロです。

これがシグモイド関数を通って出力値になりますが、シグモイド関数は入力がゼロの時には0.5を出力します。

一方、教師データは0か1ですので、z-t、つまり出力誤差は.5か-0.になります。

1バッチには44組の入力データと教師データの組を読み込ませていますが、教師データが0のデータと1のデータは半々です。

ということは、44個の出力誤差を足すとほぼゼロになってしまいます。

勾配の計算式には出力誤差が掛け算で入っているため、これがほぼゼロになると勾配もほぼゼロになって学習が進まないのです。

最初の約10バッチ分で損失関数の値が減少していないのはこのためです。

クリックすると拡大します

 

このような場合には、学習率を上げれば少しはマシになるでしょう。

学習率を0.5から.9に上げたら、次のようになりました。

 

学習が進まない期間が半分に減って、収束までの時間も短くなりました。

このように、重みパラメータの初期値と学習率は関連があることが分かります。