resnet18到resnet152模型pytorch实现

        resnet在深度学习领域的重要性不言而喻,自从15年resnet提出后,被各种深度学习模型大量引用。得益于其残差结构的设计,使得深度学习模型可以训练更深层的网络。常见的resnet有resnet18、resnet34、resnet50、resnet101、resnet152几种结构,resnet残差网络由一个卷积块和四个残差块组成,每个残差块包含多个残差结构。从残差结构上看,resnet18和resnet34结构近似,使用相同的残差结构,仅在残差结构数量上有区别,都是使用两个卷积层加一个残差连接层作为残差结构。

resnet18与resnet34的残差结构:

        输入特征图x经过两个卷积核大小为3*3的卷积层,使用padding为1的填充保持特征图大小不变,每个卷积层后接BN层和Relu层,完成两次卷积核将结果与输入特征图x直接相加。resnet50到resnet152使用另一种残差结构,这种残差结构使用两个1*1的卷积核加一个3*3的卷积核。

resnet18resnet34resnet50resnet101resnet152
block11*conv1*conv1*conv1*conv1*conv
block22*res(2*conv)3*res(2*conv)3*res(3*conv)3*res(3*conv)3*res(3*conv)
block32*residual(2*conv)4*res(2*conv)4*res(3*conv)4*res(3*conv)8*res(3*conv)
block42*residual(2*conv)6*res(2*conv)6*res(3*conv)23*res(3*conv)36*res(3*conv)
block52*residual(2*conv)3*res(2*conv)3*res(3*conv)3*res(3*conv)3*res(3*conv)
FNlinearlinearlinearlinearlinear

resnet18的模型实现:

import torch.nn as nn
from torch.nn import functional as F


# 残差单元
class Residual(nn.Module):
    def __init__(self, input_channel, out_channel, use_conv1x1=False, strides=1):
        super().__init__()
        self.conv1 = nn.Conv2d(input_channel, out_channel, kernel_size=3, stride=strides, padding=1)
        self.conv2 = nn.Conv2d(out_channel, out_channel, kernel_size=3, stride=1, padding=1)
        if use_conv1x1:
            self.conv3 = nn.Conv2d(input_channel, out_channel, kernel_size=1, stride=strides)
        else:
            self.conv3 = None
        self.bn1 = nn.BatchNorm2d(out_channel)
        self.bn2 = nn.BatchNorm2d(out_channel)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, X):
        Y = self.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        if self.conv3:
            X = self.conv3(X)
        Y += X
        return F.relu(Y)


# 多个残差单元组成的残差块
def res_block(input_channel, out_channel, num_residuals, first_block=False):
    blk = []
    for i in range(num_residuals):
        if i == 0 and not first_block:
            blk.append(Residual(input_channel, out_channel, use_conv1x1=True, strides=2))
        else:
            blk.append(Residual(out_channel, out_channel))
    return blk


def resnet18(num_channel, classes):
    block_1 = nn.Sequential(
        nn.Conv2d(num_channel, 64, kernel_size=7, stride=2, padding=3),  
        nn.BatchNorm2d(64),
        nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2, padding=1)  
    )
    block_2 = nn.Sequential(*res_block(64, 64, 2, first_block=True))
    block_3 = nn.Sequential(*res_block(64, 128, 2))
    block_4 = nn.Sequential(*res_block(128, 256, 2))
    block_5 = nn.Sequential(*res_block(256, 512, 2))
    model = nn.Sequential(block_1, block_2, block_3, block_4, block_5,
                          nn.AdaptiveAvgPool2d((1, 1)),
                          nn.Flatten(),
                          nn.Linear(512, classes)
                          )
    return model

 resnet34的实现:

def resnet34(classes):
    b1 = nn.Sequential(
        nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),  # [3,224,224]-->[1,112,112]
        nn.BatchNorm2d(64),
        nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2, padding=1)  # [1,110,110]-->[1,56,56]
    )
    b2 = nn.Sequential(*res_block(64, 64, 3, first_block=True))
    b3 = nn.Sequential(*res_block(64, 128, 4))
    b4 = nn.Sequential(*res_block(128, 256, 6))
    b5 = nn.Sequential(*res_block(256, 512, 3))
    model = nn.Sequential(b1, b2, b3, b4, b5,
                          nn.AdaptiveAvgPool2d((1, 1)),
                          nn.Flatten(),
                          nn.Linear(512, classes)
                          )
    return model

       其中残差连接1*1的卷积核,在每个残差块第一个残差结构中对输入特征图使用用于改变输入特征图通道数量,对除第一个残差块之外的其他残差块输入特征图进行特征缩放。当输入图像为[3,224,224],经过第一个卷积层,特征图变为[64,56,56]。由于之前的卷积层和池化层已经进行了两次特征缩放,在设计的时候,在第一个残差块没有对特征图做缩放,也没有改变通道数。之后的每个残差块,都会对特征图进行大小减半,通道加倍,因此在后面三个残差块中,第一个残差单元需要对输入通道进行1*1卷积核加步长为2的操作,以改变特征图大小和通道数,同时对其中第一个卷积层使用步长为2,以保证最后相加时特征图大小和通道数一致。

resnet50模型实现:

import torch
import torch.nn as nn
from torch.nn import functional as F


# 残差单元
class Residual(nn.Module):
    def __init__(self, input_channel, out_channel, use_conv1x1=False, strides=1):
        super().__init__()
        self.conv1 = nn.Conv2d(input_channel, int(out_channel / 4), kernel_size=1, stride=strides)
        self.conv2 = nn.Conv2d(int(out_channel / 4), int(out_channel / 4), kernel_size=3, stride=1, padding=1)
        self.conv3 = nn.Conv2d(int(out_channel / 4), out_channel, kernel_size=1)
        if use_conv1x1:
            self.conv4 = nn.Conv2d(input_channel, out_channel, kernel_size=1, stride=strides)
        else:
            self.conv4 = None
        self.bn1 = nn.BatchNorm2d(int(out_channel / 4))
        self.bn2 = nn.BatchNorm2d(out_channel)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, X):
        Y = self.relu(self.bn1(self.conv1(X)))
        Y = self.relu(self.bn1(self.conv2(Y)))
        Y = self.bn2(self.conv3(Y))
        if self.conv4:
            X = self.conv4(X)
        Y += X
        return F.relu(Y)


# 多个残差单元组成的残差块
def res_block(input_channel, out_channel, num_residuals, first_block=False):
    blk = []
    for i in range(num_residuals):
        if i == 0 and not first_block:
            blk.append(Residual(input_channel, out_channel, use_conv1x1=True, strides=2))
            input_channel = out_channel
        if i == 0 and first_block:
            blk.append(Residual(input_channel, out_channel, use_conv1x1=True, strides=1))
            input_channel = out_channel
        else:
            blk.append(Residual(input_channel, out_channel))
    return blk


def resnet50(num_channel, classes):
    b1 = nn.Sequential(
        nn.Conv2d(num_channel, 64, kernel_size=7, stride=2, padding=3),
        nn.BatchNorm2d(64),
        nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
    )
    b2 = nn.Sequential(*res_block(64, 256, 3, first_block=True))
    b3 = nn.Sequential(*res_block(256, 512, 4))
    b4 = nn.Sequential(*res_block(512, 1024, 6))
    b5 = nn.Sequential(*res_block(1024, 2048, 3))
    model = nn.Sequential(b1, b2, b3, b4, b5,
                          nn.AdaptiveAvgPool2d((1, 1)),
                          nn.Flatten(),
                          nn.Linear(2048, classes)
                          )
    return model


net = resnet50(num_channel=3, classes=2)
x = torch.rand(size=(1, 3, 224, 224), dtype=torch.float32)
for layer in net:
    print(layer)
    x = layer(x)
    print(x.shape)

 resnet101实现:

def resnet101(num_channel, classes):
    b1 = nn.Sequential(
        nn.Conv2d(num_channel, 64, kernel_size=7, stride=2, padding=3),  # [3,224,224]-->[64,112,112]
        nn.BatchNorm2d(64),
        nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2, padding=1)  # [1,110,110]-->[1,56,56]
    )
    b2 = nn.Sequential(*res_block(64, 256, 3, first_block=True))
    b3 = nn.Sequential(*res_block(256, 512, 4))
    b4 = nn.Sequential(*res_block(512, 1024, 23))
    b5 = nn.Sequential(*res_block(1024, 2048, 3))
    model = nn.Sequential(b1, b2, b3, b4, b5,
                          nn.AdaptiveAvgPool2d((1, 1)),
                          nn.Flatten(),
                          nn.Linear(2048, classes)
                          )
    return model

resnet152实现:

def resnet152(num_channel, classes):
    b1 = nn.Sequential(
        nn.Conv2d(num_channel, 64, kernel_size=7, stride=2, padding=3),  # [3,224,224]-->[64,112,112]
        nn.BatchNorm2d(64),
        nn.ReLU(),
        nn.MaxPool2d(kernel_size=3, stride=2, padding=1)  # [64,112,112]-->[64,56,56]
    )
    b2 = nn.Sequential(*res_block(64, 256, 3, first_block=True))
    b3 = nn.Sequential(*res_block(256, 512, 8))
    b4 = nn.Sequential(*res_block(512, 1024, 36))
    b5 = nn.Sequential(*res_block(1024, 2048, 3))
    model = nn.Sequential(b1, b2, b3, b4, b5,
                          nn.AdaptiveAvgPool2d((1, 1)),
                          nn.Flatten(),
                          nn.Linear(2048, classes)
                          )
    return model

      resnet50之后的网络出了采用3个卷结合,在残差结构内部也有一些区别,在残差结构内第一个卷积层和第二个卷积层输出通道为残差块输出通道的四分之一,并且第一个残差块需要对特征图通道进行变换,那么在代码实现上需要对第一个残差块的第一个残差结构使用1*1卷积核进行输入特征图的通道变换。

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ResNet是一种深度卷积神经网络架构,用于解决神经网络在添加更多层时训练困难和准确性下降的问题。ResNet通过引入跳跃连接技术来解决深度CNN中的梯度消失问题。在Pytorch中,我们可以使用ResNet模型来构建ResNet网络。 ResNet包括多个残差块,每个残差块由两个卷积层组成。其中,ResNet-152ResNet的一个具体实现,它包含152层。在Pytorch中,我们可以使用torchvision.models模块来实现ResNet-152。 以下是使用Pytorch实现ResNet-152的示例代码: ```python import torch import torchvision.models as models # 加载预训练的ResNet-152模型 resnet152 = models.resnet152(pretrained=True) # 将模型设置为评估模式 resnet152.eval() # 输入图像的尺寸为224x224 input_size = (3, 224, 224) input_tensor = torch.randn(1, *input_size) # 将输入传递给ResNet-152 output = resnet152(input_tensor) # 输出结果的形状 print(output.shape) ``` 在上述示例中,我们使用torchvision.models模块中的resnet152函数来加载预训练的ResNet-152模型。然后,我们将模型设置为评估模式,并创建一个随机输入张量作为示例输入。最后,我们将输入传递给ResNet-152模型并输出结果的形状。 请注意,加载预训练的模型可能需要一些时间,具体取决于网络连接和计算设备的性能。 : 使用Pytorch实现Resnet网络模型ResNet50、ResNet101和ResNet152 [2]: 但是当我们继续向神经网络添加更多层时,训练变得非常困难,并且模型的准确性开始饱和,然后也会下降。ResNet 将我们从这种情况中解救出来,并帮助解决了这个问题。 : ResNet 中的这些跳跃连接技术通过允许梯度流过的替代捷径来解决深度 CNN 中梯度消失的问题,此外,如果任何层损害了架构的性能,则跳过连接会有所帮助,那么它将被正则化跳过。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TheMatrixs

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值