# 深層学習のトレーニングのコツ
ニューラルネットワークが深くなるにつれて、そのトレーニングプロセスはますます困難になります。主な問題の一つは、いわゆる[勾配消失](https://en.wikipedia.org/wiki/Vanishing_gradient_problem)や[勾配爆発](https://deepai.org/machine-learning-glossary-and-terms/exploding-gradient-problem#:~:text=Exploding%20gradients%20are%20a%20problem,updates%20are%20small%20and%20controlled.)です。[この投稿](https://towardsdatascience.com/the-vanishing-exploding-gradient-problem-in-deep-neural-networks-191358470c11)はこれらの問題についての良い導入を提供しています。
深いネットワークのトレーニングをより効率的にするために、いくつかの技術を使用することができます。
## 値を適切な範囲に保つ
数値計算をより安定させるために、ニューラルネットワーク内のすべての値が通常[-1..1]または[0..1]の範囲内に収まるようにする必要があります。これは非常に厳密な要件ではありませんが、浮動小数点計算の性質上、異なる大きさの値を正確に操作することは困難です。例えば、10-10と1010を足すと、1010になる可能性が高く、小さい値が大きい値と同じオーダーに「変換」され、仮数部が失われるからです。
ほとんどの活性化関数は[-1..1]の範囲で非線形性を持っているため、すべての入力データを[-1..1]または[0..1]の範囲にスケールすることが理にかなっています。
## 初期の重みの初期化
理想的には、ネットワーク層を通過した後も値が同じ範囲内に収まることを望みます。そのため、値の分布を維持するように重みを初期化することが重要です。
**N(0,1)**の正規分布は良い選択ではありません。なぜなら、入力が*n*個ある場合、出力の標準偏差は*n*となり、値が[0..1]の範囲を超える可能性が高いからです。
以下の初期化方法がよく使用されます:
- 一様分布 -- `uniform`
- **N(0,1/n)** -- `gaussian`
- **N(0,1/√n_in)** -- 入力が平均0、標準偏差1の場合、同じ平均と標準偏差が維持されることを保証
- **N(0,√2/(n_in+n_out))** -- **Xavier初期化**(`glorot`)、前方および後方伝播中に信号を範囲内に保つのに役立つ
## バッチ正規化
適切な重みの初期化を行っても、トレーニング中に重みが非常に大きくなったり小さくなったりする可能性があり、それによって信号が適切な範囲を外れることがあります。これを防ぐために、**正規化**技術を使用します。いくつかの方法がありますが(重み正規化、層正規化など)、最もよく使用されるのはバッチ正規化です。
**バッチ正規化**のアイデアは、ミニバッチ全体の値を考慮し、それらの値に基づいて正規化(平均を引き、標準偏差で割る)を行うことです。これは、重みを適用した後、活性化関数の前にこの正規化を行うネットワーク層として実装されます。その結果、最終的な精度が向上し、トレーニングが速くなる可能性があります。
バッチ正規化に関する[元の論文](https://arxiv.org/pdf/1502.03167.pdf)、[Wikipediaの説明](https://en.wikipedia.org/wiki/Batch_normalization)、および[良い入門ブログ記事](https://towardsdatascience.com/batch-normalization-in-3-levels-of-understanding-14c2da90a338)([ロシア語版](https://habrahabr.ru/post/309302/)もあります)。
## ドロップアウト
**ドロップアウト**は、トレーニング中にランダムなニューロンの一定割合を削除する興味深い技術です。これは、1つのパラメータ(削除するニューロンの割合、通常10%-50%)を持つ層として実装され、トレーニング中に入力ベクトルのランダムな要素をゼロにして次の層に渡します。
一見奇妙なアイデアのように思えるかもしれませんが、MNIST数字分類器のトレーニングにおけるドロップアウトの効果を[`Dropout.ipynb`](../../../../../lessons/4-ComputerVision/08-TransferLearning/Dropout.ipynb)ノートブックで確認できます。トレーニングを高速化し、少ないトレーニングエポックでより高い精度を達成することができます。
この効果は以下のように説明できます:
- モデルにランダムなショックを与える要因と考えられ、局所的な最小値から最適化を引き離す
- *暗黙的なモデル平均化*と考えられ、ドロップアウト中にわずかに異なるモデルをトレーニングしていると言える
> *酔っ払った人が何かを学ぼうとすると、翌朝にはしらふの人よりもよく覚えていると言う人もいます。これは、機能していないニューロンを持つ脳が意味をつかむためにより適応しようとするからだと言われています。これが本当かどうかは私たち自身で試したことはありません。*
## 過学習の防止
深層学習の非常に重要な側面の一つは、[過学習](../../3-NeuralNetworks/05-Frameworks/Overfitting.md)を防ぐ能力です。非常に強力なニューラルネットワークモデルを使用する誘惑に駆られるかもしれませんが、モデルのパラメータ数とトレーニングサンプル数のバランスを常に取る必要があります。
> 以前紹介した[過学習](../../3-NeuralNetworks/05-Frameworks/Overfitting.md)の概念を理解していることを確認してください!
過学習を防ぐ方法はいくつかあります:
- 早期停止 -- 検証セットのエラーを継続的に監視し、検証エラーが増加し始めたらトレーニングを停止
- 明示的な重み減衰 / 正則化 -- 重みの絶対値が高い場合に損失関数に追加のペナルティを加えることで、モデルが非常に不安定な結果を得るのを防ぐ
- モデル平均化 -- 複数のモデルをトレーニングし、その結果を平均化することで分散を最小化
- ドロップアウト(暗黙的なモデル平均化)
## オプティマイザー / トレーニングアルゴリズム
トレーニングにおいて重要な側面の一つは、適切なトレーニングアルゴリズムを選択することです。古典的な**勾配降下法**は合理的な選択ですが、時には遅すぎたり、他の問題を引き起こすことがあります。
深層学習では、**確率的勾配降下法**(SGD)を使用します。これは、トレーニングセットからランダムに選択されたミニバッチに対して勾配降下法を適用するものです。重みは以下の式で調整されます:
wt+1 = wt - η∇ℒ
### モメンタム
**モメンタムSGD**では、以前のステップからの勾配の一部を保持します。これは、慣性を持って移動しているときに、異なる方向から衝撃を受けても軌道がすぐには変わらず、元の動きの一部を保持するのに似ています。ここでは、速度を表す別のベクトルvを導入します:
- vt+1 = γ vt - η∇ℒ
- wt+1 = wt+vt+1
ここで、パラメータγは慣性をどの程度考慮するかを示します:γ=0は古典的なSGDに対応し、γ=1は純粋な運動方程式です。
### Adam、Adagradなど
各層で信号を行列Wiで乗算するため、||Wi||に応じて勾配が0に近づいたり、無限に増加したりする可能性があります。これが勾配爆発/消失問題の本質です。
この問題の解決策の一つは、式において勾配の方向のみを使用し、絶対値を無視することです。つまり、
wt+1 = wt - η(∇ℒ/||∇ℒ||), ここで ||∇ℒ|| = √∑(∇ℒ)2
このアルゴリズムは**Adagrad**と呼ばれます。同じアイデアを使用する他のアルゴリズムには、**RMSProp**、**Adam**があります。
> **Adam**は多くのアプリケーションで非常に効率的なアルゴリズムと考えられているため、どれを使用するか迷った場合はAdamを選択してください。
### 勾配クリッピング
勾配クリッピングは上記のアイデアの拡張です。||∇ℒ|| ≤ θの場合、元の勾配を重みの最適化に使用し、||∇ℒ|| > θの場合は勾配をそのノルムで割ります。ここでθはパラメータであり、ほとんどの場合θ=1またはθ=10を使用できます。
### 学習率の減衰
トレーニングの成功は学習率パラメータηに依存することがよくあります。ηの大きな値はトレーニングを速くする傾向があり、これはトレーニングの初期段階で望ましいものですが、ηの小さい値はネットワークを微調整するのに役立ちます。そのため、ほとんどの場合、トレーニングの過程でηを減少させたいと考えます。
これは、各エポックの後にηをある数(例:0.98)で乗算することで行うことができます。または、より複雑な**学習率スケジュール**を使用することもできます。
## 異なるネットワークアーキテクチャ
問題に適したネットワークアーキテクチャを選択することは難しい場合があります。通常、特定のタスク(または類似のタスク)でうまく機能することが証明されているアーキテクチャを選択します。こちらにコンピュータビジョン用のニューラルネットワークアーキテクチャの[良い概要](https://www.topbots.com/a-brief-history-of-neural-network-architectures/)があります。
> トレーニングサンプル数に対して十分に強力なアーキテクチャを選択することが重要です。あまりに強力なモデルを選択すると[過学習](../../3-NeuralNetworks/05-Frameworks/Overfitting.md)を引き起こす可能性があります。
もう一つの良い方法は、必要な複雑さに自動的に調整されるアーキテクチャを使用することです。ある程度、**ResNet**アーキテクチャや**Inception**は自己調整型です。[コンピュータビジョンアーキテクチャについての詳細](../07-ConvNets/CNN_Architectures.md)。
**免責事項**:
この文書は、AI翻訳サービス [Co-op Translator](https://github.com/Azure/co-op-translator) を使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確な部分が含まれる可能性があることをご承知おきください。元の言語で記載された文書が公式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳をお勧めします。この翻訳の使用に起因する誤解や誤解釈について、当方は一切の責任を負いません。