完整的ResNet代码( 二 )


:分组数
:宽度
当为None的时候,则为BN层 。当采用(分组卷积)或者不为64的时候抛出错误:
'BasicBlock only supports groups=1 and base_width=64'
该错误表示在仅支持=1和=64
当>1的时候,表示在采用了空洞卷积,抛出错误 。
class BasicBlock(nn.Module):expansion = 1def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,base_width=64, dilation=1, norm_layer=None):super(BasicBlock, self).__init__()if norm_layer is None:norm_layer = nn.BatchNorm2dif groups != 1 or base_width != 64:raise ValueError('BasicBlock only supports groups=1 and base_width=64')if dilation > 1:raise NotImplementedError("Dilation > 1 not supported in BasicBlock")# Both self.conv1 and self.downsample layers downsample the input when stride != 1self.conv1 = conv3x3(inplanes, planes, stride)self.bn1 = norm_layer(planes)self.relu = nn.ReLU(inplace=True)self.conv2 = conv3x3(planes, planes)self.bn2 = norm_layer(planes)self.downsample = downsampleself.stride = stridedef forward(self, x):identity = xout = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)if self.downsample is not None:identity = self.downsample(x)out += identityout = self.relu(out)"""if norm_layer is Noneif downsample is not None:x -->conv_3x3-->bn-->relu-->conv_3x3-->bn--add--relu-->out|____________downsample_____________________|if downsample is None:x -->conv_3×3-->bn-->relu-->conv_3×3-->bn--add--relu-->out|___________________________________________|"""return out
可以看到在(基础块)中当需要进行下采样的时候,残差边需要一次下采样 。
在正式讲之前需要讲一下函数,因为网络结构中的残差层都是由这个函数决定的 。
代码解析
参数说明:
block:传入还是
:输出通道数
:传入的layer
:步长,默认为1
:是否采用空洞卷积,默认为False
这里以不采用空洞卷积,也就是=False,block取为例 。
if stride != 1 or self.inplanes != planes * block.expansion:downsample = nn.Sequential(conv1x1(self.inplanes, planes * block.expansion, stride),norm_layer(planes * block.expansion),)
上面这段代码表示什么时候采用下采样的情况,当不为1,或者通道数(初始默认取值64) ≠* block.(此时block.=4) 。输入和输出通道不相等时候,下采样结构定义为:
:
(conv1×1:(,4*,),
:BN)
layers = []layers.append(block(self.inplanes, planes, stride, downsample, self.groups,self.base_width, previous_dilation, norm_layer))self.inplanes = planes * block.expansion
上面这段代码表示,创建一个空的列表,此时的block为,将获得的放入列表中 。放入以后下一层的输入通道数为变成上一层输出通道数的4倍【也就是为下一个block做准备】 。
for _ in range(1, blocks):layers.append(block(self.inplanes, planes, groups=self.groups,base_width=self.base_width, dilation=self.dilation,norm_layer=norm_layer))
而上面这一段代码就是表示当前的会重复几次(不过需要注意的是,在每个layer中只在第一个用了1x1的残差边) 。
def _make_layer(self, block, planes, blocks, stride=1, dilate=False):norm_layer = self._norm_layerdownsample = Noneprevious_dilation = self.dilationif dilate:self.dilation *= stridestride = 1if stride != 1 or self.inplanes != planes * block.expansion:downsample = nn.Sequential(conv1x1(self.inplanes, planes * block.expansion, stride),norm_layer(planes * block.expansion),)layers = []layers.append(block(self.inplanes, planes, stride, downsample, self.groups,self.base_width, previous_dilation, norm_layer))self.inplanes = planes * block.expansionfor _ in range(1, blocks):layers.append(block(self.inplanes, planes, groups=self.groups,base_width=self.base_width, dilation=self.dilation,norm_layer=norm_layer))return nn.Sequential(*layers)