空洞卷积 Convolution with holes 是在标准的卷积映射(convolution map )里注入空洞,以此来增加感受野( reception field),捕获多尺度上下文信息。
空洞卷积实际卷积核大小K:
K=k+(k-1)(r-1)
k为原始卷积核大小;
r(dilation rate)为空洞卷积参数空洞率---kernel的间隔数量,标准卷积r=1。当r=2时,3×3卷积核尺寸扩大为3+(3-1)*(2-1)=5,即5×5;r=4,扩大为9×9。
1)2层3*3的卷积核卷积操作之后的感受野是5*5,其中卷积核(filter)的步长(stride)为1、padding为0;3层3*3的卷积核卷积操作之后的感受野是7*7,其中卷积核(filter)的步长(stride)为1、padding为0。
2)3层r=[1,2,4]的连续空洞卷积,感受野为15*15。
总结1:
现在网络模型的优化改进,其中的一个趋势就是用小卷积核来代替大卷核。从感受野的角度来看,两个3*3的卷积核串联相当于一个5*5卷积核的感受野,三个3*3的卷积核串联相当于一个7*7的卷积核感受野。所以用小卷积核来代替大卷积核想要实现同样的语义抽象等级,网络层数需要更深。大卷积核从极限的角度计算量会比小卷积核计算量大。同时,多个小卷积核串联相比于单个大卷积核来说非线性程度往往更高。此处原文链接:https://blog.csdn.net/zyazky/article/details/80967931
总结2:
空洞卷积的感受野是呈指数增长的,而感受野的大小象征了网络对全局特征的学习情况。而空洞卷积也存在两个严重缺陷:1. 空洞率过大会导致采样稀疏性,虽然利于捕获全局信息,但对于小目标的学习不利,因此常采用堆叠的空洞卷积;2. 网格化gridding效应,若堆叠的空洞率相同或存在大于1的公约数,如r=[2,2,2],对于中间的红色像素点而言,随着层数的增加,与其一同参与运算的只有蓝色标记的像素点(深浅表示利用程度),会丢失局部信息,造成网格化效应。
空洞卷积的典型应用实例ASPP
空洞金字塔池化ASPP(Atrous Spatial Pyramid Pooling),是DeeplabV2在V1的基础上,采用不同空洞率的空洞卷积并行采样,如下图所示,用于融合多尺度信息。V3通过引入1*1卷积和全局平均池化,添加了BN层改进了ASPP。
class ASPPNOBN(nn.Module): def __init__(self, in_channel=2048, depth=1024): super(ASPPNOBN, self).__init__() self.mean = nn.AdaptiveAvgPool2d((1, 1)) # (1,1)means ouput_dim self.conv = nn.Conv2d(in_channel, depth, 1, 1) self.atrous_block1 = nn.Conv2d(in_channel, depth, 1, 1) self.atrous_block6 = nn.Conv2d(in_channel, depth, 3, 1, padding=6, dilation=6) self.atrous_block12 = nn.Conv2d(in_channel, depth, 3, 1, padding=12, dilation=12) self.atrous_block18 = nn.Conv2d(in_channel, depth, 3, 1, padding=18, dilation=18) self.conv_1x1_output = nn.Conv2d(depth * 5, depth, 1, 1) def forward(self, x): size = x.shape[2:] image_features = self.mean(x) image_features = self.conv(image_features) image_features = F.upsample(image_features, size=size, mode='bilinear') atrous_block1 = self.atrous_block1(x) atrous_block6 = self.atrous_block6(x) atrous_block12 = self.atrous_block12(x) atrous_block18 = self.atrous_block18(x) out = self.conv_1x1_output(torch.cat([image_features, atrous_block1, atrous_block6, atrous_block12, atrous_block18], dim=1)) return out if __name__ == '__main__': inputs = torch.randn(2, 2048, 7, 7) net = ASPPNOBN() print(net) out = net(inputs) nn.AvgPool2d(7) print(out.shape)
输出: