您当前的位置:首页 > IT编程 > cnn卷积神经网络
| C语言 | Java | VB | VC | python | Android | TensorFlow | C++ | oracle | 学术与代码 | cnn卷积神经网络 | gnn | 图像修复 | Keras | 数据集 | Neo4j | 自然语言处理 | 深度学习 | 医学CAD | 医学影像 | 超参数 | pointnet | pytorch |

自学教程:Keras实现两个优化器:Lookahead和LazyOptimizer

51自学网 2020-02-29 16:33:07
  cnn卷积神经网络
这篇教程Keras实现两个优化器:Lookahead和LazyOptimizer写得很实用,希望能帮到您。

Jul

Keras实现两个优化器:Lookahead和LazyOptimizer

最近用Keras实现了两个优化器,也算是有点实现技巧,遂放在一起写篇文章简介一下(如果只有一个的话我就不写了)。这两个优化器的名字都挺有意思的,一个是look ahead(往前看?),一个是lazy(偷懒?),难道是两个完全不同的优化思路么?非也非也~只能说发明者们起名字太有创意了。

Lookahead #

首先登场的是Lookahead优化器,它源于论文《Lookahead Optimizer: k steps forward, 1 step back》,是最近才提出来的优化器,有意思的是大牛Hinton和Adam的作者之一Jimmy Ba也出现在了论文作者列表当中,有这两个大神加持,这个优化器的出现便吸引了不少目光。

Lookahead的思路很朴素,准确来说它并不是一个优化器,而是一个使用现有优化器的方案。简单来说它就是下面三个步骤的循环执行:

1、备份模型现有的权重θθ;

2、从θθ出发,用指定优化器更新kk步,得到新权重θ~θ~;

3、更新模型权重为θ←θ+α(θ~−θ)θ←θ+α(θ~−θ)。

下面则是我的Keras实现,写法在之前的《“让Keras更酷一些!”:小众的自定义优化器》一文中就提到过了,属于一种“侵入式”的写法:

https://github.com/bojone/keras_lookahead

用法就很简单了:

model.compile(optimizer=Adam(1e-3), loss='mse') # 用你想用的优化器
lookahead = Lookahead(k=5, alpha=0.5) # 初始化Lookahead
lookahead.inject(model) # 插入到模型中

至于效果,原论文中做了不少实验,有些有轻微提高(cifar10和cifar100那两个),有些提升还比较明显(LSTM做语言模型那个),我自己简单实验了一下,结果是没什么变化。我一直觉得优化器是一个很玄乎的存在,有时候非得SGD才能达到最优效果,有时候又非得Adam才能收敛得下去,总之不能指望单靠换一个优化器就能大幅度提升模型效果。Lookahead的出现,也就是让我们多一种选择罢了,训练时间充足的读者,多去尝试一下就好。

附:《机器之心的Lookahead的介绍》

LazyOptimizer #

LazyOptimizer优化器基本上就是为NLP准备的,当然更准确来说是为Embedding层准备的。

LazyOptimizer指出所有带动量的优化器(自然也就包括Adam以及带动量的SGD)都存在一个问题:当前batch中没被采样到的词,依然会使用历史动量来更新,这可能导致Embedding层过拟合(参考知乎讨论)。具体来说,当一个词的被采样过后,它的Embedding的梯度不为0,这个梯度也会被记录在动量中,实际更新是用动量去更新的;在后面的batch中,假如该词没有被采样到,它的Embedding的梯度为0,但是它的动量并不为0,所以该词还是被更新了。这样一来就算没有被反复采样的词,对应的Embedding也被反复更新了,就导致了过拟合。

所以,一个改进的方案是只有当该词被采样过才更新,这就是LazyOptimizer的基本原理了。

在实现上,我们要如何判断一个词有没有被采样过呢?当然终极方法肯定是传入被采样过的词的index了,但这使用上不够友好。我这里使用了一个近似的方法:判断该词的Embedding对应的梯度是否为0,如果为0意味着它“很可能”在当前batch没有被采样到。背后的原理在于,如果它没有被采样到,那么梯度一定为0,如果它被采样到了,那么梯度为0的概率是非常小的,毕竟那么多分量,同时为0的可能性很小,所以这样实现也够用了。

我的Keras实现位于:

https://github.com/bojone/keras_lazyoptimizer

这个用法也很简单,就是包装一个带动量的优化器,传入所有Embedding层,使得它成为一个新的Lazy版的优化器:

model.compile(
    loss='mse',
    optimizer=LazyOptimizer(Adam(1e-3), embedding_layers)
)

Github中还带有一个IMDB的例子,在这个例子中,如果直接用Adam(1e-3)做优化器,那么验证准确率最高只有83.7%左右,而如果用LazyOptimizer(Adam(1e-3), embedding_layers),那么基本上最优验证准确率能跑到84.9%以上,效果可见一斑。总的来说,我觉得Embedding层很大的模型(尤其是以词为单位的模型)都可以试一下,总的来说就是因为Embedding层参数量太大了,减少更新频率,让模型重点去优化其余部分。

注:这个LazyOptimizer和标准的LazyOptimizer有点不一样。标准的LazyOptimizer对没有采样过的词,所有相关的缓存量(比如动量等)也不去更新,但我这个实现中,就算该词没有被采样到,该词对应的所有缓存量还是会被更新的,有评测说这样做其实效果会更好些

keras各种优化器优化器的用法
论文中绘制神经网络工具汇总
51自学网,即我要自学网,自学EXCEL、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。
京ICP备13026421号-1