• pytorch从零实现resnet


    一、resnet的基本结构

     观察可以发现,基本模块式是

       

    二、构建BasicBlock

    本次以LinkNet34为例子进行网络搭建,首先实现基础模块BasicBlock,基本内容是【CBR】*2

    1. def BasicBlock(in_ch,out_ch,stride):
    2. return nn.Sequential(
    3. nn.Conv2d(in_ch, out_ch, 3, stride, padding=1, bias=False),
    4. nn.BatchNorm2d(out_ch),
    5. nn.ReLU(inplace=True), # inplace = True原地操作,节省显存
    6. nn.Conv2d(out_ch, out_ch, 3, stride=1, padding=1, bias=False),
    7. nn.BatchNorm2d(out_ch),
    8. nn.ReLU(inplace=True),
    9. )

    三、残差块的实现,

    由于renset残差单元可能连接两个不同维度的特征图,所以要接一个降采样操作self.downsample = shortcut,有没有取决于输入维度与输出维度是否相同。

    1. class ResidualBlock(nn.Module):
    2. # 实现子module:Residual Block
    3. def __init__(self, in_ch, out_ch, stride=1, shortcut=None):
    4. super(ResidualBlock, self).__init__()
    5. self.BasicBlock = BasicBlock(in_ch,out_ch,stride)
    6. self.downsample = shortcut
    7. def forward(self, x):
    8. out = self.BasicBlock(x)
    9. residual = x if self.downsample is None else self.downsample(x)
    10. out += residual
    11. return out

    四、下面构造类class ResNet34(nn.Module)

    1.构造类方法1

    1. def make_layer(self, in_ch, out_ch, block_num, stride=1):
    2. shortcut = None
    3. # 判断是否使用降采样 维度增加
    4. if not in_ch==out_ch:
    5. shortcut = nn.Sequential(
    6. nn.Conv2d(in_ch, out_ch, 1, stride, bias=False), # 1x1卷积用于增加维度;stride=2用于减半size;为简化不考虑偏差
    7. nn.BatchNorm2d(out_ch))
    8. layers = []
    9. layers.append(ResidualBlock(in_ch, out_ch, stride, shortcut))
    10. for i in range(1, block_num):
    11. layers.append(ResidualBlock(out_ch, out_ch)) # 后面的几个ResidualBlock,shortcut直接相加
    12. return nn.Sequential(*layers)

     2.构造类初始化代码

    1. class ResNet34(nn.Module):
    2. # 实现主module:ResNet34
    3. def __init__(self, num_classes=1):
    4. super(ResNet34, self).__init__()
    5. self.init_block = nn.Sequential(
    6. nn.Conv2d(3, 64, 7, stride=2, padding=3, bias=False),
    7. nn.BatchNorm2d(64),
    8. nn.ReLU(inplace=True),
    9. nn.MaxPool2d(3, 2, 1)
    10. )
    11. self.layer1 = self.make_layer(64, 64, 3)
    12. self.layer2 = self.make_layer(64, 128, 4, stride=2)
    13. self.layer3 = self.make_layer(128, 256, 6, stride=2)
    14. self.layer4 = self.make_layer(256, 512, 3, stride=2)
    15. # 分类用的全连接
    16. self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
    17. self.fc = nn.Linear(512, num_classes)

    3.构造类前向传播代码

    1. def forward(self, x):
    2. x = self.init_block(x)
    3. x = self.layer1(x)
    4. x = self.layer2(x)
    5. x = self.layer3(x)
    6. x = self.layer4(x)
    7. x = self.avgpool(x)
    8. x = torch.flatten(x, 1)
    9. x = self.fc(x)
    10. return nn.Sigmoid()(x) # 1x1,将结果化为(0~1)之间

    五、测试性能:

    左边使用torchvision中的models库里面的resnet,有图使用自己构建的resnet,两个一模一样,

    自己建的可以更清晰的看到内部网络的结构。

    1. import torch.nn as nn
    2. import torch
    3. from torch.nn import functional as F
    4. from torchsummary import summary
    5. from torchvision import models
    6. if __name__ == '__main__':
    7. resnet = models.resnet34(pretrained=False)
    8. summary(resnet.cuda(), (3, 512, 512))
    9. print('***************\n*****************\n')
    10. # MY RESNET
    11. resnet_my = ResNet34(num_classes=1000)
    12. summary(resnet_my.cuda(), (3, 512, 512))

    六、如何节约GPU资源,减少使用的显存,

              在本次试验中发现一些基本技巧,可以节约梯度求解时的资源占用量,请看这篇文章。

    搭建深度学习网络时节约GPU显存的技巧_两只蜡笔的小新的博客-CSDN博客

  • 相关阅读:
    ECMAScript6 学习笔记
    mysql 过滤多列重复的值(保留其中一条),对单列或者多列重复的值去重
    数据结构、算法
    SpringBoot配置多个application.properties文件
    浅谈并发容器
    dff寄存器setup hold演示
    JVM虚拟机 总结很到位
    CSDN积分获取攻略:快速积累积分的小技巧
    CMake变量可见性学习
    文心一言 4.0 ERNIE-Bot 4.0 :ERNIE-Bot 4.0 大模型深度测试体验报告
  • 原文地址:https://blog.csdn.net/weixin_44503976/article/details/126259211