当前的物体检测算法虽然各不相同, 但第一步通常是利用卷积神经网络处理输入图像, 生成深层的特征图, 然后再利用各种算法完成区域生成与损失计算, 这部分卷积神经网络是整个检测算法的“骨架”, 也被称为Backbone。
Backbone是物体检测技术的基础, 其中也涌现出了多种经典的结构, 如VGGNet、 ResNet和DenseNet等, 如图3.1所示。
本章首先介绍网络骨架的基本组成单元, 然后依次讲解各种经典的网络Backbone, 为后续的物体检测算法奠定基础。
1. 神经网络基本组成
物体检测算法使用的通常是包含卷积计算且具有深度结构的前馈神经网络, 如卷积层、 池化层、 全连接层等不同的基本层, 这些层有着不同的作用, 如图3.2所示。 本节将针对物体检测算法中常用的网络层进行一一介绍。
1) 卷积层
卷积本是分析数学中的一种运算, 在深度学习中使用的卷积运算通常是离散的。 作为卷积神经网络中最基础的组成部分, 卷积的本质是用卷积核的参数来提取数据的特征, 通过矩阵点乘运算与求和运算来得到结果。
如图3.3所示为一个基本二维卷积的运算过程, 公式为y=ωx+b。 这里的特征图(x) 大小为1×5×5, 即输入通道数为1, 卷积核(ω) 的大小为3×3, 偏置(b) 为1, 为保证输出维度和输入特征维度一致, 还需要有填充(padding) , 这里使用zero-padding, 即用0来填充。
卷积核参数与对应位置像素逐位相乘后累加作为一次计算结果。 以图3.3左上角为例, 其计算过程为1×0+0×0+1×0+0×0+1×1+0×8+1×0+0×6+1×7+1=9, 然后在特征图上进行滑动, 即可得到所有的计算结果。
在PyTorch中使用卷积非常简单, 接下来从代码角度介绍如何完成卷积操作。
1 import torch 2 from torch import nn 3 4 # 查看卷积核的基本信息, 本质上是一个Module 5 conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1, 6 padding=1, dilation=1, groups=1, bias=True) 7 print(conv) 8 # >> Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) 9 10 # 通过.weight与.bias查看卷积核的权重与偏置 11 print(conv.weight.shape) 12 # >> torch.Size([1]) 13 print(conv.bias.shape) 14 15 16 # 输入特征图, 需要注意特征必须是四维, 第一维作为batch数, 即使是1也要保留 17 # batch*channels*W*H 18 input = torch.ones(1, 1, 5, 5) 19 output = conv(input) 20 21 # 当前配置的卷积核可以使输入和输出的大小一致 22 print(input.shape) 23 >> torch.Size([1, 1, 5, 5]) 24 print(output.shape) 25 >> torch.Size([1, 1, 5, 5])
对于torch.nn.Conv2d()来说, 传入的参数含义如下:
·in_channels: 输入特征图的通道数, 如果是RGB图像, 则通道数为3。 卷积中的特征图通道数一般是2的整数次幂。
·out_channels: 输出特征图的通道数。
·kernel_size: 卷积核的尺寸, 常见的有1、 3、 5、 7。
·stride: 步长, 即卷积核在特征图上滑动的步长, 一般为1。 如果大于1, 则输出特征图的尺寸会小于输入特征图的尺寸。
·padding: 填充, 常见的有零填充、 边缘填充等, PyTorch默认为零填充。
·dilation: 空洞卷积, 当大于1时可以增大感受野的同时保持特征图的尺寸( 后面会细讲) , 默认为1。
·groups: 可实现组卷积, 即在卷积操作时不是逐点卷积, 而是将输入通道分为多个组, 稀疏连接达到降低计算量的目的( 后续会细讲) ,默认为1。
·bias: 是否需要偏置, 默认为True。在实际使用中, 特征图的维度通常都不是1, 假设输入特征图维度为m×win×hin, 输出特征图维度为n×wout×hout, 则卷积核的维度为
n×m×k×k, 在此产生的乘法操作次数为n×wout×hout×m×k×k。
2.