强势源码理解RPN区域推荐网络

本文深入探讨了在目标检测中,Anchor生成的具体实现方法,包括RBG大神的Caffe源码解读及Pytorch版本的简化实现。从参数设置到核心函数的运行逻辑,详细解释了如何生成不同尺度和长宽比的Anchor。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. Anchor Generation Layer

对于生成anchors的源码理解主要来源于两个代码

  • RBG大神的caffe源码:https://github.com/rbgirshick/py-faster-rcnn
  • Github上复现的pytorch源码:https://github.com/chenyuntc/simple-faster-rcnn-pytorch

由于两种方法生成anchors的技巧不同,故分开讨论,并主要以RBG大神的代码为主,讲解anchors的生成原理与生成技巧。

1.1 Caffe源码

  • 首先,解释一下,重要的参数

    • base_size=16,由于原图经过卷积池化后得到的特征图是原图的116\frac{1}{16}161,故用于采样anchor的特征图上的一个cell就相当于原图的16×1616 \times 1616×16区域。
    • ratios=[0.5, 1, 2],固定anchor面积下的长宽比,即[1:21:12:1][1:2 \quad 1:1 \quad 2:1][1:21:12:1]
    • scales=[8, 16, 32],即将anchors放大的倍数,具体在哪里用到会在后面详细解释
  • 其次,我们根据RBG大神的源码走一遍anchors生成的流程

    • def generate_anchors(base_size=16, ratios=[0.5, 1, 2],
                           scales=2**np.arange(3, 6)):
          """
          Generate anchor (reference) windows by enumerating aspect ratios X
          scales wrt a reference (0, 0, 15, 15) window.
          """
      
          base_anchor = np.array([1, 1, base_size, base_size]) - 1
          ratio_anchors = _ratio_enum(base_anchor, ratios)
          anchors = np.vstack([_scale_enum(ratio_anchors[i, :], scales)
                               for i in xrange(ratio_anchors.shape[0])])
          return anchors
      
      • generate_anchors() 函数是一切的开端,首先定义了base_anchor,由于图像的坐标以左上角为原点且值为(0, 0),故base_anchor的坐标(xmin, ymin, xmax, ymax)为(0, 0, 15, 15)。
      • 其次,调用_ratio_enum()函数如下
    • def _ratio_enum(anchor, ratios):
          """
          Enumerate a set of anchors for each aspect ratio wrt an anchor.
          """
      
          w, h, x_ctr, y_ctr = _whctrs(anchor)
          size = w * h
          size_ratios = size / ratios
          ws = np.round(np.sqrt(size_ratios))
          hs = np.round(ws * ratios)
          anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
          return anchors
      
      • 为了计算w, h, x_ctr, y_ctr,又调用了_whctrs()函数,如下所示
    • def _whctrs(anchor):
          """
          Return width, height, x center, and y center for an anchor (window).
          """
      
          w = anchor[2] - anchor[0] + 1
          h = anchor[3] - anchor[1] + 1
          x_ctr = anchor[0] + 0.5 * (w - 1)
          y_ctr = anchor[1] + 0.5 * (h - 1)
          return w, h, x_ctr, y_ctr
      
      • _whctrs()函数的功能就是传入参数为(左上角x,左上角y,右上角x,右上角y),将其转换为(宽, 高, 中心坐标x,中心坐标y)
    • 让我们回到_ratio_enum()函数

      • 得到base_anchor的(宽, 高, 中心坐标x,中心坐标y),经过计算值为(16, 16, 7.5, 7.5)
      • size = w x h = 16 x 16 = 256
      • size_ratios = 256[0.512]\frac{256}{[0.5 \quad 1 \quad 2]}[0.512]256 = [512,256,128][512, 256, 128][512,256,128]
      • 对size_ratios开根号,再四舍五入,得到 ws = [23, 16, 11]
      • ws和ratios相乘就得到了 hs = [12, 16, 22]
      • ws和hs其实是相同面积下,anchor不同长宽比条件下,得到的长和宽。但由于四舍五入的缘故,ws x hs的面积值不一定相等
      • 得到上面的变量值后,又调用了_mkanchors()函数返回计算后的anchors,函数如下
    • def _mkanchors(ws, hs, x_ctr, y_ctr):
          """
          Given a vector of widths (ws) and heights (hs) around a center
          (x_ctr, y_ctr), output a set of anchors (windows).
          """
      
          ws = ws[:, np.newaxis]
          hs = hs[:, np.newaxis]
          anchors = np.hstack((x_ctr - 0.5 * (ws - 1),
                               y_ctr - 0.5 * (hs - 1),
                               x_ctr + 0.5 * (ws - 1),
                               y_ctr + 0.5 * (hs - 1)))
          return anchors
      
      
      • 根据上面的代码,会得到如下的计算公式

        7.5−12[221510]=[−3.502.5]7.5 - \frac{1}{2}\left[\begin{matrix} 22 \\ 15 \\ 10 \end{matrix}\right] = \left[\begin{matrix} -3.5\\ 0\\ 2.5\end{matrix}\right]7.521221510=3.502.5

        7.5−12[121622]=[1.50−3]7.5 - \frac{1}{2}\left[\begin{matrix} 12\\ 16\\ 22\end{matrix}\right] = \left[\begin{matrix} 1.5\\ 0\\ -3\end{matrix}\right]7.521121622=1.503

        7.5+12[221510]=[18.51512.5]7.5 + \frac{1}{2}\left[\begin{matrix} 22 \\ 15 \\ 10 \end{matrix}\right] = \left[\begin{matrix} 18.5\\ 15\\ 12.5\end{matrix}\right]7.5+21221510=18.51512.5

        7.5+12[121622]=[131518]7.5 + \frac{1}{2}\left[\begin{matrix} 12\\ 16\\ 22\end{matrix}\right] = \left[\begin{matrix} 13\\ 15\\ 18\end{matrix}\right]7.5+21121622=131518

      • 最后anchors的值为[−3.51.518.513.50015152.5−312.518]\left[\begin{matrix} -3.5 & 1.5 & 18.5 & 13.5\\ 0 & 0 & 15 & 15\\ 2.5 & -3 & 12.5 & 18\end{matrix}\right]3.502.51.50318.51512.513.51518

      • 这里得到的是,面积都为256下,以(7.5, 7.5)为中心坐标的,不同长宽比例下的anchor坐标。根据坐标的计算公式,可以发现,都是以7.5为中心坐标减去一半的长或宽,那么得到的是新的(左上角x,左上角y,右上角x,右上角y)形式的坐标值。为什么坐标会是负数,因为左上角坐标超出了图片范围,故为负数。

    • 得到以上anchors后,我们直接返回到generate_anchors()函数

      • 通过一系列函数的调用,我们得到了ratio_anchors的值,即[−3.51.518.513.50015152.5−312.518]\left[\begin{matrix} -3.5 & 1.5 & 18.5 & 13.5\\ 0 & 0 & 15 & 15\\ 2.5 & -3 & 12.5 & 18\end{matrix}\right]3.502.51.50318.51512.513.51518
      • 最后一步,就是调用_scale_enum()函数,得到不同scale下,不同长宽比例的anchors。目前的scale为[8, 16, 32],对于每一个scale都要调用_scale_enum()函数;传入不同长宽比、以(7.5, 7.5)为中心坐标的anchors(即ratio_anchors的每一行),每次返回3组变换尺度后的anchors,故最后会有9组anchors。_scale_enum()函数如下
    • def _scale_enum(anchor, scales):
          """
          Enumerate a set of anchors for each scale wrt an anchor.
          """
      
          w, h, x_ctr, y_ctr = _whctrs(anchor)
          ws = w * scales
          hs = h * scales
          anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
          return anchors
      
      • 我们以[−3.51.518.513.5][-3.5 \quad 1.5 \quad 18.5 \quad 13.5][3.51.518.513.5]为例
      • 调用_whctrs()函数,得到中心坐标表示,w, h, x_ctr, y_ctr = [23127.57.5][23 \quad 12 \quad 7.5\quad 7.5][23127.57.5]
      • ws=23×[81632]=[184368736]ws = 23 \times \left[\begin{matrix} 8\\ 16\\ 32\end{matrix}\right] = \left[\begin{matrix} 184\\ 368\\ 736\end{matrix}\right]ws=23×81632=184368736,其实是宽为23的情况下,放大宽的值
      • hs=12×[81632]=[96192384]hs = 12 \times \left[\begin{matrix} 8\\ 16\\ 32\end{matrix}\right] = \left[\begin{matrix} 96\\ 192\\ 384\end{matrix}\right]hs=12×81632=96192384,其实是长为12的情况下,放大长的值
      • 由于中心坐标都是(7.5, 7.5)不变,但宽和高的值变了,所以新得到的anchors坐标需要再次调用_mkanchors()对坐标进行调整。在新的长和宽下,仍然以(7.5, 7.5)为中心坐标。
      • 最后计算得到的anchors坐标为[−83−3910056−175−87192104−359−183376200]\left[\begin{matrix} -83 & -39 & 100 & 56\\ -175 & -87 & 192 & 104\\ -359 & -183 & 376 & 200\end{matrix}\right]83175359398718310019237656104200
  • 至此,RBG大神生成Anchors的方法就介绍完毕

1.2 Pytorch源码

  • Pytorch版本就不详细解释了,直接上代码,简单易懂

    def generate_anchor_base(base_size=16, ratios=[0.5, 1, 2],
                             anchor_scales=[8, 16, 32]):
        """
        Returns:
            ~numpy.ndarray:
            An array of shape :math:`(R, 4)`.
            Each element is a set of coordinates of a bounding box.
            The second axis corresponds to
            :math:`(y_{min}, x_{min}, y_{max}, x_{max})` of a bounding box.
        """
        py = base_size / 2.
        px = base_size / 2.
    
        anchor_base = np.zeros((len(ratios) * len(anchor_scales), 4),
                               dtype=np.float32)
        for i in six.moves.range(len(ratios)):
            for j in six.moves.range(len(anchor_scales)):
                h = base_size * anchor_scales[j] * np.sqrt(ratios[i])
                w = base_size * anchor_scales[j] * np.sqrt(1. / ratios[i])
    
                index = i * len(anchor_scales) + j
                anchor_base[index, 0] = py - h / 2.
                anchor_base[index, 1] = px - w / 2.
                anchor_base[index, 2] = py + h / 2.
                anchor_base[index, 3] = px + w / 2.
        return anchor_base
    
    • 参数和caffee一致,不同点在于,计算anchor_base的方式
    • 这里的anchor_base没有-1
    • 调用了两个循环,即遍历9次,每次得到一个anchors的坐标
    • 计算的公式很奇怪,为何对ratios开根号,应该是有奇怪的转换公式的
    • 最后,是直接求anchor_base的每一个坐标,以中心坐标为基准,计算(ymin, xmin, ymax, xmax)

本文为作者原创,转载需注明出处!

<think>好的,我现在需要帮助用户了解区域提议网络RPN)的结构图,特别是关于深度学习和计算机视觉方面的内容。首先,我得回忆一下RPN的基本概念和它在目标检测中的作用。RPNFaster R-CNN中的关键部分,用于生成候选区域(Region Proposals),这样后续的网络可以对这些区域进行分类和边界框回归。 接下来,我需要确定用户的需求。用户可能希望了解RPN的结构图,包括各个组成部分及其功能。因此,我应该从输入、处理过程和输出三个方面来分解结构。输入通常是来自骨干网络(如VGG、ResNet)的特征图,这些特征图经过RPN处理后会生成候选区域。 然后,我需要详细描述RPN的各个组件。首先是3x3的卷积层,用于在特征图上滑动窗口,每个位置生成多个锚框(anchors)。锚框的尺寸和比例不同,用于捕捉不同大小和形状的目标。然后是两条并行的1x1卷积层,一条用于分类(判断锚框是否包含目标),另一条用于回归(调整锚框的位置和大小)。 在解释结构图时,应该注意使用术语的准确性,比如锚框的生成、分类得分的计算、边界框回归等。同时,可能需要提到RPN的训练过程,包括正负样本的选取和损失函数的设计。此外,还需要说明RPN如何与后续的RoI Pooling或RoI Align结合,例如在Faster R-CNN中的工作流程。 用户提供的引用材料中有提到RPN之后的操作,如RoIPooling和RoIAlign,虽然这些不属于RPN本身,但可以简要提及以展示整体流程。同时,引用[4]提到的骨干网络(backbone)也是RPN结构的重要组成部分,需要强调骨干网络在特征提取中的作用。 用户可能还希望了解结构图中的具体数据流动,例如特征图的尺寸变化、锚框的数量计算,以及如何通过NMS(非极大值抑制)筛选候选区域。这部分需要以清晰的方式呈现,可能结合示例数值帮助理解。 最后,考虑到用户要求生成相关问题,我需要准备几个与RPN相关的问题,例如优化方法、与其他组件的区别、在不同骨干网络中的表现等。这些问题应覆盖结构、训练和应用方面,帮助用户进一步探索。 总结一下,回答的结构应包括: 1. RPN的作用和位置 2. 结构图的详细分解(输入、处理、输出) 3. 关键组件解释(锚框、分类和回归层) 4. 训练方法和损失函数 5. 与后续组件的协作 6. 示例应用和骨干网络的影响 7. 相关问题 需要确保使用正确的中文术语,并引用提供的参考资料,特别是引用[2]关于RPN后的处理,以及引用[4]关于骨干网络的部分。同时,注意行内公式使用$...$,独立公式用$$...$$,并检查LaTeX语法的正确性。</think>### 区域提议网络RPN)结构详解 区域提议网络(Region Proposal Network, RPN)是目标检测模型(如Faster R-CNN)的核心组件,用于高效生成候选目标区域[^2]。其结构图可分解为以下关键部分: --- #### 1. **输入特征图** - 输入为骨干网络(如VGG、ResNet)提取的共享特征图,尺寸为$H \times W \times C$,例如$38 \times 38 \times 512$[^4]。 - 骨干网络通过卷积操作捕获图像的高层语义信息,为后续区域提议提供基础特征。 --- #### 2. **锚框生成(Anchors)** - 在每个特征图位置上生成$k$个预定义尺寸和长宽比的锚框(如$k=9$,含3种尺寸和3种比例)。 - 锚框坐标为$(x_{center}, y_{center}, w, h)$,覆盖不同潜在目标区域--- #### 3. **RPN核心处理** - **3×3卷积层**:对特征图进行滑动窗口卷积,输出维度为$H \times W \times 256$(假设通道数为256),用于捕捉局部上下文信息。 - **并行分支**: - **分类分支(cls)**:1×1卷积层,输出$H \times W \times 2k$,预测每个锚框包含目标的概率(前景/背景)。 - **回归分支(reg)**:1×1卷积层,输出$H \times W \times 4k$,预测锚框的偏移量$(Δx, Δy, Δw, Δh)$以调整位置。 --- #### 4. **输出处理** - 通过非极大值抑制(NMS)筛选高质量候选框: - 保留前$N$个得分最高的候选框(如$N=2000$)。 - 根据回归偏移调整锚框坐标,生成最终区域提议(Proposals)。 --- #### 5. **数学表达** 分类损失(交叉熵)与回归损失(Smooth L1)联合优化: $$ L = \frac{1}{N_{cls}} \sum L_{cls} + \lambda \frac{1}{N_{reg}} \sum L_{reg} $$ 其中$\lambda$用于平衡两类损失。 --- #### 6. **结构图示例(文字描述)** ``` 输入特征图 → 3×3卷积 → 分类分支(前景/背景概率) + 回归分支(坐标偏移) → 锚框调整 → NMS过滤 → 输出候选区域 ``` --- ### 关键特性 - **共享计算**:与骨干网络共享特征图,减少重复计算。 - **端到端训练**:通过反向传播联合优化分类和回归任务[^3]。 - **多尺度感知**:锚框设计适应不同目标尺寸,提升召回率。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值