Resnet基础代码

本文介绍了如何在PyTorch中定义Bottleneck模块,其包含1x1conv、3x3conv和可选的1x1conv操作,以及bottleneck_block函数用于构建ResNet50网络的基本单元。
摘要由CSDN通过智能技术生成
import torch
from torch import nn
from torch.nn import functional as F


# 1x1 conv -> 3x3 conv -> 1x1 conv
class Bottleneck(nn.Module):
    def __init__(self, in_channels, channels, stride=1, use_1x1conv=False):
        super(Bottleneck, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, channels, kernel_size=1, stride=1, bias=False)
        self.bn1 = nn.BatchNorm2d(channels)
        self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(channels)
        self.conv3 = nn.Conv2d(channels, channels * 4, kernel_size=1, stride=1, bias=False)
        self.bn3 = nn.BatchNorm2d(channels * 4)

        if use_1x1conv:
            self.conv4 = nn.Conv2d(
                in_channels, channels * 4, kernel_size=1, stride=stride
            )
        else:
            self.conv4 = None

    def forward(self, x):
        # 1x1 conv 通道数:in_channels -> channels
        out = F.relu(self.bn1(self.conv1(x)))
        # 3x3 conv 通道数:channels -> channels
        out = F.relu(self.bn2(self.conv2(out)))
        # 1x1 conv 通道数: channels -> 4*channels
        out = self.bn3(self.conv3(out))

        # 恒等映射 or 1x1 conv
        if self.conv4 == None:
            identity = x
        else:
            identity = self.conv4(x)

        out += identity
        return F.relu(out)

    def bottleneck_block(in_channels, channels, num_bottlenecks, not_FirstBlock=True):
        # 第一个neck使用1x1conv,剩余的neck不使用1x1conv
        # 第一个block的stride=1,后面的block的stride=2
        blk = []
        for i in range(num_bottlenecks):
            if i == 0:
                blk.append(
                    Bottleneck(in_channels, channels, stride=not_FirstBlock + 1, use_1x1conv=True)
                )
            else:
                blk.append(
                    Bottleneck(channels * 4, channels)
                )
        return blk

    b1 = nn.Sequential(nn.Conv2d(1, 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(*bottleneck_block(64, 64, 3, not_FirstBlock=False))
    b3 = nn.Sequential(*bottleneck_block(64 * 4, 128, 3))
    b4 = nn.Sequential(*bottleneck_block(128 * 4, 256, 3))
    b5 = nn.Sequential(*bottleneck_block(256 * 4, 512, 3))
    resnet50 = nn.Sequential(
        b1, b2, b3, b4, b5,
        nn.AdaptiveAvgPool2d((1, 1)),
        nn.Flatten(),
        nn.Linear(2048, 10)
    )

ResNet(残差网络)是由Kaiming He等人在2015年提出的,旨在解决在深度神经网络中出现的“梯度消失”问题。它引入了一种名为“短捷路径”的新模块,允许网络在每一层都能进行信息传递,从而能够搭建更深的网络结构而不会遇到性能下降的问题。下面是一个基于PyTorch库实现的基本ResNet模型的代码示例,该实例实现了ResNet的残差块(Residual Block),并且用于简单分类任务: ### ResNet模型代码 首先导入必要的库: ```python import torch.nn as nn import torch.nn.functional as F class BasicBlock(nn.Module): expansion = 1 def __init__(self, in_planes, planes, stride=1): super(BasicBlock, self).__init__() self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(planes) self.shortcut = nn.Sequential() if stride != 1 or in_planes != self.expansion*planes: self.shortcut = nn.Sequential( nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(self.expansion*planes) ) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) out += self.shortcut(x) out = F.relu(out) return out class ResNet(nn.Module): def __init__(self, block, num_blocks, num_classes=10): super(ResNet, self).__init__() self.in_planes = 64 self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(64) self.layer1 = self._make_layer(block, 64, num_blocks, stride=1) self.layer2 = self._make_layer(block, 128, num_blocks, stride=2) self.layer3 = self._make_layer(block, 256, num_blocks, stride=2) self.layer4 = self._make_layer(block, 512, num_blocks, stride=2) self.linear = nn.Linear(512*block.expansion, num_classes) def _make_layer(self, block, planes, num_blocks, stride): strides = [stride] + *(num_blocks-1) layers = [] for stride in strides: layers.append(block(self.in_planes, planes, stride)) self.in_planes = planes * block.expansion return nn.Sequential(*layers) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = self.layer1(out) out = self.layer2(out) out = self.layer3(out) out = self.layer4(out) out = F.avg_pool2d(out, 4) out = out.view(out.size(0), -1) out = self.linear(out) return out def ResNet18(num_classes=10): return ResNet(BasicBlock, [2, 2, 2, 2], num_classes=num_classes) if __name__ == "__main__": net = ResNet18() print(net) ``` ### 解释 1. **BasicBlock** 类实现了标准的 ResNet 残差块,包含两个卷积层和批规范化操作。 2. **ResNet** 类包含了整个网络结构,包括输入层、四个残差块层次(layer1、layer2、layer3、layer4)、全局平均池化层和全连接层。 3. **_make_layer** 函数用于生成指定层数和每层宽度的残差块序列。 4. **ResNet18** 函数创建了一个具有18层的 ResNet 模型。 此代码仅作为一个基础示例,用于展示如何构建一个ResNet模型,实际使用时可能需要进一步修改和优化以适应特定的任务需求,例如数据集规模、类别数等。 ### 相关问题: 1. **ResNet与其他深度学习模型相比有何优势?** ResNet通过引入短捷路径解决了深度网络中的梯度消失问题,使得深层网络的训练成为可能。此外,残差块的设计提高了网络的训练速度和泛化能力。 2. **如何在深度学习项目中选择合适的网络架构?** 选择网络架构应考虑任务特性(如图像分类、目标检测、自然语言处理等)、数据集大小、计算资源限制等因素。ResNet因其出色的性能在某些情况下是一个很好的起点,但根据具体情况可能会选择其他架构如DenseNet、BERT等。 3. **如何调试和优化ResNet模型的性能?** 有效的调试和优化策略包括监控损失函数变化、检查模型在验证集上的性能、调整学习率、使用正则化技术防止过拟合、尝试改变网络结构(如增加层数、更改激活函数)等。使用可视化工具查看模型在某个特定层的特征映射也有助于了解模型行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值