当前位置:网站首页>【使用Pytorch实现ResNet网络模型:ResNet50、ResNet101和ResNet152】
【使用Pytorch实现ResNet网络模型:ResNet50、ResNet101和ResNet152】
2022-08-02 14:08:00 【vcsir】
使用Pytorch实现Resnet网络模型:ResNet50、ResNet101和ResNet152
介绍
在深度学习和计算机视觉领域取得了一系列突破。尤其是随着非常深的卷积神经网络的引入,这些模型有助于在图像识别和图像分类等问题上取得最先进的结果。
因此,多年来,深度学习架构变得越来越深(添加更多层)以解决越来越复杂的任务,这也有助于提高分类和识别任务的性能并使其变得健壮。
但是当我们继续向神经网络添加更多层时,训练变得非常困难,并且模型的准确性开始饱和,然后也会下降。ResNet 将我们从这种情况中解救出来,并帮助解决了这个问题。
什么是 ResNet?
Residual Network (ResNet) 是著名的深度学习模型之一,由 Shaoqing Ren、Kaiming He、Jian Sun 和 Xiangyu Zhang 在他们的论文中提出。该论文在 2015 年被命名为“Deep Residual Learning for Image Recognition” 。ResNet 模型是迄今为止流行和最成功的深度学习模型之一。
残块:
随着这些 Residual 块的引入,训练非常深的网络的问题得到了缓解,ResNet 模型由这些块组成。
在上图中,我们首先注意到的是有一个直接连接跳过了模型的某些层,这种连接称为“跳过连接”,是残差块的核心。由于此跳过连接,输出不一样。如果没有跳过连接,输入 X 将乘以层的权重,然后添加一个偏置项。然后是激活函数 f(),我们得到输出为 H(x)。
H(x)=f( wx + b ) 或 H(x)=f(x)
现在引入了一种新的跳跃连接技术,输出为 H(x) 变为
H(x)=f(x)+x
但是输入的维度可能与卷积层或池化层输出的维度不同。因此,可以通过以下两种方法处理此问题:
·用跳跃连接填充零以增加其尺寸。
·1×1 卷积层被添加到输入以匹配维度。在这种情况下,输出为:H(x)=f(x)+w1.x
这里添加了一个额外的参数 w1 而使用第一种方法时没有添加额外的参数。
ResNet 中的这些跳跃连接技术通过允许梯度流过的替代捷径来解决深度 CNN 中梯度消失的问题,此外,如果任何层损害了架构的性能,则跳过连接会有所帮助,那么它将被正则化跳过。
ResNet 的架构
该架构中有一个 34 层的普通网络,其灵感来自 VGG-19,其中添加了快捷连接或跳过连接,这些跳过连接或残差块将架构转换为残差网络,如下图所示。
使用Pytorch构建 ResNet网络
让我们保留上面的图像作为参考并开始构建网络,ResNet 架构多次使用 CNN 块,所以让我们为 CNN 块创建一个类,它接受输入通道和输出通道。每个 conv 层之后都有一个 batchnorm2d,然后创建一个 ResNet 类,该类接受多个块、层、图像通道和类数的输入。函数“_make_layer”创建了 ResNet 层,它接受块的输入、残差块的数量、输出通道和步幅。然后定义不同版本的ResNet
–对于 ResNet50,层序列为 [3, 4, 6, 3]。
–对于 ResNet101,层序列为 [3, 4, 23, 3]。
–对于 ResNet152,层序列为 [3, 8, 36, 3]。
然后编写一个test()函数来检查模型是否工作正常,完整实例代码如下:
import torch
import torch.nn as nn
class block(nn.Module):
def __init__(
self, in_channels, intermediate_channels, identity_downsample=None, stride=1
):
super(block, self).__init__()
self.expansion = 4
self.conv1 = nn.Conv2d(
in_channels, intermediate_channels, kernel_size=1, stride=1, padding=0, bias=False
)
self.bn1 = nn.BatchNorm2d(intermediate_channels)
self.conv2 = nn.Conv2d(
intermediate_channels,
intermediate_channels,
kernel_size=3,
stride=stride,
padding=1,
bias=False
)
self.bn2 = nn.BatchNorm2d(intermediate_channels)
self.conv3 = nn.Conv2d(
intermediate_channels,
intermediate_channels * self.expansion,
kernel_size=1,
stride=1,
padding=0,
bias=False
)
self.bn3 = nn.BatchNorm2d(intermediate_channels * self.expansion)
self.relu = nn.ReLU()
self.identity_downsample = identity_downsample
self.stride = stride
def forward(self, x):
identity = x.clone()
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.conv2(x)
x = self.bn2(x)
x = self.relu(x)
x = self.conv3(x)
x = self.bn3(x)
if self.identity_downsample is not None:
identity = self.identity_downsample(identity)
x += identity
x = self.relu(x)
return x
class ResNet(nn.Module):
def __init__(self, block, layers, image_channels, num_classes):
super(ResNet, self).__init__()
self.in_channels = 64
self.conv1 = nn.Conv2d(image_channels, 64, kernel_size=7, stride=2, padding=3, bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.relu = nn.ReLU()
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.layer1 = self._make_layer(
block, layers[0], intermediate_channels=64, stride=1
)
self.layer2 = self._make_layer(
block, layers[1], intermediate_channels=128, stride=2
)
self.layer3 = self._make_layer(
block, layers[2], intermediate_channels=256, stride=2
)
self.layer4 = self._make_layer(
block, layers[3], intermediate_channels=512, stride=2
)
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
self.fc = nn.Linear(512 * 4, num_classes)
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.avgpool(x)
x = x.reshape(x.shape[0], -1)
x = self.fc(x)
return x
def _make_layer(self, block, num_residual_blocks, intermediate_channels, stride):
identity_downsample = None
layers = []
if stride != 1 or self.in_channels != intermediate_channels * 4:
identity_downsample = nn.Sequential(
nn.Conv2d(
self.in_channels,
intermediate_channels * 4,
kernel_size=1,
stride=stride,
bias=False
),
nn.BatchNorm2d(intermediate_channels * 4),
)
layers.append(
block(self.in_channels, intermediate_channels, identity_downsample, stride)
)
self.in_channels = intermediate_channels * 4
for i in range(num_residual_blocks - 1):
layers.append(block(self.in_channels, intermediate_channels))
return nn.Sequential(*layers)
def ResNet50(img_channel=3, num_classes=1000):
return ResNet(block, [3, 4, 6, 3], img_channel, num_classes)
def ResNet101(img_channel=3, num_classes=1000):
return ResNet(block, [3, 4, 23, 3], img_channel, num_classes)
def ResNet152(img_channel=3, num_classes=1000):
return ResNet(block, [3, 8, 36, 3], img_channel, num_classes)
def test():
net = ResNet101(img_channel=3, num_classes=1000)
print(net)
device = "cuda" if torch.cuda.is_available() else "cpu"
y = net(torch.randn(4, 3, 224, 224)).to(device)
print(y.size())
test()
对于上述测试用例,输出应为:
边栏推荐
猜你喜欢
随机推荐
5.使用RecyclerView优雅的实现瀑布流效果
What?It's 2020, you still can't adapt the screen?
统计偏科最严重的前100名学生
1.RecyclerView是什么
6. How to use the CardView production card layout effect
加强版Apktool堪称逆向神器
拥抱Jetpack之印象篇
redis基础
深度学习之 卷积网络(textCNN)
关于UDF
It is not allowed to subscribe with a(n) xxx multiple times.Please create a fresh instance of xxx
MySQL知识总结 (十) 一条 SQL 的执行过程详解
Kubernetes核心概念
spark on yarn
profiler network乱码
kotlin Android序列化
神经网络可以解决一切问题吗:一场知乎辩论的整理
LLVM系列第八章:算术运算语句Arithmetic Statement
LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)
利用红外-可见光图像数据集OTCBVS打通图像融合、目标检测和目标跟踪