参数的更新
SGD随机梯度下降法
为了找到最优参数,我们将参数的梯度(导数)作为了线索。使用参数的梯度,沿梯度方向更新参数,并重复这个步骤多次,从而逐渐靠近最优参数,这个过程称为随机梯度下降法,简称SGD。
class SGD:
def __init__(self, lr):
self.lr = lr
def update(self, params, grads):
for key in params.keys():
params[key] -= self.lr * grads[key]
- SGD的缺点是:如果函数的形状非均向,比如呈延伸状,搜索的路径就会非常低效
- SGD低效的根本原因是,它单纯朝梯度方向前进,然后梯度的方向并没有指向最小值的方向
- 因此为了SGD的缺点,我们将介绍Momentum、AdaGrad、Adam这三种方法来取代SGD
Momentum方法
- Momentum是“动量”的意思,用数学式表示为:
- v ← αv - 学习率*梯度
- W ← W + v
class Momentum:
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]
AdaGrad方法
- AdaGrad会为参数的每个元素适当地调整学习率,用数学式表示为:
- h ← h + 梯度*梯度
- W ← W - 学习率 * 梯度 / (根号h)
- 利用是的“学习率衰减”,即随着学习的进行,使参数的元素中变动较大的元素的学习率变小
class 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)
PS:这里在最后一行加上1e-7,是为了防止分母为0的情况
正则化
在机器学习的问题中,过拟合是一个很常见的问题
Dropout方法
- 是一种抑制过拟合的方法
- Dropout在学习的过程中随机删除神经元,被删除的神经元不再进行信号的传递
– 每次正向传播时,self.mask都会以False的形式保存要删除的神经元
– self.mask会随机生成与x相同形状的数组,并将值比dropout_ratio大的元素设为True
– 反向传播时的行为和ReLU相同,即正向传播时传递了的神经元,在反向传播时按原样传回信号;而正向传播时没有被传递的神经元,在反向传播时将停在那里
class Dropout:
def __init__(self, dropout_ratio=0.5):
self.dropout_ratio = dropout_ratio
self.mask = None
def forward(self, x, train_flg=True):
if train_flg:
self.mask = np.random.rand(*x.shape) > self.dropout_ratio
return x * self.mask
else:
return x * (1.0 - self.dropout_ratio)
def backward(self, dout):
return dout * self.mask