介绍
摘要
当前表现最好的目标检测器依赖于深度卷积神经网络(CNN)骨干,例如ResNet-101和Inception,得益于其强大的特征表示能力,但却面临高计算成本。相反,一些轻量级模型的检测器可以实现实时处理,但其准确性常常受到批评。本文中,我们探索了一种替代方法,通过使用手工设计的机制来增强轻量级特征,从而构建一个快速且准确的检测器。受人类视觉系统中感受野(RF)结构的启发,我们提出了一种新颖的感受野块(RFB)模块,该模块考虑了感受野的大小和偏心率之间的关系,以增强特征的可辨性和鲁棒性。我们进一步将RFB集成到SSD的顶部,构建了RFB Net检测器。为了评估其有效性,我们在两个主要基准上进行了实验,结果显示RFB Net能够在保持实时速度的同时达到先进的深度检测器的性能。代码可在https://github.com/ruinmessi/RFBNet获取。
YOLO目标检测创新改进与实战案例专栏
专栏目录: YOLO有效改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例
专栏链接: YOLO基础解析+创新改进+实战案例
文章链接
论文地址:论文地址
代码地址:代码地址
基本原理
Receptive Field Block(RFB)模块是一种多分支卷积块,旨在增强轻量级CNN模型学习到的深层特征,以提高目标检测的准确性和速度。
结构组成:
RFB模块由两个主要组件组成:多分支卷积层和后续的扩张池化或卷积层。
多分支卷积层采用不同的核大小,类似于Inception结构,用于模拟多尺度的感受野。
扩张池化或卷积层用于控制感受野的偏心性,模拟人类视觉系统中感受野大小和偏心性之间的关系。
功能:
- RFB模块旨在提高特征的可区分性和鲁棒性,使得轻量级CNN模型也能够产生深层次的特征表示。
- 通过多分支卷积和扩张操作,模拟人类视觉系统中感受野的特性,从而更好地捕获目标检测任务中的多尺度信息。
模块设计:
- RFB模块采用多个分支,每个分支包含不同的卷积核大小和扩张率,以模拟不同尺度的感受野。
- 最终,所有分支的特征图被串联起来,形成一个空间池化或卷积数组,以生成最终的特征表示。
应用:
- RFB模块被嵌入到SSD等目标检测框架中,用于改善从轻量级骨干网络提取的特征,从而提高检测器的准确性和速度。
- 通过引入RFB模块,研究人员实现了在保持实时性能的同时,达到了先进深度检测器的性能水平。
核心代码
class BasicRFB(nn.Module):
def __init__(self, in_planes, out_planes, stride=1, scale=0.1, visual=1):
super(BasicRFB, self).__init__()
self.scale = scale
self.out_channels = out_planes
inter_planes = in_planes // 8
# 定义分支0,包含两个卷积层,第一个卷积层的卷积核大小为1,第二个卷积层的卷积核大小为3,步长为1,膨胀系数为visual
self.branch0 = nn.Sequential(
BasicConv(in_planes, 2*inter_planes, kernel_size=1, stride=stride),
BasicConv(2*inter_planes, 2*inter_planes, kernel_size=3, stride=1, padding=visual, dilation=visual, relu=False)
)
# 定义分支1,包含三个卷积层,第一个卷积层的卷积核大小为1,第二个卷积层的卷积核大小为3,步长为stride,第三个卷积层的卷积核大小为3,膨胀系数为visual+1
self.branch1 = nn.Sequential(
BasicConv(in_planes, inter_planes, kernel_size=1, stride=1),
BasicConv(inter_planes, 2*inter_planes, kernel_size=(3, 3), stride=stride, padding=(1, 1)),
BasicConv(2*inter_planes, 2*inter_planes, kernel_size=3, stride=1, padding=visual+1, dilation=visual+1, relu=False)
)
# 定义分支2,包含四个卷积层,第一个卷积层的卷积核大小为1,第二个卷积层的卷积核大小为3,步长为1,第三个卷积层的卷积核大小为3,步长为stride,第四个卷积层的卷积核大小为3,膨胀系数为2*visual+1
self.branch2 = nn.Sequential(
BasicConv(in_planes, inter_planes, kernel_size=1, stride=1),
BasicConv(inter_planes, (inter_planes//2)*3, kernel_size=3, stride=1, padding=1),
BasicConv((inter_planes//2)*3, 2*inter_planes, kernel_size=3, stride=stride, padding=1),
BasicConv(2*inter_planes, 2*inter_planes, kernel_size=3, stride=1, padding=2*visual+1, dilation=2*visual+1, relu=False)
)
# 定义一个线性卷积层
self.ConvLinear = BasicConv(6*inter_planes, out_planes, kernel_size=1, stride=1, relu=False)
# 定义一个shortcut路径的卷积层
self.shortcut = BasicConv(in_planes, out_planes, kernel_size=1, stride=stride, relu=False)
# 定义一个ReLU激活层
self.relu = nn.ReLU(inplace=False)
def forward(self, x):
# 前向传播:分别通过三个分支
x0 = self.branch0(x)
x1 = self.branch1(x)
x2 = self.branch2(x)
# 将三个分支的输出沿通道维度拼接
out = torch.cat((x0, x1, x2), 1)
# 通过线性卷积层
out = self.ConvLinear(out)
# 通过shortcut路径的卷积层
short = self.shortcut(x)
# 进行加权求和
out = out * self.scale + short
# 通过ReLU激活层
out = self.relu(out)
return out
task与yaml配置
详见:https://blog.csdn.net/shangyanaf/article/details/139431807