- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊 | 接辅导、项目定制
环境
- 系统: Linux
- 语言: Python3.8.10
- 深度学习框架: Pytorch2.0.0+cu118
- 显卡:GTX2080TI
代码在之前的章节都有,我后续只贴出模型设计
对比ResNet的Block和ResNeXt的Block可以发现,最重要的改动就是卷积变成了分组卷积
构建过程如下
- 创建Block
class Block(nn.Module):
def __init__(self, input_size, hidden_size, strides=1, groups=32, conv_shortcut=True):
super().__init__()
if conv_shortcut:
self.start = nn.Sequential(
nn.Conv2d(input_size, hidden_size * 2, 1, stride=strides, bias=False),
nn.BatchNorm2d(hidden_size*2, eps=1.001e-5)
)
else:
self.start = nn.Identity()
self.conv1 = nn.Conv2d(input_size, hidden_size, 1, padding='same', bias=False)
self.bn1 = nn.BatchNorm2d(hidden_size, eps=1.001e-5)
self.relu1 = nn.ReLU()
self.conv2 = nn.Conv2d(hidden_size, hidden_size, 3, padding='same', groups=groups, bias=False)
self.bn2 = nn.BatchNorm2d(hidden_size, eps=1.001e-5)
self.relu2 = nn.ReLU()
self.conv3 = nn.Conv2d(hidden_size, hidden_size * 2, 1, stride=strides, bias=False)
self.bn3 = nn.BatchNorm2d(hidden_size*2, eps=1.001e-5)
self.relu3 = nn.ReLU()
def forward(self, inputs):
short = self.start(inputs)
x = self.conv1(inputs)
x = self.bn1(x)
x = self.relu1(x)
x = self.conv2(x)
x = self.bn2(x)
x = self.relu2(x)
x = self.conv3(x)
x = self.bn3(x)
x = self.relu3(x)
x = x + short
return x
- 创建Stack
class Stack(nn.Module):
def __init__(self, input_size, hidden_size, blocks, strides, groups=32):
super().__init__()
self.layers = nn.Sequential()
self.layers.add_module('first', Block(input_size, hidden_size, strides=strides, groups=groups))
current_size = input_size
for i in range(blocks):
self.layers.add_module('layer%d' % (i+1), Block(hidden_size*2, hidden_size, groups=groups, conv_shortcut=False))
def forward(self, inputs):
x = self.layers(inputs)
return x
- 创建模型
class ResNeXt50(nn.Module):
def __init__(self, num_classes):
super().__init__()
self.pre = nn.Sequential(
nn.ZeroPad2d(3),
nn.Conv2d(3, 64, 7, stride=2),
nn.BatchNorm2d(64, eps=1.001e-5),
nn.ReLU(),
nn.ZeroPad2d(1),
nn.MaxPool2d(3, stride=2),
)
self.stack1 = Stack(64, 128, blocks=2, strides=1)
self.stack2 = Stack(256, 256, blocks=3, strides=2)
self.stack3 = Stack(512, 512, blocks=5, strides=2)
self.stack4 = Stack(1024, 1024, blocks=2, strides=2)
self.avg = nn.AdaptiveAvgPool2d(5)
self.classifier = nn.Linear(5*5*2048, num_classes)
self.softmax = nn.Softmax(dim=1)
def forward(self, inputs):
x = self.pre(inputs)
x = self.stack1(x)
x = self.stack2(x)
x = self.stack3(x)
x = self.stack4(x)
x = self.avg(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
x = self.softmax(x)
return x
打印模型结构
model = ResNeXt50(2).to(device)
model
ResNeXt50(
(pre): Sequential(
(0): ZeroPad2d((3, 3, 3, 3))
(1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2))
(2): BatchNorm2d(64, eps=1.001e-05, momentum=0.1, affine=True, track_running_stats=True)
(3): ReLU()
(4): ZeroPad2d((1, 1, 1, 1))
(5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(stack1): Stack(
(layers): Sequential(
(first): Block(
(start): Sequential(
(0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(1): BatchNorm2d(256, eps=1.001e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(conv1): Conv2d(64, 128, kernel_size=(1, 1), stride=(1, 1), padding=same, bias=False)
(bn1): BatchNorm2d(128, eps=1.001e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu1): ReLU()
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=same, groups=32, bias=False)
(bn2): BatchNorm2d(128, eps=1.001e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu2): ReLU()
(conv3): Conv2d(128, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(256, eps=1.001e-05, momentum