1.SGD(随机梯度下降法)
将参数的梯度(导数)作为线索,沿梯度方向更新参数,重复多次逐渐靠近最优参数。该方法比较低效,当处理的函数的形状非均向时搜索路径会非常低效。
(1)数学式
W: 要更新的权重参数
∂L/∂W: 损失函数关于W的梯度
η: 学习率
(2)实现代码
class SGD:
"""随机梯度下降法(Stochastic Gradient Descent)"""
def __init__(self, lr=0.01):
self.lr = lr
def update(self, params, grads):
for key in params.keys(): # 返回矩阵params的索引
params[key] -= self.lr * grads[key]
(3)图像
2.Momentum
下坡时候越来越快,上坡时候越来越慢,可以想象成一个小球在弧面上滚动。和SGD相比更快地朝x轴方向靠近,减弱“之”字形的变动程度。
(1)数学式
W: 要更新的权重参数
∂L/∂W: 损失函数关于W的梯度
η: 学习率
v: 相当于动量,第一个值为零。
α: 设定为0.9之类的值
(2)实现代码
class Momentum:
"""Momentum SGD"""
def __init__(self, lr=0.01, momentum=0.9):
self.lr = lr
self.momentum = momentum
self.v = None
def update(self, params, grads):
if self.v is None:
self.v = {}
for key, val in params.items(): # 返回矩阵的索引和值
self.v[key] = np.zeros_like(val) # 为空,以字典型变量形式保存与参数结构相同的数据
for key in params.keys():
self.v[key] = self.momentum*self.v[key] - self.lr*grads[key]
params[key] += self.v[key]
(3)图像
3.AdaGrad
学习率衰减方法是一开始“多”学,后来逐渐“少”学的方法。AdaGrad发展了这种想法,按参数的元素进行学习率衰减,使变动大的参数的学习率逐渐减少。AdaGrad会记录过去所有梯度的平方和,所以学习越深入更新的幅度就越小。
(1)数学式
W: 要更新的权重参数
∂L/∂W: 损失函数关于W的梯度
η: 学习率
h: 保存了以前的所有梯度值的平方和
(2)实现代码
class AdaGrad:
"""AdaGrad"""
def __init__(self, lr=0.01):
self.lr = lr
self.h = None
def update(self, params, grads):
if self.h is None:
self.h = {}
for key, val in params.items():
self.h[key] = np.zeros_like(val)
for key in params.keys():
self.h[key] += grads[key] * grads[key]
params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
(3)图像
4.Adam
Adam通俗地讲就是融合了Momentum和AdaGrad方法。该方法会设置3个超参数,一个是学习率,另外两个是一次momentum系数β1和二次momentum系数β2,根据论文β1为0.9,β2为0.999时大多数情况可以顺利进行。
(1)数学式
(2)实现代码:
class Adam:
"""Adam (http://arxiv.org/abs/1412.6980v8)"""
def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
self.lr = lr
self.beta1 = beta1
self.beta2 = beta2
self.iter = 0
self.m = None
self.v = None
def update(self, params, grads):
if self.m is None:
self.m, self.v = {}, {}
for key, val in params.items():
self.m[key] = np.zeros_like(val)
self.v[key] = np.zeros_like(val)
self.iter += 1
lr_t = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)
for key in params.keys():
#self.m[key] = self.beta1*self.m[key] + (1-self.beta1)*grads[key]
#self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2)
self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])
params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)
#unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias
#unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias
#params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7)
(3)图像
总结: 很多研究中至今在使用SGD,Momentum和AdaGrad也可以试试,最近比较流行使用Adam。与SGD相比,其他三种方法学习得更快,有时最终的识别精度也比较高。