210806周五14:58 from 炎蓉
海礼这个手势代码(应该说ResNet官方写法)里,这里为什么要进行dilation和stride的转化?
image.png
直接该用多少stride和dilation就用多少不可以吗

回答:不能直接设置stride和dilation

不能随意设stride,ResNet为了控制好特征图大小,已经固定好了stride=2,stride不是独立参数,这个不能乱改,改了是牵一发动全身,很多其他参数都要改的,模型整个结构就乱套了。改了后也完全不是ResNet模型的结构了。
image.png

举个例子,你现在用的是“鸡精”,这已经是一个封装好的调料了,你只能控制加多少量的鸡精,不能决定这个鸡精里盐巴比例多少,味精比例多少。你可以自己买盐巴味精调比例,但你做出来的新东西,还能称为是“鸡精”这个调料吗?

既然stride不能乱改,也就没提供stride接口参数了。


另一方面,ResNet内很多层都有stride的,也不是什么层的stride都能改的

  1. 有哪些层
    1. maxpool用到了stride=2
    2. layer1没用
    3. layer2、3、4又用到了stride=2。其实只有layer2、3、4的stride存在变形。
  2. 此时不适合提供 stride=1、2、3等初始化接口。
  3. 而是提供replace_stride_with_dilation=[False, True, True],更规范清晰,不容易引起歧义。
  4. 也只有layer2、3、4存在变形可能,可以从stride=2,改成dilation=2来实现。

同理,dilation也不是一个独立参数,其只是stride的一个替代策略。

stride不是完全不能改,对layer2~layer5是可以改成dilation模式实现的,
所以只提供了replace_stride_with_dilation=[bool, bool, bool]的参数机制。

stride为什么能改成dilation

stride和dilation想象下其提取特征的过程,我觉得能意会到它们都是处理感受野的机制,有些相通的。
好比线性层,和卷积层,看起来操作不太一致,但底层本质是相通的,是可以互换尝试的。

好比你叫人帮你买10个苹果回来,只要最后能带回10个苹果,那是叫一个活泼开朗的去,还是叫沉默寡言的去都行,只是不同性格的人,花的钱和时间,买回来的苹果品质确实会有区别的。

为什么要改?

看做什么实验吧,可能有论文论证了有时候stride效果好,有时候dilation效果好。
好比卷积层常用语提取特征效果更好,线性层用来做最后的全连接分类更好。
各有用途。

看torchvison源码,其实也只有这里用到了转换:
image.png

我的理解效果应该是更好的,因为增大了感受野。

Bottleneck如何实现stride转dilation

注意这里会定义多层layers,
image.png
并通过conv3x3的参数设置,可以实现输出同等尺寸的特征图
image.png

简单实验示例:
image.png

注意不是说stride从2改为1,所有的dialation就从1改到2,这样尺寸是对不上的
好比你原来是44=16,换成加法是4+4+4+4=16那么现在参数4改为2,变成22=4,加法里面并不是把所有数值减半2+2+2+2,这是不对应了,需要有全局的调整,应该是对应2+2=4。

深入探究:BasicBlock,Bottleneck

注意看resnet.py源码,
resnet18、resnet34使用的是BasicBlock组件,
而50、101、152等以上用的是Bottleneck组件。

查阅资料:ResNet, torchvision, bottlenecks, and layers not as they seem. | by Erik Gaasedelen | Medium
image.png

为什么BasicBlock不支持dilation

个人猜想:
BasicBlock适用于浅层网络,Bottleneck适用于深层网络。
为了效果好,浅层网络不适合开dilation。
也有可能是技术层面问题,牵一发动全身,不好实现,或者破坏结构不能再称为是ResNet了。

那为什么BasicBlock还开放dilation接口

这个之前有提到,为了接口形式统一,这样初始化就跟Bottleneck一致了。

不光是dilation,还有groups等参数都是这个道理。