【学习笔记】【深度学习】ResNet残差网络

笔记参考视频
【6.1 ResNet网络结构,BN以及迁移学习详解】
https://www.bilibili.com/video/BV1T7411T7wa/?spm_id_from=333.788.videocard.0
【6.2 使用pytorch搭建ResNet并基于迁移学习训练】
https://www.bilibili.com/video/BV14E411H7Uw?t=316

ResNet网络结构

举例:34层网络中,第一层卷积层,然后池化层,有链接线的就是残差结构,最后通过一个平均池化下采样操作,再通过一个全连接层(输出层),基本结构就是堆叠残差结构。

网络中的亮点:

  1. 超深的网络结构(突破1000层)
  2. 提出residual模块
  3. 使用Batch Normalization加速训练(丢弃dropout)
    【疑问】为什么用很多卷积层和池化层叠加不能构建一个超深的神经网络?
    因为简单的这种堆叠效果并不会层数越深效果越好,产生问题的原因一是随着层数的加深,梯度消失或梯度爆炸的现象会更明显,另外还有精度退化问题
    通过残差网络可以解决以上问题
    在这里插入图片描述
针对层数较少和层数较多的残差结构比较
捷径和输入特征矩阵的高宽和深度需要保持一致,以为后续需要进行相加 左侧适用于层数较少的网络,右侧适用于层数较多的网络, 右侧加了1*1的卷积核,可以将深度为256的输入矩阵降维到64的矩阵,该卷积层是降维的作用 右侧方法显然节省了很多的特征向量-7万与左侧结构使用的特征向量118万比较,使用的残差结构越多,节省的参数就越多 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201119195903458.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mjg1MzQxMA==,size_16,color_FFFFFF,t_70#pic_center)
残差网络结构
【以上图中34层为例】7*7卷积层——最大池化下采样——Conv2_x对应**3层**残差结构——Conv3_x对应**4层**残差结构——Conv4_x对应**6层**残差结构——Conv5_x对应**3层**残差结构,——平均池化下采样——全连接层

实线和虚线的残差结构有什么不同?

实线部分的输入特征矩阵和输出特征矩阵的shape相同,能直接进行相加,
但是虚线残差结构中不能直接相加,输入结构是[56,56,64],输出结构是[28,28,128],可以通过stride=2将高和宽缩减为原来的一半,128可以将输入的卷积核(深度)从64变化为128

在这里插入图片描述

18层和34层中使用的残差结构——实线和虚线结构的对比

在这里插入图片描述

50、101、152更深层次中使用的残差结构——实线和虚线结构的对比

18层和34层的第一层种没有虚线残差结构,因为输入是[56,56,64]已经满足输入要求,但是对于更深层次的50、101和152,想要的输入结构是[56,56,256],所以更深层次的残差网络的第一层CON_2要有虚线结构

Batch Normalization

BN层,目的是使我们的一批(Batch)的feature map (特征矩阵)每一个channel所对应的维度满足均值为0,方差为1的分布规律
Batch Normalization能够加速网络的收敛并提升准确率,首先将图像数据进行预处理使其满足某一分布规律,进而加速处理
BN层就是使每一层的feature map 满足均值为0方差为1的分布规律

详解链接:https://blog.csdn.net/qq_37541097/article/details/104434557
在这里插入图片描述
在这里插入图片描述

迁移学习

概念:将已有网络的浅层的网络参数迁移到新的网络当中去,这样新的网络也具有识别底层通用特征的能力,就能更加快速的识别新的数据集的高维特征
优势:能快速训练一个理想的结果;当数据集较小时也能训练出理想的效果
在这里插入图片描述
在这里插入图片描述

使用pytorch搭建ResNet网络

代码地址:https://github.com/WZMIAOMIAO/deep-learning-for-image-processing/blob/master/pytorch_classification/Test5_resnet/model.py

少层次残差结构18、34

定义一个类:BasicBlock,对应的是18层和34层残差结构
参数expansion=1:表示每层中的卷积核个数有没有发生变化(如18和34中每个残差结构中的2个卷积层大小都一样)
初始化函数init

  1. 函数参数

in_channel:输入特征矩阵的深度;
out_channel:输出特征矩阵的深度(主分支上卷积核的个数)
stride (步数):默认取1
downsample(下采样参数):默认取None,对应的是虚线的残差结构——捷径中的1*1的卷积层
18层和34层中的con_3、con_4、con_5残差结构的第一层都是虚线结构,起到一个降维的作用

  1. con1:输入特征矩阵的深度、输出特征矩阵的深度、卷积核大小kernal_size=3、
    步距stride是传入的参数默认为1
    (stride=1时对应实线的残差结构,卷积处理不会改变高和宽
    stride=2时对应虚线的残差结构,卷积处理会使宽和高减半)
    padding默认为1
    bias=False就是不使用这个参数,因为这个层里使用了Batch Normalization,再使用bias是无用的
  2. 定义bn层,输入的参数对应上一层输出特征矩阵的深度
  3. 激活函数
  4. con2
    输入特征矩阵的深度、输出特征矩阵的深度、卷积核大小kernal_size=3、
    步距stride是传入的参数默认为1
    padding默认为1
    bias=False就是不使用这个参数
  5. 定义bn层
  6. 定义下采样方法
class BasicBlock(nn.Module):    
	expansion = 1

	def __init__(self, in_channel, out_channel, stride=1, downsample=None):        
		super(BasicBlock, self).__init__()        
		self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,kernel_size=3, stride=stride, padding=1, bias=False)        
		self.bn1 = nn.BatchNorm2d(out_channel)        
		self.relu = nn.ReLU()        
		self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel, kernel_size=3, stride=1, padding=1, bias=False)        
		self.bn2 = nn.BatchNorm2d(out_channel)        
		self.downsample = downsample
	# 定义正向传播函数	
	def forward(self, x):       
		identity = x        
		if self.downsample is not None:            
			identity = self.downsample(x)
		       
		out = self.conv1(x)        
		out = self.bn1(out)        
		out = self.relu(out)
		        
		out = self.conv2(out)        
		out = self.bn2(out)
		       
		out += identity        
		out = self.relu(out)
		        
		return out
	```
	以上对于18层和34层的残差结构定义完成

### 多层次残差结构50、101、152
定义一个BasicBlock类,
expansion=4对应残差结构所使用卷积核发生的变化,多层次残差结构中每个结构中第三层的卷积核个数是的第一层和第二层的卷积核的4**定义初始化函数**

```python
class Bottleneck(nn.Module):     
	expansion = 4
	
	def __init__(self, in_channel, out_channel, stride=1, downsample=None):       		
	    super(Bottleneck, self).__init__()        
	    self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel, kernel_size=1, stride=1, bias=False)  # squeeze channels        
	    self.bn1 = nn.BatchNorm2d(out_channel)        
	    # -----------------------------------------        
	    self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,kernel_size=3, stride=stride, bias=False, padding=1)        
	    self.bn2 = nn.BatchNorm2d(out_channel)        
	    # -----------------------------------------        
	    self.conv3 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel*self.expansion, kernel_size=1, stride=1, bias=False)  # self.expansion=4,第三层卷积核是第一二层的2倍
	    self.bn3 = nn.BatchNorm2d(out_channel*self.expansion)        
	    self.relu = nn.ReLU(inplace=True)        
	    self.downsample = downsample
	
	# 定义正向传播函数
	def forward(self, x):        
		identity = x        
		if self.downsample is not None:            
			identity = self.downsample(x)
	        out = self.conv1(x)        
	        out = self.bn1(out)        
	        out = self.relu(out)
	        
	        out = self.conv2(out)        
	        out = self.bn2(out)        
	        out = self.relu(out)
	        
	        out = self.conv3(out)        
	        out = self.bn3(out)
	        
	        out += identity        
	        out = self.relu(out)
	        
	        return out	
	
	```
### 	ResNet网络框架部分
block就是所对应的残差结构,会根据所定义的不同的结构传入不同的block,例如34层的block_num=[3,4,6,3]是个列表结构,num_classes是训练集的分类个数,include_top是方便在resnet网络上去搭建其他的网络
先定义输入特征矩阵的深度,in_channel=64
定义第一个7*7的卷积层con1,第一个3是输入特征矩阵的深度,也就是RGB图像,kernel_size=7,为了将高和宽缩减为原来的一半,padding=3
定义最大池化下采样层
self_layer1对应con_2中的一系列残差结构
self_layer2对应con_3中的一系列残差结构,以此类推

【自定义make_layer函数】
channel是第一层的卷积核的个数,block_num是指包含了多少个残差结构
这个if语句,18层和34层的第一层会直接跳过,但是多层次的就不会跳过,而且18层和34层的除第一层以外的也不会跳过这个函数,因为符合了stide=2,也就是不等于1的条件

这个for循环没有从0开始是因为第0层是虚线结构,第1层及往后都是实线结构,所以用for循环去实现
*layers中的 ***** 是将列表转化为非关键字参数的形式传入到sequential中                   

avgpool——平均池化下采样
fc—— 全连接                                                                                                                                                                                                                                                                                                                       
  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值