当前位置: 首页 > news >正文

pytorh学习笔记——cifar10(五)ResNet网络结构

一、理论基础

resnet网络结构的理论基础看这里,这篇博文讲得简洁而清晰:深度学习卷积神经网络CNN之ResNet模型网络详解说明(超详细理论篇)-CSDN博客

ResNet网络是参考了VGG19网络,并在此基础上进行修改,通过短路机制加入了残差单元。

残差块的基本结构:

图1
图1

上图中,网络分为左右两支,左网络是主干分支,右网络是残差网络

 ResNet的结构与VGG网络的比较:

二、实现过程

新建resnet.py:

1、定义一个基本的块,类似于图1的结构,包含主干网络和残差网络:

class BasicBlock(nn.Module):   # 定义一个基本块,由主干和残差分支组成def __init__(self, in_channels, out_channels, stride=1):super(BasicBlock, self).__init__()self.layer = nn.Sequential(  # 左网络(也就是主干分支)nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1),  # 这三行代码来自标准的VGGNet网络# 第一次卷积有可能进行下采样,所以stride=stridenn.BatchNorm2d(out_channels),nn.ReLU(),nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1),   # 第二次卷积不进行下采样,这样每个基本快就只进行一次下采样nn.BatchNorm2d(out_channels))if in_channels != out_channels:  # 如果输入通道数和输出通道数不同,说明输入和输出的维度不同,需要添加一个下采样层self.shortcut = nn.Sequential(  # 右网络(也就是残差分支)nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1),nn.BatchNorm2d(out_channels),)else:self.shortcut = nn.Sequential()  # 如果输入和输出的维度相同,就不需要添加下采样层def forward(self, x):   # 定义前向传播out = self.layer(x)   # 执行左网络out += self.shortcut(x)   # 执行右网络out = F.relu(out)   # 激活函数return out

 2、定义ResNet网络结构

class ResNet(nn.Module):  # 定义ResNet网络def make_layer(self, block, out_channels, stride, num_blocks):  # 生成网络层# 参数:# block:用于构建网络层的基本模块# out_channels:输出通道数,表示该层的特征图数量。# stride:步长,用于下采样操作。# num_blocks:该层中要生成的block数量。layers = []  # 定义一个列表,用来保存网络层for i in range(num_blocks):  # 生成num_blocks个blockif i == 0:  # 如果是第一个block,需要下采样in_stride = strideelse:in_stride = 1  # 其他block不需要下采样layers.append(block(self.in_channels, out_channels, in_stride))  # 将block添加到列表中self.in_channels = out_channels  # 更新输入通道数return nn.Sequential(*layers)  # 将列表中的网络层串联组合成一个网络层def __init__(self, block, num_blocks, num_classes=10):super(ResNet, self).__init__()self.in_channels = 32  # 定义输入通道数self.conv1 = nn.Sequential(  # 定义第1个卷积层,这个层不用残差,就是标准的VGGNet网络nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(32),nn.ReLU())self.layer_1 = self.make_layer(BasicBlock, 64, 2, 2)   # 生成第1个网络层self.layer_2 = self.make_layer(BasicBlock, 128, 2, 2)  # 生成第2个网络层self.layer_3 = self.make_layer(BasicBlock, 256, 2, 2)  # 生成第2个网络层self.layer_4 = self.make_layer(BasicBlock, 512, 2, 2)  # 生成第2个网络层self.fc = nn.Linear(512, 10)  # 全连接层,输入为512,输出为10def forward(self, x):out = self.conv1(x)  # 执行第1个卷积层out = self.layer_1(out)  # 执行第1个网络层out = self.layer_2(out)  # 执行第2个网络层out = self.layer_3(out)  # 执行第3个网络层out = self.layer_4(out)  # 执行第4个网络层out = F.avg_pool2d(out, 2)  # 最大池化,池化核大小为2out = out.view(out.size(0), -1)  # 将输出展平out = self.fc(out)  # 全连接层return out

3、resnet.py脚本的完整内容:

import torch
import torch.nn as nn
import torch.nn.functional as Fclass BasicBlock(nn.Module):  # 定义一个基本模块,由主干和残差分支组成def __init__(self, in_channels, out_channels, stride=1):super(BasicBlock, self).__init__()self.layer = nn.Sequential(  # 左网络(也就是主干分支)nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1),  # 这三行代码来自标准的VGGNet网络# 第一次卷积有可能进行下采样,所以stride=stridenn.BatchNorm2d(out_channels),nn.ReLU(),nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1),  # 第二次卷积不进行下采样,这样每个基本快就只进行一次下采样nn.BatchNorm2d(out_channels))if in_channels != out_channels:  # 如果输入通道数和输出通道数不同,说明输入和输出的维度不同,需要添加一个下采样层self.shortcut = nn.Sequential(  # 右网络(也就是残差分支)nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1),# 为了保证左右网络的维度相同,使用了同一个stridenn.BatchNorm2d(out_channels),)else:self.shortcut = nn.Sequential()  # 如果输入和输出的维度相同,就不需要添加下采样层def forward(self, x):  # 定义前向传播out = self.layer(x)  # 执行左网络out += self.shortcut(x)  # 加上右网络out = F.relu(out)  # 激活函数return outclass ResNet(nn.Module):  # 定义ResNet网络def make_layer(self, block, out_channels, stride, num_blocks):  # 生成网络层# 参数:# block:用于构建网络层的基本模块# out_channels:输出通道数,表示该层的特征图数量。# stride:步长,用于下采样操作。# num_blocks:该层中要生成的block数量。layers = []  # 定义一个列表,用来保存网络层for i in range(num_blocks):  # 生成num_blocks个blockif i == 0:  # 如果是第一个block,需要下采样in_stride = strideelse:in_stride = 1  # 其他block不需要下采样layers.append(block(self.in_channels, out_channels, in_stride))  # 将block添加到列表中self.in_channels = out_channels  # 更新输入通道数return nn.Sequential(*layers)  # 将列表中的网络层串联组合成一个网络层def __init__(self, block=BasicBlock):super(ResNet, self).__init__()self.in_channels = 32  # 定义输入通道数self.conv1 = nn.Sequential(  # 定义第1个卷积层,这个层不用残差,就是标准的VGGNet网络nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(32),nn.ReLU())self.layer_1 = self.make_layer(block, 64, 2, 2)   # 生成第1个网络层self.layer_2 = self.make_layer(block, 128, 2, 2)  # 生成第2个网络层self.layer_3 = self.make_layer(block, 256, 2, 2)  # 生成第2个网络层self.layer_4 = self.make_layer(block, 512, 2, 2)  # 生成第2个网络层self.fc = nn.Linear(512, 10)  # 全连接层,输入为512,输出为10def forward(self, x):out = self.conv1(x)  # 执行第1个卷积层out = self.layer_1(out)  # 执行第1个网络层out = self.layer_2(out)  # 执行第2个网络层out = self.layer_3(out)  # 执行第3个网络层out = self.layer_4(out)  # 执行第4个网络层out = F.avg_pool2d(out, 2)  # 最大池化,池化核大小为2out = out.view(out.size(0), -1)  # 将输出展平out = self.fc(out)  # 全连接层return outdef resnet():return ResNet(BasicBlock)  # 生成ResNet网络

4、训练 

将之前的train.py脚本中的
net = VGGNet().to(device),改为:
​​​​​​​net = resnet().to(device),即可运行开始训练:


http://www.mrgr.cn/news/57262.html

相关文章:

  • VTK的学习方法-第二类型应用
  • 数据通信与网络课程展示图谱问答展示系统
  • 408算法题leetcode--第38天
  • YOLOv8-seg训练自己的分割数据集
  • 基于单片机优先级的信号状态机设计
  • 【面试经典150】day 5
  • 万能接口PCIE
  • Linux中Kconfig结构分析
  • 【电子通识】四线电阻屏原理
  • 【高等数学学习记录】无穷小的比较
  • 16天自制CppServer-day02
  • 带权并查集注意事项
  • 华帝携手抖音头部达人,金牌导演李力持量身打造厨电定制微短剧
  • Java避坑案例 - 接口设计_版本控制策略
  • solidworks管理员运行install.bat提示[sC]0penService 失败 5:拒绝访问。请按任意键继续...
  • HTML、CSS 和 JavaScript 的介绍
  • 防火墙概述
  • C++:模板(2)
  • Android 12.0进程保活白名单功能实现
  • SpringBoot高级-底层原理
  • 数据结构《顺序表》
  • 探索 JavaScript 事件机制(一):从基础概念到实战应用
  • sql注入 --二次注入堆叠注入文件读取getshell
  • Windows 操作系统中事件驱动架构与注册表
  • 申请https证书
  • 从0开始学Python-day6-元祖、字典、集合