PyTorch深度学习实战(9)——学习率优化

news2024/12/24 22:42:01

PyTorch深度学习实战(9)——学习率优化

    • 0. 前言
    • 1. 学习率简介
    • 2. 梯度值、学习率和权重之间的相互作用
    • 3. 学习率优化实战
      • 3.1 学习率对缩放后的数据集的影响
      • 3.2 学习率对未缩放数据集的影响
    • 小结
    • 系列链接

0. 前言

学习率( learning rate )是神经网络训练中一个重要的超参数,用于控制模型更新参数的步长大小,它决定了每次迭代中模型参数更新的幅度。学习率的选择对于训练的结果具有重要影响,学习率过高会导致模型震荡不收敛甚至发散,无法有效优化目标函数;而学习率过低则会导致收敛速度缓慢,需要更多的迭代才能达到较好的效果。本节首先介绍学习率如何影响模型训练,并通过修改学习率观察不同学习率对模型性能的影响。

1. 学习率简介

在神经网络训练中,我们通过最小化损失函数来优化模型的参数。梯度下降是一种常用的优化算法,它通过计算损失函数对于每个参数的导数来指导参数的更新,而学习率就是梯度下降算法中的一个重要的调节参数。
为了了解学习率对模型训练的影响,我们尝试拟合以下简单方程:

y = 3 × x y=3\times x y=3×x

其中, y y y 是输出, x x x 是输入。给定一组输入和预期输出值,我们使用不同的学习率拟合方程,以了解学习率的影响。

(1) 定义输入和输出数据集:

x = [[1],[2],[3],[4]]
y = [[3],[6],[9],[12]]

(2) 定义 feed_forward() 函数,此处使用的网络并不包含隐藏层:

y = w × x + b y=w\times x+b y=w×x+b

在以上函数中,我们尝试估计参数 w w w b b b

from copy import deepcopy
import numpy as np
def feed_forward(inputs, outputs, weights):
    out = np.dot(inputs,weights[0])+ weights[1]
    mean_squared_error = np.mean(np.square(out - outputs))
    return mean_squared_error

(3) 定义 update_weights() 函数利用梯度下降更新网络权重:

def update_weights(inputs, outputs, weights, lr):
    original_weights = deepcopy(weights)
    org_loss = feed_forward(inputs, outputs, original_weights)
    updated_weights = deepcopy(weights)
    for i, layer in enumerate(original_weights):
        for index, weight in np.ndenumerate(layer):
            temp_weights = deepcopy(weights)
            temp_weights[i][index] += 0.0001
            _loss_plus = feed_forward(inputs, outputs, temp_weights)
            grad = (_loss_plus - org_loss)/(0.0001)
            updated_weights[i][index] -= grad*lr
    return updated_weights

(4) 将权重和偏差值初始化为随机值:

W = [np.array([[0]], dtype=np.float32), np.array([[0]], dtype=np.float32)]

权重和偏差值随机初始化为 0,输入权重值的形状为 1 x 1,因为输入中每个数据点的形状为 1 x 1,偏置值的形状为 1 x 1 (输出中只有一个节点,每个输出只有一个值)。

(5) 将学习率设为 0.01 执行 update_weights() 函数,循环迭代 1,000 次,并检查权重值( W )随时间的变化:

weight_value = []
for epx in range(1000):
    W = update_weights(x,y,W,0.01)
    weight_value.append(W[0][0][0])

在以上代码中,设置学习率为 0.01 并重复调用 update_weights() 函数以在每个 epoch 结束时获取修改后的权重。此外,在每个 epoch 中,我们将最近更新的权重作为输入,以在下一 epoch 中继续更新权重。

(6) 绘制每个 epoch 结束时的权重参数值:

import matplotlib.pyplot as plt
plt.plot(weight_value)
plt.title('Weight value over increasing epochs')
plt.xlabel('Epochs')
plt.ylabel('Weight value')
plt.show()

权重变化

可以看到,在上图中,权重值逐渐增加,最终在 3 附近达到稳定。
为了了解学习率对权重更新的影响,我们测试当学习率为 0.11 时,权重值随时间的变化情况,下图显示了使用不同学习率时,权重的变化情况:

权重变化

可以看到,当学习率非常小时( 0.01 )时,权重值缓慢向最优值移动(需要更多的 epoch);而在学习率较高( 0.1 )时,权重值最初变化较为剧烈,然后迅速得到最优值(需要较少的 epoch);而当学习率过高( 1 )时,权重值无法达到最优值。
学习率低时权重值没有大幅变化的原因是我们将权重更新量限制为 梯度x学习率,本质上是由于学习率较小导致更新量较小;当学习率过高时,权重更新量相应较高,损失的变化非常小,以至于权重无法达到最优值。

2. 梯度值、学习率和权重之间的相互作用

为了更深入地了解梯度值、学习率和权重之间的相互作用,我们只运行 10epochupdate_weights() 函数,并打印以下值以了解它们如何随 epoch 变化:

  • 每个 epoch 开始时的权重值
  • 权重更新前的损失
  • 少量更新权重后的损失
  • 梯度值

修改 update_weights() 函数以打印以上值:

def update_weights(inputs, outputs, weights, lr):
    original_weights = deepcopy(weights)
    org_loss = feed_forward(inputs, outputs, original_weights)
    updated_weights = deepcopy(weights)
    for i, layer in enumerate(original_weights):
        for index, weight in np.ndenumerate(layer):
            temp_weights = deepcopy(weights)
            temp_weights[i][index] += 0.0001
            _loss_plus = feed_forward(inputs, outputs, temp_weights)
            grad = (_loss_plus - org_loss)/(0.0001)
            updated_weights[i][index] -= grad*lr
            if(i % 2 == 0):
                print('weight value:', np.round(original_weights[i][index],2), 
                      'original loss:', np.round(org_loss,2), 
                      'loss_plus:', np.round(_loss_plus,2), 
                      'gradient:', np.round(grad,2), 
                      'updated_weights:', np.round(updated_weights[i][index],2))
    return updated_weights

在以上代码中,打印原始权重值( original_weights[i][index])、损失( org_loss)、权重更新后损失值( _loss_plus)、梯度( grad )以及更新后的权重值( updated_weights)。使用不同的学习率,观察以上各值如何随着 epoch 变化。
学习率 0.01 时:

W = [np.array([[0]], dtype=np.float32), np.array([[0]], dtype=np.float32)]
weight_value = []
for epx in range(10):
    W = update_weights(x,y,W,0.01)
    weight_value.append(W[0][0][0])
print(W)
import matplotlib.pyplot as plt
plt.plot(weight_value[:100])
plt.title('Weight value over increasing epochs when learning rate is 0.01')
plt.xlabel('Epochs')
plt.ylabel('Weight value')
plt.show()

输出结果如下所示:

学习率为 0.01

可以看到,当学习率为 0.01 时,损失值缓慢下降,权重值也缓慢向最优值移动。
学习率为 0.1,改变学习率参数值运行相同代码的输出如下:

学习率为 0.1

对比学习率分别为 0.010.1 的结果,主要区别如下:与学习率为 0.1 时相比,学习率为 0.01 时,权重的更新要慢得多,更新速度较慢的原因是学习率较低,因为权重是通过梯度乘以学习率来更新的。
除了权重更新的幅度,我们还要注意权重更新的方向:当权重值小于最优值时梯度为负,当权重值大于最优值时梯度为正,从而保证了网络在正确的方向上更新权重值。
最后,我们观察与学习率为 1 时的运行结果,学习率为 1,改变学习率参数值运行相同代码的输出如下:

学习率为 1

从上图中可以看出,权重与最优值间的偏离较大,除此之外,权重值更新幅度较大,因此权重值的微小变化几乎不会影响梯度的变化,权重并不能收敛于最优值。
一般来说,学习率越低越好。这样,模型能够缓慢学习,并将权重调整为最佳值,学习率参数值通常设置在 0.00010.01 之间。

3. 学习率优化实战

我们已经了解到学习率在获得最佳权重方面起着关键作用。当学习率较小时,权重会平滑的向最优值移动,而当学习率较大时,权重会在非最优值处振荡(陷于局部最优值)。为了理解不同学习率的影响,我们将使用 Fashion MNIST 进行以下实验:

  • 在缩放后的数据集上使用较高学习率 (0.1)
  • 在缩放后的数据集上使用较低学习率 (0.00001)
  • 在未缩放的数据集上使用较低学习率 (0.001)
  • 在未缩放的数据集上使用较高学习率 (0.1)

3.1 学习率对缩放后的数据集的影响

在本节中,我们将使用不同学习率对比模型在训练和验证数据集上的准确率。

3.1.1 较高学习率

本节中,我们使用 Adam 优化器,训练过程中唯一的变化是定义 get_model() 函数时,修改优化器中的学习率,将学习率( lr )修改为 0.1。除了对 get_model() 函数进行的修改之外,其他代码都与神经网络训练一节中完全相同。修改优化器,使其学习率为 0.1 ( lr=1e-1):

def get_model():
    model = nn.Sequential(
        nn.Linear(28 * 28, 1000),
        nn.ReLU(),
        nn.Linear(1000, 10)
    ).to(device)

    loss_fn = nn.CrossEntropyLoss()
    optimizer = Adam(model.parameters(), lr=1e-1)
    return model, loss_fn, optimizer

执行代码后,模型在训练和验证数据集上对应的准确率和损失变化如下:

准确率和损失变化

3.1.2 中等学习率

通过修改 get_model() 函数并从头开始重新训练模型,将优化器的学习修改为 0.001

def get_model():
    model = nn.Sequential(
        nn.Linear(28 * 28, 1000),
        nn.ReLU(),
        nn.Linear(1000, 10)
    ).to(device)

    loss_fn = nn.CrossEntropyLoss()
    optimizer = Adam(model.parameters(), lr=1e-3)
    return model, loss_fn, optimizer

在以上代码中,我们修改了 lr 参数值,与训练和验证数据集对应的准确率和损失值变化如下:

准确率和损失值变化

从以上输出结果可以看出,当学习率从 0.1 降低到 0.001 时,模型性能有了大幅提升。

3.1.3 较低学习率

通过修改 get_model() 函数并从头开始重新训练模型,将优化器的学习率修改为 0.00001,并运行模型更多的 epoch (100):

def get_model():
    model = nn.Sequential(
        nn.Linear(28 * 28, 1000),
        nn.ReLU(),
        nn.Linear(1000, 10)
    ).to(device)

    loss_fn = nn.CrossEntropyLoss()
    optimizer = Adam(model.parameters(), lr=1e-5)
    return model, loss_fn, optimizer

在以上中,我们修改了 lr 参数值,与训练和验证数据集对应的准确率和损失变化如下:

准确率和损失变化

从上图中,我们可以看到模型的学习速度相对而言慢了很多,与学习率为 0.001 时相比,需要 100epoch 模型才能达到约 89% 的准确率,而学习率为 0.001 时只需要 8epoch。此外,与较大学习率相比,当学习率较低时,训练和验证损失之间的差距要小得多。这是因为,当学习率较低时,权重更新幅度也要低得多,训练和验证损失之间的差距并不会迅速扩大。
我们已经了解了学习率对训练和验证数据集准确率的影响。在下一节中,我们将了解不同学习率的权重值在各层之间的分布变化。

3.1.4 不同学习率的模型参数分布

我们已经了解到,在较高学习率时( 0.1),模型被无法正确训练(模型欠拟合)在学习率中等( 0.001 )或低 (0.00001 )时可以得到较高的准确率。中等学习率能够快速过拟合,而较低学习率需要更长的时间才能达到与中等学习率模型相近的准确率。在本节中,我们将了解参数分布如何衡量模型过拟合和欠拟合。
在我们使用的简单模型中有四个参数组:

  • 连接输入层和隐藏层的层的权重
  • 隐藏层中的偏置值
  • 连接隐藏层和输出层的层的权重
  • 输出层中的偏置值

可以使用以下代码来观察参数的分布情况:

for ix, par in enumerate(model.parameters()):
    if(ix == 0):
        plt.subplot(141)
        plt.hist(par.cpu().detach().numpy().flatten())
        plt.title('Distribution of weights conencting input to hidden layer')
    elif(ix == 1):
        plt.subplot(142)
        plt.hist(par.cpu().detach().numpy().flatten())
        plt.title('Distribution of biases of hidden layer')
    elif(ix == 2):
        plt.subplot(143)
        plt.hist(par.cpu().detach().numpy().flatten())
        plt.title('Distribution of weights conencting hidden to output layer')
    elif(ix == 3):
        plt.subplot(144)
        plt.hist(par.cpu().detach().numpy().flatten())
        plt.title('Distribution of biases of output layer')

plt.show()

使用三种不同的学习率,输出结果如下所示:

模型参数分布

在上图中,我们可以看到:

  • 当学习率较高时,与中低学习率相比,参数的分布范围大得多
  • 当参数分布范围较大时,就会发生过拟合

3.2 学习率对未缩放数据集的影响

在本节中,我们在定义数据集类时使用原始未缩放数据集:

class FMNISTDataset(Dataset):
    def __init__(self, x, y):
        x = x.float()
        x = x.view(-1,28*28)
        self.x, self.y = x, y 
    def __getitem__(self, ix):
        x, y = self.x[ix], self.y[ix] 
        return x.to(device), y.to(device)
    def __len__(self): 
        return len(self.x)

使用不同学习率训练模型,准确率和损失随 epoch 的变化如下:

准确率和损失变化

在上图中可以看到,当数据集并未缩放时,学习率为 0.1 时无法训练出准确的模型,而学习率为 0.001 时准确率也会下降,当学习率非常小时( 0.00001 )时,模型同样能够学习得到较优性能,但出现了过拟合问题。我们可以通过查看网络各层的权重参数分布来理解这种情况发生的原因:

权重分布

可以看到,与较高的学习率相比,当模型学习率较低时,权重的范围相对小得多。在未缩放数据集上学习率为 0.00001 等价于在缩放数据集上学习率为 0.001 时的模型性能,这时学习率较低时权重可以以较小幅度进行修改,因为在这种情况下 梯度x学习率 是一个非常小的值。通常,学习率过低会导致训练模型需要较长时间,而学习率过高会导致模型训练变得不稳定。

小结

学习率的优化是神经网络训练中不可或缺的一环,合理地选择学习率及采用适当的调整策略,能够帮助提升模型的训练效果。本节中,我们介绍了学习率影响模型训练的原理,并通过实战展示了不同学习率对模型性能的影响。

系列链接

PyTorch深度学习实战(1)——神经网络与模型训练过程详解
PyTorch深度学习实战(2)——PyTorch基础
PyTorch深度学习实战(3)——使用PyTorch构建神经网络
PyTorch深度学习实战(4)——常用激活函数和损失函数详解
PyTorch深度学习实战(5)——计算机视觉基础
PyTorch深度学习实战(6)——神经网络性能优化技术
PyTorch深度学习实战(7)——批大小对神经网络训练的影响
PyTorch深度学习实战(8)——批归一化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/840156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(十二)大数据实战——hadoop集群之HDFS高可用自动故障转移

前言 本节内容主要介绍一下hadoop集群下实现HDFS高可用的自动故障转移,HDFS高可用的自动故障转移主要通过zookeeper实现故障的监控和主节点的切换。自动故障转移为 HDFS 部署增加了两个新组件:ZooKeeper 和 ZKFailoverController (ZKFC&…

【笔记】湖仓一体架构演进与发展

https://www.bilibili.com/video/BV1oF411F7rQ/?spm_id_from333.788.recommend_more_video.0&vd_sourcefa36a95b3c3fa4f32dd400f8cabddeaf

Linux中的firewall-cmd

2023年8月4日,周五上午 目录 打开端口关闭端口查看某个端口是否打开查看当前防火墙设置firewall-cmd中的服务在防火墙中什么是服务?为什么会有服务?打开或关闭服务查看某个服务是否打开firewall-cmd中的 zones查看所有可用的zones&#xff0…

elementui Cascader 级联选择使用心得

相信大家对于elementui并不陌生,作为适配Vue的优秀UI框架之一,一直被所有的开发者痛并快乐着。今天要记录的就是里边的主角之一Cascader。 首先先介绍一下Cascader ---> 当一个数据集合有清晰的层级结构时,可通过级联选择器逐级查看并选择…

OBS视频视频人物实时扣图方法(四种方式)

图片擦除一些杂乱图像 参考:https://www.bilibili.com/video/BV1va411G7be https://github.com/Sanster/lama-cleaner第一种:色度键选项 第二种:浏览器建立窗口选项 参考视频:https://www.bilibili.com/video/BV1WS4y1C7QY http…

Java8 list多属性去重

大家好,我是三叔,很高兴这期又和大家见面了,一个奋斗在互联网的打工人。 在 Java 开发中,我们经常会面临对 List 中的对象属性去重的需求。然而,当需要根据多个属性来进行去重时,情况会稍微复杂一些。本篇…

js实现原型链污染,沙箱绕过

一、沙箱绕过 1.概念 沙箱绕过"是指攻击者利用各种方法和技术来规避或绕过应用程序或系统中的沙箱(sandbox)。沙箱是一种安全机制,用于隔离和限制应用程序的执行环境,从而防止恶意代码对系统造成损害。它常被用于隔离不受信…

开放式耳机的音质不如入耳式耳机吗?开放式耳机的优缺点?

​开放式耳机的音质不一定不如入耳式耳机。音质取决于多种因素,包括耳机的设计、音频技术和材料质量等。因此,不能简单地将开放式耳机和入耳式耳机进行比较,并得出开放式耳机的音质不如入耳式的结论。不同的耳机类型都有各自的优势和劣势&…

常用HTML标签大全

🧑‍💻作者名称:DaenCode 🎤作者简介:啥技术都喜欢捣鼓捣鼓,喜欢分享技术、经验、生活。 😎人生感悟:尝尽人生百味,方知世间冷暖。 文章目录 一.HTML介绍二.HTML使用2.1.…

嵌入式开发学习(STC51-15-红外遥控)

内容 使用外部中断功能,使按下红外遥控器,将对应键值编码数据解码后通过数码管显示 红外遥控介绍 红外线简介 人的眼睛能看到的可见光按波长从长到短排列,依次为红、橙、黄、绿、青、蓝、紫; 其中红光的波长范围为 0.62&…

读发布!设计与部署稳定的分布式系统(第2版)笔记28_控制层上

1. 控制层囊括所有在后台运行的成功处理生产负载的软件和服务 1.1. 处理用户生产数据的那些软件,就是生产软件 1.2. 主要工作是管理其他软件的软件,就是控制层 1.3. 工具和问题之间存在着重叠和空白,并不是每个工具组合都能协同工作&#…

LeetCode 28题:找出字符串中第一个匹配项的下标

题目 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。 示例 1: 输入:haystac…

2023 8-5

430. 扁平化多级双向链表 前序遍历(递归) 脖子左歪45度,多级链表变成了二叉树,输出先序即可。 前序遍历再将结果存放在双向链表中,通过将链表存入节点来改变原来的节点 /* // Definition for a Node. class Node { public:int val;Node* prev;Node* next;Node* child; }; *…

springboot+maven插件调用mybatis generator自动生成对应的mybatis.xml文件和java类

mybatis最繁琐的事就是sql语句和实体类,sql语句写在java文件里很难看,字段多的表一开始写感觉阻力很大,没有耐心,自动生成便成了最称心的做法。自动生成xml文件,dao接口,实体类,虽一直感觉不太优…

百度秋招攻略,百度网申笔试面试详解

百度秋招简介 作为行业巨头,百度向社会提供的岗位一直都是非常吃香的,每年也都有很多考生密切关注,百度发布的招聘广告,以尽可能的让自己进入这家企业工作,实现自己的人生价值。那么百度每年的秋招时间是多久&#xf…

【ChatGPT 指令大全】怎么利用ChatGPT写报告

目录 选定切入角度 报告开头 大纲生成 草稿撰写 研究报告 提出反对观点 报告总结 研究来源 总结 随着人工智能技术的快速发展,自然语言处理技术在各个领域的应用越来越广泛。其中,ChatGPT作为目前最先进的自然语言处理模型之一,其强…

微信支付官方文档怎么看

博主介绍:✌全网粉丝3W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…

angular-mat-select 多选 实现按选择顺序排序

mat-select 正常情况下,多选后,已选项是按列表顺序进行排序,如果我想实现按照点击项目的顺序进行排序,我该如何做呢? [参考网址](Angular order of selected option in multiple mat-select - Stack Overflow) sortComparator是Angular Material中mat-select组件的一个属…

springboot第34集:ES 搜索,nginx

#用search after解决深分页性能问题 #第一页 GET /bank/_search {"size": 10,"sort": [{"account_number": {"order": "asc"}}] }#第二页 GET /bank/_search {"size": 10,"sort": [{"account_numb…

中国1km分辨率月最低温度数据集(1901-2021年)介绍

该数据为中国逐月最低温度数据,空间分辨率为0.0083333(约1km),时间为1901.1-2021.12。数据格式为NETCDF,即.nc格式。数据单位为0.1 ℃。该数据集是根据CRU发布的全球0.5气候数据集以及WorldClim发布的全球高分辨率气候…