x_ahead = x + mu * v
# evaluate d(x_ahead) (the gradient at x_ahead instead of at x)
v = mu * v - learning_rate * dx_ahead
x += v然而这里需要计算 d(x_ahead)。在实践中,人们更愿意将更新表达与动量法相同的形式,因此则变为如下代码(注意 x_ahead 重新命名为 x ,详细推导见链接):
v_prev = v # back this up
v = mu * v - learning_rate * dx # velocity update stays the same
x += -mu * v_prev + (1 + mu) * v # position update changes form 其中,第二行更新速度 的格式与动量法保持一致,而第三行 更新的代码格式相当提前抵达“lookahead”位置进行计算,因而更快收敛。
<hr/>在上面的算法中,我们平均地全局地使用了固定学习率来处理所有参数。调整学习率是一个昂贵的步骤,有很多算法可以自适应地调整学习率,即接收高梯度的权重将降低其有效学习率,而接收小或不频繁更新的权重将提高其有效学习率。这类算法称为自适应学习率算法(adaptive learning rate method)。
Adam算法的本质是RMSProp + Momentum,简化的代码如下所示:
# Adam
m = beta1 * m + (1-beta1) * dx
v = beta2 * v + (1-beta2) * (dx**2)
x += - learning_rate * m / (np.sqrt(v) + eps)其中,Adam算法与 RMSProp 更新类似,除了使用“平滑”版本的梯度 m 而不是原始的梯度向量 dx 。论文中的推荐值为eps = 1e-8,beta1 = 0.9,beta2 = 0.999。
完整的 Adam 更新还包括一个偏置(bias)矫正机制,因为 m, v 两个矩阵初始为0,在没有完全热身之前存在偏差,需要采取一些补偿措施。使用偏差校正机制的代码如下所示:
# t is your iteration counter going from 1 to infinity
m = beta1 * m + (1-beta1) * dx
mt = m / (1-beta1**t)
v = beta2 * v + (1-beta2) * (dx**2)
vt = v / (1-beta2**t)
x += - learning_rate * mt / (np.sqrt(vt) + eps)在实践中,目前建议使用 Adam 作为默认算法,并且通常比 RMSProp 稍微好一点。但是,通常也值得尝试使用 SGD+Nesterov Momentum 作为替代方案。
最后推荐一下CS231n课程:深度网络参数的优化目前是一个非常活跃的研究领域。实践中使用反向传播算法计算出梯度用于执行参数的更新。而这个参数最优问题的本质就是一个凸优化问题。这些都可以在CS231n课件中找到相关的内容。
除此以外,CS231n课件中还有一些进行深度学习前或深度学习时的一些注意事项(Gradient Checks、Sanity Checks、Babysitting the learning process: Tips/Tricks),值得反复学习! 参考链接:https://cs231n.github.io/neural-networks-3/#anneal