可以看到根据层数 num_layers
的不同,网络的具体配置也不同:
- Block 的类型不同:18-layer 和 34-layer 的 Block 类型相同,50-layer、101-layer 和 152-layer 的类型相同。这里的 Block 指的是上图中括号内的内容
- Layer 内 Block 的重复数量不同
这些具体的配置都被存在下面这个字典中:
# Specification
resnet_spec = {18: ('basic_block', [2, 2, 2, 2], [64, 64, 128, 256, 512]),
34: ('basic_block', [3, 4, 6, 3], [64, 64, 128, 256, 512]),
50: ('bottle_neck', [3, 4, 6, 3], [64, 256, 512, 1024, 2048]),
101: ('bottle_neck', [3, 4, 23, 3], [64, 256, 512, 1024, 2048]),
152: ('bottle_neck', [3, 8, 36, 3], [64, 256, 512, 1024, 2048])}
这个字典的 key 是 num_layers
,返回的依次是 Block 类型,具体每层 Layer 的 Block 重复次数,每层 Layer 的 Out Channel 数目。之所以 Channel 数有 5 个而 Layer 只有 4 个,是因为在 Layer 1 之前,其实还有 Conv + ReLU + BN(也就是上图中的 conv1 部分),我习惯把这个叫作 Layer 0.
因此,get_resnet
这个 ResNet 的 Constructor 函数,只能构造上面 resnet_spec
这个字典里配置好的网络结构。这个函数就是根据 resnet_spec
返回的配置,调用 ResNetV2
这样的 ResNet 类构造网络。如果要用其他新的配置,则不能用 get_resnet
函数,而是需要自己直接调用 ResNetV2
或 ResNetV1b
类,就像 resnet50_v1s
那样。
- 用
ResNetV1b
这样的网络的
以 resnet50_v1s
作为例子,resnet50_v1s
是 ResNetV1b
类的具体化。按照 Net -> Body/Head -> Layer -> Block -> Operator 这样的层级结构,一个 Layer 包含多个 Block,且负责 Subsampling。resnet50_v1s
包含 4 个 Layer,每个 Layer 依次包含 3、4、6、3 个 Block。其中,每个 Layer 的第一个 Block 负责 Subsampling,具体是由中间 Stride = 2 的 3 x 3 的 Conv Operator 完成。
Block BottleneckV1b
的具体结构如下图所示:
因此,整个 resnet50_v1s
在 deep_stem=False
时的网络结构,简单的示意图如下:
ResNet 以 ResNetV1b
类为例,具体各种各样的 ResNet 是由以下几个因素决定:
- Block 类型:
BottleneckV1b
还是其他 Block 类型 - Layer:有多少个 Layer,其中具体某个 Layer 含有多少个 Block,由
ResNetV1b
中的layers
参数控制,比如resnet50_v1s
的layers
就是[3, 4, 6, 3]
deep_stem
:是否用多个3 x 3
的 filter 代替像7 x 7
这样的大 filter
这个 50-layer 是怎么算的呢?是一个 Conv 或者 FC 算作一个 Layer,1 + 3 * (3 + 4 + 6 +3) + 1 = 50