θ=θ−η⋅∇θJ(θ) .
例如在线性回归中,损失函数是:
J(θ)=12∑mi=1(hθ(x(i))−y(i))2
使用梯度下降的方法使得 J(θ) 最小化
对于BGD来说
θj=θj−α.∑mi=1∂J(θ)∂θj
其中:
∂J(θ)∂θj=(hθ(x(i))−y(i))x(i)j
缺点:需要整个数据集执行一次梯度更新,更新速度非常慢。 不能在线更新模型。
批量梯度下降保证收敛到凸函数的全局最小值和非凸函数的局部最小值。
代码如下:
for i in range(nb_epochs):
params_grad = evaluate_gradient(loss_function, data, params)
params = params - learning_rate * params_grad
θ=θ−η⋅∇θJ(θ;x(i);y(i))
每一个样本执行一次梯度更新。
优点:更新速度快,可以在线学习。
缺点:SGD执行具有高方差的频繁更新,这导致目标函数大幅波动。如图:
SGD的这个特点也有可能使得函数找到更好的极值点,跳出局部最小值,找到全局最小值。当逐渐减小学习率时,SGD就和BGD一样了,会收敛到凸函数的全局最小值和非凸函数的局部最小值。
代码如下:
for i in range(nb_epochs):
np.random.shuffle(data)
for example in data:
params_grad = evaluate_gradient(loss_function, example, params)
params = params - learning_rate * params_grad
θ=θ−η⋅∇θJ(θ;x(i:i+n);y(i:i+n))
它是上两种方法的这种,选取一部分样本计算梯度,进行参数更新。
优点:1.降低了参数更新的方差,得到更稳定的收敛
2.可以利用最先进的深度学习库通用的高度矩阵优化,使的mini-batch计算非常高效。普通的mini-batch大小范围介于50到256之间。mini-batch梯度下降通常是训练神经网络时选择的算法,并且当使用mini-batch时通常也使用术语SGD。
ps:稳定是收敛与不稳定的收敛,例如一组数收敛到1,第一组数[10,9,8,7,6,5,4,3,2,1]与第二组数[10,11,9,4,1,1,1,2,2,1],第一组数是稳定的收敛,第二组数是不稳定的收敛。
代码如下:
for i in range(nb_epochs):
np.random.shuffle(data)
for batch in get_batches(data, batch_size=50):
params_grad = evaluate_gradient(loss_function, batch, params)
params = params - learning_rate * params_grad
如何选择正确的学习率。学习率太小收敛太慢。学习率太大导致损失函数在极值点波动或发散。
调整训练期间的学习速率。例如根据预定义的时间减少学习率,或者当epoch之间的目标的变化降到阈值以下时,即early stopping。 然而,这些时间计划和阈值必须提前定义,因此不能适应数据集的特性。
对所有参数使用相同的学习率。 如果数据稀疏,并且每个特征具有不同的使用频率,我们不想将其全部更新到相同的程度,但是对使用频率较少的特征执行更大的更新。
(ps:数据稀疏,例如对于文本分类问题,通常使用bag-of-words作为特征,每个文档都用一个向量表示,向量的长度是词表的长度,并且有很多值是0,代表文档中没有这个词。那么这个数据就是稀疏数据。而对于图片来说,每个图片都有像素,且值不为0,这个数据就是稠密数据)
SGD很难从陡峭的区域上跳出来,陡峭的区域指的是一个维度上的表面比在另一个维度上的表面更加陡的区域,这在局部最优中是常见的。在这些情况下,SGD在峡谷的斜坡上振荡,在图2中仅沿着底部向本地最佳方向前进。
SGD without momentum
SGD with momentum
Momentum 是一种有助于在相关方向上加速SGD并抑制振荡的方法,如图所示。它通过将过去时间步长的更新向量的分数 γ 添加到当前更新向量来实现:
vt=γvt−1+η∇θJ(θ)
θ=θ−vt
γ 通常是0.9或者类似的值。
对于梯度指向相同方向的维度,动量项增加,并且减少梯度改变方向的维度的更新。 因此获得更快的收敛和减少振荡。
Adagrad是一种参数的自适应学习率算法,对常用的参数执行较小的更新,对不常用的参数执行较大更新。 因此,它非常适合处理稀疏数据。
以前,我们对所有参数 θ 同时执行更新,因为每个参数 θi 使用相同的学习速率 η 。 Adagrad在每个时间步长t对每个参数 θi 使用不同的学习速率,首先表示出Adagrad的每个参数更新,然后将其向量化。 gt,i 是参数 θi 在时间步长t时候的梯度:
gt,i=∇θJ(θi)
SGD更新 θi
θt+1,i=θt,i−η⋅gt,i
Adagrad 改变 θi 的学习率:
θt+1,i=θt,i−ηGt,ii+ϵ√⋅gt,i
Gt∈Rd×d 是一个对角矩阵,每一个对角元素是 θi 到时间t的梯度的和。 ϵ 是一个平滑参数,为了不让分母为0。不用平方根的话,算法表现不好。
Adagrad的主要优点之一是它不需要手动调整学习速率。 大多数实现使用默认值0.01。
Adagrad的主要弱点是它在分母中的平方梯度的积累:由于每个增加的项都是正数,累积的总和在训练期间保持增长。 这又导致学习速率收缩并且最终变得无穷小,在该点处算法不再能够获取额外的知识。 以下算法旨在解决这个缺陷。
Adadelta是Adagrad的延伸,旨在减少其单调降低的学习率。 Adadelta不是累积所有过去的平方梯度,而是将累积过去的梯度的窗口限制到一定的固定大小w。
不是无效地存储以前的平方梯度w,梯度的和被递归地定义为所有过去平方梯度的衰减平均值。在时间步长t处的运行平均值 E[g2]t 仅取决于前一个平均值和当前梯度(作为与动量项相似的分数γ):
E[g2]t=γE[g2]t−1+(1−γ)g2t.
我们将γ设置为与动量项相似的值,约为0.9。为了清楚起见,我们现在根据参数更新向量Δθt重写我们的原始的SGD更新:
Δθt=−η⋅gt,i .
θt+1=θt+Δθt .
因此,我们以前导出的Adagrad的参数更新向量采用以下形式:
Δθt=−ηGt+ϵ√⊙gt .
我们现在简单地将对角矩阵 Gt 替换为过去平方梯度的衰减平均值 E[g2]t :
Δθt=−ηE[g2]t+ϵ√gt .
由于分母只是梯度的均方根(RMS)误差准则,所以我们可以用简写:
Δθt=−ηRMS[g]tgt .
作者注意到,此更新中的单位(以及SGD,Momentum或Adagrad)不匹配,即更新应具有与参数相同的假设单位。为了实现这一点,他们首先定义了另一个指数衰减的平均值,这时候不是平方的梯度,而是平方的参数更新:
E[Δθ2]t=γE[Δθ2]t−1+(1−γ)Δθ2t .
因此参数更新的均方根误差为:
RMS[Δθ]t=E[Δθ2]t+ϵ−−−−−−−−−√ .
由于 RMS[Δθ]t 未知,我们用参数更新的RMS近似到上一个时间步长。 用RMS[Δθ]t−1 替换先前更新规则中的学习速率η最终得到Adadelta更新规则:
Δθt=−RMS[Δθ]t−1RMS[g]tgt .
θt+1=θt+Δθt .
使用Adadelta,我们甚至不需要设置默认学习率,因为它已从更新规则中消除.
Adaptive Moment Estimation –Adam是另一种计算每个参数的自适应学习速率的方法。 除了存储如Adadelta和RMSprop的过去的平方梯度 vt 的指数衰减平均值之外,Adam还保持过去梯度 mt 的指数衰减平均值,类似于momentum:
mt=β1mt−1+(1−β1)gt .
vt=β2vt−1+(1−β2)g2t .
mt 和 vt 分别是梯度的第一时刻(平均值)和第二时刻(非中心方差)的估计。 由于 mt 和 vt 初始化为0的向量,Adam的作者观察到它们偏向零,特别是在初始时间步长期间,以及当衰减率小(即 β1和β2 接近1)时。
它们通过计算偏差校正的第一和第二力矩估计来抵消这些偏差:
m^=mt1−βt1 .
v^=vt1−βt2 .
然后他们使用这些更新参数,正如我们在Adadelta和RMSprop中看到的,它产生了Adam更新规则:
θt+1=θt−ηv^√+ϵm^t .
作者提出 β1 的默认值为0.9, β2 的默认值为0.999,ε的默认值为 10−8 时在实践中运作良好。
原文地址:
http://sebastianruder.com/optimizing-gradient-descent/index.html#batchgradientdescent