0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

深層学習前編2 勾配消失問題~学習率最適化手法 講義課題視聴レポート (現場で潰しが効くディープラーニング講座)

Last updated at Posted at 2019-07-08

深層学習前編2

勾配消失問題

  • 勾配消失問題とは誤差逆伝播法が下位層に進んでいくにつれて、勾配がどんどん緩やかになっていく問題。つまり、下位層のパラメータを更新してもほとんど値が変わらず最適値に収束しなくなってしまう
  • 特にシグモイド関数を使っている場合に起きやすい。その理由はシグモイド関数の微分は最大値が0.25であるためパラメータの更新値が必然的に小さくなってしまうからである
勾配消失問題の解決法1 活性化関数の選択
  • ReLU関数を使用する(ReLU関数については活性化関数の項で説明済み)
勾配消失問題の解決法2 初期値の設定
  • ReLU関数、シグモイド関数、双曲線正接関数を使う場合にXavierという手法をつかって重みの初期値を設定すると勾配消失問題の解決につながる
  • Xavierとは標準正規分布でランダムに生成した値を前の層のノード数で除算し、各パラメータの初期値とする方法
    network['W1'] = wieght_init * np.random.randn(input_layer_size, hidden_layer_1_size)
    network['W2'] = wieght_init * np.random.randn(hidden_layer_1_size, hidden_layer_2_size)
    network['W3'] = wieght_init * np.random.randn(hidden_layer_2_size, output_layer_size)
  • またReLU関数にはHeという設定方法もある
  • Heとは標準正規分布でランダムに生成した値を前の層のノード数で除算し、√2を掛けたものを各パラメータの初期値とする方法
    network['W1'] = np.random.randn(input_layer_size, hidden_layer_1_size) / np.sqrt(input_layer_size) * np.sqrt(2)
    network['W2'] = np.random.randn(hidden_layer_1_size, hidden_layer_2_size) / np.sqrt(hidden_layer_1_size) * np.sqrt(2)
    network['W3'] = np.random.randn(hidden_layer_2_size, output_layer_size) / np.sqrt(hidden_layer_2_size) * np.sqrt(2)
  • 重みの初期値を0に設定してしまうとすべてのデータが同じ値で次の層に渡されるのでパラメータの更新がされなくなってしまう
勾配消失問題の解決法3 バッチ正規化
  • ミニバッチ単位で入力値のデータの偏りを抑制する手法。活性化関数に値を渡す前後に、バッチ正規化の処理を行う層を加える。
  • バッチ正規化を行うことで、計算の高速化や勾配消失問題の解消などの効果がある

無題9.png

実装演習
  • 初期値ランダム シグモイド関数
    無題.png
    無題1.png
    無題2.png
    無題3.png
    無題4.png
    無題5.png
    無題6.png

  • 初期値ランダム ReLU関数
    無題7.png
    無題8.png
    無題9.png
    無題10.png
    無題11.png
    無題12.png
    無題13.png

  • 初期値Xavier シグモイド関数
    無題14.png
    無題15.png
    無題16.png
    無題17.png
    無題18.png
    無題19.png
    無題20.png

  • 初期値He ReLU関数
    無題21.png
    無題22.png
    無題23.png
    無題24.png
    無題25.png
    無題26.png
    無題27.png

  • 初期値He シグモイド関数
    無題28.png
    無題29.png

  • 初期値Xavier ReLU関数
    無題30.png
    無題31.png

考察
  • 予想通り初期値ランダムでシグモイド関数を使った場合は勾配消失を起こし学習が進まなかった
  • 初期値ランダムでReLU関数を使うと、時間はかかるが学習が進み最終的な精度も高くなることが確認できた
  • 初期値をXavierで決めシグモイド関数を使うと、勾配消失は起こらなかったがReLU関数ほど良い結果は得られなかった
  • 初期値をHeで決めReLU関数を使うと、初期値をランダムで比べた時に比べ学習が早く進み、同程度に良い結果が得られた
  • 初期値をHeで決めシグモイド関数を使うと、初期値をXavierで決めたときと同じような結果になった
  • 初期値をXavierで決めReLU関数を使うと初期値をHeで決めた時と同じような結果を得られた
  • 全体的にReLE関数を使ったほうが良い結果を得ることができた。学習データの性質によってはシグモイド関数のほうが良い結果を出すことも考えられる。

学習率最適化法

  • 勾配降下法を行うとき、学習率の大小により学習の結果が左右される。
  • 最適な学習率を求める方法としてモメンタム、AdaGrad、RMSPrp、Adamなどがある
モメンタム
  • モメンタムとは重みの修正量に、前回の重みの修正量を加算する方法

無題10.png

  • μは前回の重みの加算量を決めるハイパーパラメータで通常0.5~0.9の範囲から選ばれる
  • モメンタムの利点は局所的最適解ではなく、大域的最適解を得ることができる点や勾配が急な点から、なだらかな点に行くまでの時間が早いなどがあげられる。
  • pythonで記述すると以下の通りになる
v[key] = momentum * v[key] - learning_rate * grad[key]
network.params[key] += v[key]
AdaGrad
  • AdaGradとは誤差をパラメータで微分した値の二乗和を使って学習率の値を調整する方法

無題11.png

  • θは分子が0にならないようにするための微小な値
  • モメンタムと違い、勾配の緩やかな斜面に対して最適値に近づけることができる
  • 学習率が徐々に小さくなる(増加することはない)ので鞍点問題を引き起こすことがある
  • 鞍点問題とは多次元データを扱っているとき、ある次元から見た場合は極小値だが別の次元から見た場合は極大値になる点で学習が止まってしまう現象である
  • pythonで記述すると以下の通りになる
if i == 0:
  h[key] = np.full_like(network.params[key], 1e-4)
else:
  h[key] += np.square(grad[key])
network.params[key] -= learning_rate * grad[key] / (np.sqrt(h[key]))
RMSProp
  • RMSPropとはAdaGradを改良したもので、勾配の二乗和ではなく勾配の指数移動平均を使って学習率を更新する方法である

無題12.png

  • 利点として、局所的最適値にならず大域的最適値となる点やハイパーパラメータの調整が必要になる場合が少ない点があげられる
  • pythonで記述すると以下の通りになる
if i == 0:
  h[key] = np.zeros_like(network.params[key])
h[key] *= decay_rate
h[key] += (1 - decay_rate) * np.square(grad[key])
network.params[key] -= learning_rate * grad[key] /(np.sqrt(h[key]) + 1e-7)
Adam
  • Adamとは勾配の和と勾配の二乗和を使って学習率を更新する方法
  • pythonで記述すると以下の通りになる
learning_rate_t  = learning_rate * np.sqrt(1.0 - beta2 ** (i + 1)) / (1.0 - beta1 ** (i + 1))    
for key in ('W1', 'W2', 'W3', 'b1', 'b2', 'b3'):
    if i == 0:
        m[key] = np.zeros_like(network.params[key])
        v[key] = np.zeros_like(network.params[key])
            
    m[key] += (1 - beta1) * (grad[key] - m[key])
    v[key] += (1 - beta2) * (grad[key] ** 2 - v[key])            
    network.params[key] -= learning_rate_t * m[key] /(np.sqrt(v[key]) + 1e-7)
実装演習
  • 以下は初期値を分散0.01のランダムな値、関数をReLU関数にした時の実装
    無題.png
    無題1.png
    無題2.png

  • モメンタム
    無題3.png
    無題4.png

  • 慣性を0.8にした場合
    無題25.png

  • 慣性を1にした場合
    無題6.png

  • 慣性0.9で学習率を0.01から0.05にした場合
    無題7.png
    無題8.png

  • AdGrad
    無題9.png
    無題10.png
    無題11.png

  • RMSProp
    無題12.png
    無題13.png
    無題14.png

  • Adam
    無題15.png
    無題16.png
    無題17.png

  • シグモイド関数を使った場合(学習率最適化手法は未使用)
    無題18.png
    無題19.png

  • 初期値を分散1のランダムな値、関数はシグモイド関数を使用した場合
    無題20.png
    無題21.png

  • 初期値を分散0.01のランダムな値、関数はシグモイド関数を使用し、バッチ正規化を実行した場合
    無題22.png
    無題23.png

考察
  • 初期値をランダムに決定し、ReLU関数を使った場合学習がうまくいかなかった
  • 同じ条件でモメンタムを使用すると、学習は遅いが最終的に良い結果を得られた
  • ここから慣性の値を変更してみたが学習はうまくいかなかった。今回の条件に関して言えば、慣性の値は0.9が最適のようだ
  • そのため慣性の値を変えずに学習率を増やしてみると、早い段階でよい結果を得ることができた
  • 今回の条件ではAdaGrad、RMSProp、Adamで学習した場合、パラメータの調整をせずに良い結果を得ることができた
  • 通常の確率的勾配降下法をシグモイド関数で行った結果、勾配消失を起こし学習が進まなかった
  • 学習率と初期値の分散の値を調整してみたところ、分散1、学習率0.5のとき比較的良い結果を得ることができた。しかしXavierや学習率最適化法を使ったほうが、手早く良い結果を得ることができると考える
  • 最適化法を使わずにバッチ正規化だけ実行した場合、学習は少し進んでいるようだが良い結果を得ることができなかった。どれか1つの最適化手法を使うのではなく、複数の手法を組み合わせて使うことが望ましいと考える

次へ(過学習~最新のCNN )

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?