最近在进行神经网络的训练的时候,经常会遇到这种情况:在多次进行训练尝试之后,为了平衡模型的训练速度和损失大小,选择了一个相对比较合适的学习率,但是训练集的损失下降到一定的程度后,就出现不再下降的情况,而是在一个范围内上下震荡。
比如:我网络中所使用的损失函数是 MSE 均方误差函数,在训练了20轮后出现了 MSE 一直在0.01到0.03之间来回震荡的情况,不能进一步下降,继而收敛。这里用画图的方式来表示,横坐标是迭代次数,纵坐标是损失函数。
出现这种情况通常可以通过适当降低学习率的方式进行改善,但是又一个问题出现了,学习率低就会出现训练时间过长的情况,感觉上好像这两者是矛盾的双方,么有办法兼顾,这个时候有一个方案出现了,它可以作为一个平衡的解决方案。
学习率衰减的基本思想就是:学习率随着训练的进行逐渐衰减,这样就可以在前期节省时间,快速得到一个最优解,又可以在后期避免震荡,让模型的训练更稳定。下面我们一起入门学习率衰减。
别有心理压力,只要跟着我一步一步来,你会发现其实并没有想像中的那么困难。当然,如果你看完了这篇教程之后,发现自己明白了很多,却又几乎什么都记不得,那也是很正常的——我认为,这里只是让你明白基本的原理和怎么应用,以后你还需要多练习,多使用,才能熟练掌握学习率衰减的使用。
除了作为入门教程之外,本文还试图成为可以在日常工作中的参考手册。就博主本人的经历来说,这个目标还是完成得不错的——你看,我自己也没能把所有的东西记下来,不是吗?
最重要的是——请给我10分钟,不会让你失望的 😃
学习率衰减的方法有很多种,这里简单的介绍几个常用的学习率衰减方法:
tf.train.piecewise_constant——分段常数衰减tf.train.inverse_time_decay——反时限衰减tf.train.polynomial_decay——多项式衰减tf.train.exponential_decay——指数衰减tf.train.natural_exp_decay——自然指数衰减tf.train.cosine_decay——余弦衰减tf.train.linear_cosine_decay——线性余弦衰减tf.train.noisy_linear_cosine_decay——噪声线性余弦衰减tf.train.piecewise_constant()——指定间隔的分段常数是不是觉得太多了,有点大脑发蒙,别担心,我们这里只重点讲一下tf.train.exponential_decay——指数衰减。
无论是哪个学习率衰减函数都返回衰减之后的学习率,当然也包括我们的指数衰减。
在训练模型时,通常建议随着训练的进行逐步降低学习率,这样可以科学的降低学习率,充分利用学习率高低各自的优势进行训练,进而找到最优解。先来看一下exponential_decay的函数参数:
tf.train.exponential_decay( learning_rate, global_step, decay_steps, decay_rate, staircase=False, name=None )参数:
learning_rate是初始学习率,这个是可以自行设置的。decay_rate是衰减指数,可设为任意值,但是一般都是设置成略小于1的值,比如0.98,0.9。global_step是用于衰减计算的全局步数,类似于一个时钟。decay_steps是衰减步数,每间隔decay_steps步衰减一次learning_rate值。staircase是控制衰减方式的参数,若为True,则以不连续的间隔衰减学习率,即阶梯型衰减学习率;若为False,则是标准指数型衰减,即连续型衰减学习率.name是操作的名称,默认为 ExponentialDecay,可选项。学习率的衰减公式如下:
decayed_learning_rate = learning_rate * np.power(decay_rate, (global_step / decay_steps))使用到的参数是什么含义,都在上面的介绍中,已经写的很清楚了。下图中灰色的线条是staircase=False的情况,也就是连续型衰减学习率;黑色的线条就是staircase=True的情况,也就是阶梯型衰减学习率。
图源——Tensorflow+实战Google深度学习框架书籍的4.4.1节。下载方式在博客『学习资源』索引中。
红色的线条代表staircase=True,首字母缩写也就是S_T; 蓝色的线条代表staircase=False,首字母缩写也就是S_F。
有的小伙伴比较疑惑,global_step怎么设置呢?global_step到底是怎么完成自动加1的???关键就在这一句代码:
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_steps)只要有这句代码,就可以实现自动加1。不信的话就运行上述代码,可以得到如下结果:
0.009895192 1 0.009791483 2 0.009688861 3 0.009587315 4 0.009486833 5 0.009387404 6 0.009289017 7 0.00919166 8 0.009095325 9 0.009 10如果去掉其中的 global_step=global_steps 这一句,那么 global_step 的自动加1的操作就会失效,可以自己用上面的代码试一下,这里直接给出结果了:
0.01 0 0.01 0 0.01 0 0.01 0 0.01 0 0.01 0 0.01 0 0.01 0 0.01 0 0.01 0省略号上面是神经网络的前面定义部分,省略号下面是最后的损失函数计算部分,省略号就是网络结构部分,只要对应各个位置进行代码的重构就可以实现学习率衰减。
博主注:要特别注意,学习率衰减这个功能虽然在一些情况下,比固定学习率要好用,但是同时也有几个参数需要微调,比如learning_rate、decay_steps、decay_rate、staircase这四个参数,这都是需要自己根据网络结构进行调整的,对应于不同网络结构和数据集,相应的情况自然就复杂起来了,但是只要是能满足于最后的最优解就是好的,要相信阳光总在风雨后 😃
如果想要更多的资源,欢迎关注 @我是管小亮,文字强迫症MAX~
回复【福利】即可获取我为你准备的大礼,包括C++,编程四大件,NLP,深度学习等等的资料。
想看更多文(段)章(子),欢迎关注微信公众号「程序员管小亮」~