先列举一下在深度学习中,我们常见的优化算法有哪些:
- 最基本的如梯度下降(Gradient Descent)—— GD
然后还有一些GD的变体: - 随机梯度下降法(Stochastic Gradient Descent)——SGD
- 小批量梯度下降——mini-batch GD
- 动量梯度下降——Momentum
- 均方根算法(root mean square prop) ——RMSprop
- 自适应矩估计(Adaptive Moment Estimation)——Adam
以上这些之前在吴恩达的课程学过,还有其他的优化算法还没有仔细研究过。
下面这个网站里有都有介绍,有兴趣的可以看看
http://ruder.io/optimizing-gradient-descent/index.html
GD因为是同时处理整个训练集,所以也叫Batch 梯度下降法,GD很简单就不详细介绍了。想看的话我前面博客有介绍。
不过看到有一张图真的是太直观了,所以我贴一下。
GD就是对 cost function J J J 的 “downhill”
SGD:是mini-batch的一个特例,每个mini-batch都只有一个样本
看下Batch GD 和 SGD 在代码上的不同,更有助于理解
- (Batch)GD:
X = data_input
Y = lables
layers_dims = 神经网络的深度(层)矩阵
parameters = initialize_parameters(layers_dims) # 参数初始化
# for loop 迭代 num_iterations 次,更新参数
for i in range(0, num_interations):
predict_lables, caches = forward_propagation(X, parameters) # 前向传播计算预测标签和必要的参数
cost = compute_cost(predict_lables, Y) # 利用预测标签和真实标签求cost function
grads = backward_propagation(predict_lables, caches, parameters) # 后向传播计算梯度值
parameters = update_parameters(parameters, grads) # 更新参数
- SGD
X = data_input
Y = labels
parameters = initialize_parameters(layers_dims)
for i in range(0, num_iterations):
for j in range(0, m):
a, caches = forward_propagation(X[:,j], parameters)
cost = compute_cost(a, Y[:,j])
grads = backward_propagation(a, caches, parameters)
parameters = update_parameters(parameters, grads)
很清晰明了,SGD是对m个样本每一个都要算一次梯度,数量大的时候,速度更快。
但是它是摆动着趋向minimum point,永远不会收敛,会一直在最小值附近摆动。
GD 和 SGD 的运算效果如下图所示
摆动的原理和mini-batch一样,稍后介绍
- Mini-Batch GD
mini-batch 每次更新所用的样本数是介于GD和SGD之间。也就是说mini-batch是把所有样本随机分成很多组,一组一组的计算(SGD就是每组一个样本,Mini-Batch = m)
注意:X、Y的随机分组必须是同步的。
SGD 和 mini-batch 的运算效果如下图所示
摆动的原因:
mini-batch是在得到样本的子集之后就开始更新,但是不同的子集的更新方向都不同,所以cost不会平滑到收敛,而是抖动到收敛。
实现mini-batch的两个步骤:
一:样本随机化(X、Y要同步)
效果如下图所示
关键代码实现如下:
# 对(X,Y)进行随机改组
permutation = list(np.random.permutation(m))
shuffled_X = X[:, permutation]
shuffled_Y = Y[:, permutation].reshape((1,m))
二:实现分组
假设随机分成64组的话(mini-batch),展示效果如下图所示
(pictures from the deep learning courses of Andrew NG)
关键代码实现:
"""
如果小批量的大小(mini-batch_size)为 64,而总的样本数 m 不是64 的倍数,
那么前 n-1 组中的样本数均为64,最后一组的样本数为 m - 64*(n-1)。(n=m/64向下取整)
"""
num_complete_minibatches = math.floor(m/mini_batch_size) # mini-batch_size = 64 的mini-batch数量
for k in range(0,num_complete_minibatches):
mini_batch_X = shuffled_X[:, k*mini_batch_size:(k+1)*mini_batch_size]
mini_batch_Y = shuffled_Y[:, k*mini_batch_size:(k+1)*mini_batch_size]
mini_batch = (mini_batch_X, mini_batch_Y)
mini_batches.append(mini_batch) # 把n-1组的mini-batch都存放在mini-batches的list中
if m % mini_batch_size != 0:
mini_batch_X = shuffled_X[:, num_complete_minibatches * mini_batch_size:]
mini_batch_Y = shuffled_Y[:, num_complete_minibatches * mini_batch_size:]
mini_batch = (mini_batch_X,mini_batch_Y)
mini_batches.append(mini_batch) # 把最后一组也放到mini-batches的list中
mini-batch 的选择问题:
肯定是在1~m之间选择
如果训练集较小(<2000)的话,直接使用batch梯度下降法就可以
如果训练集比较大的话,一般的mini-batch 大小为64到512(2的整数次方)比较常见。
具体多大,就需要自己尝试了。
.
- Momentum :克服mini-batch的摆动,利用之前的梯度来平滑更新。采用的是指数加权移动平均的方式来实现平滑。
v t = β v t − 1 + ( 1 − β ) θ t v_{t} = \beta v_{t-1} + (1-\beta) \theta_t vt=βvt−1+(1−β)θt简言之,就是给前一个速度施加一定的权重来影响当前的速度。
所以,把指数加权平均的方式应用到Momentum中后,参数更新规则如下:
{ v d W [ l ] = β v d W [ l ] + ( 1 − β ) d W [ l ] W [ l ] = W [ l ] − α v d W [ l ] \begin{cases} v_{dW^{[l]}} = \beta v_{dW^{[l]}} + (1 - \beta) dW^{[l]} \\ W^{[l]} = W^{[l]} - \alpha v_{dW^{[l]}} \end{cases} { vdW[l]=βvdW[l]+(1−β)dW[l]W[l]=W[l]−αvdW[l]
{ v d b [ l ] = β v d b [ l ] + ( 1 − β ) d b [ l