【PyTorch】3-基础实战(ResNet)

devtools/2024/9/19 6:42:36/ 标签: pytorch, 人工智能, python

PyTorch:3-基础实战

注:所有资料来源且归属于thorough-pytorch(https://datawhalechina.github.io/thorough-pytorch/),下文仅为学习记录

3.1:ResNet基本介绍

退化现象(degradation):增加网络层数的过程中,随着训练准确率逐渐饱和,继续增加层数,训练准确率出现下降的现象。且这种下降不是过拟合。

快捷连接(shortcut connection):将输入直接连接到后面的层,一定程度缓解了梯度消失和梯度爆炸,消除深度过大导致神经网络训练困难的问题。

梯度消失和梯度爆炸的根源:DNN结构,和,反向传播算法

梯度爆炸:网络层之间的梯度(值大于 1.0)重复相乘导致的指数级增长

梯度消失:网络层之间的梯度(值小于 1.0)重复相乘导致的指数级变小

3.2:torchvision的源代码

卷积核封装

封装3x3和1x1卷积核

python">def conv3x3(in_planes: int, out_planes: int, stride: int = 1, groups: int = 1, dilation: int = 1) -> nn.Conv2d:"""3x3 convolution with padding"""return nn.Conv2d(in_planes,			# 输入通道数out_planes,			# 输出通道数kernel_size=3,		# 卷积核尺寸stride=stride,		# 步长padding=dilation,	# 填充groups=groups,		# 分组bias=False,			# 偏移量dilation=dilation,	# 空洞卷积的中间间隔)def conv1x1(in_planes: int, out_planes: int, stride: int = 1) -> nn.Conv2d:"""1x1 convolution"""return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)# 解释同上

基本模块设计

ResNet常见的大小有ResNet-18,ResNet-34,ResNet-50、ResNet-101和ResNet-152,其中网络后面的数字代表的是网络的层数

两个基本模块:BasicBlock和BottleNeck

两个block类输入一个通道为in_planes维的度特征图,输出一个planes*block.expansion维的特征图,其中planes的数目大小等于in_planes。

支路上的downsample操作:对shortcut支路进行大小或维度上的调整。

shortcut connection

【1】同等维度的映射:输入输出直接相加
F ( x ) + x F(x)+x F(x)+x
【2】不同维度的映射:给x补充一个线性映射来匹配维度(通常是1x1卷积)

basic block

BasicBlock模块用来构建resnet18和resnet34

python">class BasicBlock(nn.Module):expansion: int = 1def __init__(self,inplanes: int,planes: int,stride: int = 1,downsample: Optional[nn.Module] = None,groups: int = 1,base_width: int = 64,dilation: int = 1,norm_layer: Optional[Callable[..., nn.Module]] = None,) -> None:super().__init__()if norm_layer is None:norm_layer = nn.BatchNorm2dif groups != 1 or base_width != 64:raise ValueError("BasicBlock only supports groups=1 and base_width=64")if dilation > 1:raise NotImplementedError("Dilation > 1 not supported in BasicBlock")# Both self.conv1 and self.downsample layers downsample the input when stride != 1self.conv1 = conv3x3(inplanes, planes, stride)self.bn1 = norm_layer(planes)self.relu = nn.ReLU(inplace=True)self.conv2 = conv3x3(planes, planes)self.bn2 = norm_layer(planes)self.downsample = downsampleself.stride = stridedef forward(self, x: Tensor) -> Tensor:identity = x  			# 备份out = self.conv1(x)  	# 对x做卷积 out = self.bn1(out)  	# 对x归一化 out = self.relu(out)  	# 对x用激活函数out = self.conv2(out)  	# 对x做卷积out = self.bn2(out)  	# 归一化if self.downsample is not None:identity = self.downsample(x)out += identity  		# 进行downsampleout = self.relu(out)return out
bottle neck

BottleNeck模块用来构建resnet50,resnet101和resnet152

python">class Bottleneck(nn.Module):expansion: int = 4  # 对输出通道进行倍增def __init__(self,inplanes: int,planes: int,stride: int = 1,downsample: Optional[nn.Module] = None,groups: int = 1,base_width: int = 64,dilation: int = 1,norm_layer: Optional[Callable[..., nn.Module]] = None,) -> None:super().__init__()if norm_layer is None:norm_layer = nn.BatchNorm2dwidth = int(planes * (base_width / 64.0)) * groups# Both self.conv2 and self.downsample layers downsample the input when stride != 1self.conv1 = conv1x1(inplanes, width)self.bn1 = norm_layer(width)self.conv2 = conv3x3(width, width, stride, groups, dilation)self.bn2 = norm_layer(width)self.conv3 = conv1x1(width, planes * self.expansion)self.bn3 = norm_layer(planes * self.expansion)self.relu = nn.ReLU(inplace=True)self.downsample = downsampleself.stride = stride# Bottleneckd forward函数和BasicBlock类似def forward(self, x: Tensor) -> Tensor:identity = xout = 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)if self.downsample is not None:identity = self.downsample(x)out += identityout = self.relu(out)return out

网络整体结构

python">class ResNet(nn.Module):def __init__(self,block: Type[Union[BasicBlock, Bottleneck]], # 选择基本模块layers: List[int],							# 每一层block的数目构成 -> [3,4,6,3]num_classes: int = 1000, 					# 分类数目zero_init_residual: bool = False, 			# 初始化#######其他卷积构成,与本文ResNet无关######groups: int = 1,width_per_group: int = 64,replace_stride_with_dilation: Optional[List[bool]] = None,#########################################norm_layer: Optional[Callable[..., nn.Module]] = None, # norm层) -> None:super().__init__()_log_api_usage_once(self)if norm_layer is None:norm_layer = nn.BatchNorm2dself._norm_layer = norm_layerself.inplanes = 64 # 输入通道#######其他卷积构成,与本文ResNet无关######self.dilation = 1 # 空洞卷积if replace_stride_with_dilation is None:# each element in the tuple indicates if we should replace# the 2x2 stride with a dilated convolution insteadreplace_stride_with_dilation = [False, False, False]if len(replace_stride_with_dilation) != 3:raise ValueError("replace_stride_with_dilation should be None "f"or a 3-element tuple, got {replace_stride_with_dilation}")self.groups = groupsself.base_width = width_per_group#########################################self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False)self.bn1 = norm_layer(self.inplanes)self.relu = nn.ReLU(inplace=True)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)# 通过_make_layer带到层次化设计的效果self.layer1 = self._make_layer(block, 64, layers[0])  # 对应着conv2_xself.layer2 = self._make_layer(block, 128, layers[1], stride=2, dilate=replace_stride_with_dilation[0])  # 对应着conv3_xself.layer3 = self._make_layer(block, 256, layers[2], stride=2, dilate=replace_stride_with_dilation[1])  # 对应着conv4_xself.layer4 = self._make_layer(block, 512, layers[3], stride=2, dilate=replace_stride_with_dilation[2])  # 对应着conv5_x# 分类头self.avgpool = nn.AdaptiveAvgPool2d((1, 1))self.fc = nn.Linear(512 * block.expansion, num_classes)# 模型初始化for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity="relu")elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)if zero_init_residual:for m in self.modules():if isinstance(m, Bottleneck) and m.bn3.weight is not None:nn.init.constant_(m.bn3.weight, 0)  # type: ignore[arg-type]elif isinstance(m, BasicBlock) and m.bn2.weight is not None:nn.init.constant_(m.bn2.weight, 0)  # type: ignore[arg-type]# 层次化设计def _make_layer(self,block: Type[Union[BasicBlock, Bottleneck]], # 基本构成模块选择planes: int,  								# 输入的通道blocks: int, 								# 模块数目stride: int = 1, 							# 步长dilate: bool = False, 						# 空洞卷积,与本文无关) -> nn.Sequential:norm_layer = self._norm_layerdownsample = None 							# 是否采用下采样####################无关#####################previous_dilation = self.dilation if dilate:self.dilation *= stridestride = 1#############################################if stride != 1 or self.inplanes != planes * block.expansion:downsample = nn.Sequential(conv1x1(self.inplanes, planes * block.expansion, stride),norm_layer(planes * block.expansion),)# 使用layers存储每个layerlayers = []layers.append(block(self.inplanes, planes, stride, downsample, self.groups, self.base_width, previous_dilation, norm_layer))self.inplanes = planes * block.expansionfor _ in range(1, blocks):layers.append(block(self.inplanes,planes,groups=self.groups,base_width=self.base_width,dilation=self.dilation,norm_layer=norm_layer,))# 将layers通过nn.Sequential转化为网络return nn.Sequential(*layers)def _forward_impl(self, x: Tensor) -> Tensor:# See note [TorchScript super()]x = self.conv1(x)  		# conv1   x shape [1 64 112 112]x = self.bn1(x)   		# 归一化处理   x = self.relu(x)  		# 激活函数x = self.maxpool(x)  	# conv2_x的3x3 maxpool, x shape [1 64 56 56]x = self.layer1(x) # layer 1x = self.layer2(x) # layer 2x = self.layer3(x) # layer 3x = self.layer4(x) # layer 4x = self.avgpool(x) 	# 自适应池化x = torch.flatten(x, 1) x = self.fc(x) 			# 分类return xdef forward(self, x: Tensor) -> Tensor:return self._forward_impl(x) 

模型步骤

【1】首先是一个7 x 7的卷积作用在输入的3维图片上,并输入一个64维的特征图(即self.inplanes的初始值),通过BatchNorm层,ReLU层,MaxPool层。

【2】然后经过_make_layer()函数构建的4层layer。

【3】最后经过一个AveragePooling层,再经过一个fc层得到分类输出。

【4】在网络搭建起来后,还对模型的参数(Conv2d、BatchNorm2d、last BN)进行了初始化。

一个_make_layer()构建一个layer层,每一个layer层是两种基本模块的堆叠。

输入参数中block代表该layer堆叠模块的类型,可选BasicBlock或者BottleNeck。blocks代表该layer中堆叠的block的数目;planes与该layer最终输出的维度数有关,注意最终输出的维度数为planes * block.expansion。

变体

【1】Wider ResNet。

【2】DarkNet53。只是使用到了残差连接从而复用特征。

【3】ResNeXt。提出了一种介于普通卷积核深度可分离卷积的这种策略:分组卷积。通过控制分组的数量(基数)来达到两种策略的平衡。分组卷积的思想源自Inception,ResNeXt的每个分支的拓扑结构是相同的。

3.3:模型保存

【1】确定保存路径

【2】调用save函数

python">save_path = "./FahionModel.pkl"
torch.save(model, save_path)

http://www.ppmy.cn/devtools/21097.html

相关文章

模型实战(19)之 从头搭建yolov9环境+tensorrt部署+CUDA前处理 -> 实现目标检测

从头搭建yolov9环境+tensorrt部署实现目标检测 yolov9虚拟环境搭建实现训练、推理与导出导出onnx并转为tensorrt模型Python\C++ - trt实现推理,CUDA实现图像前处理文中将给出详细实现源码python、C++效果如下:output_video_1 1. 搭建环境 拉去官方代码根据配置下载虚拟环境所…

正则表达式的常见语法

目录 一、基本的正则表达式语法 1.1 字符类 1.2 单个字符的特殊表示 1.3 量词表示 1.4 边界匹配 1.5 分组与捕获 二 、java中的使用 在Java中使用正则表达式进行字符串匹配可以说是一个很重要的技能,尤其对于需要进行文本处理或者字符替换的程序来说&#xff0…

前端三剑客 HTML+CSS+JavaScript ⑤ HTML文本标签

别困在过去,祝你有勇气开始,下一行 —— 24.4.24 一、文本标签 1.特点 1.用于包裹:词汇、短语等 2.通常写在排版标签里面(h1~h6、p、div) 3.排版标签更宏观(大段的文字),文本标签更微…

智慧码头港口:施工作业安全生产AI视频监管与风险预警平台方案

一、建设思路 随着全球贸易的快速发展,港口作为连接海洋与内陆的关键节点,其运营效率和安全性越来越受到人们的关注。为了提升港口的运营效率和安全性,智慧港口视频智能监控系统的建设显得尤为重要。 1)系统架构设计 系统应该采…

【Redis(8)】Spring Boot整合Redis和Guava,解决缓存穿透、缓存击穿、缓存雪崩等缓存问题

在缓存技术的挑战及设计方案我们介绍了使用缓存技术可能会遇到的一些问题,那么如何解决这些问题呢? 在构建缓存系统时,Spring Boot和Redis的结合提供了强大的支持,而Guava的LoadingCache则为缓存管理带来了便捷的解决方案。下面我…

谁在钉钉上做AI Agent?

在这个中国最大的TO B流量池里,有最适合AI Agent生长的“原生”环境,有足够有边界的平台设计,也更有无数真实可见的AI产业需求,和已经在全面开放的数据和TO B服务流程,这些串联到一起也恰构成着AI在中国产业落地的最丰…

【C++类和对象】探索static成员、友元以及内部类

💞💞 前言 hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥个人主页&#x…

OpenHarmony实战开发-如何实现进度条 (Progress)

Progress是进度条显示组件,显示内容通常为目标操作的当前进度。 创建进度条 Progress通过调用接口来创建,接口调用形式如下: Progress(options: {value: number, total?: number, type?: ProgressType}) ts其中,value用于设置…

从零开始的vscode配置及安装rust教程

配置vscode的rust环境 下载安装vscodemac 环境1. 下载安装rust2. 配置 mac vscode环境3. 创建一个测试项目 windows 环境1. 安装c运行环境2. 安装配置rustup3. 配置windows vscode环境4. 创建一个测试项目 下载安装vscode 1.官网应用程序下载 vscode:https://code.v…

阿里云难题学习笔记

1、下列内存区段增长方是向低地址方向的有( )? A: 文本段 B: 数据段 C: 堆区 D: 栈区 解析: 在内存管理中,不同的内存区段增长方向是不同的。栈区(Stack)的增长方向是向低地址方向的&…

Python爬虫--Scrapy框架安装

Scrapy框架安装 , Scrapy 是 Python 领域专业的爬虫开发框架,已经完成爬虫程序的大部分通用工具 它使用了 Twisted 异步网络库来处理网络通讯。整体架构大致如下 第一步:挂小灰机或者将要安装的文件下载到本地 Scrapy 框架安装踩坑中 为什…

Python_AI库 Matplotlib的应用简例:绘制与保存折线图

本文默认读者已具备以下技能: 熟悉Python基础语法,以自行阅读python代码块熟悉Vscode或其它编辑工具的应用 在数据可视化领域,Matplotlib无疑是一个强大的工具。它允许我们创建各种静态、动态、交互式的可视化图形,帮助我们更好…

C 练习实例36 - 求100之内的素数

C 练习实例36 - 求100之内的素数 题目: 求100之内的素数。 程序分析: 质数(prime number)又称素数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数整除。 程序源代码&#x…

排序试题解析(二)

8.4.3 01.在以下排序算法中,每次从未排序的记录中选取最小关键字的记录,加入已排序记录的 末尾,该排序算法是( A ). A.简单选择排序 B.冒泡排序 C.堆排序 D.直接插入排序 02.简单选择排序算法的比较次数和移动次数分别为( C )。…

STM32标准库外部中断和定时器知识点总结

目录 前言 一、EXIT外部中断 (1)对射式红外传感器计次 (2)旋转编码器计次 二、TIM定时器 1.定时器定时中断 2.定时器外部时钟 3.TIM输出比较 (1)PWM驱动呼吸灯 (2)PWM驱动舵…

介绍一个开源IOT组态项目

项目介绍 金合可视化平台是一款强大而操作简便的低代码平台,专为满足物联网领域的可视化开发需求而设计。通过该平台,用户可以利用拖拽配置的方式,轻松创建个性化的可视化大屏,无需熟练的编程技能,大幅提高了开发效率。…

【免费源码下载】完美运营版商城 虚拟商品全功能商城 全能商城小程序 智慧商城系统 全品类百货商城php+uniapp

简介 完美运营版商城/拼团/团购/秒杀/积分/砍价/实物商品/虚拟商品等全功能商城 干干净净 没有一丝多余收据 还没过手其他站 还没乱七八走的广告和后门 后台可以自由拖曳修改前端UI页面 还支持虚拟商品自动发货等功能 挺不错的一套源码 前端UNIAPP 后端PHP 一键部署版本&am…

RuoYi-Vue-Plus (SPEL 表达式)

RuoYi-Vue-Plus 中SPEL使用 DataScopeType 枚举类中: /*** 部门数据权限*/DEPT("3", " #{#deptName} #{#user.deptId} ", " 1 0 "), PlusDataPermissionHandler 拦截器中定义了解析器: buildDataFilter 方法中根据注解的…

VTC视频时序控制器原理以及Verilog实现

文章目录 一、前言二、视频时序控制原理三、Verilog实现3.1 代码3.2 仿真以及分析 一、前言 VTC(Video Timing Controller)是一种用于产生视频时序的控制器,在图像领域经常会输出各种分辨率和帧率的视频格式。因此为了方便,设置一…

Windows设置右键打开管理员CMD

参考方法:Windows设置右键打开CMD - 知乎 (zhihu.com) 按参考方法创建右键CMD,在command默认项的数值数据中填入 powershell.exe -Command "Start-Process cmd -ArgumentList /s,/k,pushd \"%V\" -Verb RunAs"