恒等快,若x和H(x)的维度相等
恒等快,若x和H(x)的维度不相等,需要将x卷积bn,relu在送入H(x)
自适应池化操作
inplanes 是提供给block的通道数,planes表示block的输出通道。大家知道,在做残差相加的时候,我们必须保证残差的维度与真正输出的维度相等(注意这里维度是宽高以及深度)这样我们才能把它们堆到一起,所以程序中出现了降采样操作。
if stride != 1 or self.inplanes != planes * block.expansion:大家注意到这个if语句,它存在两种条件使他为真。第一就是stride != 1,我们以下图为例,输入56×56×256输出为28×28×512,显然stride=2(resnet没有pooling)这时我们满足第一个条件,所以进入降采样操作,令stride=2,这样我的残差输出就变成了28×28。
再看第二个条件 self.inplanes != planes * block.expansion,这是self.inplanes=256,而planes =512(这里因为basic block,block.expansion=1),所以第二个条件满足,那么进行降采样用1×1卷积改变通道数。
总之,这个步骤就是为了匹配维度。
resnet结构如图
pytorch代码如下`
# -*- coding: utf-8 -*-
# @Time : 2020/11/24 18:05
# @Author : Refrain_ouc
# @FileName: resnet_ouc.py
# @Software: PyCharm
import torch
import torch.nn as nn
import torch.nn.functional as F
class BasicBlock(nn.Module):
expansion =1
def __init__(self,in_planes,planes,stride=1):
self.conv1=nn.Sequential(
nn.Conv2d(in_planes,planes,kernel_size=3,stride=stride,padding=1),
nn.BatchNorm2d(planes),
nn.ReLU(True)
)
self.conv2=nn.Sequential(
nn.Conv2d(planes,planes*self.expansion,kernel_size=3,stride=1,padding=1),
nn.BatchNorm2d(planes*self.expansion),
)
self.shortcut=nn.Sequential()
if stride!=1 or in_planes!=planes*self.expansion:
self.shortcut=nn.Sequential(
nn.Conv2d(in_planes,planes*self.expansion,kernel_size=1,stride=stride),
nn.BatchNorm2d(planes*self.expansion)
)
def forward(self,input):
output=self.conv1(input)
output=self.conv2(output)
output=output+self.shortcut
output=F.relu(output)
return output
class BottleBolck(nn.Module):
expansion=4
def __init__(self,in_planes,planes,stride=1):
self.conv1=nn.Sequential(
nn.Conv2d(in_planes,planes,kernel_size=1,stride=stride),
nn.BatchNorm2d(planes),
nn.ReLU(True)
)
self.conv2=nn.Sequential(
nn.Conv2d(planes,planes,kernel_size=3,stride=1,padding=1),
nn.BatchNorm2d(planes),
nn.ReLU(True)
)
self.conv3=nn.Sequential(
nn.Conv2d(planes,planes*self.expansion,kernel_size=1,stride=1),
nn.BatchNorm2d(planes*self.expansion)
)
self.shortcut=nn.Sequential()
if stride!=1 or in_planes!=planes*self.expansion:
self.shortcut=nn.Sequential(
nn.Conv2d(in_planes,planes*self.expansion,kernel_size=1,stride=1),
nn.BatchNorm2d(planes*self.expansion)
)
def forward(self,input):
output=self.conv1(input)
output=self.conv2(output)
output=self.conv3(output)
output=output+self.shortcut
output=F.relu((output))
return output
class Resnet(nn.Module):
def __init__(self,block,num_layer,num_class=10):
self.in_planes=64
self.conv=nn.Sequential(
nn.Conv2d(3,64,kernel_size=7,stride=2,padding=3),
nn.BatchNorm2d(64),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=3,stride=2,padding=1),
)
self.conv1=self.make_layer(block=block,planes=64,num_layer=num_layer[0],stride=1)
self.conv2=self.make_layer(block=block,planes=128,num_layer=num_layer[1],stride=2)
self.conv3=self.make_layer(block=block,planes=256,num_layer=num_layer[2],stride=2)
self.conv4=self.make_layer(block=block,planes=512,num_layer=num_layer[3],stride=2)
self.aver_pool=nn.AdaptiveAvgPool2d((1,1))
self.linera=nn.Linear(512*block.expansion,num_class)
def forward(self,x):
output=self.conv(x)
output=self.conv1(output)
output=self.conv2(output)
output=self.conv3(output)
output=self.conv4(output)
output=self.aver_pool(output)
#output.size(channel,h,w)
output=output.view(output.size(0),-1)
output=self.linera(output)
return output
def make_layer(self,block,planes,num_layer,stride):
layer=[]
strides=[stride]+[1]*(num_layer-1)
for stride in strides:
layer.append(block(self.in_planes,planes,stride))
self.in_plances=planes*block.expansion
return nn.Sequential(*layer)
版权声明:本文为qq_41333847原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。