AI-For-Beginners/translations/zh-TW/lessons/4-ComputerVision/08-TransferLearning/TrainingTricks.md

108 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 深度學習訓練技巧
隨著神經網絡的深度增加,其訓練過程變得越來越具有挑戰性。一個主要的問題是所謂的[梯度消失](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<sup>-10</sup> 和 10<sup>10</sup> 相加,結果很可能是 10<sup>10</sup>,因為較小的數值會被“轉換”到與較大數值相同的量級,從而導致尾數丟失。
大多數激活函數在 [-1..1] 範圍內具有非線性特性,因此將所有輸入數據縮放到 [-1..1] 或 [0..1] 範圍是有意義的。
## 初始權重初始化
理想情況下,我們希望數值在通過網絡層後仍保持在相同的範圍內。因此,初始化權重時需要以某種方式保留數值的分佈。
正態分佈 **N(0,1)** 並不是一個好主意,因為如果我們有 *n* 個輸入,輸出的標準差將是 *n*,數值很可能會跳出 [0..1] 範圍。
以下是常用的初始化方法:
- 均勻分佈 -- `uniform`
- **N(0,1/n)** -- `gaussian`
- **N(0,1/√n_in)** 保證對於均值為零且標準差為 1 的輸入,輸出仍保持相同的均值和標準差
- **N(0,√2/(n_in+n_out))** -- 所謂的 **Xavier 初始化** (`glorot`),它有助於在前向和反向傳播中保持信號在範圍內
## 批量正規化
即使有了適當的權重初始化,訓練過程中權重仍可能變得非常大或非常小,從而使信號超出適當範圍。我們可以通過使用某些**正規化**技術將信號拉回範圍內。雖然有多種正規化技術(如權重正規化、層正規化),但最常用的是批量正規化。
**批量正規化**的想法是考慮小批量中的所有數值,並基於這些數值進行正規化(即減去均值並除以標準差)。它被實現為一個網絡層,在應用權重後但在激活函數之前執行此正規化。結果是,我們可能會看到更高的最終準確性和更快的訓練速度。
這是批量正規化的[原始論文](https://arxiv.org/pdf/1502.03167.pdf)、[維基百科上的解釋](https://en.wikipedia.org/wiki/Batch_normalization)以及[一篇很好的入門博客文章](https://towardsdatascience.com/batch-normalization-in-3-levels-of-understanding-14c2da90a338)(還有[俄文版](https://habrahabr.ru/post/309302/))。
## Dropout
**Dropout** 是一種有趣的技術,在訓練過程中隨機移除一定比例的神經元。它也被實現為一個層,具有一個參數(要移除的神經元百分比,通常為 10%-50%),在訓練過程中,它會將輸入向量的隨機元素設為零,然後再傳遞到下一層。
雖然這聽起來像是一個奇怪的想法,但你可以在 [`Dropout.ipynb`](../../../../../lessons/4-ComputerVision/08-TransferLearning/Dropout.ipynb) 筆記本中看到 Dropout 對 MNIST 數字分類器訓練的影響。它加快了訓練速度,並使我們能夠在更少的訓練輪次中實現更高的準確性。
這種效果可以用幾種方式解釋:
- 它可以被認為是對模型的一種隨機衝擊因素,將優化從局部最小值中拉出
- 它可以被認為是*隱式模型平均化*,因為我們可以說在 Dropout 過程中,我們正在訓練稍微不同的模型
> *有人說,當一個醉酒的人試圖學習某些東西時,與清醒的人相比,他第二天早上會記得更清楚,因為一個有些神經元失效的大腦會更努力地適應以抓住意義。我們自己從未測試過這是否是真的。*
## 防止過擬合
深度學習的一個非常重要的方面是能夠防止[過擬合](../../3-NeuralNetworks/05-Frameworks/Overfitting.md)。雖然使用非常強大的神經網絡模型可能很有吸引力,但我們應該始終平衡模型參數的數量與訓練樣本的數量。
> 確保你理解我們之前介紹的[過擬合](../../3-NeuralNetworks/05-Frameworks/Overfitting.md)概念!
有幾種方法可以防止過擬合:
- 提前停止 -- 持續監控驗證集上的誤差,當驗證誤差開始增加時停止訓練。
- 顯式權重衰減 / 正則化 -- 在損失函數中添加一個對權重絕對值的額外懲罰,防止模型產生非常不穩定的結果
- 模型平均化 -- 訓練多個模型,然後對結果進行平均。這有助於最小化方差。
- Dropout隱式模型平均化
## 優化器 / 訓練算法
訓練的另一個重要方面是選擇好的訓練算法。雖然經典的**梯度下降**是一個合理的選擇,但它有時可能太慢,或者導致其他問題。
在深度學習中,我們使用**隨機梯度下降**SGD這是一種應用於隨機選擇的小批量的梯度下降。權重的調整公式如下
w<sup>t+1</sup> = w<sup>t</sup> - η∇ℒ
### 動量
在**動量 SGD** 中,我們保留了前幾步的部分梯度。這類似於當我們帶著慣性移動時,受到一個不同方向的衝擊,我們的軌跡不會立即改變,而是保留了一部分原始運動。這裡我們引入另一個向量 v 來表示*速度*
- v<sup>t+1</sup> = γ v<sup>t</sup> - η∇ℒ
- w<sup>t+1</sup> = w<sup>t</sup> + v<sup>t+1</sup>
這裡參數 γ 表示我們考慮慣性的程度:γ=0 對應於經典 SGDγ=1 是純粹的運動方程。
### Adam、Adagrad 等
由於在每一層中,我們將信號乘以某個矩陣 W<sub>i</sub>,根據 ||W<sub>i</sub>||,梯度可能會減小接近 0或者無限增大。這正是梯度爆炸/消失問題的本質。
解決這個問題的一種方法是僅在公式中使用梯度的方向,而忽略其絕對值,即:
w<sup>t+1</sup> = w<sup>t</sup> - η(∇ℒ/||∇ℒ||),其中 ||∇ℒ|| = √∑(∇ℒ)<sup>2</sup>
這種算法稱為 **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) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤讀概不負責。