spp模块借鉴了空间金字塔的思想,通过SPP模块实现了局部特征和全局特征融合,丰富了特征图的表达能力,有利于待检测图像中目标大小差异较大的情况,所以对检测的精度上有了很大的提升。有很多yolov3的版本加了spp模块,所以我也在我的yolov3(bubbliiiing版)中尝试加了spp模块。具体代码如下:
class SPPBottleneck(nn.Module): """Spatial pyramid pooling layer used in YOLOv3-SPP""" def __init__( self, in_channels, out_channels, kernel_sizes=(5, 9, 13) ): super().__init__() hidden_channels = in_channels // 2 self.conv1 = nn.Sequential(nn.Conv2d(in_channels, hidden_channels, 1, stride=1), nn.ReLU(), nn.BatchNorm2d(hidden_channels) ) self.m = nn.ModuleList( [ nn.MaxPool2d(kernel_size=ks, stride=1, padding=ks // 2) for ks in kernel_sizes ] ) conv2_channels = hidden_channels * (len(kernel_sizes) + 1) self.conv2 = nn.Sequential(nn.Conv2d(conv2_channels, out_channels, 1, stride=1), nn.ReLU(), nn.BatchNorm2d(out_channels) )
def forward(self, x): x = self.conv1(x) x = torch.cat([x] + [m(x) for m in self.m], dim=1) x = self.conv2(x) return x
其中输入和输出为darknet中最后一个卷积层的输出channel,这两个channel的大小是一样的。
在网络的body中添加self.spp
self.spp = SPPBottleneck(1024,1024)
随后将darknet第一个输出载入spp模块中即可
x0 = self.spp(x0)
此外,再添加网络中出了个小问题,忘记加入bn层了,导致loss居高不下,又是一个小细节,嘻嘻嘻。