PyTorch深度学习实战(10)——过拟合及其解决方法

news2024/11/24 17:34:26

PyTorch深度学习实战(10)——过拟合及其解决方法

    • 0. 前言
    • 1. 过拟合基本概念
    • 2. 添加 Dropout 解决过拟合
    • 3. 使用正则化解决过拟合
      • 3.1 L1 正则化
      • 3.2 L2 正则化
    • 4. 学习率衰减
    • 小结
    • 系列链接

0. 前言

过拟合 (Overfitting) 是指在机器学习中,模型过于复杂而导致在训练数据上表现良好,但在新的未见过的数据上表现不佳的现象。直观的讲,可能会在训练过程中出现模型的训练准确率约为 100%,而测试准确率仅有 80% 左右的情况。在本文中,我们直观地介绍训练与测试准确率之间的差异的原因以及解决方法。

1. 过拟合基本概念

在《神经网络性能优化技术》中,我们经常看到这样的现象——训练数据集的准确率通常超过 95%,而验证数据集的准确率大约只为 89%。从本质上讲,这表明该模型在未见过的数据上的泛化程度不高,也表明模型正在学习训练数据集的异常数据,这些情况并不适用于验证数据集。
当模型过度关注于训练数据中的细节和噪音时,会导致过拟合。过拟合通常发生在模型复杂度过高、训练数据量较少或训练数据不平衡的情况下。当模型太过复杂时,它可能在训练数据中学习到了噪声和随机性,并将其视为普遍规律。当训练数据量较少时,模型可能没有足够的样本来全面学习数据的特征分布,从而容易出现过拟合。过拟合现象使得模型对训练数据中的个别特征过于敏感,而无法正确地推广到新的数据。可以使用以下策略降低模型过拟合的影响:

  • 增加训练数据的数量,确保数据集更加全面和多样化
  • 减少模型的复杂度,例如减少参数数量或使用正则化方法
  • 使用交叉验证等技术来评估模型的性能,并进行模型选择
  • 提前停止训练,即在模型开始过拟合之前停止迭代
  • 进行特征选择,删除不相关或冗余的特征
  • 数据预处理,例如归一化/标准化数据,处理异常值等

2. 添加 Dropout 解决过拟合

Dropout 是一种用于减少神经网络过拟合的正则化技术。在训练过程中,Dropout 会随机地将一部分神经元的输出置为 0 (即丢弃),从而降低神经网络对特定神经元的依赖性。具体来说,在每次训练迭代中,Dropout 会以一定的概率随机选择部分神经元,并将其输出置为 0,这意味着每个神经元都有一定的概率被“关闭”,从而迫使网络学习到更加鲁棒和独立的特征表示。

Dropout
通过引入 Dropout,神经网络无法过度依赖某些特定神经元,因为它们的输出可能随时被丢弃。这样可以有效地减少神经网络的复杂性,降低模型对训练数据的噪音和过拟合的敏感性,提高模型的泛化能力。在训练完成后,通常不再应用 Dropout,而是使用所有的神经元进行推理和预测。这是因为在测试阶段,我们希望模型能够充分利用所有可用的神经元来最大限度地提取特征和进行预测。
正常模型训练时,每次计算 loss.backward() 时,都更新模型权重。通常,神经网络中包含数以百万计的参数,因此可能虽然大多数参数有助于训练模型,但某些参数可能会针对训练图像进行微调,从而导致它们的值仅由训练数据集中的少数图像决定,这会导致模型在训练数据上具有较高精度,但在验证数据集上的泛化能力较差。
由于 Dropout 在训练和验证过程中具有不同操作,因此必须预先指定模型的模式为 model.train() (处于训练阶段)或 model.eval() (处于验证阶段)。
定义架构时,在 get_model() 函数中指定 Dropout 如下:

from torch.optim import SGD, Adam
def get_model():
    model = nn.Sequential(
        nn.Dropout(0.5),
        nn.Linear(28 * 28, 1000),
        nn.ReLU(),
        nn.Dropout(0.5),
        nn.Linear(1000, 10)
    ).to(device)

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

在以上代码中,还在线性激活前添加了 Dropout,训练和验证数据集的损失和准确率变化如下所示:

训练和验证数据集的损失和准确率变化
使用相同的架构,未使用 Dropout 时训练和验证数据集的损失和准确率变化如下所示:

训练和验证数据集的损失和准确率变化
可以看出,训练数据集和验证数据集的准确率之间的差异没有之前模型差距那么大,有效的降低了模型的过拟合。
绘制两种情况下隐藏层的权重直方图,可以看到使用 Dropout 时训练和测试准确率之间的差距低于没有 Dropout 时模型训练和测试准确率的差距:

隐藏层的权重直方图
隐藏层的权重直方图

3. 使用正则化解决过拟合

除了训练准确率远高于验证准确率外,过拟合的另一个特征是网络中的某些权重值显著高于其他权重值,高权重值可能是模型为了拟合训练数据中异常值的表现。正则化是一种惩罚模型中具有较高值的权重的技术,因此,需要同时最小化训练数据的损失以及权重值。在本节中,我们将学习两类正则化:

  • L1 正则化
  • L2 正则化

3.1 L1 正则化

L1 正则化计算如下:
在这里插入图片描述

L 1   l o s s = − 1 n ( ∑ i = 1 n ( y i ∗ l o g ( p i ) + ( 1 − y i ) ) + Λ ∑ j = 1 m ∣ w j ∣ ) L1\ loss=-\frac 1n(\sum_{i=1}^n(y_i*log(p_i)+(1-y_i))+\Lambda \sum_{j=1}^m|w_j|) L1 loss=n1(i=1n(yilog(pi)+(1yi))+Λj=1mwj)
上述公式的第一部分是在以上模型中用于优化的分类交叉熵损失,而第二部分是指模型权重值的绝对值之和, Λ \Lambda Λ 是用于平衡交叉熵损失和权重绝对值的权重系数。L1 正则化通过将权重的绝对值合并到损失值的计算中来确保它惩罚具有较高绝对值的权重,L1 正则化在训练模型的同时进行:

def train_batch(x, y, model, opt, loss_fn):
    prediction = model(x)
    l1_regularization = 0
    for param in model.parameters():
      l1_regularization += torch.norm(param,1)
    batch_loss = loss_fn(prediction, y) + 0.0001*l1_regularization
    batch_loss.backward()
    optimizer.step()
    optimizer.zero_grad()
    return batch_loss.item()

在以上代码中,首先初始化 l1_regularization,并对所有层的权重和偏置进行了正则化。torch.norm(param,1) 提供了权重和偏置值的绝对值。此外,使用一个非常小的权重系数 (0.0001) 来平衡参数绝对值之和对损失函数的影响。
使用 L1 正则化后,训练和验证数据集上的损失和准确率的变化如下所示:

损失和准确率的变化
可以看到训练数据集和验证数据集的准确率差异相比没有 L1 正则化时更小。

3.2 L2 正则化

L2 正则化计算如下:
在这里插入图片描述
L 2   l o s s = − 1 n ( ∑ i = 1 n ( y i ∗ l o g ( p i ) + ( 1 − y i ) ∗ l o g ( 1 − p i ) ) + Λ ∑ j = 1 m w j 2 ) L2\ loss =-\frac 1n(\sum_{i=1}^n(y_i*log(p_i)+(1-y_i)*log(1-p_i))+\Lambda \sum_{j=1}^mw_j^2) L2 loss=n1(i=1n(yilog(pi)+(1yi)log(1pi))+Λj=1mwj2)
其中,第一部分是指分类交叉熵损失,而第二部分是指模型权重值的平方和, Λ \Lambda Λ 是用于平衡交叉熵损失和权重平方和的权重系数。与 L1 正则化类似,通过将权重的平方和纳入损失计算来惩罚较高权重值。L2 正则化同样在训练模型的同时进行:

def train_batch(x, y, model, opt, loss_fn):
    prediction = model(x)
    l2_regularization = 0
    for param in model.parameters():
      l2_regularization += torch.norm(param,2)
    batch_loss = loss_fn(prediction, y) + 0.01*l2_regularization
    batch_loss.backward()
    optimizer.step()
    optimizer.zero_grad()
    return batch_loss.item()

在以上代码中,正则化的权重参数 (0.01) 略高于 L1 正则化,因为权重通常在 -11 之间,并且执行平方后会得到更小的结果值,如果权重参数较小,将导致在整体损失计算第二项的影响非常小。
使用 L2 正则化后,训练和验证数据集上的损失和准确率的变化情况如下所示:

损失和准确率的变化
可以看到 L2 正则化同样可以令验证和训练数据集的准确率和损失更接近。
最后,我们比较没有进行正则化和使用 L1/L2 正则化的权重,观察网络层的权重分布,如下图所示:

网络层的权重分布

可以看到,与不执行正则化相比,执行 L1/L2 正则化时参数的分布范围非常小,这可能会减少为异常数据更新权重的机会。
我们已经知道了较高的学习率在缩放和未缩放的数据集上均难以得到最佳结果,在下一节中,我们将学习如何在模型开始过拟合时自动降低学习率.

4. 学习率衰减

在以上模型中,我们在模型训练过程中使用恒定的学习率,但是,通常可以将权重快速更新到接近最佳状态,在模型训练后期可以进行缓慢的更新,因为模型训练初期的损失较高,而在后期损失较低。这就需要模型训练初期具有较高学习率,然后随着模型接近最佳的准确率,学习率也需要逐渐降低,因此我们这需要了解在何时降低学习率。
一种常用的方法是持续监控验证损失,如果验证损失在一段 epoch 内没有减少,就降低学习率。PyTorch 提供了调度方法 lr_scheduler,当验证损失在之前的 “x” 个 epoch 内没有减少时,降低学习率:

from torch import optim
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer,
                                                factor=0.5,patience=0,
                                                threshold = 0.001,
                                                verbose=True,
                                                min_lr = 1e-5,
                                                threshold_mode = 'abs')

在以上代码中,指定如果某个值在接下来的 nepoch (使用 patience参数指定)没有提高指定阈值(使用 threshold 参数指定),则学习率衰减为原来的 0.5 倍(即变为原来的 1/2,使用 factor 参数指定),且使用参数 min_lr 指定学习率的最小值 (不低于 1e-5),并且使用参数 threshold_mode 指定阈值模式(此处使用 abs,以确保超过指定的最小阈值)。接下来,在训练模型时应用 lr_scheduler,并在模型训练时监测验证损失:

trn_dl, val_dl = get_data()
model, loss_fn, optimizer = get_model()
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer,
                                                factor=0.5,
                                                patience=0,
                                                threshold = 0.001,
                                                verbose=True,
                                                min_lr = 1e-5,
                                                threshold_mode = 'abs')

train_losses, train_accuracies = [], []
val_losses, val_accuracies = [], []
for epoch in range(30):
    # print(epoch)
    train_epoch_losses, train_epoch_accuracies = [], []
    for ix, batch in enumerate(iter(trn_dl)):
        x, y = batch
        batch_loss = train_batch(x, y, model, optimizer, loss_fn)
        train_epoch_losses.append(batch_loss) 
    train_epoch_loss = np.array(train_epoch_losses).mean()

    for ix, batch in enumerate(iter(trn_dl)):
        x, y = batch
        is_correct = accuracy(x, y, model)
        train_epoch_accuracies.extend(is_correct)
    train_epoch_accuracy = np.mean(train_epoch_accuracies)
    for ix, batch in enumerate(iter(val_dl)):
        x, y = batch
        val_is_correct = accuracy(x, y, model)
        validation_loss = val_loss(x, y, model, loss_fn)
        scheduler.step(validation_loss)
    val_epoch_accuracy = np.mean(val_is_correct)
    train_losses.append(train_epoch_loss)
    train_accuracies.append(train_epoch_accuracy)
    val_losses.append(validation_loss)
    val_accuracies.append(val_epoch_accuracy)

在以上代码中,指定只要验证损失在连续的 epoch 内没有减少,就激活调度程序,学习率降低 0.5 倍,模型上执行调度程序输出如下:

Epoch     3: reducing learning rate of group 0 to 5.0000e-04.
Epoch     5: reducing learning rate of group 0 to 2.5000e-04.
Epoch     7: reducing learning rate of group 0 to 1.2500e-04.
Epoch    11: reducing learning rate of group 0 to 6.2500e-05.
Epoch    13: reducing learning rate of group 0 to 3.1250e-05.
Epoch    14: reducing learning rate of group 0 to 1.5625e-05.
Epoch    15: reducing learning rate of group 0 to 1.0000e-05.

训练和验证数据集的准确率和损失随时间变化如下:

请添加图片描述

通过使用调度程序,即使对模型进行了 30 个(或更多) epoch 的训练,也没有严重的过拟合问题,这是因为当学习率衰减的极小时,权重的更新也变得非常小,因此训练和验证准确率之间的差距也非常小。

小结

过拟合是指机器学习模型在训练集上表现很好,但在测试集或未见过的数据上表现较差的现象。过拟合是由于模型在训练过程中过度拟合了训练数据的特点和噪声,导致了对训练样本的过度依赖和泛化能力不足。为了解决过拟合问题,选择适当的方法需要对具体问题和数据进行分析,并在模型构建和调优过程中进行实验和验证。在实践中,通常需要权衡模型的复杂度和泛化能力,以获得更好的结果。

系列链接

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

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

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

相关文章

问题解决方案

前端开发 1、npm安装的时候老是卡住 reify:rxjs: timing reifyNode:node_modules/vue/cli/node_modules 查看当前使用的那个镜像 nrm lsnpm ---------- https://registry.npmjs.org/yarn --------- https://registry.yarnpkg.com/cnpm --------- https://r.cnpmjs.org/taobao …

推荐系统工作小结

最初的构想 由于我们的技术团队中并没有人真正用大数据的方法做过推荐系统。所以我们定的步骤是先解决有没有的问题。然后再持续地进行效果优化的工作。 现状 但一方面考虑到要快速上线。另一方面也希望对推荐系统的效果有一个合理的参照。我们打算先使用达观数据的推荐系统云…

无涯教程-Perl - endpwent函数

描述 此功能告诉系统您不再希望使用getpwent从密码文件读取条目。在Windows下,使用Win32API::Net函数从域服务器获取信息。 语法 以下是此函数的简单语法- endpwent返回值 此函数不返回任何值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perlwhile(($name, $pas…

不知道ai绘画工具有哪些?那就赶紧把这些AI绘画工具收藏下来

近年来,AI技术的发展很快,在很多领域都取得了新的进展,这其中也包括了绘画领域。 最近,我看到了几幅用AI生成的图片,被深深地吸引住了。 所以,我就去找了几个AI绘画工具尝试制作AI图片。 尝试完之后发现…

论文解读|使用深度卷积网络的图像超分辨率

原创 | 文 BFT机器人 论文标题:Image Super-Resolution Using Deep Convolutional Networks 网址:https://arxiv.org/abs/1501.00092 代码:https://github.com/Edwardlzy/SRCNN 01 摘要 提出了一种单幅图像超分辨率(SR&#x…

docker菜谱

DockerHub:https://hub.docker.com/ 记录docker常用软件安装,欢迎大家投稿。😎😎😎 文章目录 1. Redis 1. Redis 1、下载redis镜像: docker pull redis:6.2.8 docker pull redis:7.0.02、启动容器&#x…

python入门篇01- 安装python必备环境和helloworld书写

目录 1. 前言简介 1.1 python简介: 1.1.1 Python是一种高级编程语言, 1.1.2 Python的命名是受到了英国喜剧团体Monty Python的启发。 1.1.3从1990年开始,Python获得了一些用户 1.2 python与java的区别 2. python书写helloworld 2.1 安装pytho…

pytorch求导

pytorch求导的初步认识 requires_grad tensor(data, dtypeNone, deviceNone, requires_gradFalse)requires_grad是torch.tensor类的一个属性。如果设置为True,它会告诉PyTorch跟踪对该张量的操作,允许在反向传播期间计算梯度。 x.requires_grad 判…

选择移动CRM需必备哪几大功能?

随着信息技术的飞速发展,移动CRM成为企业数字化转型的必备工具。本文将探讨移动CRM主要功能有哪些?帮助大家在CRM选型中少走弯路,认识移动CRM可以做哪些事。 1.整合客户数据 移动CRM的首要功能是帮助企业轻松采集和整合客户数据。通过移动设…

基于Java+SpringBoot制作一个智能用电小程序

在当今快节奏的生活中,高效利用能源变得越来越重要。制作一个智能用电小程序,旨在帮助您更智能地管理家庭电器的用电,从而提升能源利用效率,助您掌握用电情况,降低能耗成本,实现绿色低碳生活。 目录 一、小程序1.1 项目创建1.2 首页轮播图快捷导航iconfont图标引入

【LeetCode 75】第二十三题(2352)相等行列对

目录 题目: 示例: 分析: 代码运行结果: 题目: 示例: 分析: 题目很简洁,就是要我们寻找行与列相同的对数。相同行与列不仅是要元素相同,还需要顺序也一样&#xff08…

Apipost接口自动化测试入门

今天我们来聊一聊接口自动化测试。以往我们都是以以代码的形式编写自动化测试脚本做自动化测试,网上也有非常多的攻略,那么在不会代码的情况下该怎么做接口自动化呢,今天给大家介绍Apipost自动化测试模块,不用写代码也能做接口自动…

ROS获取IMU的数据

消息格式 上ROS官网查看👉ROS ROS官网给定的主题,一般我们使用第二个。   实现思路 (1)maweiUbuntu:~/catkin_ws/src$ catkin_create_pkg imu_pkg roscpp rospy sensor_msgs 实现代码👇   //imu_node.cpp #in…

云知识库软件的推荐清单,你看看你喜欢哪一个?

在选择云知识库软件时,有很多因素需要考虑,如功能、易用性、可定制性、安全性、价格等。下面是一些我喜欢的云知识库软件推荐清单: Confluence: Confluence是一款由Atlassian开发的知识管理和协作工具。它提供了强大的编辑和协作…

P1144 最短路计数(SPFA)(内附封面)

最短路计数 题目描述 给出一个 N N N 个顶点 M M M 条边的无向无权图,顶点编号为 1 ∼ N 1\sim N 1∼N。问从顶点 1 1 1 开始,到其他每个点的最短路有几条。 输入格式 第一行包含 2 2 2 个正整数 N , M N,M N,M,为图的顶点数与边数…

小程序裂变怎么做?小程序裂变机制有哪些?

做了小程序就等于“生意上门”?其实并不是这样。小程序跟流量平台较为明显的区别就在于小程序并非“自带流量”,而是需要企业利用自己的营销推广能力来建立引流渠道,从而完成用户的拉新和留存、转化。因此,想要用小程序来增加自己…

国内首届“熵密杯”密码应用安全竞赛 | 赛宁网安全面保障

​​为进一步提升商用密码合规、正确、有效的应用意识,提高密码应用安全防护水平,由中国密码学会支持,2023商用密码大会执委会主办,南京赛宁信息技术有限公司提供技术支撑的首届“熵密杯”密码应用安全竞赛将于8月10日在郑州举办。…

python基于自己模型数据集和权重混淆矩阵生成

混淆矩阵(Confusion Matrix)是用于评估分类模型性能的一种表格形式。它显示了在分类问题中模型的预测结果与实际标签之间的各种组合情况。 混淆矩阵通常用于二分类问题,但也可以扩展到多分类问题。对于二分类问题,它由四个重要的…

dotNet 之网络TCP

**硬件支持型号 点击 查看 硬件支持 详情** DTU701 产品详情 DTU702 产品详情 DTU801 产品详情 DTU802 产品详情 DTU902 产品详情 G5501 产品详情 ARM dotnet 编程 dotNet使用TCP,可以使用Socket和TcpClient 、TcpListener类 2种,对于高级用户&…

win11下docker安装testsigma自动化测试平台教程

Testsigma是一个基于云端的、支持测试左移的、以AI驱动测试的自动化平台,适用于Web、移动应用以及RESTful服务等各种应用的测试服务。 一、如何开始使用? 有三种方式:1、直接使用 Testsigma Cloud(目前已经不开放个人邮箱注册&am…