ToB企服应用市场:ToB评测及商务社交产业平台

标题: 深入浅出之FPN (Feature Pyramid Networks for Object Detection)网络 [打印本页]

作者: 鼠扑    时间: 2024-10-30 18:00
标题: 深入浅出之FPN (Feature Pyramid Networks for Object Detection)网络
FPN(Feature Pyramid Network),即特征金字塔网络,是一种用于解决目标检测和语义分割中多尺度问题的深度学习网络结构。以下是对FPN网络的详细先容:
一、概述

FPN网络是在2017年的CVPR会议上提出的,主要目的是通过特征融合的方式,在不显著增长计算量的情况下,提升多尺度目标的检测性能,尤其是对小目标的检测能力。它通过构建多尺度特征金字塔,将高层特征图的语义信息与低层特征图的空间信息举行融合,生成具有丰富多尺度信息的特征表示。
二、FPN的提出配景、时间及作者

提出配景
 为了增强语义性,传统的物体检测模型通常只在深度卷积网络的末了一个特征图上举行后续操作,而这一层对应的下采样率(图像缩小的倍数)通常又比较大,如16、32,造成小物体在特征图上的有效信息较少,小物体的检测性能会急剧降落,这个问题也被称为多尺度问题。 ​ 解决多尺度问题的关键在于怎样提取多尺度的特征。传统的方法有图像金字塔(Image Pyramid),主要思路是将输入图片做成多个尺度,不同尺度的图像生成不同尺度的特征,这种方法简朴而有效,大量使用在了COCO等竞赛上,但缺点黑白常耗时,计算量也很大。 ​ 从前面几大主干网络的内容可以知道,卷积神经网络不同层的大小与语义信息不同,本身就雷同一个金字塔结构。
        

         如上图,金字塔底部可以较为浅层特征图,金字塔顶部可以较为深层特征图!
        浅层的特征图感受野小,比较适合检测小目标(要检测大目标,则其只“看”到了大目标的一部门,有效信息不敷);深层的特征图感受野大,适合检测大目标(要检测小目标,则其”看“到了太多的配景噪音,冗余噪音太多),因此FPN应运而生!!!
        2017年的FPN(Feature Pyramid Network)方法融合了不同层的特征,较好地改善了多尺度检测问题。
提出时间及作者
FPN由何凯明等人在2017年提出,这一网络结构的提出为解决物体检测中的多尺度问题提供了新的思路。
三、主要贡献

FPN的主要贡献在于:
四、优缺点

优点
缺点(相对而言):

五、网络结构

FPN的网络结构主要由自底向上的特征提取路径和自顶向下的特征融合路径构成。自底向上的路径是基础网络(如ResNet)的正向传播过程,用于提取不同层次的特征图。自顶向下的路径则通过上采样和横向连接的方式,将高层特征图的语义信息与低层特征图的空间信息举行融合。
 FPN的总体架构如上图所示,主要包含自下而上网络、自上而下网络、横向连接与卷积融合4个部门。
FPN网络通过以下步调实现多尺度特征的提取和融合:

六、pytorch实现

  1. '''FPN in PyTorch.
  2. See the paper "Feature Pyramid Networks for Object Detection" for more details.
  3. '''
  4. import torch
  5. import torch.nn as nn
  6. import torch.nn.functional as F
  7. from torch.autograd import Variable
  8. class Bottleneck(nn.Module):
  9.     expansion = 4
  10.     def __init__(self, in_planes, planes, stride=1):
  11.         super(Bottleneck, self).__init__()
  12.         self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)
  13.         self.bn1 = nn.BatchNorm2d(planes)
  14.         self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
  15.         self.bn2 = nn.BatchNorm2d(planes)
  16.         self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False)
  17.         self.bn3 = nn.BatchNorm2d(self.expansion*planes)
  18.         self.shortcut = nn.Sequential()
  19.         if stride != 1 or in_planes != self.expansion*planes:
  20.             self.shortcut = nn.Sequential(
  21.                 nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False),
  22.                 nn.BatchNorm2d(self.expansion*planes)
  23.             )
  24.     def forward(self, x):
  25.         out = F.relu(self.bn1(self.conv1(x)))
  26.         out = F.relu(self.bn2(self.conv2(out)))
  27.         out = self.bn3(self.conv3(out))
  28.         out += self.shortcut(x)
  29.         out = F.relu(out)
  30.         return out
  31. class FPN(nn.Module):
  32.     def __init__(self, block, num_blocks):
  33.         super(FPN, self).__init__()
  34.         self.in_planes = 64
  35.         self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
  36.         self.bn1 = nn.BatchNorm2d(64)
  37.         # Bottom-up layers
  38.         self.layer1 = self._make_layer(block,  64, num_blocks[0], stride=1)
  39.         self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
  40.         self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
  41.         self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
  42.         # Top layer
  43.         self.toplayer = nn.Conv2d(2048, 256, kernel_size=1, stride=1, padding=0)  # Reduce channels
  44.         # Smooth layers
  45.         self.smooth1 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)
  46.         self.smooth2 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)
  47.         self.smooth3 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)
  48.         # Lateral layers
  49.         self.latlayer1 = nn.Conv2d(1024, 256, kernel_size=1, stride=1, padding=0)
  50.         self.latlayer2 = nn.Conv2d( 512, 256, kernel_size=1, stride=1, padding=0)
  51.         self.latlayer3 = nn.Conv2d( 256, 256, kernel_size=1, stride=1, padding=0)
  52.     def _make_layer(self, block, planes, num_blocks, stride):
  53.         strides = [stride] + [1]*(num_blocks-1)
  54.         layers = []
  55.         for stride in strides:
  56.             layers.append(block(self.in_planes, planes, stride))
  57.             self.in_planes = planes * block.expansion
  58.         return nn.Sequential(*layers)
  59.     def _upsample_add(self, x, y):
  60.         '''Upsample and add two feature maps.
  61.         Args:
  62.           x: (Variable) top feature map to be upsampled.
  63.           y: (Variable) lateral feature map.
  64.         Returns:
  65.           (Variable) added feature map.
  66.         Note in PyTorch, when input size is odd, the upsampled feature map
  67.         with `F.upsample(..., scale_factor=2, mode='nearest')`
  68.         maybe not equal to the lateral feature map size.
  69.         e.g.
  70.         original input size: [N,_,15,15] ->
  71.         conv2d feature map size: [N,_,8,8] ->
  72.         upsampled feature map size: [N,_,16,16]
  73.         So we choose bilinear upsample which supports arbitrary output sizes.
  74.         '''
  75.         _,_,H,W = y.size()
  76.         return F.upsample(x, size=(H,W), mode='bilinear') + y
  77.     def forward(self, x):
  78.         # Bottom-up
  79.         c1 = F.relu(self.bn1(self.conv1(x)))
  80.         c1 = F.max_pool2d(c1, kernel_size=3, stride=2, padding=1)
  81.         print(f'c1:{c1.shape}')
  82.         c2 = self.layer1(c1)
  83.         print(f'c2:{c2.shape}')  
  84.         c3 = self.layer2(c2)
  85.         print(f'c3:{c3.shape}')
  86.         c4 = self.layer3(c3)
  87.         print(f'c4:{c4.shape}')
  88.         c5 = self.layer4(c4)
  89.         print(f'c5:{c5.shape}')
  90.         # Top-down
  91.         p5 = self.toplayer(c5)
  92.         print(f'p5:{p5.shape}')
  93.         p4 = self._upsample_add(p5, self.latlayer1(c4))
  94.         print(f'latlayer1(c4):{self.latlayer1(c4).shape}, p4:{p4.shape}')
  95.         p3 = self._upsample_add(p4, self.latlayer2(c3))
  96.         print(f'latlayer1(c3):{self.latlayer2(c3).shape}, p3:{p3.shape}')
  97.         p2 = self._upsample_add(p3, self.latlayer3(c2))
  98.         print(f'latlayer1(c2):{self.latlayer3(c2).shape}, p2:{p2.shape}')
  99.         # Smooth
  100.         p4 = self.smooth1(p4)
  101.         p3 = self.smooth2(p3)
  102.         p2 = self.smooth3(p2)
  103.         return p2, p3, p4, p5
  104. def FPN18():
  105.     # return FPN(Bottleneck, [2,4,23,3])
  106.     return FPN(Bottleneck, [2,2,2,2])
  107. def test():
  108.     net = FPN18()
  109.     fms = net(Variable(torch.randn(1,3,600,900)))
  110.     for fm in fms:
  111.         print(fm.size())
  112.     # p=[fms[0], fms[1], fms[2] , fms[3]]
  113.     # print(p)
  114. test()
复制代码
七、FPN的演化版本

FPN(Feature Pyramid Networks,特征金字塔网络)自提出以来,在目标检测、语义分割等范畴展现出了强盛的性能。随着计算机视觉范畴的发展,FPN也经历了一系列的后续演化版本,这些版本在保持FPN基本思想的基础上,举行了不同的改进和优化。以下是一些FPN的后续演化版本:
需要留意的是,随着计算机视觉技能的不断发展,新的FPN演化版本也在不断涌现。因此,在实际应用中,需要根据具体任务和数据集的特点选择符合的FPN版本或变体。同时,也可以借鉴最新的研究成果,对FPN举行进一步的改进和优化。
八、应用场景

FPN的应用场景非常广泛,主要包括:
总之,FPN作为一种创新的特征融合网络结构,在计算机视觉范畴具有广泛的应用前景和紧张的研究价值。
参考:

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4