directory
Abstract
Implement the residual module
ResNet18, ResNet34
RseNet50, RseNet101, RseNet152,
Abstract
ResNet (Residual Neural Network) was proposed by four Chinese including Kaiming He of Microsoft Research, successfully trained 152-layer Neural Network by using ResNet Unit, and won the champion in ILSVRC2015 competition. The error rate of top5 is 3.57%, and the number of parameters is lower than VGGNet, so the effect is very obvious.
The innovation of the model lies in the idea of residual learning, which adds a direct channel in the network to transmit the original input information directly to the following layers, as shown in the figure below:
In traditional convolutional networks or fully connected networks, there are more or less problems such as information loss and loss during information transmission, and at the same time, gradient disappearance or gradient explosion will result in the failure of training of deep networks. ResNet solves this problem to some extent by directly bypassing the input information to the output to protect the integrity of the information. The entire network only needs to learn the part of the difference between the input and output, simplifying the learning objectives and difficulties. The pairing of VGGNet and ResNet is shown below. The biggest difference with ResNet is that there are many bypasses that connect the input directly to the next layer, which is also known as shortcut or Skip connections.
In ResNet network structure, two residual modules will be used, one is two 3*3 convolutional networks connected together as a residual module, and the other is 1*1, 3*3 and 1*1 convolutional networks connected together as a residual module. As shown below:
ResNet has different network layers. The most common ones are 18-layer, 34-layer, 50-layer, 101-layer, and 152-layer. They are all made up of the residual modules stacked on top of each other. The following figure shows the different ResNet models.
Implement the residual module
The first residual module
class ResidualBlock(nn.Module) :
Implementation child module: Residual Block
def __init__(self, inchannel, outchannel, stride=1, shortcut=None) :
super(ResidualBlock, self).__init__()
self.left = nn.Sequential(
nn.Conv2d(inchannel, outchannel, 3, stride, 1, bias=False),
nn.BatchNorm2d(outchannel),
nn.ReLU(inplace=True),
nn.Conv2d(outchannel, outchannel, 3.1.1, bias=False),
nn.BatchNorm2d(outchannel))
self.right = shortcut
def forward(self, x) :
out = self.left(x)
residual = x if self.right is None else self.right(x)
out += residual
return F.relu(out)
Copy the code
The second residual module
class Bottleneck(nn.Module) :
def __init__(self,in_places,places, stride=1,downsampling=False, expansion = 4) :
super(Bottleneck,self).__init__()
self.expansion = expansion
self.downsampling = downsampling
self.bottleneck = nn.Sequential(
nn.Conv2d(in_channels=in_places,out_channels=places,kernel_size=1,stride=1, bias=False),
nn.BatchNorm2d(places),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=places, out_channels=places, kernel_size=3, stride=stride, padding=1, bias=False),
nn.BatchNorm2d(places),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=places, out_channels=places*self.expansion, kernel_size=1, stride=1, bias=False),
nn.BatchNorm2d(places*self.expansion),
)
if self.downsampling:
self.downsample = nn.Sequential(
nn.Conv2d(in_channels=in_places, out_channels=places*self.expansion, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(places*self.expansion)
)
self.relu = nn.ReLU(inplace=True)
def forward(self, x) :
residual = x
out = self.bottleneck(x)
if self.downsampling:
residual = self.downsample(x)
out += residual
out = self.relu(out)
return out
Copy the code
ResNet18, ResNet34
import torch
import torchvision
from torch import nn
from torch.nn import functional as F
from torchsummary import summary
class ResidualBlock(nn.Module) :
Implementation child module: Residual Block
def __init__(self, inchannel, outchannel, stride=1, shortcut=None) :
super(ResidualBlock, self).__init__()
self.left = nn.Sequential(
nn.Conv2d(inchannel, outchannel, 3, stride, 1, bias=False),
nn.BatchNorm2d(outchannel),
nn.ReLU(inplace=True),
nn.Conv2d(outchannel, outchannel, 3.1.1, bias=False),
nn.BatchNorm2d(outchannel)
)
self.right = shortcut
def forward(self, x) :
out = self.left(x)
residual = x if self.right is None else self.right(x)
out += residual
return F.relu(out)
class ResNet(nn.Module) :
ResNet34 ResNet34 contains a Residual block at each layer with a Residual block at the _make_layer function
def __init__(self, blocks, num_classes=1000) :
super(ResNet, self).__init__()
self.model_name = 'resnet34'
# First few layers: Image conversion
self.pre = nn.Sequential(
nn.Conv2d(3.64.7.2.3, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(3.2.1))
There is residual block at 3,4,6,3
self.layer1 = self._make_layer(64.64, blocks[0])
self.layer2 = self._make_layer(64.128, blocks[1], stride=2)
self.layer3 = self._make_layer(128.256, blocks[2], stride=2)
self.layer4 = self._make_layer(256.512, blocks[3], stride=2)
Full connection for classification
self.fc = nn.Linear(512, num_classes)
def _make_layer(self, inchannel, outchannel, block_num, stride=1) :
""" Build layer with multiple residual blocks
shortcut = nn.Sequential(
nn.Conv2d(inchannel, outchannel, 1, stride, bias=False),
nn.BatchNorm2d(outchannel),
nn.ReLU()
)
layers = []
layers.append(ResidualBlock(inchannel, outchannel, stride, shortcut))
for i in range(1, block_num):
layers.append(ResidualBlock(outchannel, outchannel))
return nn.Sequential(*layers)
def forward(self, x) :
x = self.pre(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = F.avg_pool2d(x, 7)
x = x.view(x.size(0), -1)
return self.fc(x)
def ResNet18() :
return ResNet([2.2.2.2])
def ResNet34() :
return ResNet([3.4.6.3])
if __name__ == '__main__':
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = ResNet34()
model.to(device)
summary(model, (3.224.224))
Copy the code
RseNet50, RseNet101, RseNet152,
import torch
import torch.nn as nn
import torchvision
import numpy as np
print("PyTorch Version: ",torch.__version__)
print("Torchvision Version: ",torchvision.__version__)
__all__ = ['ResNet50'.'ResNet101'.'ResNet152']
def Conv1(in_planes, places, stride=2) :
return nn.Sequential(
nn.Conv2d(in_channels=in_planes,out_channels=places,kernel_size=7,stride=stride,padding=3, bias=False),
nn.BatchNorm2d(places),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))class Bottleneck(nn.Module) :
def __init__(self,in_places,places, stride=1,downsampling=False, expansion = 4) :
super(Bottleneck,self).__init__()
self.expansion = expansion
self.downsampling = downsampling
self.bottleneck = nn.Sequential(
nn.Conv2d(in_channels=in_places,out_channels=places,kernel_size=1,stride=1, bias=False),
nn.BatchNorm2d(places),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=places, out_channels=places, kernel_size=3, stride=stride, padding=1, bias=False),
nn.BatchNorm2d(places),
nn.ReLU(inplace=True),
nn.Conv2d(in_channels=places, out_channels=places*self.expansion, kernel_size=1, stride=1, bias=False),
nn.BatchNorm2d(places*self.expansion),
)
if self.downsampling:
self.downsample = nn.Sequential(
nn.Conv2d(in_channels=in_places, out_channels=places*self.expansion, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(places*self.expansion)
)
self.relu = nn.ReLU(inplace=True)
def forward(self, x) :
residual = x
out = self.bottleneck(x)
if self.downsampling:
residual = self.downsample(x)
out += residual
out = self.relu(out)
return out
class ResNet(nn.Module) :
def __init__(self,blocks, num_classes=1000, expansion = 4) :
super(ResNet,self).__init__()
self.expansion = expansion
self.conv1 = Conv1(in_planes = 3, places= 64)
self.layer1 = self.make_layer(in_places = 64, places= 64, block=blocks[0], stride=1)
self.layer2 = self.make_layer(in_places = 256,places=128, block=blocks[1], stride=2)
self.layer3 = self.make_layer(in_places=512,places=256, block=blocks[2], stride=2)
self.layer4 = self.make_layer(in_places=1024,places=512, block=blocks[3], stride=2)
self.avgpool = nn.AvgPool2d(7, stride=1)
self.fc = nn.Linear(2048,num_classes)
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
elif isinstance(m, nn.BatchNorm2d):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
def make_layer(self, in_places, places, block, stride) :
layers = []
layers.append(Bottleneck(in_places, places,stride, downsampling =True))
for i in range(1, block):
layers.append(Bottleneck(places*self.expansion, places))
return nn.Sequential(*layers)
def forward(self, x) :
x = self.conv1(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.avgpool(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
return x
def ResNet50() :
return ResNet([3.4.6.3])
def ResNet101() :
return ResNet([3.4.23.3])
def ResNet152() :
return ResNet([3.8.36.3])
if __name__=='__main__':
#model = torchvision.models.resnet50()
model = ResNet50()
print(model)
input = torch.randn(1.3.224.224)
out = model(input)
print(out.shape)
Copy the code