深度学习----------------------残差网络ResNet

news2024/11/18 5:39:52

目录

  • ResNet
    • 加更多的层总是改进精度吗?
    • 残差块
    • ResNet块细节
    • 不同的残差块
    • ResNet块
    • ResNet架构
    • 总结
  • ResNet代码实现
    • 残差块
    • 输入和输出形状一致
    • 增加输出通道数的同时,减半输出的高和宽
    • ResNet模型
    • 观察ResNet中不同模块的输入形状是如何变化的
    • 训练模型
  • 问题
  • ResNet为什么能训练出1000层的模型?
    • ResNet是这样解决的
  • 问题

ResNet

在这里插入图片描述




加更多的层总是改进精度吗?

在这里插入图片描述

虽然 F 6 F_6 F6这个模型更加复杂了,但是实际上可能学偏了,学到的可能不如小模型的最优点近。

那么应该怎么做呢?
就是说每一层增加模型的复杂度,将包含前一层模型(即: F 2 F_2 F2包含 F 1 F_1 F1)。如右边图。所以学到的模型比之前的模型更大,所以不会比之前的更差。(函数的大小代表着它的复杂程度)




残差块

串联一个层改变函数类,我们希望能扩大函数类
残差块加入快速通道(右边)来得到f(x)=x+g(x)的结构

在这里插入图片描述




ResNet块细节

在这里插入图片描述
1×1的卷积是为了变换通道,为了最后能够进行相加。

假设卷积层要对通道进行变换,那么没加1×1的卷积就加不回去了。加入了1×1的卷积来把通道数变到合适的范围能够按照原数相加。

在这里插入图片描述




不同的残差块

在这里插入图片描述




ResNet块

高宽减半ResNet块(步幅2)
后接多个高宽不变ResNet块

虚线框的叫ResNet块。
在这里插入图片描述

进入第一步将高宽减半,然后通道数增加1倍。右边的1×1卷积将输入的通道数也增加1倍。

在这里插入图片描述




ResNet架构

类似VGG和GoogleNet的总体框架,但替换成了ResNet块。

在这里插入图片描述

下面的152是指包含152个卷积层,层数越少越快。
在这里插入图片描述




总结

    ①残差块使得很深的网络更加容易训练
        甚至可以训练一千层的网络

    ②残差网络对随后的深度神经网络设计产生了深远影响,无论是卷积类网络还是全连接类网络




ResNet代码实现

残差块

import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l
 
 
class Residual(nn.Module):  #@save
    def __init__(self, input_channels, num_channels,
                 use_1x1conv=False, strides=1):
        super().__init__()
        # 可以设置stride=2
        self.conv1 = nn.Conv2d(input_channels, num_channels,
                               kernel_size=3, padding=1, stride=strides)
        # 第一个参数,这里它接收的是self.conv1的输出通道数,意味着self.conv2的输入通道数与self.conv1的输出通道数相同。
        self.conv2 = nn.Conv2d(num_channels, num_channels,
                               kernel_size=3, padding=1)
        # 如果存在一个额外的卷积层,它主要用于调整输入X的通道数,使其与self.conv2的输出通道数相匹配
        if use_1x1conv:
            # 可以设置stride=2
            self.conv3 = nn.Conv2d(input_channels, num_channels,
                                   kernel_size=1, stride=strides)
        else:
            self.conv3 = None
        # 定义两个批归一化层self.bn1和self.bn2,用来加速训练过程。
        self.bn1 = nn.BatchNorm2d(num_channels)
        self.bn2 = nn.BatchNorm2d(num_channels)
        self.relu = nn.ReLU(inplace=True) # inplace原地操作,不创建新变量,对原变量操作,节约内存

 
    def forward(self, X):
        Y = F.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        if self.conv3:
            X = self.conv3(X)
        Y += X
        return F.relu(Y)



输入和输出形状一致

blk = Residual(3,3)
X = torch.rand(4, 3, 6, 6)
Y = blk(X)
print(Y.shape)

结果:
在这里插入图片描述




增加输出通道数的同时,减半输出的高和宽

# 输入通道数为3,输出通道数为6,原先是3将它增加到6则输出的高和宽将会减半
blk = Residual(3,6, use_1x1conv=True, strides=2)
print(blk(X).shape)

结果:
在这里插入图片描述




ResNet模型

ResNet:

在这里插入图片描述
GoogLeNet:
在这里插入图片描述

    ResNet的前两层跟之前介绍的GoogLeNet中的一样:

# 第一个卷积层接受1个通道(例如灰度图像)的输入,并输出64个特征图(或称为通道)。
# 在输出通道数为64、步幅为2的 7×7 卷积层后,接步幅为2的 3×3 的最大池化层。
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
                   nn.BatchNorm2d(64), nn.ReLU(),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
                   #减少特征图的高度和宽度,并通过1的填充来稍微保持空间信息。
                   

    GoogLeNet在后面接了4个由Inception块组成的模块。
     ResNet则使用4个残差块组成的模块,每个模块使用若干个同样输出通道数的残差块。第一个模块的通道数同输入通道数一致。由于之前已经使用了步幅为2最大池化层,所以无须减小高和宽。之后的每个模块在第一个残差块里将上一个模块的通道数翻倍,并将高和宽减半。

# resnet_block函数用于生成一个阶段的残差块列表。第三个参数是残差块的数量,后面我们都使用的是2
def resnet_block(input_channels, num_channels, num_residuals,
                 first_block=False):
    blk = []
    # 在循环中,对于每个残差块,如果它不是阶段中的第一个块且不是第一个阶段的第一个块(通过not first_block判断),则使用strides=2的Residual来减半特征图的高度和宽度。
    for i in range(num_residuals):
    	# 这里的first_block就是b2,b2作为第一阶段
        if i == 0 and not first_block:
            blk.append(Residual(input_channels, num_channels,
                                use_1x1conv=True, strides=2))
        else:
            blk.append(Residual(num_channels, num_channels))
    return blk

问题:预备阶段b1高宽减半,第一阶段b2第一块为什么不减少高宽,第二阶段b3,第三阶段b4,第四阶段b5又减少高宽了呢?
由于b1(b1通常不被视为一个单独的“阶段”,而是作为网络的预处理部分)已经完成了特征图的尺寸减少。
b2作为第一个阶段,其第一个残差块不会改变特征图的尺寸,因为前面已经减半已经很多了。
b3、b4、b5等后续阶段继续减少特征图尺寸是为了适应网络结构的深层设计、减少计算量。

    接着在ResNet加入所有残差块,这里每个模块使用2个残差块。


# b2作为第一个阶段,其第一个残差块不会改变特征图的尺寸(因为first_block=True)。
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))

    最后,与GoogLeNet一样,在ResNet中加入全局平均池化层,以及全连接层输出。

net = nn.Sequential(b1, b2, b3, b4, b5,
                    nn.AdaptiveAvgPool2d((1,1)),
                    nn.Flatten(), nn.Linear(512, 10))

    每个模块有4个卷积层(不包括恒等映射的 1×1 卷积层)。加上第一个 7×7 卷积层和最后一个全连接层,共有18层。 因此,这种模型通常被称为ResNet-18。如下图:

在这里插入图片描述
    通过配置不同的通道数和模块里的残差块数可以得到不同的ResNet模型,例如更深的含152层的ResNet-152。 虽然ResNet的主体架构跟GoogLeNet类似,但ResNet架构更简单,修改也更方便。这些因素都导致了ResNet迅速被广泛使用。




观察ResNet中不同模块的输入形状是如何变化的

X = torch.rand(size=(1, 1, 224, 224))
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__,'output shape:\t', X.shape)

结果:
批量大小、通道数、高度、宽度

在这里插入图片描述
①第一步经过一个conv,第二步经过一个max pooling其中步幅都为2,所以224/2/2=56。

②没有进行高宽减半所以没有变化

③进行减半(strides=2)

④进行减半(strides=2)

⑤进行减半(strides=2)

⑥AdaptiveAvgPool2d设置的高宽为1×1

⑦经过展平层,只剩下参数批量大小和所有通道数的总和。

⑧固定输出为10,即:只有10种类别




训练模型

lr, num_epochs, batch_size = 0.05, 10, 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=96)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

结果:
在这里插入图片描述




问题

①为什么LeNet 的batch size大于1000收敛会比较慢?
batch size等于1000的时候,里面大部分图片都是很相似的图片,所以重复的图片在重复计算,所以会导致收敛进度。

②f(x)=x+g(x),这样就能保证至少不会变坏吗?如果g(x)不是变好,而是变坏呢?
训练g(x),模型发现g(x)很难训练或者训练没什么好处的话,它就拿不到梯度。加上g(x)对loss下降没什么明显的话,它在做梯度反传的时候拿不到什么梯度,所以它的权重不会被更新,很可能是一个很小的权重,所以不会有什么贡献。(有梯度下降在,最次就是0作用,不可能负作用。)

③ResNet实现里最后* ResNet_Block里 * 号是什么意思?
* 是把python中的list展开,ResNet_Block是一个list,* 号就是把list展开成一堆的输入。




ResNet为什么能训练出1000层的模型?

ResNet是怎么处理梯度消失使得训练出1000层的模型?
避免梯度消失(方法一):将乘法变加法,ResNet就是这么做的。

x是输入,y是输出,f其中的变换(例:10个卷积层的样子)。里面有个w是要进行更新的,计算梯度的话

在这里插入图片描述
在这里插入图片描述
假设在这个网络上面的一层再加一层会怎么样?
假设f为10层卷积层,这个g的意思是在这10层上面再加10层。

在这里插入图片描述
在这里插入图片描述

假设新加的层拟合能力比较强的话,下面这个会很快变得特别小。可以简单认为它的导数等价于你的预测值和真实值之间的差别是有一定的关系的。假设预测的比较好的情况下,则下面的值会变得比较小。如果它很小的话,一个很小的值乘之前的梯度,那么梯度会比之前小很多。梯度小很多的话,要么增大学习率(但很有可能增大也没有太多用,因为不能增的太大,因为这是对于靠近数据底部层的更新,如果增的太大的话可能会不稳定。)
在这里插入图片描述

ResNet是这样解决的

y"=本来来自于下一层网络的输入在加上g(f(x))

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
假设这个值很小的话
在这里插入图片描述
最差也等于下面这个
在这里插入图片描述

ResNet能够有效训练深层(1000层)的关键是:将乘法运算改为加法运算(残差连接),从而避免底层的梯度消失,使得最靠近数据的层的权重也能够获得较大的梯度(大数+小数=大数,大数×小数=小数),深层网络得以有效更新。




问题

学习率可不可以让靠近输出的小一些,靠近输入的大一些,这样会不会就可以缓解梯度消失的问题?
可以的,但是不是那么好设置,就是不知到靠近输入设置多大,靠近输出设置多大点。

为什么深层的网络,底层比较难训练?是因为它拿到的梯度一般比较小?
是的

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

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

相关文章

JRE和JDK概念区分

1.JRE Java Runtime Environment:java运行环境。JVMJava类库。开发好的java程序,直接运行,可只安装JRE。 2.JDK Java Development Kit:java软件开发工具包。JREJava开发工具。编译、运行java代码。 3.总结 JRE就是运行Java字…

制作网页底部以及<footer>置底

目录 前言 页脚置底 页脚置底的几种方法 使用calc()设置内容高度 使用flex布局 将内容部分的margin-bottom改为负值【不推荐】 一个网页底部Demo HTML部分: CSS部分: 效果: 其他说明 margin负值特性 下面以一个具体的例子来说明…

Edge-TTS:微软推出的,免费、开源、支持多种中文语音语色的AI工具[Python代码]

Edge-TTS,由微软推出的这款免费、开源的AI工具,为用户带来了丰富多样的中文语音体验。它不仅支持多种中文语音语色,还能实现流畅自然的语音合成。Edge-TTS凭借其高度可定制化的特点,广泛应用于智能助手、语音播报、教育培训等领域…

加速自动驾驶模型迭代,数据存算一体是关键

自动驾驶的每一个业务阶段都会涉及到 AI 深度学习算法和算力的参与,机器视觉,深度学习,传感器技术等均在自动驾驶领域发挥着重要的作用。自动驾驶系统不断迭代的前提是算法的持续优化,目前,自动驾驶发展的瓶颈主要在于…

【笔记】0基础python学爬虫(未完)

(一)用requests发送get请求 安装好pycharm(跳过) 在本地控制台输入pip install requests 安装requests模块 with防止资源浪费 不论f文件有没有执行成功最后都会关闭 请求获取url resp requests.get(url) resp.text获取源代码…

Redis的持久化、主从架构、哨兵高可用架构

目录 1.Redis持久化 1.1 RDB快照 1.2AOF 1.3混合持久化 2.Redis主从架构 2.1主从工作原理 2.1.1全量复制 2.1.2增量复制 3.Redis哨兵高可用架构 3.1哨兵架构模型 3.2哨兵模式的作用 3.3故障转移机制 3.4主节点选举机制 4.Redis管道-pipeline 1.Redis持久化 有两种…

MyBatis-Plus 一、(基础应用)

MyBatis-Plus(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 mybatis 、mybatis-plus 二者区别: MyBatis: 所有SQL语句全部自己写手动解析实…

EPCE-HDR

【GitHub】 【Paper】 摘要 由于相机能力的限制,数字图像通常比真实场景辐射更窄的动态光照范围。为了解决这个问题,高动态范围(HDR)重建被提出,以恢复动态范围,更好的表示真实世界的场景。然而&#xff0c…

haproxy编译安装

一、haproxy简介 HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。 HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬…

Ubuntu 22.04中MySQL 8 设置忽略大小

Ubuntu 22.04中MySQL 8 设置忽略大小 一、解决完整流程 //根据官网内容说的大概意思就是不能安装完了修改忽略大小写了,只能在初始化的时候做修改。我用的版本是8.0.39//更新软件包 1、sudo apt update //安装MySQL 如果安装了可以忽略这个步骤 2、sudo apt insta…

【计算机三级-数据库技术】数据库及数据库对象

数据库及数据库对象 第一节 创建及维护数据库 一、SQL server数据库分类 1)系统数据库(系统自动创建): master、msdb、tempdb、model、resource 2)用户数据库 保存与用户业务有关的数据。 二、SQL server数据库组成…

【660线代】线性代数一刷错题整理

线代一阶 2024.8.7日 1. 2. 2024.8.8日 1. 2024.8.9日 1. 2. 3. 2024.8.12日 1. 2. 2024.8.13日 1. 2. 3. 2024.8.15日 1. 2. 3. 4. 5. 6. 线代二阶 2024.8.17日 1. 2. 3. 2024.8.18日 1. 至此,660线性代数部分完成。 祝各位一战成硕!

鸿蒙关于可以实现滚动效果的容器组件的相关知识

一、滚动的用途 生活中,我们在使用各种APP应用的过程中,总是可以看到一些轮播图、内容页面的滑动、组件切换的效果等,这些都是为了提高用户的体验而设计的功能。在编程中,滚动的用途非常广泛,我们经常用在用户界面的交…

Umi-OCR 文字识别工具

免费开源的离线orc识别功能 git地址 感谢大佬的贡献 Umi-OCR 文字识别工具 使用说明 • 下载地址 • 更新日志 • 提交Bug 免费,开源,可批量的离线OCR软件 适用于 Windows7 x64 、Linux x64 免费:本项目所有代码开源&#x…

C++ 程序寻找通过 2 个点的线(Program to find line passing through 2 Points)

在数学和计算机科学中,找到通过两个点的线的方程是一个基础问题。假设我们有两个点 P1​(x1​,y1​) 和 P2​(x2​,y2​),我们想要找到通过这两个点的直线方程。 直线方程的形式 直线的方程通常表示为 ymxb,其中 m 是斜率,b 是 …

PMP核心知识点—之项目管理基础

知识点1:项目的临时性 项目的临时性是指项目有明确的开始时间和结束时间,但并不能表示项目的周期短,项目的周期从几个月、几年到几十年都有。 知识点2:项目的独特性 独特的产品、服务或成果。 知识点3:项目创造商业价值…

ARCGIS 纸质小班XY坐标转电子要素面

1、准备好excel 坐标 小班号、点位链接的顺序、X、Y 4个缺一不可,需要注意的是,点位顺序的格式最好为数字,若为其他格式可能会出现排序混乱,会以1-9 11-19等字符串的排序连接。 excel文件转为csv才能识别,CSV只能保留第…

错过了游科的黑神话?别急,国内这些公司也在招聘中,都是做3A游戏的,速来!

近日,由游戏科学工作室打造的3A游戏——《黑神话:悟空》,不仅在国内引起了前所未有的关注,在全球范围内也引发了巨大轰动。 游戏玩家们举国欢庆的同时,无数游戏从业者也点燃了对国产3A游戏的憧憬与期待! 据说游科在某…

Java 通用代码生成器光,电音之王尝鲜版八,完善数据库自动反射功能和多对多候选功能

Java 通用代码生成器光,电音之王尝鲜版八,完善数据库自动反射功能和多对多候选功能 Java 通用代码生成器光,电音之王尝鲜版八,此版本完善了数据库自动反射功能。完善了多对多候选功能。尝鲜版八在以前的版本上修复了大量缺陷和功…

PDF文件切割,无大小限制

前言 公司让学习一个东西,让写一个学习总结,我想这不是AI的拿手好戏,直接把近100M的PDF喂给他,然后他说吃不下,太大了 小事,那么多在线PDF工具网站,分分钟拆开,然后找了半天也都是…