卷积神经网络中的优化算法比较

卷积神经网络一般力求能够做到 end to end 的训练, end to end 训练也是目前深度学习的主流. 训练中主要采用 Back Propagation 算法, 而 BP 算法是我们早就学过的梯度下降算法的一种实现. 因此, CNN 中的各种优化算法还是在梯度下降算法上面做手脚, 这篇文章的主要目的是总结和比较深度学习中各种常用的优化算法. 这这篇文章中不会涉及到怎么求(偏)导数, 我们假设已经得到了(偏)导数.

Stochastic Gradient Descent

基本的 SGD

原始的 SGD 方法在机器学习中经常被称为 Vanilla update, 这和我们在高中学习过的梯度下降算法没有什么区别, 都是先求(偏)导数, 然后, 以一定的学习速率, 利用该(偏)导数去更新要优化的参数.

     
     
# Vanilla update
x += - learning_rate * dx

Momentum Update

Momentum update 是一种加快收敛速度的方法(注意, 这里说的不是计算速度). 这个方法来自于物理中的启发. loss function 看做是一座山, 对于参数的初始化看做是在这个山坡上面随机放一个小球. 这个小球的初始速度为 0, 其相对于地面(或者更严格的说是山谷, 也是Loss Function 优化过程中的局部最优点)的势能为  U=mgh U=mgh, 其中,  m m 是小球的质量,  g g 是重力加速度, h 是小球的位置相对于山谷最低点的高度. 因为  m m 和  g g 都是常数, 因此, 势能正比与高度  h h. 优化过程看以看做是模拟这个小球在山坡上的状态. 小球来自于地球引力的受力为  F=mg F=mg, 而这恰好是 Loss Function 的梯度. 另外一方面, 小球的整体受力为  F=ma,ag F=ma,a≠g, 因为其中还有摩擦力等其它因素.

     
     
# Momentum update
v = mu * v - learning_rate * dx # integrate velocity
x += v # integrate position

这里的变量 mu 就是我们在各种深度学习框架中/论文中见到的 momentum. 一般设置为 0.9, 0.99 等. 然而, 把 mu 理解为摩擦(或者加上其它的因素)更好. mu 的作用是在小球在山坡上滚动的过程中来降低小球的动能. 否则, 如果没有这个因素, 那么, 小球永远不会停下来, 优化过程也永远不会停止.

Nesterov Momentum

Nesterov Momentum 是最近比较流行的一种与传统的momentum update稍有不同的方法, Nesterov Momentum 在凸优化中有较强的理论保证收敛, 并且,在实践中, Nesterov Momentum也比单纯的 Momentum 的效果要好. 核心思想是: 注意到 momentum 方法, 如果只看 mu * v 项, 那么, 当前的 x 进过 momentum 的作用会变成 x+ mu*v. 因此, 可以把 x+ mu*v 这个位置看做是当前优化的一个”展望”位置, 所以, 可以在 x+ mu*v 求导, 而不是原始的 x


     
     
x_ahead = x + mu * v
# evaluate dx_ahead (the gradient at x_ahead instead of at x)
v = mu * v - learning_rate * dx_ahead
x += v

自适应优化算法

在优化的过程中, 如果学习率设置的过大, 那么, 小球就会在山谷之间跳来跳去, 无法到达最低点, 如果是非常缓慢地降低学习速率, 那么, 虽然小球跳来跳去的现象会有缓解, 但是, 效果不明显, 浪费了计算资源, 而如果快速降低学习速率, 那么, 小球可能会很快到达一个(不是那么好的)局部最优点, 而不能到达一个更好的局部最优点. 通常, 在实验中有下面三种方法:

Step decay 每隔几个epoch减少一次learning rate, 一般是每运行5个epoch左右把learning rate减少一半, 或者是每隔20个epoch减少为原来的1/10. 然而,具体的learning rate 的调整方法还是要看网络的设计和模型. 另外, 还有一种方法是, 在训练的过程中观察training error和validation error, 当validation error不再减小的时候, 减小learning rate.

Exponential decay 的数学描述是  α=α0ekt α=α0e−kt, 其中  α0,k α0,k 是超参数,  t t 是迭代次数.

1/t decay 的数学描述是 α=α01+kt α=α01+kt 其中  (α0,k (α0,k) 是超参数,  t t 是迭代次数.

PS: 我一般使用第一种方法.

逐个调整参数

上面讨论过的所有的方法都是所有的参数都使用相同的调整策略. 调整学习率的代价一般比较高, 因此, 有许多研究还是如何自动调学习率, 甚至是调整每一个需要优化的参数的学习率. 在这些方法中往往会引入更多的超参数, 但是, 这些方法对超参数的设置并不是那么敏感, 因此, 总会比上面讨论过的调整学习率的方法要好用.

AdaGrad

pass

     
     
# Assume the gradient dx and parameter vector x
cache += dx** 2
x += - learning_rate * dx / (np.sqrt(cache) + eps)

cache 的大小和gradient的大小相同, 记录的是每个参数的梯度的平方和. 之后,cache 用来以 element-wise 的方式 normalize 参数的更新. 从上面的代码中可以看出, 梯度较高的权重的有效 learning rate 会减小, 相应的梯度较低的权重的有效 learning rate 会增大. 这里, 让我感到不解的是, sqrt 操作非常重要,如果没有 sqrt 操作, 该算法的效果非常差. eps 用来避免出现除 0 错误的,一般设置为  104 10−4 到  108 10−8 之间. (这种方法,在 CNN 中训练中极为常见, 比如在 batch normalization 中也是通过这种方法避免出现除 0 的错误). Adagrad 的缺点是,在深度学习中, 这种方法导致学习率的调整太激进, 因此常常过早结束了学习过程.

RMSProp

RMSProp是一个非常高效的算法, 但是目前并没有发表. Hinton 老爷子果然任性. RMSProp 对 AdaGrad 稍作改进, 是的算法不再像 AdaGrad 那么激进 它使用的是 moving average of squared gradients, 有关 moving average 的相关解释可以参考 batch normalization 的实现说明.

     
     
cache = decay_rate * cache + ( 1 - decay_rate) * dx** 2
x += - learning_rate * dx / (np.sqrt(cache) + eps)

decay_rate 是超参数, 一般可以设置为 0.9,0.99,0.999 0.9,0.99,0.999. 其中, x+= 操作和Adagrad完全相同, 但是, 变量cache是leaky的,所以, RMSProp 仍然根据每个权重的gradient来调整learning rate.

Adam

Adam 是最近提出的一种算法, 该算法和(下面将要介绍的)带有momentum的RMSprop比较类似, 过程类似于:

     
     
m = beta1*m + ( 1-beta1)*dx
v = beta2*v + ( 1-beta2)*(dx** 2)
x += - learning_rate * m / (np.sqrt(v) + eps)

该方法和 RMSProp 唯一的区别是 “smooth” 过程, 这里使用的是 m 来做 smooth 操作, 而不是使用原始的 gradient vector dx. 论文中推荐的超参数为 eps=1e-6, bata1=0.9, beta2=0.999, 在实践中, 推荐使用Adam方法. Adam 算法通常会比 RMSProp 算法效果好. 另外,也可以尝试 SGD+Nesterov Momentum. 完整的Adam算法中还包括 bias 的纠正机制, 这是因为,在刚开始的几个steps中,m 和 v 都要初始化, 并且在 warm up 之前他们都 biased at zero. 更多的细节可以参考论文原文.

Reference

cs231n

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值