cs231n'18: Course Note 7

Neural Networks Part 3: Learning and Evaluation

梯度檢驗

梯度的數值計算方法是:
f=df(x)dx=f(x+h)f(xh)2h f^{'} = \frac{\mathrm{d} f(x)}{\mathrm{d} x} = \frac{f(x+h) - f(x-h)}{2h}
梯度檢驗的方法是:
rel_err=fafnmax(fa+fn,ϵ) rel\_err = \frac{|f_a^{'} - f_n^{'}|}{\max \left(|f_a^{'}| + |f_n^{'}|, \epsilon \right)}

def rel_error(x, y):
    return np.max(np.abs(x - y) / (np.maximum(1e-8, np.abs(x) + np.abs(y))))

梯度檢驗是要注意的點:

  1. rel_error應該比1e-7小,如果NN很深的話,因爲誤差是累積的,所以rel_error可能會大一點。
  2. 梯度檢驗對精度很敏感,要用雙精度類型,np.float64;另外,如果梯度數值很小的話,對梯度檢驗也是不利的,所以儘量使梯度的數值在1.0數量級上。
  3. 在奇點處,函數的左右極限是不相等的,梯度檢驗在奇點處是不準確的。對於NN來說,可能引入奇點的只有relu或者SVM。對於relu或者SVM來說,檢驗函數是否過奇點很簡單:(x+h)和(x-h)符號相反。雖然在NN中函數取值到奇點附近不是一個小概率事件,但是因爲梯度檢驗並不是對所有點都進行,所以不是大問題。
  4. 抽樣檢驗。沒必要檢驗所有data和所有參數的grad。僅僅抽樣幾個sample檢驗,每個sample檢驗幾個參數就可以了。但是這裏要注意的是coverage的問題,因爲weights的個數比bias要多很多,所以如果兩者合在一起抽樣的話,有很大概率bias會檢測不到。
  5. h太小也會有問題,1e-5即可
  6. 不要在訓練開始時進行梯度檢驗,待穩定後再進行。
  7. loss和reg分開檢驗。先令reg=0,檢查loss的grad;然後在令loss=0,檢查reg項的grad,或者增大reg,那麼總的loss和grad都會增大。
  8. 避免dropout的隨機性,使用相同的random seed來進行dropout。

Sanity Check

  1. softmax最初的loss應該爲 lnC\ln C,SVM爲 C1C-1。如果不是,那很大概率是初始化有問題。
  2. reg增大,loss也會增加
  3. 在正式訓練之前,選取一個小的樣本,將reg設爲0,然後overfit這個小樣本。

訓練過程中的debug

learning rate

Learning rate

黃色:loss飛了,lr太大

藍色:線性下降,lr太小

紅色:剛好

綠色:開始下降太陡,然後不再下降,lr太大

batch size

batch size

噪聲太多,說明batch size太小;曲線的趨勢說明lr還可以

overfitting

train/val的差距太大,表明overfitting,需要加樣本,加L2,加dropout等等。

train/val的差距太小,表明模型容量太小,表達能力不足,需要增加層數或者參數。

Ratio of weights:updates

updates與weights幅度的比例不要太小,1e-3左右比較合適,即:
lrdW2W21e3 \frac{\left \| lr \cdot \mathrm{d} W\right \|^2}{\left \| W\right \|^2} \approx 1e-3

每一層的激活/梯度分佈

畫出每一層的激活/梯度分佈的柱狀圖,應該符合預期的概率分佈。

第一層參數可視化

圖像不應該有太多噪聲點。

超參數的優化

優化超參數是訓練當中花費時間最長的一步。這裏只是提了幾點指導性的方法:

  1. 選擇一個合適大小的val set,在這個set上做validation,不要做many folds cross-validation。
  2. lr和reg的範圍一般用指數形式:
learning_rate = 10 ** np.uniform(-6, 1)
  1. 用random search,不要用grid search
  2. 如果最優值落到了邊界上,考慮擴大邊界
  3. 先選擇一個大的範圍,lr大概在1e-3到1e-5之間,每次test僅做幾個epoch,然後逐步縮小範圍,精調。

參數更新

Course note裏寫的比較簡單,重要的內容都在視頻中。
這裏羅列了幾種SGD參數更新的方法,具體在作業裏講,僅把pytorch函數記錄在此。

Vanilla SGD
while True:
  dx = computer_gradient(x)
  x += - learning_rate * dx

Vanilla SGD實現很簡單,但在實際應用中有很多問題:

  1. 如果函數在一個維度下降很快(陡),而在另外一個維度下降很慢(緩)。在陡的維度,函數變化很大,在緩的維度,函數變化很小,所以函數雖然會持續向最小值收斂,但收斂曲線會像在兩堵牆之間來回反彈一樣zig-zag前進,效率很低。因爲要學習的函數通常是幾千維的,所以這種情況幾乎是肯定發生的。
  2. 會卡在局部極小值點或者鞍點,這纔是最大的問題。1和2其實是同一個問題,想象一下1的極限情況就是在鞍點處,曲線在一個方向幾乎不動,而在其他方向會像打乒乓一樣來回反彈。
  3. 因爲是stochastic的,每次抽樣的mini-batch會引入noise,vanilla SGD對這種誤差敏感,造成收斂曲線抖動。
Momentum SGD
vx = 0
while True:
  dx = computer_gradient(x)
  vx = rho * vx - learning_rate * dx   # running mean of gradients, rho = 0.9 or 0.99
  x += vx

在Vanilla SGD的基礎上加入動量(momentum)的概念,這與股票研究中的momentum是一個道理。

  1. 由於momentum的存在,在鞍點處,即使某一方向dx等於0,vx仍然不爲0,參數依然會更新,收斂曲線有概率衝過鞍點。
  2. 同樣,由於momentum的存在,在緩的方向收斂速度會增大,減少zig-zag的頻率。
  3. 會減少noise對收斂的影響。

注意:理論上講,Vanilla SGD的問題在Momentum SGD中依然會存在,但是因爲momentum的引入,會大大緩解。實際上,即使是下面介紹的更先進的方法依然不會完全避免上述問題,但是會使問題出現的概率大大的降低。

Nesterov Momentum SGD
old_v = 0
v = 0
while True:
  dx = computer_gradient(x)
  old_v = v
  v = rho * v - learning_rate * dx
  x += - rho * old_v + (1 + rho) * v

Momentum SGD的另一個變種。特徵在於先對velocity進行更新,然後再做參數更新。

上面三個SGD極其變種僅僅引入了velocity的概念,下面幾種參數更新的方法把dx的滑動均值也納入更新函數中。

Adagrad
grad_squared = 0
while True:
  dx = computer_gradient(x)
  grad_squared += dx * dx
  x += - learning_rate * dx / (np.sqrt(grad_squared) + eps)

Adagrad的作用是,當dx大時,參數更新時會除以一個較大的數;而dx小時,相應的除以一個較小的數。從而平衡在各個方向上的收斂速度。但是learning rate會隨着學習的深入越來越小。

RMSprop
grad_squared = 0
while True:
  dx = computer_gradient(x)
  grad_squared = decay_rate * grad_squared + (1 - grad_squared) * dx * dx
  x += - learning_rate * dx / (np.sqrt(grad_squared) + eps)

RMSprop引入了一個decay來緩解Adagrad中learning rate隨學習深入而減小的問題。

Adam
first_moment = 0
second_moment = 0
for t in range(1, num_iterations):
  dx = computer_gradient(x)
  first_moment = beta1 * first_moment + (1 - beta1) * dx
  second_moment = beta2 * second_moment + (1 - beta2) * dx * dx
  first_unbias = first_moment / (1 - beta1 ** t)
  second_unbias = second_moment / (1 - beta2 ** t)
  x += - learning_rate * first_unbias / (np.sqrt(second_unbias) + eps)

Adam是將momentum和dx的滑動均值統統考慮進來。注意,這裏加入一個unbias項是因爲:如果沒有unbias項,那麼在訓練開始的時候,second_moment爲0,此時更新x需要除以一個很小的數,導致learning rate會很大。

Best practise:Adam ( beta1 = 0.9,beta2 = 0.999,learning_rate = 1e-3 )

Learning rate decay

隨着學習的深入,逐步減小learning rate,通常與SGD一起用,Adam事實上本身已經實現了learnig rate decay。實踐中,訓練開始並不設置learnig rate decay,訓練幾個epoch後,如果loss不再降低,就要考慮加入learning rate decay。

Second-order optimization

使用first-oder和second-oder梯度,但是需要算Hessian矩陣,太複雜很少用。

Model Ensembles

  1. 同一模型,不同初始化參數
  2. 最好的幾個模型
  3. 同一模型在不同時間點上的訓練參數
  4. 對不同時間點上的模型參數取平均值
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章