fori inrange (nb_epochs ):params_grad =evaluate_gradient (loss_function ,data ,params )params =params -learning_rate *params_grad 对于给定的迭代次数,我们首先基于输入的罚函数 loss_function 对输入的参数向量 params 计算梯度向量 params_grad。注意,最新的深度学习程序库中,提供了自动求导的功能,能够高效、快速地求给定函数对于特定参数的导数。如果你希望自己写代码求出梯度值,那么「梯度检查」会是一个不错的注意。(你可以参考这里,了解关于如何检查梯度的相关建议。) 然后,我们对参数减去梯度值乘学习率的值,也就是在反梯度方向,更新我们参数。当目标函数 J(θ) 是一凸函数时,则批量梯度下降法必然会在全局最小值处收敛;否则,目标函数则可能会局部极小值处收敛。 随机梯度下降法(Stochastic Gradient Descent) 相比批量梯度下降法,随机梯度下降法的每次更新,是对数据集中的一个样本(x,y)求出罚函数,然后对其求相应的偏导数: 因为批量梯度下降法在每次更新前,会对相似的样本求算梯度值,因而它在较大的数据集上的计算会有些冗余(redundant)。而随机梯度下降法通过每次更新仅对一个样本求梯度,去除了这种冗余的情况。因而,它的运行速度被大大加快,同时也能够「在线」学习。 随机梯度下降法更新值的方差很大,在频繁的更新之下,它的目标函数有着如下图所示的剧烈波动。
—image—SGD 函数波动,来源:Wikipedia 相比批量梯度下降法的收敛会使目标函数落入一个局部极小值,SGD 收敛过程中的波动,会帮助目标函数跳入另一个可能的更小的极小值。另一方面,这最终会让收敛到特定最小值的过程复杂化,因为该方法可能持续的波动而不停止。但是,当我们慢慢降低学习率的时候,SGD 表现出了与批量梯度下降法相似的收敛过程,也就是说,对非凸函数和凸函数,必然会分别收敛到它们的极小值和最小值。 相比批量梯度下降法的代码,在如下的代码中,我们仅仅加入了一个循环,用以遍历所有的训练样本并求出相应的梯度值。注意,如这里所说,在每次迭代中,我们会打乱训练数据集。 fori inrange (nb_epochs ):np .random .shuffle (data )forexample indata :params_grad =evaluate_gradient (loss_function ,example ,params )params =params -learning_rate *params_grad 小批量梯度下降法(Mini-Batch Gradient Descent) 小批量梯度下降法集合了上述两种方法的优势,在每次更新中,对 n 个样本构成的一批数据,计算罚函数 J(θ),并对相应的参数求导: 这种方法,(a) 降低了更新参数的方差(variance),使得收敛过程更为稳定;(b) 能够利用最新的深度学习程序库中高度优化的矩阵运算器,能够高效地求出每小批数据的梯度。通常一小批数据含有的样本数量在 50 至 256 之间,但对于不同的用途也会有所变化。小批量梯度下降法,通常是我们训练神经网络的首选算法。同时,有时候我们也会使用随机梯度下降法,来称呼小批量梯度下降法(译者注:在下文中,我们就用 SGD 代替随机梯度下降法)。注意:在下文对于随机梯度法优化的介绍中,为方便起见,我们会省略式子中的参数 x(i:i+n),y(i:i+n)。 如下的代码所示,我们不再对每个样本进行循环,而是对每批带有 50 个样本的小批数据进行循环: fori inrange (nb_epochs ):np .random .shuffle (data )forbatch inget_batches (data ,batch_size =50):params_grad =evaluate_gradient (loss_function ,batch ,params )params =params -learning_rate *params_grad 面临的挑战 由于 Vanilla 小批量梯度下降法并不能保证良好地收敛,这给我们留下了如下待解决的挑战: (责任编辑:本港台直播) |