優化器 -自適應梯度策略
上面不管是衰減因子,或是引入動量,都必需花費冗長的時間手動調整學習率或及它參數(decay, mu )。而且如果遇上有鞍點的函數,就會卡在局部最小值中。這是因為局部最小值的斜率也是 0 。
是否有比較方便可自動調整學習率,且可避開卡在鞍點的方法呢? 為了解決上述的問題,目前已開發出許多演算法,對學習率進行優化,這也是深度學習大幅進步的原因。通常這些演算法都蠻複雜的,所以就把這些演算法包進優化器中。所以我們常說的優化器,就是為了解決學習率的問題。常用的優化器有 AdaGrad,RMSprop,Adam。
自適應梯度通常有很複雜的演算及公式,一般人要用 Python 寫出其實有難度,所以都交給 tensorflow 包含在優化器中,直接調用即可,所以底上也僅大略說明其公式及特性。
Adagrad
Ada 是 Adaptive[əˋdæptɪv](自適應, 調節的) 的縮寫。
SGD 或動量在更新 x 值時,都是使用相同的學習率 (r)。而 Ada 則是每次的迭代,都會改變學習率,稱為學習率衰減(請注意喔,不是上面的衰減因子)。
Adagrad的公式如下 :
先計算 $(G_{t^{2}} = \sum_{t=1}^{n}(\bigtriangledown f(x)_{t})^{2})$ (每次迭代的斜率平方)總合
下一步的 x 標識為$(x_{t+1})$,其公式為 $(x_{t+1}=x_{t}(1-\frac{-r}{\sqrt{G_{t^{2}}}+\varepsilon})=x_{t}(1-\frac{-r}{\sqrt{\sum_{t=1}^{n}(\bigtriangledown f(x)_{t})^{2}}+\varepsilon}) )$
分母中的 $(\varepsilon)$ 是為了避免分母等於 0,稱為平滑項,一般設定為 1e-7。
Adagrad類別如下
import numpy as np
from MBGD import MBGD
class Adagrad(MBGD):
def __init__(self, a, b, x, y, lr, batch_size):
super().__init__(a, b, x, y, lr, batch_size)
self.sum_grad_a = 0
self.sum_grad_b = 0
# epsilon
self.e = 1e-6
def update(self):
self.a_old = self.a
self.b_old = self.b
grad_a, grad_b = self.gradient()
# 累加梯度平方和
self.sum_grad_a += grad_a ** 2
self.sum_grad_b += grad_b ** 2
# 梯度更新
self.a = self.a_old - (self.lr / (np.sqrt(self.sum_grad_a) + self.e)) * grad_a
self.b = self.b_old - (self.lr / (np.sqrt(self.sum_grad_b) + self.e)) * grad_b
self.loss = self.mse()
主程式如下
import threading import time from Adagrad import Adagrad from Regression import * import pylab as plt def runnable(): for i in range(epoch): gd.update() a=gd.a b=gd.b loss=gd.loss ax[0].clear() ax[0].set_xlim(-5,5) ax[0].set_ylim(-30, 30) ax[0].scatter(x, y) ax[0].plot([x[0], x[-1]],[a*x[0]+b, a*x[-1]+b], c="orange") ax[0].set_title(f'{a:.6f}x+{b:.6f}') print('iter=' + str(i) + ', loss=' + '{:.2f}'.format(gd.loss)) ax[1].set_xlim(-10,15) ax[1].set_ylim(-10, 15) ax[1].set_title(f'iter:{i+1:03d} Loss: {loss:6f}') ax[1].plot([gd.a_old, a], [gd.b_old, b], c='r') ax[1].scatter(a, b, c='g') ax[1].set_xlabel("a") ax[1].set_ylabel("b") plt.draw() time.sleep(0.5) epoch=200 x,y=getData(100) mesh, loss=getLoss(x,y) fig, ax=plt.subplots(nrows=1, ncols=2, figsize=(12,4)) a2=ax[1].contourf(mesh[0], mesh[1], loss,15, cmap=plt.cm.Purples) plt.colorbar(a2,ax=ax[1]) lr = 3 a = -9; b = -9 ax[1].scatter(a, b, c='g') batch_size=25 gd = Adagrad(a, b, x, y, lr, batch_size) t=threading.Thread(target=runnable) t.start() plt.show()
RMSProp
RMSProp 是 Root Mean Square Propagation[͵prɑpəˋgeʃən] 均方根傳播法的縮寫。Adagrad 會愈來愈慢,而RMSProp 就是 Adagrad 的改良,依梯度大小對學習率進行加強或衰減。
因為 Adagrad 的分母中,各個梯度平方總合可能過大,所以就變用平均數。公式如下 $(x_{t+1}=x_{t}(1-\frac{-r}{\sqrt{\frac{G_{t^{2}}}{n}}+\varepsilon})=x_{t}(1-\frac{-r}{\sqrt{\frac{\sum_{t=1}^{n}(\bigtriangledown f(x)_{t})^{2}}{n}}+\varepsilon}))$
說穿了就是把每次梯度的平方總合再除以 n ,計算其平均值,這樣可以緩解 Adagrad 學習率下降過快的問題。
RMSP類別繼承Adagrad類別,程式碼如下
from Adagrad import Adagrad
import numpy as np
class RMSP(Adagrad):
def __init__(self, a, b, x, y, lr, batch_size, rho):
super().__init__(a, b, x, y, lr, batch_size)
self.rho = rho
def update(self):
self.a_old = self.a
self.b_old = self.b
grad_a, grad_b = self.gradient()
self.sum_grad_a = self.rho * self.sum_grad_a + (1 - self.rho) * grad_a ** 2
self.sum_grad_b = self.rho * self.sum_grad_b + (1 - self.rho) * grad_b ** 2
self.a = self.a_old - (self.lr / (np.sqrt(self.sum_grad_a) + self.e)) * grad_a
self.b = self.b_old - (self.lr / (np.sqrt(self.sum_grad_b) + self.e)) * grad_b
self.loss = self.mse()
主程式同Adagrad,只是 lr 不同,並加了 rho參數
#以上同Adagrad lr = 0.5 a = -9; b = -9 ax[1].scatter(a, b, c='g') batch_size=25 rho=0.9 gd = RMSP(a, b, x, y, lr, batch_size, rho) t=threading.Thread(target=runnable) t.start() plt.show()
Adam
Adam 為 Adaptive Moment Estimation 的縮寫,是動量 + RMSProp
$(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})$
$(\tilde{m}_{t} = \frac{m_{t}}{1-\beta_{1}^{t}})$
$(\tilde{v}_{t} = \frac{v_{t}}{1-\beta_{2}^{t}})$
$(x_{t+1} = x_{t}- \frac{r}{\sqrt{\tilde{v}_{t}}+\varepsilon}\tilde{m}_{t})$
$(f”(x)_{t})$是第 t 次的二階導數。發表此演算法的作者建議每個參數的預設值如下
Adam 類別繼承 MBGD
from MBGD import MBGD
import numpy as np
class Adam(MBGD):
def __init__(self, a, b, x, y, lr, batch_size, beta1, beta2):
super().__init__(a, b, x, y, lr, batch_size)
self.beta1 = beta1
self.beta2 = beta2
self.e = 1e-6
# 動量累加項
self.sum_ma = 0
self.sum_mb = 0
# 梯度平方和累加項
self.sum_grad_a = 0
self.sum_grad_b = 0
def update(self):
self.a_old = self.a
self.b_old = self.b
# 計算梯度
grad_a, grad_b = self.gradient()
# 累加動量
self.sum_ma = self.beta1 * self.sum_ma + (1 - self.beta1) * grad_a
self.sum_mb = self.beta1 * self.sum_mb + (1 - self.beta1) * grad_b
# 累加梯度平方和
self.sum_grad_a = self.beta2 * self.sum_grad_a + (1 - self.beta2) * grad_a ** 2
self.sum_grad_b = self.beta2 * self.sum_grad_b + (1 - self.beta2) * grad_b ** 2
# 梯度更新
self.a -= (self.lr * self.sum_ma) / (np.sqrt(self.sum_grad_a) + self.e)
self.b -= (self.lr * self.sum_mb) / (np.sqrt(self.sum_grad_b) + self.e)
self.loss = self.mse()
主程式如下
#前面同Adagrad
lr = 0.5
a = -9; b = -9
ax[1].scatter(a, b, c='g')
batch_size=25
beta1=0.5
beta2=0.9
gd = Adam(a, b, x, y, lr, batch_size, beta1, beta2)
t=threading.Thread(target=runnable)
t.start()
plt.show()
參考資料
優化器 (optimizer) 是編譯 Keras 模型的所需的兩個參數之一:
from keras import optimizers
model = Sequential()
model.add(Dense(64, kernel_initializer='uniform', input_shape=(10,)))
model.add(Activation('softmax'))
sgd = optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='mean_squared_error', optimizer=sgd)
先產生實體一個優化器物件,然後將它傳入 model.compile(),像上述示例中一樣, 可以通過名稱來調用優化器。在後一種情況下,將使用優化器的默認參數。
# 傳入優化器名稱: 默認參數將被採用
model.compile(loss='mean_squared_error', optimizer='sgd')
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()。
本站參考如下並進行修改:
https://dotblogs.com.tw/shaynling/2019/10/22/141120