Resnet
method
Resnet引入了所谓残差连接的思想:对于每一个层,我们要学习的不是$\mathcal{H}(x)$,而是$\mathcal{F}(x) = \mathcal{H}(x) - x$。换句话讲,我们不需要再学之前层学过的东西,而是要学两者的差距。
注意Resnet在连接时,存在两种不同的连接方式: $$ y = \mathcal{F}(x,{W_i})+x \ $$
$$ y = \mathcal{F}(x,{W_i})+W_sx $$
当跨越维度连接时,有两种可选方案来解决维度不适配的问题:1) 补0 2)投影。消融实验表明,这两种方法对结果没有本质影响。
不同的Resnet配置如下:
code
BasicBlock
见resnet.py
。
Resnet
提供了两种原版结构:BasicBlock
和BottleNeck
。此处不再深究两者的区别,以默认的BasicBlock
为例:
|
|
每一个BasicBlock
对应的是这样一个模块:
其__init__
参数中的inplanes
和planes
分别指代input channel
和output channel
,一个简单示例如下:
|
|
其forward
部分如下:
|
|
注意到其中的残差连接部分。值得注意的是,为了进行维度匹配,forward
中还存在self.downsample
部分,是一个channel维度不匹配的二维卷积。之后在Resnet
的解释中会详细说明:
|
|
Resnet
观察其forward
函数,我们逐个分析其中的模块:
|
|
self.conv1(x)
使用7x7卷积核,将图片的channel从3变为64,同时特征图长宽缩短一半。
|
|
self.maxpool(x)
将特征图长宽再缩短一半。
|
|
之后是模块的主体部分:
|
|
首先看这4个层中共有的特征:64/128/256/512
是输出通道数,layers[i]
是通道的层数。
注意到layer1
和其它模块参数的不同之处:无stride
。这决定了:
- 每一个layer第一个
BasicBlock
的状态:
|
|
第一个layer用于缩小特征图和增加channel数(stride=1
时除外)。其它的layer保持特征图的尺寸不变。
|
|
- 是否含有downsample层:
|
|
当跨层进行残差连接时,可能会出现维度不匹配的问题,这时候需要进行downsampling以使得维度匹配:
|
|
self.avgpool
所使用的是torch.nn.AdaptiveAvgPool2d
,使用时只需要指定最后两维的尺寸(H_0, W_0)
即可。
self.fc
将图片分为1000类。
最后我们对模型的使用做一个总结(以resnet34为例):
|
|
|
|