<目次>
勾配消失問題とは?原因や対策についてもご紹介
やりたいこと/概要
STEP0:前提
STEP1:勾配消失問題の原因と流れ
STEP2:サンプルプログラム
STEP3:まとめと学び
勾配消失問題とは?原因や対策についてもご紹介
やりたいこと/概要
ニューラルネットワークの学習において良く起きる問題の1つに「勾配消失問題」があります。
本記事では、この問題がニューラルネットワークにどのような影響を与えるか?について、原因・仕組み・実際の例を通じて分かりやすく紹介します。
STEP0:前提
モデルの学習において、勾配が0になってしまい学習がうまく進まない現象を「勾配消失問題」と呼びます。
特に隠れ層が多い深層学習モデルでは、誤差逆伝播の過程で微小な勾配が何度も掛け合わされることで、結果的に勾配が0に近づく現象がよく見られます。
(図110)
STEP1:勾配消失問題の原因と流れ
STEP1-1:勾配消失問題が発生する流れ
簡単なモデルを使って、勾配消失がどのように起こるかを見ていきます。
(図121)住宅ローンを契約するかどうか?のモデル
【学習の流れ】
① 重み”w”、”v”とバイアス”b”、”c”に初期値を設定
(図122)
↓
② 入力⇒出力の方向に値が伝播
(図123)
↓
③ 正解値”t”と出力”y”の差から「誤差を計算」
(図124)
↓
④ 誤差”E”を「出力層⇒隠れ層」の方向に逆伝播して重み”v”を更新
(図125)
更新式の例(v1):
v1 = v1 - η * (∂E/∂v1)
これは「v1の変化が誤差Eにどれだけ影響を与えるか?」を表しています。
たとえば、”Acceptability”が最終判断に80%貢献する場合、v1はその割合に近づくように調整されます。
↓
⑤ 次に「隠れ層⇒入力層」の方向に誤差を逆伝播し、w11を更新
(図126)
更新式の例(w11):
w11 = w11 - η * (∂E/∂w11) = w11 - η * (∂E/∂Acceptability) * (∂Acceptability/∂w11)
例えば、(∂E/∂Acceptability)=0.01、(∂Acceptability/∂w11)=0.02 のとき、
勾配値は 0.01 × 0.02 = 0.0002 とさらに小さくなります。
学習率ηが0.01など小さい値だと、入力層に近い層の勾配がほとんど0に近づき、学習が止まります。
STEP1-2:勾配消失が起きる根本原因
上記の流れは「現象としての発生メカニズム」ですが、根本原因は「微小な導関数値を持つ関数を使っている」ことにあります。
例えば、シグモイド関数の導関数は最大でも0.25です。
N層あると、0.25^N という乗算がかかり、勾配は急激に0へ近づきます。
(図131)
STEP2:サンプルプログラム
以下は、実際に勾配消失問題が起こる様子を確認するPythonコードです。
import numpy as np from keras.models import Sequential from keras.layers import Dense, Activation from keras.initializers import RandomNormal from keras.datasets import mnist # 入力xの次元 M = 784 # 隠れ層h1の次元(クラス数) J = 128 # 隠れ層h2の次元(クラス数) K = 10 # エポック数 epoch_num = 10 # ミニバッチのサイズ mini_batch_size = 128 def multi_layer_perceptron(X_train,t_train,X_test,t_test): X,t = X_train,t_train ############################################ # STEP1:モデルの定義 ############################################ w_init = RandomNormal(mean=1,stddev=1) model = Sequential() # 入力層 - 隠れ層の定義 model.add(Dense(input_dim=M, units=J, kernel_initializer=w_init)) model.add(Activation('sigmoid')) # 隠れ層 - 出力層の定義 model.add(Dense(units=K, kernel_initializer=w_init)) model.add(Activation('softmax')) ############################################ # STEP2:誤差関数の定義 # STEP3:最適化手法の定義(例:確率的勾配降下法) ############################################ model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['accuracy']) ############################################ # STEP4:セッションの初期化 ############################################ # ⇒今回は不要 # (TensorFlow v2以降はSessionを使用しないため) ############################################ # STEP5:学習 ############################################ model.fit(X, t, epochs=epoch_num, batch_size=mini_batch_size) ############################################ # STEP6:学習結果の確認 ############################################ classes = np.argmax(model.predict(X,batch_size=mini_batch_size),axis=1) prob = model.predict(X,batch_size=mini_batch_size) print("*******************************") print("classified: ",t==classes) print("probability: ",prob) print("*******************************") ############################################ # STEP7:学習結果の評価 ############################################ X_,t_ = X_test,t_test evaluation = model.evaluate(X_,t_) print(evaluation) def main(): # テストデータを「学習用」と「テスト用」に分ける (X_train, T_train), (X_test, T_test) = mnist.load_data() X_train = X_train.reshape(X_train.shape[0],28*28) X_train = X_train / 255.0 X_test = X_test.reshape(X_test.shape[0],28*28) X_test = X_test / 255.0 # トレーニング&評価 multi_layer_perceptron(X_train, T_train, X_test, T_test) if __name__ == "__main__": main()
このプログラムを実行すると、Epoch=2以降で誤差が減らなくなり、学習が進んでいないことが確認できます。
(図141)
STEP3:まとめと学び
勾配消失問題は、深いニューラルネットワークにおける学習の停滞を招く重大な課題です。
特にシグモイドなど微小な導関数を持つ関数を使う場合に起こりやすく、対策として以下が有効です。
- ReLU関数など勾配が消失しにくい活性化関数を使う
- バッチ正規化を導入する
- 残差接続(ResNet構造)を活用する
- He初期化など適切な重み初期化手法を採用する
こうした工夫により、層が深いモデルでも安定した学習が可能となります。