【论文阅读总结】用于目标检测的特征金字塔网络(FPN)

Feature Pyramid Networks for Object Detection

  • 1.摘要
  • 2.引言
    • 2.1 低级特征对于检测小物体很重要
    • 2.2 算法目标
  • 3. 文献综述
    • 3.1 Hand-engineered features and early neural networks
    • 3.2 Deep ConvNet object detectors
    • 3.3 Methods using multiple layers
  • 4.Feature Pyramid Networks【特征金字塔】
    • 4.1 Bottom-up pathway【自下而上路径】
    • 4.2 Top-down pathway and lateral connections【自上而下路径和横向连接】
  • 5. 应用
    • 5.1 Feature Pyramid Networks for RPN【用于RPN的特征金字塔网络】
    • 5.2 Feature Pyramid Networks for Fast R-CNN【Fast R-CNN的特征金字塔网络】
  • 6.特征金字塔的优点与结论
  • 7.论文阅读总结
  • 8. `mask rcnn`使用`FPN`相关代码实现
    • 8.1 Resnets模块构建
    • 8.2 FPN构建
    • 8.3 源码问题

本文参加新星计划人工智能(Pytorch)赛道: https://bbs.csdn.net/topics/613989052

  • 论文链接:
    • https://arxiv.org/pdf/1612.03144.pdf

1.摘要

  • 特征金字塔
    • 用于检测不同尺度对象的识别系统的基本组成部分。
    • 特征金字塔需要大量计算和内存
    • 特征金字塔计算和内存都是密集型的。
  • 特征金字塔网络(FPN)的体系结构
    • 利用深度卷积网络固有的多尺度金字塔层次来构造具有边际额外成本特征金字塔
    • 具有横向连接的自顶向下架构,用于在所有尺度上构建高级语义特征图
    • 是一种通用的特征提取器,在一些应用中显示出显著改进

2.引言

  • 基于图像金字塔构建的特征金字塔 【特征化图像金字塔】 为识别不同尺度的物体构成了标准解决方案的基础。
    • 这些金字塔比例不变,因为对象的比例变化通过在金字塔中移动其级别来抵消
    • 该特性使模型能够通过在位置和金字塔级别上扫描模型来检测大范围内的对象
      在这里插入图片描述
  • 手工提取特征很大程度上被深度卷积网络(ConvNets)提取的特征所取代的原因。
    • 能够表示更高层次的语义
    • ConvNets虽然对尺度变化也具鲁棒性,从而有助于从单个输入尺度上计算的特征中进行识别。即使有了这种稳健性但是仍然需要金字塔来获得最准确的结果
  • 图像金字塔的每个级别进行特征化的主要优点
    • 产生了多尺度特征表示,所有级别都是语义强的,包括高分辨率级别
  • 图像金字塔问题
    • 图像金字塔的每个层次特征化具有明显的局限性。推断时间显著增加,使得这种方法对于实际应用来说不切实际
    • 图像金字塔上的端到端网络在测试集内存方面是不可行
    • 因此,如果利用图像金字塔,则仅在测试时间使用图像金字塔,这会在训练/测试时间推断之间产生不一致
  • 注意图像金字塔并不是计算多尺度特征表示的唯一方法
    • 深层ConvNet逐层计算特征层次,通过下采样层,特征层次具有固有的多尺度金字塔形状
    • 网络中的这种特征层次结构产生了不同空间分辨率的特征图,引入了由不同深度引起的较大语义差距导致高分辨率特征图具有低水平的特征,这些特征损害了它们识别物体的表现能力

2.1 低级特征对于检测小物体很重要

  • 单镜头检测器(SSD)是第一次尝试使用ConvNet的金字塔特征层次结构。
  • 理想情况下,SSD样式的金字塔将重用在正向过程中计算的来自不同层的多尺度特征图,因此不会产生成本。
  • 但为了避免使用低级特征,SSD放弃了重复使用已经计算的层,而是从网络的高层开始构建金字塔,然后添加几个新层。
  • 因此,它错过了重用特征层次结构的高分辨率特征图的机会。我们证明这些对于检测小物体很重要

2.2 算法目标

  • 自然地利用ConvNet特征层次结构的金字塔形状,同时创建在所有尺度上都具有强语义的特征金字塔
  • 为了实现目标,我们依赖于通过自上而下的路径横向连接低分辨率、语义强的特征高分辨率、语义弱的特征相结合的架构。
  • 结果是一个在所有级别都具有丰富语义的特征金字塔,并是从单个输入图像尺度快速构建【单张图片构建的】。
  • 这些特征金字塔可用于替换特征化的图像金字塔,而不牺牲表现力、速度或内存
  • 使用架构的区别
    • 其他论文采用自上而下和跳过连接的类似架构目标是生成一个精细分辨率的高级特征图,在该图上进行预测。
    • 我们的方法利用该体系结构作为特征金字塔,其中在每个级别上独立地进行预测(例如,对象检测)
  • 特征金字塔很容易扩展到掩模方案,并与严重依赖图像金字塔的最先进方法相比,提高了实例分割平均召回率(AR)和速度
  • 特征金字塔结构可以用所有尺度进行端到端训练,并在训练/测试时一致使用,这将是使用图像金字塔不可行的内存 【解决内存不足问题】
  • FPN能够实现比所有现有的最先进的方法更高的精度。此外,这种改进是在不增加单尺度基线测试时间的情况下实现的。
    在这里插入图片描述

3. 文献综述

3.1 Hand-engineered features and early neural networks

  • 手工提取特征和早期神经网络
    • SIFT特征最初是在尺度空间极值处提取的,并用于特征点匹配。
    • HOG特征,以及后来的SIFT特征,都是在整个图像金字塔上密集计算的。
    • 这些HOG和SIFT金字塔已被用于图像分类、物体检测、人体姿态估计等许多工作。
    • Dollár等人通过首先计算稀疏采样(按比例)的金字塔,然后对缺失水平进行插值证明了快速金字塔计算

3.2 Deep ConvNet object detectors

  • 深度卷积物体检测
    • 随着现代深度ConvNets的发展,OverFeat和R-CNN等物体探测器在精度上有了显著提高。
    • OverFeat采用了一种类似于早期神经网络人脸检测器的策略,将ConvNet作为图像金字塔上的滑动窗口检测器
    • R-CNN采用了基于区域提案的策略,其中每个提案在使用ConvNet进行分类之前都进行了规模归一化
    • SPPnet证明了这种基于区域的检测器可以更有效地应用于在单个图像尺度上提取的特征图。
    • 最近更准确的检测方法,如Fast R-CNN和Faster R-CNN提倡使用从单个尺度计算的特征,因为它在准确性和速度之间提供了良好的权衡。然而,多尺度检测仍然表现更好,尤其是对于小物体。

3.3 Methods using multiple layers

  • 使用多层特征的方法
    • 通过在ConvNet中使用不同的层来改进检测和分割
    • FCN在多个尺度上对每个类别的部分分数求和,以计算语义分割
    • 其他几种方法(HyperNet、ParseNet和ION)在计算预测之前连接多层的特征,这相当于对转换后的特征求和。
    • SSD和MS-CNN在不组合特征或分数的情况下预测特征层次的多个层的对象
    • 最近有一些方法利用横向/跳跃连接,在分辨率和语义级别上关联低级别特征图,包括用于分割的U-Net和SharpMask,用于人脸检测的重组器网络,以及用于关键点估计的堆叠沙漏网络。
    • Ghiasi等人提出了FCN的拉普拉斯金字塔表示,以逐步细化分割。
    • 尽管这些方法采用了金字塔形状的体系结构,但它们不同于在所有级别上独立进行预测的特征化图像金字塔
    • 对于金字塔结构,仍然需要图像金字塔来识别多个尺度的对象
      在这里插入图片描述

4.Feature Pyramid Networks【特征金字塔】

  • 目标
    • 利用ConvNet的金字塔特征层次结构,该层次结构具有从低到高的语义,并构建一个贯穿始终的具有高级语义的特征金字塔。产生的特征金字塔网络是通用的
  • 重点关注模块
    • 滑动窗口提议器(区域提议网络,简称RPN
    • 基于区域的检测器(Fast R-CNN)
  • 实现方法
    • 任意大小的单尺度图像作为输入,并以全卷积的方式在多个级别上输出成比例大小的特征图
    • 该过程独立于骨干卷积架构,使用ResNets骨干卷积架构。
  • 金字塔的构建包括
    • 自下而上路径
    • 自上而下路径
    • 横向连接

4.1 Bottom-up pathway【自下而上路径】

  • 自下而上路径
    • 主干ConvNet的前馈计算,它计算由几个尺度的特征图组成的特征层次,尺度步长为2
    • 通常有许多层产生相同大小的输出映射,这些层处于同一网络阶段。
    • 对于特征金字塔,为每个阶段定义一个金字塔级别。
    • 选择每个阶段最后一层的输出作为我们的特征图参考集,将对其进行丰富以创建我们的金字塔。
    • 因为每个阶段的最深层都应该具有最强的特征
  • 具体使用方法
    • 对于ResNets,使用每个阶段的最后一个残差块输出的特征激活
    • 对于conv2、conv3、conv4和conv5输出,将这些最后残差块的输出表示为{C2、C3、C4、C5},并注意到它们相对于输入图像具有{4、8、16、32}个像素的步长。
    • 由于conv1占用大量内存,因此没有将其包含在金字塔中。
      在这里插入图片描述

4.2 Top-down pathway and lateral connections【自上而下路径和横向连接】

  • 自上而下路径和横向连接

    • 通过从更高的金字塔级别上采样空间上更粗糙但语义上更强的特征图来产生更高分辨率的特征
    • 然后,通过横向连接,利用自下而上路径的特征增强特征
    • 每个横向连接合并来自自下而上路径和自上而下路径的相同空间大小的特征图。
    • 自下而上的特征图具有较低级别的语义,但它的激活更准确地定位,因为它被下采样的次数更少
      在这里插入图片描述
  • 自上而下特征图的构建块

    • 对于较粗分辨率的特征图,将空间分辨率上采样2倍(使用最近邻上采样)。
    • 然后通过逐元素相加将上采样映射与相应的自下而上映射(其经历1×1卷积层以减小通道维度)合并。
    • 迭代此过程,直到生成最精细的分辨率映射。
    • 开始迭代时,需在C5上附加一个1×1的卷积层,即可生成最粗略的分辨率图。
    • 最后,在每个合并的图上附加一个3×3的卷积来生成最终的特征图,这是为了减少上采样的混叠效应。
    • 最后一组特征图被称为{P2,P3,P4,P5},对应于分别具有相同空间大小{C2,C3,C4,C5}
  • 因为金字塔的所有级别都使用共享分类器/回归器,所以固定了所有特征图中的特征维度(通道数,表示为d,设置d=256)。所有额外的卷积层都有256个通道输出

  • 在这些额外的层中不存在非线性,我们根据经验发现这些层的影响很小。
    在这里插入图片描述

5. 应用

  • 此方法是在深层ConvNets中构建特征金字塔的通用解决方案。
  • 在下文中,在RPN中采用了特征金字塔来生成边界框建议,在Fast R-CNN中采用了方法来进行对象检测。
  • 为了证明方法的简单性和有效性,对的原始系统进行了最小的修改,使其适应特征金字塔

5.1 Feature Pyramid Networks for RPN【用于RPN的特征金字塔网络】

  • RPN是一种滑动窗口类不可知对象检测器RPN称区域建议网络,用来提取前景与背景】。
    • 最初RPN设计中,在单尺度卷积特征图的顶部,在密集的3×3滑动窗口上评估小型子网络,执行对象/非对象二元分类和边界框回归。
    • 是通过3×3卷积层和两个用于分类和回归的2个1×1卷积来实现的,我们称之为网络头【network head】
    • 对象/非对象标准和边界框回归目标是关于一组称为锚点的参考框定义的。
    • 具有多个预定义的比例和纵横比,以覆盖不同形状的对象
  • 通过用FPN替换单比例特征图来调整RPN
    • 特征金字塔的每个级别上附加一个相同设计的头部(3×3conv和两个节点1×1个conv)。因为头部在所有金字塔级别的所有位置上密集滑动,因此没有必要在特定级别上设置多尺度

    • 为每个级别分配一个单一比例的锚点

      • 将锚点定义为在{P2、P3、P4、P5、P6}上,分别具有{32*32、64*64、128*128、256*256、512*512}像素的区域。
      • 在每个级别使用多个纵横比{1:2、1:1、2:1}的锚点。所以金字塔上总共有15个锚。
        在这里插入图片描述
    • 根据锚点的交集(IoU)比率和ground-truth bounding boxes为锚点分配训练标签。

    • 如果对于给定的ground-truth bounding boxes具有最高的IoU,或者对于任何ground-truth bounding boxesIoU超过0.7,则被分配正标签,如果IoU对于所有ground-truth bounding boxes都低于0.3,则将被分配负标签
      在这里插入图片描述

    • ground-truth框的比例并没有明确用于将其分配给金字塔的级别;

    • ground-truth框与相关联,已被分配到金字塔级别。

  • 头部【heads】参数在所有特征金字塔级别上是共享的
    • 评估了不共享参数的替代方案,并观察到了类似的准确性。
    • 共享参数的良好性能表明:特征金字塔的所有级别共享相似的语义级别
    • 这一优点类似于使用特征化图像金字塔的优点,其中公共头部分类器可以应用于以任何图像尺度计算的特征
  • 总结:通过调整,RPN可以用FPN进行训练和测试。

5.2 Feature Pyramid Networks for Fast R-CNN【Fast R-CNN的特征金字塔网络】

  • Fast R-CNN

    • 一种基于区域的对象检测器,使用感兴趣区域(RoI)来提取特征。
    • Fast R-CNN最常见的是在单尺度特征图上执行。
    • 要将其与FPN一起使用,需要将不同规模的ROI分配到金字塔级别
      在这里插入图片描述
  • 特征金字塔训练Fast R-CNN实现

    • 当基于区域的检测器在图像金字塔上运行时,需要调整它们的分配策略。
    • 通过将宽度w和高度hRoI(在网络的输入图像上)分配给我们的特征金字塔的层 P k P_k Pk
      • 224是规范的ImageNet预训练大小
      • k 0 k_0 k0 w × h = 22 4 2 w×h=224^2 w×h2242RoI应该映射到的目标层
        在这里插入图片描述
      • 类似于使用 C 4 C_4 C4作为单尺度特征图的基于ResNet的Faster R-CNN系统,将 k 0 k_0 k0设置为4
      • 意味着如果RoI的尺度变小(例如,224的1/2),则应该将其映射到更精细的分辨率级别(例如,k=3)。
    • 将预测头部(在Fast R-CNN中,头是类特定的分类器和边界框回归器)附加到所有级别的所有ROI
      • 头部都共享参数,无论在那一级别。
    • ResNet模块与特征金字塔的不同
      • ResNetconv5层(一个9层深子网络)被用作conv4特征的顶部,特征金字塔使用conv5最为顶部
      • ResNet不同的是,我们只简单地采用RoI池来提取7×7个特征,并在最终分类和边界框回归层之前附加两个隐藏的1024-d完全连接(fc)层(每个层后面跟着ReLU)。
      • 这些层是随机初始化的,因为ResNets中没有可用的预训练fc层。
      • 与标准conv5头相比,我们的2-fc MLP head头重量更轻、速度更快
  • 总结:基于这些调整,可以在特征金字塔的顶部训练和测试Fast R-CNN

6.特征金字塔的优点与结论

  • 优点
    • 特征金字塔大大提高了RPN对对象尺度变化的鲁棒性【在小物体(AR1ks)上的性能提高了12.9分】
    • 自下而上的金字塔上,不同级别之间存在很大的语义差距,尤其是对于非常深的ResNets,即自上而下路径非常重要。
    • 通过横向连接从自下而上的映射的更精细级别直接传递到自上而下映射找到更精确的特征位置
    • RPN是一种具有固定窗口大小的滑动窗口检测器,因此在金字塔级别上扫描可以提高其对尺度方差的鲁棒性
    • FPN在检测器要识别的小物体上具有良好的性能
    • 对于基于区域的对象检测器,我们的特征金字塔优于单尺度特征
    • Fast R-CNN在高分辨率特征图上使用低级别特征,删除自上而下的连接会显著降低准确性
    • 共享特征可以小幅度提高准确性,还减少了测试时间
    • 特征金字塔不依赖于图像金字塔,只使用单个输入图像比例,但在小规模对象上仍然具有出色的AP。
    • 是一个通用的特征提取器,可以取代图像金字塔来解决其他多尺度检测问题
  • 结论
    • 提出了一个干净简单的框架,用于在ConvNets中构建特征金字塔
    • 该方法比几个强大的基线和竞赛获胜者有了显著的改进。
    • 它为特征金字塔的研究和应用提供了一个实用的解决方案,而不需要计算图像金字塔
    • 研究表明:尽管深度ConvNets具有强大的代表能力及其对尺度变化的隐含鲁棒性,但使用金字塔表示来明确解决多尺度问题仍然至关重要。

7.论文阅读总结

  • 低级特征对于检测小物体很重要,所以不可以舍弃前期特征图
  • 特征金字塔每个阶段的最深层都应该具有最强的特征,提出了自下而上路径
  • 低级特征对于检测小物体很重要,需将特征图大小与通道统一,即较粗分辨率的特征图**【小的特征图】**生成最精细的分辨率映射 【大的特征图】,提出了自上而下路径和横向连接

8. mask rcnn使用FPN相关代码实现

  • tensorflow相关文章链接:Mask R-cnn 代码运行报错总结
  • pytorch相关文章链接:pytorch环境之mask-rcnn源码实现

8.1 Resnets模块构建

  • dentity_block:输入维度和输出维度相同,可以串联,用于加深网络的

    • 代码位置
      在这里插入图片描述
    def identity_block(input_tensor, kernel_size, filters, stage, block,use_bias=True, train_bn=True):
        """
        The identity_block is the block that has no conv layer at shortcut【identity_block是在快捷方式中没有对流层的块】
        IdentityBlock输入维度和输出维度相同,可以串联,用于加深网络的
    
        :param input_tensor:input tensor 【输入张量】
        :param kernel_size: default 3, the kernel size of middle conv layer at main path 【默认值3,主路径上中间conv层的内核大小】
        :param filters: list of integers, the nb_filters of 3 conv layer at main path 【整数列表,主路径上3个conv层的nbfilter】
        :param stage: integer, current stage label, used for generating layer names 【整数,当前阶段标签,用于生成图层名称】
        :param block: 'a','b'..., current block label, used for generating layer names 【“a”,“b”。。。,当前块标签,用于生成图层名称】
        :param use_bias: Boolean. To use or not use a bias in conv layers. 【布尔值。在对流层中使用或不使用偏置。】
        :param train_bn: Boolean. Train or freeze Batch Norm layers 【布尔值。训练或冻结批次标准层】
        :return:
        """
    
        nb_filter1, nb_filter2, nb_filter3 = filters
        conv_name_base = 'res' + str(stage) + block + '_branch'
        bn_name_base = 'bn' + str(stage) + block + '_branch'
    
        x = KL.Conv2D(nb_filter1, (1, 1), name=conv_name_base + '2a',use_bias=use_bias)(input_tensor)
        x = BatchNorm(name=bn_name_base + '2a')(x, training=train_bn)
        x = KL.Activation('relu')(x)
    
        x = KL.Conv2D(nb_filter2, (kernel_size, kernel_size), padding='same',name=conv_name_base + '2b', use_bias=use_bias)(x)
        x = BatchNorm(name=bn_name_base + '2b')(x, training=train_bn)
        x = KL.Activation('relu')(x)
    
        x = KL.Conv2D(nb_filter3, (1, 1), name=conv_name_base + '2c',use_bias=use_bias)(x)
        x = BatchNorm(name=bn_name_base + '2c')(x, training=train_bn)
    
        x = KL.Add()([x, input_tensor])
        x = KL.Activation('relu', name='res' + str(stage) + block + '_out')(x)
        return x
    
  • conv_block:输入和输出的维度是不一样的,所以不能连续串联,它的作用是改变网络的维度;

    • 代码位置
      在这里插入图片描述
    def conv_block(input_tensor, kernel_size, filters, stage, block,strides=(2, 2), use_bias=True, train_bn=True):
        """
        conv_block is the block that has a conv layer at shortcut 【conv块是在快捷方式中具有conv层的块】
        ConvBlock输入和输出的维度是不一样的,所以不能连续串联,它的作用是改变网络的维度;
    
        :param input_tensor:input tensor 【输入张量】
        :param kernel_size:default 3, the kernel size of middle conv layer at main path 【默认值3,主路径上中间conv层的内核大小】
        :param filters:list of integers, the nb_filters of 3 conv layer at main path 【整数列表,主路径上3个conv层的nbfilter】卷积核个数,channel个数
        :param stage:integer, current stage label, used for generating layer names 【整数,当前阶段标签,用于生成图层名称】
        :param block:'a','b'..., current block label, used for generating layer names 【“a”,“b”。。。,当前块标签,用于生成图层名称】
        :param strides:步长 strides=(2, 2)
        :param use_bias:Boolean. To use or not use a bias in conv layers. 【布尔值。在对流层中使用或不使用偏置。】
        :param train_bn:Boolean. Train or freeze Batch Norm layers Note that from stage 3, the first conv layer at main path is with subsample=(2,2) And the shortcut should have subsample=(2,2) as well
                         【布尔值。训练或冻结批次标准层 注意,从第3阶段开始,主路径上的第一个对流层具有子样本=(2,2) 快捷方式也应具有子采样=(2,2)】
        :return:
        """
    
    
        nb_filter1, nb_filter2, nb_filter3 = filters
        conv_name_base = 'res' + str(stage) + block + '_branch'
        bn_name_base = 'bn' + str(stage) + block + '_branch'
    
        x = KL.Conv2D(nb_filter1, (1, 1), strides=strides,name=conv_name_base + '2a', use_bias=use_bias)(input_tensor)
        x = BatchNorm(name=bn_name_base + '2a')(x, training=train_bn)
        x = KL.Activation('relu')(x)
        # 使用kernel_size大小的卷积核卷积,padding="same",特征图大小不变
        x = KL.Conv2D(nb_filter2, (kernel_size, kernel_size), padding='same',name=conv_name_base + '2b', use_bias=use_bias)(x)
        x = BatchNorm(name=bn_name_base + '2b')(x, training=train_bn)
        x = KL.Activation('relu')(x)
        # 升维,增加channel通道数
        x = KL.Conv2D(nb_filter3, (1, 1), name=conv_name_base +'2c', use_bias=use_bias)(x)
        x = BatchNorm(name=bn_name_base + '2c')(x, training=train_bn)
        # 恒等映射
        shortcut = KL.Conv2D(nb_filter3, (1, 1), strides=strides,name=conv_name_base + '1', use_bias=use_bias)(input_tensor)
        shortcut = BatchNorm(name=bn_name_base + '1')(shortcut, training=train_bn)
    
        x = KL.Add()([x, shortcut])
        x = KL.Activation('relu', name='res' + str(stage) + block + '_out')(x)
        return x
    
  • resnet_graph:Resnets结构

    • 代码位置
      在这里插入图片描述
    def resnet_graph(input_image, architecture, stage5=False, train_bn=True):
        """
        Build a ResNet graph.【构建ResNet图。】
    
        :param input_image:
        :param architecture: Can be resnet50 or resnet101 【可以是resnet50或resnet101】
        :param stage5: Boolean. If False, stage5 of the network is not created【布尔值。如果为False,则不创建网络的阶段5】
        :param train_bn:Boolean. Train or freeze Batch Norm layers 【布尔值。训练或冻结批次标准层】
        :return:
        """
    
    
        assert architecture in ["resnet50", "resnet101"]
        # Stage 1
        x = KL.ZeroPadding2D((3, 3))(input_image) # 将特征图外部添加0,使边缘特征提取更加充分
        x = KL.Conv2D(64, (7, 7), strides=(2, 2), name='conv1', use_bias=True)(x) # 卷积,卷积核为7*7,channel=64,扫描步长为2,卷积核有偏差项,总参数为7*7+1
        x = BatchNorm(name='bn_conv1')(x, training=train_bn) # 批量归一化
        x = KL.Activation('relu')(x)  # 非线性激活函数
        C1 = x = KL.MaxPooling2D((3, 3), strides=(2, 2), padding="same")(x) # 最大池化
        # Stage 2
        x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1), train_bn=train_bn)
        # 残差网络映射操作
        x = identity_block(x, 3, [64, 64, 256], stage=2, block='b', train_bn=train_bn)
        C2 = x = identity_block(x, 3, [64, 64, 256], stage=2, block='c', train_bn=train_bn)
        # Stage 3
        x = conv_block(x, 3, [128, 128, 512], stage=3, block='a', train_bn=train_bn)
        x = identity_block(x, 3, [128, 128, 512], stage=3, block='b', train_bn=train_bn)
        x = identity_block(x, 3, [128, 128, 512], stage=3, block='c', train_bn=train_bn)
        C3 = x = identity_block(x, 3, [128, 128, 512], stage=3, block='d', train_bn=train_bn)
        # Stage 4
        x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a', train_bn=train_bn)
        block_count = {"resnet50": 5, "resnet101": 22}[architecture]
        for i in range(block_count):
            x = identity_block(x, 3, [256, 256, 1024], stage=4, block=chr(98 + i), train_bn=train_bn)
        C4 = x
        # Stage 5
        if stage5:
            x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a', train_bn=train_bn)
            x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b', train_bn=train_bn)
            C5 = x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c', train_bn=train_bn)
        else:
            C5 = None
        return [C1, C2, C3, C4, C5]
    

8.2 FPN构建

  • 代码位置
    在这里插入图片描述
if callable(config.BACKBONE):
    # 特征图大小在减小,channel通道数再增加
    _, C2, C3, C4, C5 = config.BACKBONE(input_image, stage5=True,train_bn=config.TRAIN_BN)
else:
    _, C2, C3, C4, C5 = resnet_graph(input_image, config.BACKBONE,stage5=True, train_bn=config.TRAIN_BN)
# Top-down Layers 【自上而下层:特征融合,对应位置相加】
# ,通道数全部要统一为config.TOP_DOWN_PYRAMID_SIZE=256
P5 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c5p5')(C5)
# p5上采样(使用线性插值),与c4(统一通道数的c4)特征融合
P4 = KL.Add(name="fpn_p4add")([KL.UpSampling2D(size=(2, 2), name="fpn_p5upsampled")(P5),KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c4p4')(C4)])
# p4上采样,与c3(统一通道数的c3)特征融合
P3 = KL.Add(name="fpn_p3add")([KL.UpSampling2D(size=(2, 2), name="fpn_p4upsampled")(P4),KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c3p3')(C3)])
# p3上采样,与c2(统一通道数的c2)特征融合
P2 = KL.Add(name="fpn_p2add")([KL.UpSampling2D(size=(2, 2), name="fpn_p3upsampled")(P3),KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c2p2')(C2)])
# Attach 3x3 conv to all P layers to get the final feature maps.【将3x3 conv附加到所有P层以获得最终的要素地图。】
# 特征再次融合:通道数不变
P2 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME", name="fpn_p2")(P2)
P3 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME", name="fpn_p3")(P3)
P4 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME", name="fpn_p4")(P4)
P5 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME", name="fpn_p5")(P5)
# P6 is used for the 5th anchor scale in RPN. Generated by subsampling from P5 with stride of 2.【P6用于RPN中的第五锚定标度。通过步距为2的P5的二次采样生成。】
P6 = KL.MaxPooling2D(pool_size=(1, 1), strides=2, name="fpn_p6")(P5)  # 以p6特征图大小作为区域框的生成

# Note that P6 is used in RPN, but not in the classifier heads.【注意,P6用于RPN,但不用于分类器头部。】
rpn_feature_maps = [P2, P3, P4, P5, P6]
mrcnn_feature_maps = [P2, P3, P4, P5]

8.3 源码问题

  • tensorflow版本这个源码并没有实际运行起来,tensorflow2版本改动太大,官网是1版本的,虽然报错修改,但是运行的输出有问题,并且出现了损失为nan1后期使用的pytorch框架实现的,只是使用这个代码看如何实现的,因为pytorch版本封装好了,看不到实际如何构建步骤。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/1947.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式:BSP的理解

BSP概念总结BSP定义BSP的特点BSP的主要工作BSP在嵌入式系统和Windowsx系统中的不同BSP和PC机主板上的BIOS区别BSP与 HAL关系嵌入式计算机系统主要由 硬件层,中间层,系统软件层和应用软件层四层组成。硬件层:包含CPU,存储器(SDRAM&…

Mybatis(一):环境搭建

Mybatis(一):环境搭建前言一、MyBatis简介1、MyBatis历史2、MyBatis特性3、MyBatis下载4、和其它持久化层技术对比二、搭建MyBatis1、开发环境2、创建maven工程2.1 打包方式:jar2.2 引入依赖3、创建MyBatis的核心配置文件4、创建m…

通俗简介:操作系统之进程的管理与调度

操作系统是一个复杂的软件,具备许多功能。其中,进程的管理与调度是与我们密切相关的。本文将对操作系统功能中进程管理与调度作出介绍。 目录 一、进程 二、 进程管理 1、进程管理的概念 2、进程结构体的核心属性 3、进程调度 (1&#…

如何将pdf文件压缩?pdf压缩软件哪个好

PDF是一种常见的文档格式,因为包括文本格式和图像,我们往往采用这种格式进行文件传输和分享,但是也常常会因为pdf文件过大导致使用起来非常不方便,那么如何如何将pdf文件压缩(https://www.yasuotu.com/pdfyasuo&#x…

禁用非必需插件,让 IDEA 飞起

文章首发于个人博客,欢迎访问关注:https://www.lin2j.tech IDEA 为我们提供了众多的插件,但是这些插件并不都是必须的。如果电脑的性能不够强,反而会带来一些不必要的资源消耗。 因此这里整理了一些不常用的插件,可以…

如何让AI帮你干活-娱乐(3)

背景今天的话题会偏代码技巧一些,对于以前没有接触过代码的朋友或者接触代码开发经验较少的朋友会有些吃力。上篇文章介绍了如何广视角的生成相对稳定的视频。昨天的实现相对简单,主要用的是UI界面来做生成。但是生成的效果其实也显而易见,不…

【个人首测】百度文心一言 VS ChatGPT GPT-4

昨天我写了一篇文章GPT-4牛是牛,但这几天先别急,文中我测试了用GPT-4回答ChatGPT 3.5 和 Notion AI的问题,大家期待的图片输入也没有出现。 昨天下午百度发布了文心一言,对标ChatGPT,录屏无实机演示让百度股价暴跌。但是晚上百度就…

不要迷信 QUIC

很多人都在强调 QUIC 能解决 HoL blocking 问题,不好意思,我又要泼冷水了。假设大家都懂 QUIC,不再介绍 QUIC 的细节,直接说问题。 和 TCP 一样,QUIC 也是一个基于连接的,保序的可靠传输协议,T…

【测试开发篇4】测试模型

目录 一、软件测试V模型 编码前 概要设计: 详细设计: 编码后: 单元测试&集成测试 系统测试 验收测试 V模型的特点 优点: 缺点: 二、软件测试W模型 编码之前: 编码的时候: 编…

全网最详细,Jmeter性能测试数据写入文件(总结)看这篇就够了......

目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 jmeter 性能测试数据…

RK3568平台开发系列讲解(Linux系统篇)消息队列

🚀返回专栏总目录 文章目录 一、创建消息队列二、发送和接收消息三、内核结构沉淀、分享、成长,让自己和他人都能有所收获!😄 📢消息队列在如下两个方面上比管道有所增强: 消息队列中的数据是有边界的,发送端和接收端能以消息为单位进行交流,而不再是无分隔的字节流…

Android---动态权限申请

目录 权限分类 动态权限核心函数 简易实现案例 完整代码 Google 在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限和危险权限。App 每次在使用危险权限时需要动态的申请并得到用户的授权才能使用。 权限分类 系统权限分为两类:正常…

队列实现及leetcode相关OJ题

上一篇写的是栈这一篇分享队列实现及其与队列相关OJ题 文章目录一、队列概念及实现二、队列源码三、leetcode相关OJ一、队列概念及实现 1、队列概念 队列同栈一样也是一种特殊的数据结构,遵循先进先出的原则,例如:想象在独木桥上走着的人&am…

计算机网络管理 TCP三次握手的建立过程,Wireshark抓包分析并验证TCP三次握手建立连接的报文

⬜⬜⬜ ---🟧🟨🟩🟦🟪 (*^▽^*)欢迎光临 🟧🟨🟩🟦🟪---⬜⬜⬜ ✏️write in front✏️ 📝个人主页:陈丹宇jmu 🎁欢迎各位→…

【Linux入门篇】操作系统安装、网络配置

目录 🍁Linux详解 🍂1.操作系统 🍂2.操作系统组成 🍂3.操作系统历史 🍂4.常见的Linux系统 🍂5.centos7下载 🍂6.安装centos7 🍁linux初始化配置 🍃1.虚拟机系统安装后操作…

从零实现深度学习框架——学习率调整策略介绍

引言 本着“凡我不能创造的,我就不能理解”的思想,本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架,该框架类似PyTorch能实现自动求导。 要深入理解深度学习,从零开始创建的经验非常重要,从自己可以理解的角度出发,尽量不使用外部完备的框架前提下,实现我…

【微信小程序】-- 案例 - 自定义 tabBar(四十六)

💌 所属专栏:【微信小程序开发教程】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…

kali内置超好用的代理工具proxychains

作者:Eason_LYC 悲观者预言失败,十言九中。 乐观者创造奇迹,一次即可。 一个人的价值,在于他所拥有的。所以可以不学无术,但不能一无所有! 技术领域:WEB安全、网络攻防 关注WEB安全、网络攻防。…

31. 下一个排列

题目链接:https://leetcode.cn/problems/next-permutation/解题思路:整数数组的 下一个排列 是指其整数的下一个字典序更大的排列,其实也就是把整数所有数字从左往右组合成一个数,则下一个排列就是将数组中的所有元素重新组合成一…

【跟着chatgpt学go】Gooutine和Channel

Goroutine Goroutine 是 Go 语言中的一种并发机制,它是一种轻量级线程,可以通过关键字 go 启动一个新的 Goroutine。相比传统的线程,Goroutine 拥有更小的栈空间,因此可以创建更多的 Goroutine。 下面是一个简单的 Goroutine 的…