Adam AdamW
Adam核心计算流程
-
初始化参数
- 初始化一阶矩(动量)向量
mm0=0=0和二阶矩(梯度平方的指数平均)向量v0v0=0。0。 - 设定超参数:学习率
η(η(默认0.001)、动量衰减因子β1β1(默认0.9)、二阶矩衰减因子β2β2(默认0.999)、数值稳定常数ϵ(ϵ(默认1e-8)
- 初始化一阶矩(动量)向量
-
计算当前梯度
在时间步t,t,计算损失函数对参数θtθ_{t} 的梯度gtg_{t} -
更新一阶矩(动量项)
对梯度进行指数加权移动平均,模拟动量效果:mtm_{t}=β1β1⋅m_{t−1}+(1−β1)⋅mt−1g_{t}+(1−β1)⋅gt -
更新二阶矩(梯度平方的指数平均)
计算梯度平方的移动平均,用于自适应调整学习率:vtv_{t}=β2⋅v_{t−1}=β2+(1−β2)⋅g_{t}^{2}⋅vt−1+(1−β2)⋅gt2 -
偏差校正(Bias Correction)
因初始时刻mtmt 和vtvt 偏向0,需通过时间步 t 修正:mtm_{t}=mtm_{t}/(1−β1t1−β_{1}^{t})vtv^{t}=vtv^{t}/(1−β21−β_{2}t) -
参数更新
结合修正后的矩估计调整学习率,更新参数
class AdamOptimizer:
def __init__(self, learning_rate=0.01, beta1=0.9, beta2=0.999, epsilon=1e-8):
self.lr = learning_rate
self.beta1 = beta1
self.beta2 = beta2
self.epsilon = epsilon
self.m = 0
self.v = 0
self.t = 0
def update(self, params, grads):
self.t += 1
for param, grad in zip(params, grads):
self.m[param] = self.beta1 * self.m[param] + (1 - self.beta1) * grad
self.v[param] = self.beta2 * self.v[param] + (1 - self.beta2) * grad**2
m_hat = self.m[param] / (1 - self.beta1**self.t)
v_hat = self.v[param] / (1 - self.beta2**self.t)
param = param - self.lr * m_hat / (np.sqrt(v_hat) + self.epsilon)
return params
weight decay
权重衰减,本质上希望对权重进行惩罚,权重绝对值越大越不好
w = w - lr * w.grad - lr * weight_decay * w
L2正则化,表示对权重的衰减比例和权重绝对值的平方成正比
final_loss = loss + wd * all_weights.pow(2).sum() / 2
Adam在实现L2正则化的时候是直接修改梯度,随后梯度会参与动量的计算,导致L2正则化的梯度就会被抵消掉,导致效果不佳
grad_w = grad_w + weight_decay * w
AdamW
AdamW 的实现方法与传统的 L2 正则化不同,它直接对权重进行衰减,而不是将其加到损失函数上(改变grad_w)
grad_w = grad_w
# update step
w = w - learning_rate * grad_w - learning_rate * weight_decay * w