RepPoint:可形变卷积生成的目标轮廓点集

论文题目为:
RepPoints: Point Set Representation for Object Detection

idea总结:

  1. 改变目标检测领域中对于目标用矩形框的表现形式,而是采用点集的形式来表现一个物体的轮廓
  2. 特征抽取后,配合deformable convolution来进对物体中心点的偏移量学习,得到其点集的位置.
  3. 提出deformable RoI pooling.
  4. 提出三种转换方式,将点集转化为矩形框方便评测该目标检测算法的指标

respoints 表示

传统目标检测采用一个4-D的向量来表示一个物体B=(x,y,w,h),其分别代表了物体的中心点(x,y)坐标,物体框的宽与高.

respoint则是用一组点集来表示,其中n代表了取样点的数量(文中设置为9).建议为某个数的平方
R=\{(x_{k},y_{k})\}^{n}_{k=1}

如图表示,respints在backbone骨干网络抽取特征后,通过其RepPointsHead结构转化成9个物体的轮廓点,然后,这9个点形成物体边框的pseudo box,然后再转化为传统目标检测的bbox.

image

回顾传统的多阶段目标检测

传统的两阶段目标检测流程:

  1. 通过预设的锚点(anchor)来覆盖一定范围的边界框比例和纵横比.
  2. 对于锚点,将其中心点处的图像特征作为对象特征,生成有关锚点是否为目标对象的置信度得分,并通过边界框回归生成精炼的边界框(bbox proposals)
  3. 在第二阶段,通过 RoI-pooling 或 RoI-Align从(2)中获得的边界框建议提取对象特征.
  4. 经过改进的特征将通过边界框回归产生最终的边界框目标。
  5. 对于多阶段方法,还通过边界框回归,使用改进的特征来生成中间的改进的边界框建议(S2)。在生成最终的边界框目标之前,可以多次重复此步骤,用以修正目标框边界.

边界框与点集回归对比

逐步完善边界框定位和特征提取对于多阶段目标检测方法的成功至关重要。

对于bbox表现形式:

4-d的回归量\left(\Delta x_{p}, \Delta y_{p}, \Delta w_{p}, \Delta h_{p}\right) map到原始的建议框bounding box proposal\mathcal{B}_{p}=\left(x_{p}, y_{p}, w_{p}, h_{p}\right):
\mathcal{B}_{r}=\left(x_{p}+w_{p} \Delta x_{p}, y_{p}+h_{p} \Delta y_{p}, w_{p} e^{\Delta w_{p}}, h_{p} e^{\Delta h_{p}}\right)

对于ground truth bounding box \mathcal{B}_{t}=(x_{t},y_{t},w_{t},h_{t}),我们的loss是要使\mathcal{B}_{r}更接近gt,所以其4-d的loss为:
\hat{\mathcal{F}}\left(\mathcal{B}_{p}, \mathcal{B}_{t}\right)=\left(\frac{x_{t}-x_{p}}{w_{p}}, \frac{y_{t}-y_{p}}{h_{p}}, \log \frac{w_{t}}{w_{p}}, \log \frac{h_{t}}{h_{p}}\right)

对于respoint形式

\mathcal{R}_{r}=\left\{\left(x_{k}+\Delta x_{k}, y_{k}+\Delta y_{k}\right)\right\}_{k=1}^{n}

\left\{\left(\Delta x_{k}, \Delta y_{k}\right)\right\}_{k=1}^{n}是预测点的offset.

所以我们只需要学习其offset,然后加到原始点坐标即可.

RPDet:anchor free的respoint 检测器

其流程如下图所示:

image
  1. 使用中心点作为对象的初始表示.
  2. 基于中心点,通过deformable convolution 来学习每个中心点的偏移量,如9个点偏移量来表示物体,则用一个3 X 3的可变形卷积.然后利用偏移量对物体位置进行回归.
  3. 经过两次deformable convolution的offset偏移量回归矫正,形成respints object

其RPDet的head主要算法结构如图所示:

image

其中locate subnet 与class subnet两个子网络的输入都是通过rpn主干网络抽取的相同图像特征.

我们看到通过center point生成respoint的奥秘在于locate subnet中那个 3 X 3 的可变形卷积自动学习得到的关于物体的感受野位置

respoint 生成bbox的三种方法:

  1. Min-max function.在RepPoints上执行两个轴上的Min-max操作以确定Bp,等效于所有采样点上的边界框值.
  2. Partial min-max function.在两个轴上分别对样本点的子集进行最小-最大运算,以获得矩形框值.
  3. Moment-based function.RepPoints的平均值和标准偏差用于计算矩形框Bp的中心点和比例,其中比例与全球共享的可学习乘数λx和λy相乘。(代码中默认使用这种方式)

loss的计算:

  1. location loss:先将respoint转换为伪框(pseudo box),然后计算pseudo box与ground- truth bounding box的loss.(论文中使用左上角与右下角之间的smooth l1 loss来得到location loss)
  2. classification loss:采用FocalLoss的形式来解决类别不平衡问题

代码分析

RPDet的代码在https://github.com/microsoft/RepPoints.已合并如mmdetion框架中,我们来看mmdetion中的代码:

config文件:
config/reppoints/reppoints_moment_r50_fpn_1x.py

#model定义
model = dict(
    type='RepPointsDetector',
    pretrained='torchvision://resnet50',
    backbone=dict(
        type='ResNet',
        depth=50,
        num_stages=4,
        out_indices=(0, 1, 2, 3),
        frozen_stages=1,
        style='pytorch'),
    neck=dict(
        type='FPN',
        in_channels=[256, 512, 1024, 2048],
        out_channels=256,
        start_level=1,
        add_extra_convs=True,
        num_outs=5,
        norm_cfg=norm_cfg),
    bbox_head=dict(
        type='RepPointsHead',
        num_classes=81,
        in_channels=256,
        feat_channels=256,
        point_feat_channels=256,
        stacked_convs=3,
        num_points=9,
        gradient_mul=0.1,
        point_strides=[8, 16, 32, 64, 128],
        point_base_scale=4,
        norm_cfg=norm_cfg,
        loss_cls=dict(
            type='FocalLoss',
            use_sigmoid=True,
            gamma=2.0,
            alpha=0.25,
            loss_weight=1.0),
        loss_bbox_init=dict(type='SmoothL1Loss', beta=0.11, loss_weight=0.5),
        loss_bbox_refine=dict(type='SmoothL1Loss', beta=0.11, loss_weight=1.0),
        transform_method='moment'))

其主干网络采用restnet+fpn的形式,正常的多尺度抽取图像特征;

下面我们结合reppoint-head的结构图,来看两个subnet是如何发挥作用的:
mmdet/models/anchor_heads/resppoints_head.py

@HEADS.register_module
class RepPointsHead(nn.Module):
    def __init__(self,****)
#部分省略初始化定义

        # we use deformable conv to extract points features
        #dcn的kernel大小即为定义点的数量,即用一个dcn的感受野来表示物体轮廓
        self.dcn_kernel = int(np.sqrt(num_points))
        self.dcn_pad = int((self.dcn_kernel - 1) / 2)
        assert self.dcn_kernel * self.dcn_kernel == num_points, \
            "The points number should be a square number."
        assert self.dcn_kernel % 2 == 1, \
            "The points number should be an odd square number."
        #可变形卷积的初始化x,y偏移量
        dcn_base = np.arange(-self.dcn_pad,
                             self.dcn_pad + 1).astype(np.float64)
        dcn_base_y = np.repeat(dcn_base, self.dcn_kernel)
        dcn_base_x = np.tile(dcn_base, self.dcn_kernel)
        dcn_base_offset = np.stack([dcn_base_y, dcn_base_x], axis=1).reshape(
            (-1))
        self.dcn_base_offset = torch.tensor(dcn_base_offset).view(1, -1, 1, 1)
        self._init_layers()

     def _init_layers(self):
        self.relu = nn.ReLU(inplace=True)
        self.cls_convs = nn.ModuleList()
        self.reg_convs = nn.ModuleList()
        #两个subnet分别都有3个3X3的卷积进行特征抽取工作
        for i in range(self.stacked_convs):
            chn = self.in_channels if i == 0 else self.feat_channels
            self.cls_convs.append(
                ConvModule(
                    chn,
                    self.feat_channels,
                    3,
                    stride=1,
                    padding=1,
                    conv_cfg=self.conv_cfg,
                    norm_cfg=self.norm_cfg))
            self.reg_convs.append(
                ConvModule(
                    chn,
                    self.feat_channels,
                    3,
                    stride=1,
                    padding=1,
                    conv_cfg=self.conv_cfg,
                    norm_cfg=self.norm_cfg))
        #respoint利用dcn进行offset学习部分网络定义
        pts_out_dim = 4 if self.use_grid_points else 2 * self.num_points
        self.reppoints_cls_conv = DeformConv(self.feat_channels,
                                             self.point_feat_channels,
                                             self.dcn_kernel, 1, self.dcn_pad)
        self.reppoints_cls_out = nn.Conv2d(self.point_feat_channels,
                                           self.cls_out_channels, 1, 1, 0)
        self.reppoints_pts_init_conv = nn.Conv2d(self.feat_channels,
                                                 self.point_feat_channels, 3,
                                                 1, 1)
        self.reppoints_pts_init_out = nn.Conv2d(self.point_feat_channels,
                                                pts_out_dim, 1, 1, 0)
        self.reppoints_pts_refine_conv = DeformConv(self.feat_channels,
                                                    self.point_feat_channels,
                                                    self.dcn_kernel, 1,
                                                    self.dcn_pad)
        self.reppoints_pts_refine_out = nn.Conv2d(self.point_feat_channels,
                                                  pts_out_dim, 1, 1, 0)
    #网络前馈计算
    def forward_single(self, x):
        dcn_base_offset = self.dcn_base_offset.type_as(x)
        # If we use center_init, the initial reppoints is from center points.
        # If we use bounding bbox representation, the initial reppoints is
        #   from regular grid placed on a pre-defined bbox.
        if self.use_grid_points or not self.center_init:
            scale = self.point_base_scale / 2
            points_init = dcn_base_offset / dcn_base_offset.max() * scale
            bbox_init = x.new_tensor([-scale, -scale, scale,
                                      scale]).view(1, 4, 1, 1)
        else:
            points_init = 0
        cls_feat = x
        pts_feat = x
        for cls_conv in self.cls_convs:
            cls_feat = cls_conv(cls_feat)
        for reg_conv in self.reg_convs:
            pts_feat = reg_conv(pts_feat)
        # initialize reppoints
        pts_out_init = self.reppoints_pts_init_out(
            self.relu(self.reppoints_pts_init_conv(pts_feat)))
        if self.use_grid_points:
            pts_out_init, bbox_out_init = self.gen_grid_from_reg(
                pts_out_init, bbox_init.detach())
        else:
            pts_out_init = pts_out_init + points_init
        # refine and classify reppoints
        pts_out_init_grad_mul = (1 - self.gradient_mul) * pts_out_init.detach(
        ) + self.gradient_mul * pts_out_init
        dcn_offset = pts_out_init_grad_mul - dcn_base_offset
        cls_out = self.reppoints_cls_out(
            self.relu(self.reppoints_cls_conv(cls_feat, dcn_offset)))
        pts_out_refine = self.reppoints_pts_refine_out(
            self.relu(self.reppoints_pts_refine_conv(pts_feat, dcn_offset)))
        if self.use_grid_points:
            pts_out_refine, bbox_out_refine = self.gen_grid_from_reg(
                pts_out_refine, bbox_out_init.detach())
        else:
            pts_out_refine = pts_out_refine + pts_out_init.detach()
        return cls_out, pts_out_init, pts_out_refine

总结与tips

这篇论文在我的理解中,更像是将可形变卷积应用在了目标检测领域,通过定位和分类的监督loss来监督可形变卷积对于物体偏移量的学习,使得卷积的学习变得可解释性.启发我们可以可以用不同的监督信息来使用可形变卷积.

respoint 如何解决同一位置多个物体的遮挡问题:

In RPDet, we show that this issue can be greatly alleviated by using the FPN structure [24] for the following reasons: first, objects of different scales will be assigned to different image feature levels, which addresses objects of different scales and the same center points locations; second, FPN has a high-resolution feature map for small objects, which also reduces the chance of two objects having centers located at the same feature position.

作者认为通过rpn结构将不同比例对象分配给不同的图像特征的方式来解决;

但这种方式能放解决像行人检测中多个行人遮挡问题还有待商榷.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271