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

本次以LinkNet34为例子进行网络搭建,首先实现基础模块BasicBlock,基本内容是【CBR】*2
- def BasicBlock(in_ch,out_ch,stride):
- return nn.Sequential(
- nn.Conv2d(in_ch, out_ch, 3, stride, padding=1, bias=False),
- nn.BatchNorm2d(out_ch),
- nn.ReLU(inplace=True), # inplace = True原地操作,节省显存
- nn.Conv2d(out_ch, out_ch, 3, stride=1, padding=1, bias=False),
- nn.BatchNorm2d(out_ch),
- nn.ReLU(inplace=True),
- )
由于renset残差单元可能连接两个不同维度的特征图,所以要接一个降采样操作self.downsample = shortcut,有没有取决于输入维度与输出维度是否相同。
- class ResidualBlock(nn.Module):
- # 实现子module:Residual Block
- def __init__(self, in_ch, out_ch, stride=1, shortcut=None):
- super(ResidualBlock, self).__init__()
- self.BasicBlock = BasicBlock(in_ch,out_ch,stride)
- self.downsample = shortcut
-
- def forward(self, x):
- out = self.BasicBlock(x)
- residual = x if self.downsample is None else self.downsample(x)
- out += residual
- return out
- def make_layer(self, in_ch, out_ch, block_num, stride=1):
- shortcut = None
- # 判断是否使用降采样 维度增加
- if not in_ch==out_ch:
- shortcut = nn.Sequential(
- nn.Conv2d(in_ch, out_ch, 1, stride, bias=False), # 1x1卷积用于增加维度;stride=2用于减半size;为简化不考虑偏差
- nn.BatchNorm2d(out_ch))
- layers = []
- layers.append(ResidualBlock(in_ch, out_ch, stride, shortcut))
- for i in range(1, block_num):
- layers.append(ResidualBlock(out_ch, out_ch)) # 后面的几个ResidualBlock,shortcut直接相加
- return nn.Sequential(*layers)
- class ResNet34(nn.Module):
- # 实现主module:ResNet34
- def __init__(self, num_classes=1):
- super(ResNet34, self).__init__()
- self.init_block = nn.Sequential(
- nn.Conv2d(3, 64, 7, stride=2, padding=3, bias=False),
- nn.BatchNorm2d(64),
- nn.ReLU(inplace=True),
- nn.MaxPool2d(3, 2, 1)
- )
- self.layer1 = self.make_layer(64, 64, 3)
- self.layer2 = self.make_layer(64, 128, 4, stride=2)
- self.layer3 = self.make_layer(128, 256, 6, stride=2)
- self.layer4 = self.make_layer(256, 512, 3, stride=2)
- # 分类用的全连接
- self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
- self.fc = nn.Linear(512, num_classes)
- def forward(self, x):
- x = self.init_block(x)
- x = self.layer1(x)
- x = self.layer2(x)
- x = self.layer3(x)
- x = self.layer4(x)
- x = self.avgpool(x)
- x = torch.flatten(x, 1)
- x = self.fc(x)
- return nn.Sigmoid()(x) # 1x1,将结果化为(0~1)之间
左边使用torchvision中的models库里面的resnet,有图使用自己构建的resnet,两个一模一样,
自己建的可以更清晰的看到内部网络的结构。
- import torch.nn as nn
- import torch
- from torch.nn import functional as F
- from torchsummary import summary
- from torchvision import models
-
- if __name__ == '__main__':
-
- resnet = models.resnet34(pretrained=False)
- summary(resnet.cuda(), (3, 512, 512))
-
- print('***************\n*****************\n')
- # MY RESNET
- resnet_my = ResNet34(num_classes=1000)
- summary(resnet_my.cuda(), (3, 512, 512))


在本次试验中发现一些基本技巧,可以节约梯度求解时的资源占用量,请看这篇文章。
搭建深度学习网络时节约GPU显存的技巧_两只蜡笔的小新的博客-CSDN博客