Thoroughly get to know ResNet50

Here Insert Picture Description
pytorch achieve resnet50 code is as follows:
(1) a block implemented as 1x1,64,3x3,64,1x1,256. This code, 1x1-convolution kernel just to change the number of output channels, 3x3 convolution may change the size of the convolution kernel, and parameters related to stride. I.e. defined Bottleneck (inplanes, planes, stride, downsample), may be altered convolution kernel size.

class Bottleneck(nn.Module):
  expansion = 4

  def __init__(self, inplanes, planes, stride=1, downsample=None):
    super(Bottleneck, self).__init__()
    self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, stride=stride, bias=False) # change
    self.bn1 = nn.BatchNorm2d(planes)
    self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, # change
                 padding=1, bias=False)
    self.bn2 = nn.BatchNorm2d(planes)
    self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)
    self.bn3 = nn.BatchNorm2d(planes * 4)
    self.relu = nn.ReLU(inplace=True)
    self.downsample = downsample
    self.stride = stride

  def forward(self, x):
    residual = x

    out = self.conv1(x)
    out = self.bn1(out)
    out = self.relu(out)

    out = self.conv2(out)
    out = self.bn2(out)
    out = self.relu(out)

    out = self.conv3(out)
    out = self.bn3(out)

    if self.downsample is not None:
      residual = self.downsample(x)

    out += residual
    out = self.relu(out)

    return out

Abstract resnet realization: _make_layer () function to achieve a layer.
1 stressed point : After a block of each layer, the number of channels becomes. 4 Planes, and therefore the number of input channels shall be the next block. 4 Planes, it defines self.inplanes = planes * block.expansion. planes unchanged, always for incoming parameters, such as 64,128,256,512. Each time the number of output channels is made after a block, which means the number of input channels to the next block has changed.
Stressed point 2 : self.layer1 = self._make_layer (Block, 64, Layers [0])
self.layer2 = self._make_layer (Block, 128, Layers [. 1], a stride of = 2)
self.layer3 = Self. Make_layer ( Block, 256, Layers [2], stride = 2)
self.layer4 = Self. make_layer (Block, 512, Layers [. 3], stride = 2)
can be seen when each layer constructed incoming stride parameters is not the same, then this parameter represents what is it? Enter _make_layer () function to see the impact of this stride is to build the first block, the other block are not subject to stride affected. Enter __init block of
() Function can be seen, the influence of the first two stride 3x3 convolution, this time may affect the size of the feature map. Summary, the first Layer (a total of three block, each block has 3 layers, layer 9, are unaffected by the stride, i.e., stride = 1, it does not change the size of the feature map); Second Layer (co 4 block, each block has three layers, layer 12 were affected by the first stride block of the second layer, may alter the size of the feature map, the remaining layer 11 did not change the size of the feature map); the third layer (of 6 block, each block has three layers, a total of 18 layers. affected by the stride of a block of the second layer, may alter the size of the feature map, the remaining layer 17 did not change the size of the feature map) ... IV similar to a layer above, not repeat them.

class ResNet(nn.Module):
  def __init__(self, block, layers, num_classes=1000):
    self.inplanes = 64
    super(ResNet, self).__init__()
    self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,
                 bias=False)
    self.bn1 = nn.BatchNorm2d(64)
    self.relu = nn.ReLU(inplace=True)
    self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=0, ceil_mode=True) # change
    self.layer1 = self._make_layer(block, 64, layers[0])
    self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
    self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
    self.layer4 = self._make_layer(block, 512, layers[3], stride=2)   # different
    self.avgpool = nn.AvgPool2d(7)
    self.fc = nn.Linear(512 * block.expansion, num_classes)

    for m in self.modules():
      if isinstance(m, nn.Conv2d):
        n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
        m.weight.data.normal_(0, math.sqrt(2. / n))
      elif isinstance(m, nn.BatchNorm2d):
        m.weight.data.fill_(1)
        m.bias.data.zero_()

  def _make_layer(self, block, planes, blocks, stride=1):
    downsample = None
    if stride != 1 or self.inplanes != planes * block.expansion:
      downsample = nn.Sequential(
        nn.Conv2d(self.inplanes, planes * block.expansion,
              kernel_size=1, stride=stride, bias=False),
        nn.BatchNorm2d(planes * block.expansion),
      )

    layers = []
    layers.append(block(self.inplanes, planes, stride, downsample))
    self.inplanes = planes * block.expansion
    for i in range(1, blocks):
      layers.append(block(self.inplanes, planes))

    return nn.Sequential(*layers)

  def forward(self, x):
    x = self.conv1(x)
    x = self.bn1(x)
    x = self.relu(x)
    x = self.maxpool(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

resnet50 call resnet categories:

def resnet50(pretrained=False):
  """Constructs a ResNet-50 model.
  Args:
    pretrained (bool): If True, returns a model pre-trained on ImageNet
  """
  model = ResNet(Bottleneck, [3, 4, 6, 3])
  if pretrained:
    model.load_state_dict(model_zoo.load_url(model_urls['resnet50']))
  return model

Guess you like

Origin blog.csdn.net/qq_42278791/article/details/90690747