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))