深度学习100问之学习率衰减

前言

最近在进行神经网络的训练的时候,经常会遇到这种情况:在多次进行训练尝试之后,为了平衡模型的训练速度和损失大小,选择了一个相对比较合适的学习率,但是训练集的损失下降到一定的程度后,就出现不再下降的情况,而是在一个范围内上下震荡。

比如:我网络中所使用的损失函数是 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节。下载方式在博客『学习资源』索引中。

实例对比

import tensorflow as tf
import matplotlib.pyplot as plt

learning_rate = 0.01
decay_rate = 0.9
global_steps = 1000
decay_steps = 100

global_step = tf.Variable(0, trainable=False)

c = tf.train.exponential_decay(
                learning_rate,
                global_step,
                decay_steps,
                decay_rate,
                staircase=True)
d = tf.train.exponential_decay(
                learning_rate,
                global_step,
                decay_steps,
                decay_rate,
                staircase=False)

S_T = []
S_F = []

with tf.Session() as sess:
    for i in range(global_steps):
        S_T = sess.run(c, feed_dict={global_step: i})
        S_T.append(T_c)
        S_F = sess.run(d, feed_dict={global_step: i})
        S_F.append(F_d)

plt.figure()
plt.plot(range(global_steps), S_T, 'r-', label='staircase_True')
plt.plot(range(global_steps), S_F, 'b-', label='staircase_False')
plt.title('exponential_decay')
plt.xlabel('step')
plt.ylabel('learing rate')
plt.show()

在这里插入图片描述

红色的线条代表staircase=True,首字母缩写也就是S_T;
蓝色的线条代表staircase=False,首字母缩写也就是S_F。

推荐代码

import tensorflow as tf
import numpy as np

x = tf.placeholder(tf.float32, shape=[None, 1], name='x')
y = tf.placeholder(tf.float32, shape=[None, 1], name='y')
w = tf.Variable(tf.constant(0.0))

global_steps = tf.Variable(0, trainable=False)

# ......
# ......

learning_rate = tf.train.exponential_decay(
    0.01, global_steps, 10, 0.9, staircase=False)
    
loss = tf.pow(w * x - y, 2)# 损失函数可以随意变换

train_step = tf.train.AdamOptimizer(
    learning_rate).minimize(loss, global_step=global_steps)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(10):
        sess.run(train_step, feed_dict={x: np.linspace(1, 2, 10).reshape(
            [10, 1]), y: np.linspace(1, 2, 10).reshape([10, 1])})
        print(sess.run(learning_rate))
        print(sess.run(global_steps))

总结

有的小伙伴比较疑惑,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_ratedecay_stepsdecay_ratestaircase这四个参数,这都是需要自己根据网络结构进行调整的,对应于不同网络结构和数据集,相应的情况自然就复杂起来了,但是只要是能满足于最后的最优解就是好的,要相信阳光总在风雨后 😃

如果想要更多的资源,欢迎关注 @我是管小亮,文字强迫症MAX~

回复【福利】即可获取我为你准备的大礼,包括C++,编程四大件,NLP,深度学习等等的资料。

想看更多文(段)章(子),欢迎关注微信公众号「程序员管小亮」~

在这里插入图片描述

参考文章

  • 11
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
深度学习训练过程中,学习率衰减是一种常用的技术,可以帮助模型更好地收敛到最优解。以下是几种常见的学习率衰减策略: 1. 学习率衰减:在训练的每个epoch或每个固定的步骤后,将学习率乘以一个衰减因子来降低学习率。例如,每个epoch结束后将学习率乘以0.1,或者每隔一定步骤将学习率减小为原来的一半。 ```python # 定义初始学习率衰减因子 initial_lr = 0.1 decay_factor = 0.1 # 创建优化器并设置初始学习率 optimizer = torch.optim.SGD(model.parameters(), lr=initial_lr) # 在每个epoch结束后进行学习率衰减 for epoch in range(num_epochs): # ... 训练模型 ... # 学习率衰减 lr = initial_lr * (decay_factor ** epoch) for param_group in optimizer.param_groups: param_group['lr'] = lr ``` 2. 学习率阶段性衰减:将训练过程分为多个阶段,每个阶段使用不同的学习率。例如,前10个epoch使用较高的学习率,然后降低到较低的学习率。 ```python # 定义不同阶段的学习率和对应的epoch数 lr_schedule = [ {'epoch': 0, 'lr': 0.1}, {'epoch': 10, 'lr': 0.01}, {'epoch': 20, 'lr': 0.001} ] # 创建优化器并设置初始学习率 optimizer = torch.optim.SGD(model.parameters(), lr=lr_schedule[0]['lr']) # 在每个epoch结束后进行学习率衰减 for epoch in range(num_epochs): # ... 训练模型 ... # 学习率衰减 for schedule in lr_schedule: if epoch >= schedule['epoch']: lr = schedule['lr'] for param_group in optimizer.param_groups: param_group['lr'] = lr ``` 3. 学习率按时间表衰减:根据训练的总步骤数或总epoch数,使用预定义的学习率衰减函数来动态调整学习率。 ```python from torch.optim.lr_scheduler import StepLR # 创建优化器 optimizer = torch.optim.SGD(model.parameters(), lr=0.1) # 创建学习率衰减策略 scheduler = StepLR(optimizer, step_size=10, gamma=0.1) # 在每个epoch结束后进行学习率衰减 for epoch in range(num_epochs): # ... 训练模型 ... # 更新学习率 scheduler.step() ``` 以上是一些常见的学习率衰减策略,你可以根据实际情况选择适合你的模型和数据集的策略。这些策略可以帮助模型在训练过程中更好地收敛,并提高模型的性能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是管小亮

一口吃掉你的打赏,嗝~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值