優化器 – Optimizer
損失函數(Loss Function)在進行梯度下降(Gradient Descent)時,需要反覆計算梯度(微分)並更新參數。當模型規模變大、資料量增加時,計算成本會顯著提高,且收斂速度可能變慢。為了降低計算量、提升訓練效率並加快收斂速度,學術界提出了大量改良方法,例如 Momentum、AdaGrad、RMSprop、Adam 等。這些用來改善參數更新過程的方法,統稱為優化器(Optimizer)。
meshgrid
mesh[mɛʃ] 篩孔, 網線
numpy 的 meshgrid 是一個很好用的功能,可以產生每列 x 軸的座標及每行 y 軸的座標。
🔒 更多內容,請登入會員繼續閱讀。
立即登入上述不論是 x 軸或 y 軸,都是[1,n] 的二維陣列。
標示座標
如果要標示每行每列的座標,代碼如下
import numpy as np
a = range(5)
b = range(5)
x,y = np.meshgrid(a, b)
for row in zip(x, y):
for col in zip(row[0], row[1]):
print(col, end='')
print()
結果:
(0, 0)(1, 0)(2, 0)(3, 0)(4, 0)
(0, 1)(1, 1)(2, 1)(3, 1)(4, 1)
(0, 2)(1, 2)(2, 2)(3, 2)(4, 2)
(0, 3)(1, 3)(2, 3)(3, 3)(4, 3)
(0, 4)(1, 4)(2, 4)(3, 4)(4, 4)
傳統思維產生格點
如果要在二維平面上產生格點如下圖

傳統思維的代碼如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入plt.scatter
plt.scatter(x, y) 其中的 x 是 x 軸的集合,y 是 y 軸的集合,代碼如下
import pylab as plt
x=[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
y=[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4]
plt.scatter(x,y,c='b')
plt.show()
上面藍色的 x, y 值,光 5*5 就打到快骨折,那麼如果是 20*20 的話,不就沒完沒了
meshgrid 產生 x , y 集合
把 meshgrid 產生的 x, y,由 [1,n] 的二維陣列轉成一維陣列 (x.reshape(-1)),再放入 plt.scatter(x, y) 就完成了。
🔒 更多內容,請登入會員繼續閱讀。
立即登入plt 自動將二維轉成一維
上述的 x=x.reshape(-1) 其實是多餘的,因為 plt 會自動將多維扁平化成一維,所以只需如下代碼即可。
import numpy as np
import pylab as plt
a = range(5)
b = range(5)
x,y = np.meshgrid(a, b)
plt.scatter(x,y, s=0.5)
plt.show()
總結
meshgrid 的主要目的並不是要產生 (x, y) 的配對,而是要產生 x 軸的 list 及 y 軸的 list,方便傳給 plt.plot()
常態梯度下降
底下四種梯度下降 BGD、SGD、MBGD、SGDM 屬於比較簡單的運算,所以稱為常態梯度下降。
共用函數
底下的函數,在每種梯度下降都會用到,所以獨立成一個 Init.py 檔,供每種說明引用,完整代碼如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入BGD 損失率圖解
BGD 是Batch Gradient Descent (批次梯度下降) 的縮寫。
BDG的損失函數梯度下降後,
$(\frac{\sigma Loss(a,b)}{\sigma a}=\frac{2}{n}\sum_{i=1}^{n}(ax_{i}+b-\tilde{y_{i}})*x_{i})$
$(\frac{\sigma Loss(a,b)}{\sigma b}=\frac{2}{n}\sum_{i=1}^{n}(ax_{i}+b-\tilde{y_{i}}))$
底下是BDG 類別 BDG.py 的代碼
🔒 更多內容,請登入會員繼續閱讀。
立即登入執行 BGD 的主程式的代碼如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入
SGD 隨機梯度下降
SGD 為 Stochastic [stəˈkæstɪk] Gradient Descent 的縮寫。
BDG 損失函數梯度下降後,公式為$(\frac{\sigma Loss(a,b)}{\sigma a}=\frac{2}{n}\sum_{i=1}^{n}(ax_{i}+b-\tilde{y_{i}})*x_{i})$,必需將所有的 $(x_{i})$ 及 $(y_{i})$全都計算一遍。如果 i 只有幾百或幾千個,那電腦還可應付,但如果有上百萬,上億個點呢,這下就吃不消了。
SGD 就是把 $(\sum)$ 拿掉,然後使用亂數隨便取一個 x 及 y 來計算,這樣原本要加總計算上億個值,變成只要計算一次,就快很多了。當然啦,天下沒有白吃的午餐,如下圖所示,會呈現極不穩定的狀態。
SGD類別如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入主程式如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入
MBGD 小批量梯度下降
MBGD為 mini-batch gradient descent的縮寫。
因為SGD隨便選一個點來計算實在是不準確,所以就隨便選個100個點,或1000個點來計算。由底下的圖式可看出,確實平穩了許多,速度也快很多。MBGD 計算損失時,會產生 np.nan,所以如果遇到 np.nan 時,就中斷。
SGD 實在是上不了台面的,所以一般人家講的 SGD,其實是指 MBGD。
MBGD類別如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入主程式如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入
SGD + 動量
上述的 MBGD 很容易卡在鞍點,所以可以再加入動量。本例應該是 MBGDM,但大家都稱 MBGD 為 SGD,所以本例命名為 SGDM
SGDM類別如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入主程式如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入
自適應梯度下降
底下三種梯度下降分別為 Ada、RMSP、Adam 會依不同狀況改變下降的值,稱為自適應梯度下降。自適應梯度下降是常態梯度下降的變型,改良常態梯度下降的一些缺點或加快其收斂速度。
自適應梯度下降有著非常猙獰計算,簡直到了變態的行為,可以把它們稱為變態梯度下降。
keras 官網 https://keras.io/zh/optimizers/ 介紹的的優化器有 RMSProp,AdaGrad,Adadelta,Adam,Adamax,Nadam。
Ada
Ada 是 Adaptive[əˋdæptɪv](自適應, 調節的) 的縮寫。
SGD 或動量在更新 x 值時,都是使用相同的學習率 (r)。而 Ada 則是每次的迭代,都會改變學習率,稱為學習率衰減(請注意喔,不是上面的衰減因子)。
Adagrad的公式如下 :
先計算 $(G_{t} = \sum_{t=1}^{n}f'(x_{t})^{2})$,也就是先計算每次導數平方總合
下一步的 x 標識為$(x_{t+1})$,其公式為 $(x_{t+1}=x_{t}-\frac{lr}{\sqrt{G_{t}}+\varepsilon}*f'(x_{t+1})=x_{t}-\frac{lr}{\sqrt{\sum_{t=1}^{n}f'(x_{t})^{2}}+\varepsilon}*f'(x_{t+1}))$
分母中的 $(\varepsilon)$ (epsilon) 是為了避免分母等於 0,稱為平滑項,一般設定為 1e-7。
Adagrad類別如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入主程式如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入
RMSP
RMSP 是 Root Mean Square Propagation[͵prɑpəˋgeʃən] 均方根傳播法的縮寫。
RMSP 就是 Ada 的改良,依梯度大小對學習率進行加強或衰減,比 Ada 更快進入收斂。
RMSP 的公式如下 :
$(G_{t+1}=\rho G_{t}+(1-\rho)f'(x_{t+1})^2)$,其中的 $(\rho)$ 一般設定為 0.9
RMSP類別繼承Ada類別,程式碼如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入主程式同Adagrad,只是 lr 不同,並加了 rho參數
🔒 更多內容,請登入會員繼續閱讀。
立即登入
Adam
Adam 是 RMSP 加上動量的改良版,而 RMPS 又源自於 Ada 的改良版。也就是說 Ada => RMSP => Adam,所以名稱以 Ada + M = Adam。
那為什麼不用 RMSPM 這個名稱呢? 因為 Adam 有 $(\beta_{1})$ 及 $(\beta_{2})$ 二個參數,也就是多了 $(\beta_{2})$ 這個參數,這跟 RMSP 完全不同,所以只能說 Adam 是 Ada 及 RMSP 二者的進化版。
$(m_{t} = \beta_{1} m_{t-1}+(1-\beta_{1})f'(x_{t}))$
$(v_{t} = \beta_{2} v_{t-1}+(1-\beta_{2})f'(x_{t})^2)$
$(\beta_{1})$ 及 $(\beta_{2})$ 是二個接近 1 的值,一般 $(\beta_{1})$ 設定為 0.9, $(\beta_{2})$ 設定為 0.999。
然後要進行修正
$(\tilde{m}_{t} = \frac{m_{t}}{1-\beta_{1}^{t}})$,裏面的$(\beta_{1}^{t})$ 是 $(\beta_{1})$ 的 t 次方
$(\tilde{v}_{t} = \frac{v_{t}}{1-\beta_{2}^{t}})$,裏面的$(\beta_{2}^{t})$ 是 $(\beta_{2})$ 的 t 次方
$(x_{t+1} = x_{t}- \frac{lr}{\sqrt{\tilde{v}_{t}}+\varepsilon}\tilde{m}_{t})$
底下的代碼,Adam 類別繼承 MBGD
🔒 更多內容,請登入會員繼續閱讀。
立即登入主程式如下
🔒 更多內容,請登入會員繼續閱讀。
立即登入優化器公共參數
Keras 優化器的公共參數
參數 clipnorm 和 clipvalue 能在所有的優化器中使用,用於控制梯度裁剪(Gradient Clipping):
from keras import optimizers
# 所有參數梯度將被裁剪,讓其l2範數最大為1:g * 1 / max(1, l2_norm)
sgd = optimizers.SGD(lr=0.01, clipnorm=1.)
from keras import optimizers
# 所有參數d 梯度將被裁剪到數值範圍內:
# 最大值0.5
# 最小值-0.5
sgd = optimizers.SGD(lr=0.01, clipvalue=0.5)
SGD
keras.optimizers.SGD(lr=0.01, momentum=0.0, decay=0.0, nesterov=False)
隨機梯度下降優化器。
包含擴展功能的支援: – 動量(momentum)優化, – 學習率衰減(每次參數更新後) – Nestrov 動量 (NAG) 優化
參數
- lr: float >= 0. 學習率。
- momentum: float >= 0. 參數,用於加速 SGD 在相關方向上前進,並抑制震盪。
- decay: float >= 0. 每次參數更新後學習率衰減值。
- nesterov: boolean. 是否使用 Nesterov 動量。
RMSprop
keras.optimizers.RMSprop(lr=0.001, rho=0.9, epsilon=None, decay=0.0)
RMSProp 優化器.
建議使用優化器的默認參數 (除了學習率 lr,它可以被自由調節)
這個優化器通常是訓練迴圈神經網路RNN的不錯選擇。
參數
- lr: float >= 0. 學習率。
- rho: float >= 0. RMSProp梯度平方的移動均值的衰減率.
- epsilon: float >= 0. 模糊因數. 若為None, 默認為 epsilon()。
- decay: float >= 0. 每次參數更新後學習率衰減值。
Adagrad
keras.optimizers.Adagrad(lr=0.01, epsilon=None, decay=0.0)
Adagrad 優化器。
Adagrad 是一種具有特定參數學習率的優化器,它根據參數在訓練期間的更新頻率進行自我調整調整。參數接收的更新越多,更新越小。
建議使用優化器的默認參數。
參數
- lr: float >= 0. 學習率.
- epsilon: float >= 0. 若為None, 默認為 epsilon().
- decay: float >= 0. 每次參數更新後學習率衰減值.
Adadelta
keras.optimizers.Adadelta(lr=1.0, rho=0.95, epsilon=None, decay=0.0)
Adadelta 優化器。
Adadelta 是 Adagrad 的一個具有更強魯棒性的的擴展版本,它不是累積所有過去的梯度,而是根據漸變更新的移動視窗調整學習速率。 這樣,即使進行了許多更新,Adadelta 仍在繼續學習。 與 Adagrad 相比,在 Adadelta 的原始版本中,您無需設置初始學習率。 在此版本中,與大多數其他 Keras 優化器一樣,可以設置初始學習速率和衰減因數。
建議使用優化器的默認參數。
參數
- lr: float >= 0. 學習率,建議保留預設值。
- rho: float >= 0. Adadelta梯度平方移動均值的衰減率。
- epsilon: float >= 0. 模糊因數. 若為None, 默認為 epsilon()。
- decay: float >= 0. 每次參數更新後學習率衰減值。
Adam
keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)
Adam 優化器。
默認參數遵循原論文中提供的值。
參數
- lr: float >= 0. 學習率。
- beta_1: float, 0 < beta < 1. 通常接近於 1。
- beta_2: float, 0 < beta < 1. 通常接近於 1。
- epsilon: float >= 0. 模糊因數. 若為None, 默認為 epsilon()。
- decay: float >= 0. 每次參數更新後學習率衰減值。
- amsgrad: boolean. 是否應用此演算法的 AMSGrad 變種,來自論文 “On the Convergence of Adam and Beyond”。
Adamax
keras.optimizers.Adamax(lr=0.002, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0)
Adamax 優化器,來自 Adam 論文的第七小節.
它是Adam演算法基於無窮範數(infinity norm)的變種。 默認參數遵循論文中提供的值。
參數
- lr: float >= 0. 學習率。
- beta_1/beta_2: floats, 0 < beta < 1. 通常接近於 1。
- epsilon: float >= 0. 模糊因數. 若為None, 默認為 epsilon()。
- decay: float >= 0. 每次參數更新後學習率衰減值。
Nadam
keras.optimizers.Nadam(lr=0.002, beta_1=0.9, beta_2=0.999, epsilon=None, schedule_decay=0.004)
Nesterov 版本 Adam 優化器。
正像 Adam 本質上是 RMSProp 與動量 momentum 的結合, Nadam 是採用 Nesterov momentum 版本的 Adam 優化器。
默認參數遵循論文中提供的值。 建議使用優化器的默認參數。
參數
- lr: float >= 0. 學習率。
- beta_1/beta_2: floats, 0 < beta < 1. 通常接近於 1。
- epsilon: float >= 0. 模糊因數. 若為None, 默認為 epsilon()。
