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

news/2024/12/23 4:11:38/

目录

  • 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 d2lclass Residual(nn.Module):  #@savedef __init__(self, input_channels, num_channels,use_1x1conv=False, strides=1):super().__init__()# 可以设置stride=2self.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=2self.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 += Xreturn 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.ppmy.cn/news/1516550.html

相关文章

有效提高媒体曝光率,智能推荐为什么是“最大的计算系统之一”?

导语:我认为很少有人意识到,推荐系统是世界上构想过的最大的计算系统之一。——Jensen Huang  在信息过载的时代背景下,智能推荐系统已广泛应用于电子商务、社交媒体、新闻资讯、视频音乐、旅游出行等领域,为用户提…

计算机毕业设计推荐-基于python的新能源汽车销售数据可视化分析【python-爬虫-大数据定制】

💖🔥作者主页:毕设木哥 精彩专栏推荐订阅:在 下方专栏👇🏻👇🏻👇🏻👇🏻 实战项目 文章目录 实战项目 一、基于python的新能源汽车销售…

声音克隆GPT-SoVITS 2.0软件和详细的使用教程!

天命人,请允许我先蹭个热点! 原始声音: 播放 克隆声音: 播放 文章写了一半,被《黑神话悟空》刷屏了。突发奇想,用里面的声音来做个素材试试看。 B站捞了一点声音素材,随便剪一剪&#xff0c…

SSRF漏洞与redis未授权访问的共同利用

1.利用靶场Pikachu来认识SSRF漏洞 1.什么是SSRF SSRF漏洞允许攻击者通过向服务器发起请求来伪造请求。这种漏洞的核心在于攻击者能够控制服务器向任意目标地址发起请求,而这些请求通常是攻击者无法直接从客户端发起的。 简单来说,假设你的网站有一个功能…

C语言经典案例分享

题目:输入三个整数 x、y、z,请把这三个数由小到大输出。 程序分析:我们想办法把最小的数放到 x 上,先将 x 与 y 进行比较,如果 x>y 则将 x 与 y 的值进行交换,然后再用 x 与 z 进行比较,如果…

CMakeLists.txt文件编写学习总结

CMakeLists.txt文件编写学习总结 一、CMakeLists.txt基础知识1.1 基本结构1.2 主要命令cmake_minimum_requiredprojectadd_executableadd_libraryinclude_directoriestarget_include_directoriesfind_packagetarget_link_libraries 二、CMakelists 常用的变量2.1 CMake 预定义变…

二十三种模式之单例模式(基础了解)

1.设计模式的分类 创建型模式(五种):工厂方法模式、单例模式、抽象工厂模式、原型模式、建造者模式。结构型模式(七种):适配器模式、代理模式、装饰器模式、桥接模式、外观模式、享元模式、组合模式。行为型模式(十一种):状态模式、模板方法…

服务器机柜是什么意思?

服务器机柜主要是用来存放、保护和管理服务器设备的一个专用设备和设施,整体是一种类似于柜子的结构,通常是由金属材质多制成的,具有多个格子或者是槽位,用来安全和组织多台服务器,接下来小编就来具体介绍一下服务器机…