【勾配消失しない重みの初期値】Excelでモンテカルロシミュレーションしてみた
勾配消失や勾配爆発を避けるには重み初期値の設定が重要
ニューラルネットワークでは、前の層からの信号に重みを掛けた線形和に活性化関数を掛けて次の層への出力としますが、活性化関数によって結構な情報量が削り取られます。
例えばシグモイド関数は
f(x) = 1/(1+e-x)
で表されますが、概ねx<-4は0に、x>4は1に丸められます。
0から1の意味ある数字に変換されるのは、xが概ね-4<x<4の範囲にある時だけです。
一旦、この範囲から外れると、xが小さすぎる場合は勾配消失、逆に大きすぎる場合は勾配爆発になる可能性が高まります。
【勾配消失と勾配爆発はなぜ起こるのか?】その原因と対策をExcelで調べてみた
従って学習をうまく進めるためには出だしが肝心で、重みの初期値をどうやって決めるかが重要になるといえます。
「ゼロから作るディープラーニング」にはスタンフォード大学の授業で行った実験を引用して、重みの初期値をどうやって設定するのが良いかが解説されています。
この実験はPythonで行われていますので、ここではExcelで実験してみて更に理解を深めたいと思います。
Excelによるモンテカルロシミュレーションを行列演算で効率化
行列演算では行列サイズに留意
シミュレーション方法は簡単です。
100入力で5層の隠れ層(各層には100個のニューロン)を持つニューラルネットワークに、標準正規分布に従う1,000組の入力を流し、各隠れ層の出力の分布を調べるというものです。
一種のモンテカルロシミュレーションです。
ただExcelで行うには規模が大きすぎますので、行列を使います。
行列は複数の線形和を一気に計算できるので効率が良いのです。
行列の計算で注意すべき点は、行列のサイズです。
例えば、次の行列は3行2列の行列、または3×2の行列といいます。
行と列を間違わないようにして下さい。
これが大事になるのは、行列同士の掛け算をする時です。
2つの行列を掛け算をする時には、前の行列の列数と、後の行列の行数が一致していないといけません。
例えば、前の行列のサイズが3×2ならば、後の行列のサイズは2×?でないといけません。
これが一致していれば、掛け算した後の行列のサイズは3×?になります。
入力数と出力数から行列サイズを決定する
これさえ押さえておけば、今回の計算はサイズを大きくするだけです。
入力が100個ですので、横に並べて書けば1×100の入力行列になります。
次の隠れ層1では100個のニューロンがあります。
そして、各ニューロンが100個の入力信号を受けるので100個の重みが掛けられます。
従って、各ニューロンにつき100個の重みが必要で、100ニューロンありますので、100×100の行列になります。
これが隠れ層1の重み行列になります。
入力行列が1×100で、隠れ層1の重み行列が100×100ですので、隠れ層1の線形和は1×100の行列になります。
この100個の成分一つひとつについて活性化関数(シグモイド関数)を通すと、これも1×100の行列になり、これが隠れ層1の出力になります。
そして、これが隠れ層2の入力になり、以降は隠れ層5まで同様の計算になります。
以上をまとめると次のようになります。
乱数の数も行列サイズに反映する
これだけでも行列の有用性が分かりますが、行列の威力はこれだけではありません。
1,000組の入力を流してモンテカルロシミュレーションをしますが、入力行列を1,000×100として1,000組の入力を流してしまえば、1,000回のモンテカルロシミュレーションが一遍にできてしまいます。
つまり、このようにします。
Excelに実装する
これをExcelに実装すると、次のようになります。
【入力行列】
【重み行列】
【線形和行列】
入力行列×重み行列(活性化関数前)
【出力行列】
活性化関数後
以上が隠れ層1層目の計算ですので、同じように2層目から5層目まで入力します。
すると、隠れ層1層目から5層目までの出力行列がz1からz5として計算されます。
つまり、すべての隠れ層出力の1,000回分のモンテカルロシミュレーションが一瞬にしてできてしまいます。
各出力行列のサイズは1,000×100なので、10万個の数値が入っています。
これら10万個の値をヒストグラムで表示させることにより、分布の偏りを調べることができます。
モンテカルロシミュレーションの結果
重み初期値が標準正規分布だと勾配消失
まずは重みの初期値を標準正規分布に従う乱数で決めた場合のシミュレーションを行います。
標準正規分布とは、平均ゼロ、標準偏差1の正規分布のことです。
各層の重みパラメータは100×100=10,000個あり、5層合せて5万個あります。
これらの初期値を標準正規分布に従う乱数で設定するということです。
正規分布乱数の生成方法については、こちらを参照下さい。
エクセルを使って正規分布の乱数を生成する方法をわかりやすく解説
隠れ層5層での各出力値の分布は次のようになりました。
横軸が出力値で0から1になっています。
これは活性化関数としてシグモイド関数を使っているためです。
各層とも、0付近と1付近に出力値が集中していることが分かります。
これはシグモイド関数の感度の悪い領域ですので、学習効率が悪いということですね。
また勾配降下法で勾配を求める時にシグモイド関数を微分しますが、シグモイド関数の微分のグラフは下図のようになっていて、xがゼロから離れるほどゼロに近づきます。
ということは、隠れ層がディープになるとそれらが掛け合わされますので、勾配はどんどんゼロに近づき勾配消失が起きてしまいます。
従って、この初期値は良くないことが分かります。
重み初期値の標準偏差が小さすぎると表現力がなくなる
次に、重みの初期値を平均ゼロ、標準偏差0.01の正規分布に従う乱数で設定してみます。
結果は次のようになりました。
今度は一転して中央(0.5付近)に出力値が集中してしまいました。
xが0.5付近ではシグモイド関数の微分値が大きい(といっても高々0.25)ので勾配消失は起きにくくなりますが、今度は表現力のなさが問題になってきます。
各隠れ層で100個のニューロンがありますが、それぞれのニューロンが同じような値を出力するということは、100個もある必要がなくなってしまいます。
つまり少しの特徴しか考慮しない、表現力のないニューラルネットワークになってしまうのです。
「Xavierの初期値」だと丁度いい
このように重みパラメータの初期値を設定する時の標準偏差を1にすると出力がばらつき過ぎてしまい、0.01にすると集中し過ぎてしまいます。
ということは、その間である0.1くらいにしたらいい具合になるのではないかという予想がつきますね。
Xavierさんという人が、これを理論化したそうです。
これは「Xavierの初期値」として知られていて、前の層のニューロン数がn個の場合、1/√nの標準偏差に従う正規分布乱数で重みの初期値を設定すると良いようです。
今回の場合は入力層も隠れ層もすべて100個のニューロンですので、0.1になります。
それではこれに従って重みパラメータの初期値を設定してみましょう。
結果は次のようになりました。
x=0.5を中心に適度にばらついた良い出力分布になりました。
5層目へ行くに従って徐々にばらつきが小さくなっていますが、許容範囲でしょう。
尚、このシミュレーションでは1バッチでのアクティベーション分布しか見ていませんが、重みが収束するまで学習させた時のXavierの初期値の有効性については、こちらでExcelシミュレーションしていますので良かったら参照してみて下さい。
誤差逆伝播法を行列演算でExcelに実装してXavierの初期値の有効性を実験してみた
活性化関数が左右対称でない場合は「Heの初期値」
尚、このXavierの初期値は万能ではないことも知られています。
シグモイド関数やtanh関数のように、左右対称の活性化関数を使う時限定です。
ReLU関数のようにx=0を境に左右対称でない活性化関数を使う場合には、Heさんが提唱した「Heの初期値」が良いといわれています。
Heの初期値では標準偏差2/√nに従う正規分布乱数で、重みの初期値を決めるのが良いそうです。
それではまず、ReLU関数を使う場合に、Xavierの初期値で重みパラメータを決めた場合の出力分布を見てみましょう。
いずれの層も一番左の値が飛び抜けて大きくなっていますが、これはx=0~0.1が多く出現していることを示しています。
しかし、この中に含まれているのは実際にはx=0に丸められたデータがほとんどです。
つまり、ReLU関数をかます前の線形和の値ではマイナスになっていたデータがほとんどです。
xの初期値や重みの初期値は、平均ゼロを中心とする正規分布で決めているので、このような値が一定程度出てくるのは致し方ないところです。
問題はそれ以外のデータです。
1層目では1まで出力データが満遍なくばらついていますが、ディープな層へ行くに従い、ばらつきが小さくなっています。
これは表現力や勾配消失という点でよろしくないことです。
次にHeの初期値でシミュレーションした場合の結果は次の通りです。
「Xavierの初期値」と「Heの初期値」の差は分散の加法性で説明できる
見事に5層目までばらつきが維持されています。
でも、なぜReLU関数の場合は√2倍にするとうまく行くのでしょうか?
これは分散の加法性で説明できます。
【分散の加法性とは?】足し算だけでなく平均値にも応用する方法を解説
ReLU関数ではxがマイナスの領域をゼロとしてまとめてしまうため、データのばらつきが約半分になってしまいます。
一方、ばらつきというのは分散で考えると足したり引いたりして定量化できますというのが、分散の加法性で主張していることです。
ReLU関数を通った値の分散は、シグモイド関数やtanh関数のそれの約半分になります。
分散が1/2になるということは、標準偏差は1/√2になります。
ですから、ReLU関数を使う場合は重みの初期値を√2倍して下駄を履かせてやれば丁度うまく行くのです。