卷积输入输出尺寸公式
这是一条比较完整的输出尺寸公式,考虑到了stride, padding, dilation, 这里的括号表示的是向下取整,这实际上是卷积图的边边剩下的部分比卷积核小,所以抛弃了这次卷积的结果。
其实,若用另一种视角看,可以把空洞卷积当成更改了卷积核尺寸K的值,K -> d × (K-1) +1
,因此该公式可以更简洁的被表示为Out = floor((In + 2P − K)/S+1)
tensorflow 版本
tensorflow 版本的padding是通过直接选模式参数进行的,可选’SAME’,’VALID’.前者是通过padding在前后左右补零,使得输出尺寸保持不变(或以步长倍数缩小),非常常用,后者则是不进行padding,实际上应该是等价于上边总公式P=0的情况。
SAME: Out = ceil(In/S)
VALID: Out = ceil((In − K + 1)/S)
pytorch 版本
pytorch中padding是需要自己设置值的,因此输出尺寸就按照一开始的公式来即可。以下再看一些例子。
>>> m = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3)
>>> input = torch.randn(20,3,24,24)
>>> m(input).shape
torch.Size([20, 64, 12, 12])
>>> input = torch.randn(20,3,25,25)
>>> m(input).shape
torch.Size([20, 64, 13, 13])
>>> input = torch.randn(20,3,24,24)
>>> m = nn.Conv2d(3, 64, kernel_size=6, stride=2, padding=3)
>>> m(input).shape
torch.Size([20, 64, 13, 13])
>>> m = nn.Conv2d(3, 64, kernel_size=6, stride=2, padding=2)
>>> m(input).shape
torch.Size([20, 64, 12, 12])
>>> input = torch.randn(20,3,25,25)
>>> m = nn.Conv2d(3, 64, kernel_size=6, stride=2, padding=3)
>>> m(input).shape
torch.Size([20, 64, 13, 13])
>>> m = nn.Conv2d(3, 64, kernel_size=6, stride=2, padding=2)
>>> m(input).shape
torch.Size([20, 64, 12, 12])
这里可以观察到:
- 若是需要保持
- 对于奇数卷积核,通过让
padding=(k-1)/2
,即可实现SAME的效果。即输出尺寸保持不变或以步长倍数缩小(对于奇数输入尺寸则向上取整) - 对于偶数卷积核,若是偶数输入尺寸,则
padding=floor((k-1)/2)
可实现SAME的效果 - 对于偶数卷积核,若是奇数输入尺寸,则
padding=ceil((k-1)/2)
可实现SAME的效果
因此,建议不要用偶数卷积核。。。然后记住padding=(k-1)/2
,即可实现tf中SAME的效果了。把padding带入一开始的总公式,可以得到Out = floor((In − 1)/S+1)
,这实际上与SAME公式等效,可以看下边代码的暴力验证。
>>> a = lambda x:np.ceil(x/5)
>>> b = lambda x:np.floor((x-1)/5+1)
>>> c = [np.random.randint(6,100) for i in range(10)]
>>> [a(rand)==b(rand) for rand in c]
[True, True, True, True, True, True, True, True, True, True]
总结
虽然想了半天这个公式,但实际使用时好像也就SAME功能用得比较多,因此记住核心:
- 用奇数卷积核
padding=(k-1)/2
- 若是空洞卷积,则代入
K -> d × (K-1) +1