深度学习之参数优化方法
优化问题:给定目标函数f(x),我们需要找到一组参数x,使得f(x)的值最小
1.Vanilla update
tensorflow实现
optimizer = tf.train.GradientDescentOptimizer(learning_rate=self.learning_rate)
直接进行优化
train_op
= optimizer.minimize(loss)
x += - learning_rate * dx
对于训练数据集,我们首先将其分成n个batch,每个batch包含m个样本。我们每次更新都利用一个batch的数据,而非整个训练集。即:
好处在于:
当训练数据太多时,利用整个数据集更新往往时间上不显示。batch的方法可以减少机器的压力,并且可以更快地收敛
当训练集有很多冗余时(类似的样本出现多次),batch方法收敛更快。以一个极端情况为例,若训练集前一半和后一半梯度相同。那么如果前一半作为一个batch,后一半作为另一个batch,那么在一次遍历训练集时,batch的方法向最优解前进两个step,而整体的方法只前进一个step
2.Momentum update动量更新
tensorflow实现
optimizer = tf.train.MomentumOptimizer(lr, 0.9)
直接进行优化
train_op
= optimizer.minimize(loss)
v = mu * v - learning_rate * dx # integrate velocity
x += v # integrate position
SGD方法的一个缺点是,其更新方向完全依赖于当前的batch,因而其更新十分不稳定。解决这一问题的一个简单的做法便是引入momentum。
momentum即动量,它模拟的是物体运动时的惯性,即更新的时候在一定程度上保留之前更新的方向,同时利用当前batch的梯度微调最终的更新方向。这样一来,可以在一定程度上增加稳定性,从而学习地更快,并且还有一定摆脱局部最优的能力:
其中一般的,v初始为0,mu是优化参数,一般初始化参数为0.9,当使用交叉验证的时候,参数mu一般设置成[0.5,0.9,0.95,0.99],在开始训练的时候,梯度下降较快,可以设置mu为0.5,在一段时间后逐渐变慢了,mu可以设置为0.9、0.99。也正是因为有了“惯性”,这个比SGD会稳定一些。
3.Nesterov Momentum
x_ahead = x + mu * v
v = mu * v - learning_rate * dx_ahead
x += v
这是Momentum update的改进版,之前我们采用v
= mu * v - learning_rate * dx
的方法计算增量,其中的dx还是当前的x,但是我们已经知道了,下一刻的惯性将会带我们去的位置,所以现在我们要用加了mu*v之后的x,来更新位置(在更新后的位置而不是在原点求解梯度),下面的图很形象:
4.Adagrad
tensorflow实现
optimizer = tf.train.AdagradientOptimizer(learning_rate=self.learning_rate)
直接进行优化
train_op
= optimizer.minimize(loss)
cache
+= dx**2
x += - learning_rate * dx / (np.sqrt(cache) + eps)
上面提到的方法对于所有参数都使用了同一个更新速率。但是同一个更新速率不一定适合所有参数。比如有的参数可能已经到了仅需要微调的阶段,但又有些参数由于对应样本少等原因,还需要较大幅度的调动。Adagrad就是针对这一问题提出的,自适应地为各个参数分配不同学习率的算法。
前期gt较小的时候,chche累加 regularizer较大,能够放大梯度
后期gt较大的时候,chche累加regularizer较小,能够约束梯度
适合处理稀疏梯度
5.RMSprop
tensorflow实现
optimizer = tf.train.RMSPropOptimizer(0.001, 0.9)
直接进行优化
train_op
= optimizer.minimize(loss)
cache=
decay_rate*cache+
(1-
decay_rate)* dx**2
x+=-
learning_rate* dx/
(np.sqrt(cache)+
eps)
6.Adam
tensorflow函数:
class tf.train.AdamOptimizer
__init__(learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-08, use_locking=False, name='Adam')
直接进行优化
train_op = optimizer.minimize(loss)
m = beta1*m + (1-beta1)dx
v = beta2*v + (1-beta2)
v = beta2*v
+ (1-beta2)(dx**2)
x += - learning_rate
* m / (np.sqrt(v) + eps)
有点像RMSProp+momentum