<目次>
勾配消失問題の対策(解決策)をご紹介(Kerasプログラムあり)
(1-1) 勾配消失問題とは?
(1-2) 勾配消失問題の対策方針
(1-3) 活性化関数による対策(tanh・ReLU)
(1-4) サンプルプログラム)
勾配消失問題の対策(解決策)をご紹介(Kerasプログラムあり)
(1-1) 勾配消失問題とは?
勾配消失問題とは、ニューラルネットワークの学習において、誤差逆伝播の際に勾配が層を伝っていく中で徐々に小さくなり、最終的に学習が進まなくなる現象を指します。
→(参考)勾配消失問題とは?原因や対策についてもご紹介
(1-2) 勾配消失問題の対策方針
勾配消失の主な原因は、「微分すると値が小さくなる関数(例:シグモイド関数)」を用いている点にあります。そのため、対策としては「微分しても値が小さくなりにくい関数」を活性化関数として使うことが考えられます。ただし、出力層には「確率の関数」である必要があるため、シグモイド関数やソフトマックス関数を使うのが一般的です。一方、隠れ層に関しては、より勾配消失の影響を受けにくい活性化関数への変更が有効です。
Before(勾配消失が発生している例)
隠れ層にシグモイド関数を使用した場合の学習の様子です。
(図121)
Epoch 1/100 469/469 [==============================] - 2s 4ms/step - loss: 3.2976 - accuracy: 0.1034 Epoch 2/100 469/469 [==============================] - 2s 4ms/step - loss: 2.3066 - accuracy: 0.1049 ~中略~ Epoch 100/100 469/469 [==============================] - 2s 4ms/step - loss: 2.3097 - accuracy: 0.1040 313/313 [==============================] - 1s 2ms/step - loss: 2.3104 - accuracy: 0.1009 [2.3104090690612793, 0.10090000182390213]
(1-3) 活性化関数による対策(tanh・ReLU)
対策①:双曲線正接関数(tanh)
tanh関数(ハイパボリックタンジェント)は、シグモイド関数に似た形状をしていますが、出力範囲が「-1〜1」となっており、勾配がより保たれやすいです。
特にx=0のときに最大の勾配(1)を持つため、シグモイドよりも勾配消失が起きにくい特性を持ちます。
(図120①)
(図121)After(tanh関数を使用)
Epoch 1/100 469/469 [==============================] - 3s 4ms/step - loss: 3.1688 - accuracy: 0.1031 Epoch 2/100 469/469 [==============================] - 2s 4ms/step - loss: 2.3066 - accuracy: 0.1039 ~中略~ Epoch 100/100 469/469 [==============================] - 2s 4ms/step - loss: 1.9901 - accuracy: 0.2111 313/313 [==============================] - 1s 2ms/step - loss: 1.9830 - accuracy: 0.2085 [1.9829636812210083, 0.2084999978542328]
対策②:ReLU
ReLU(Rectified Linear Unit)は、f(x) = max(0, x) で定義され、xが0以下のときは0、xが0より大きいときは1の勾配を持ちます。
この特性により、大きなxに対しても勾配が消失しないため、深層学習でよく利用されます。
また、数式がシンプルで計算効率が良いこともメリットです。
さらに、x<0の領域で微小な勾配を持たせるLeaky ReLUも存在します。
(図131)
(図122)After(ReLU関数を適用)
Epoch 1/100 469/469 [==============================] - 2s 4ms/step - loss: 363.2008 - accuracy: 0.4561 Epoch 2/100 469/469 [==============================] - 2s 4ms/step - loss: 12.7101 - accuracy: 0.7627 ~中略~ Epoch 100/100 469/469 [==============================] - 2s 3ms/step - loss: 0.9683 - accuracy: 0.9020 313/313 [==============================] - 1s 2ms/step - loss: 1.4856 - accuracy: 0.8799 [1.4856008291244507, 0.8798999786376953]
(1-4) サンプルプログラム
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 = 100 # ミニバッチのサイズ 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('relu')) # 隠れ層 - 出力層の定義 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()