Adam優化器
計算t時間步的梯度:
首先,計算梯度的指數移動平均數, 初始化爲0。
係數爲指數衰減率,控制權重分配(動量與當前梯度),通常取接近於1的值。默認爲0.9
其次,計算梯度平方的指數移動平均數,初始化爲0。
係數爲指數衰減率,控制之前的梯度平方的影響情況。默認爲0.999
第三,由於初始化爲0,會導致偏向於0,尤其在訓練初期階段。
所以,此處需要對梯度均值進行偏差糾正,降低偏差對訓練初期的影響。
第四,與 類似,因爲初始化爲0導致訓練初始階段偏向0,對其進行糾正。
第五,更新參數,初始的學習率乘以梯度均值與梯度方差的平方根之比。
其中默認學習率α=0.001
,避免除數變爲0。
由表達式可以看出,對更新的步長計算,能夠從梯度均值及梯度平方兩個角度進行自適應地調節,而不是直接由當前梯度決定。
python 實現
import sys
import autograd.numpy as np
from autograd import grad
EPOCHS = 1000
class Adam:
def __init__(self, loss, weights, lr=0.001, beta1=0.9, beta2=0.999, epislon=1e-8):
self.loss = loss
self.theta = weights
self.lr = lr
self.beta1 = beta1
self.beta2 = beta2
self.epislon = epislon
self.get_gradient = grad(loss)
self.m = 0
self.v = 0
self.t = 0
def minimize_raw(self):
self.t += 1
g = self.get_gradient(self.theta)
self.m = self.beta1 * self.m + (1 - self.beta1) * g
self.v = self.beta2 * self.v + (1 - self.beta2) * (g * g)
self.m_cat = self.m / (1 - self.beta1 ** self.t)
self.v_cat = self.v / (1 - self.beta2 ** self.t)
self.theta -= self.lr * self.m_cat / (self.v_cat ** 0.5 + self.epislon)
def minimize(self):
self.t += 1
g = self.get_gradient(self.theta)
lr = self.lr * (1 - self.beta2 ** self.t) ** 0.5 / (1 - self.beta1 ** self.t)
self.m = self.beta1 * self.m + (1 - self.beta1) * g
self.v = self.beta2 * self.v + (1 - self.beta2) * (g * g)
self.theta -= lr * self.m / (self.v ** 0.5 + self.epislon)
def minimize_show(self, epochs=5000):
for _ in range(epochs):
self.t += 1
g = self.get_gradient(self.theta)
lr = self.lr * (1 - self.beta2 ** self.t) ** 0.5 / (1 - self.beta1 ** self.t)
self.m = self.beta1 * self.m + (1 - self.beta1) * g
self.v = self.beta2 * self.v + (1 - self.beta2) * (g * g)
self.theta -= lr * self.m / (self.v ** 0.5 + self.epislon)
print("step{: 4d} g:{} lr:{} m:{} v:{} theta:{}".format(self.t, g, lr, self.m, self.v, self.theta))
final_loss = self.loss(self.theta)
# print("final loss:{} weights:{}".format(final_loss, self.theta))