CornerNet:Detecting Objects as Paired Keypoints

论文思想

将检测问题建模成关键点检测问题,通过检测左上、右下两个关键点来回归出检测框,是一种anchor free 的目标检测算法。主要解决了anchor based方法的两大问题:

  1. anchor based方法分配gt的策略会很大程度的导致正负样本不平衡的请款
  2. anchor boxes生成会引入大量的超参,训练比较难

模型架构

以640*640为输入data,总Flops达到707.76GFLOPs
各个模块占比情况

layerhourglass backbonetl_poolbr_pooltl_heatbr_heattl_offbr_offtl_embbr_emb
Flops51.745%11.162%11.162%4.419%4.419%4.274%4.274%4.272%4.272%

backbone

cornernet论文中backbone选择的是包含2个hourglasses的stacked hourglass网络,每个hourglasses中包含5次下采样和5次上采样过程,使用stride=2的3*3 conv替换maxpool以增强网络的学习能力。

输入data会经过stem layer(77 stride=2的conv+reslayer stride=2)将feature map降为(640/4)(6404),通道数变为256。之后经过hourglass module。
hourglass结构就是类似沙漏的网络结构,先经过5次下采样将160
160256变为(160/32)(160/32)512,之后再通过5次上采样将55512恢复成160160*256。之所以设计这样的网络结构主要是为了捕获各个尺度下的信息,从而更适合关键点检测这种需要综合考虑局部和全局信息的任务。由于下采样、上采样过程中会产生信息损失,因此使用skip layer将下采样前的特征加回到上采样后的feature map中,减少信息损失。
hourglass

intermediate supervision

传统的识别或者检测网络,loss只比较最后的预测与ground truth之间的差异。因为堆叠沙漏网络的每一个子沙漏网络都会有heat map作为预测,所以将每个沙漏输出的heat map参与到loss中,实验证实,预测精确度要远远好于只考虑最后一个沙漏预测的loss,这种考虑网络中间部分的监督训练方式,就叫做中间监督。

tl_pool br_pool

cornernet中提出了corner pool的概念。object的角点通常来说都是没有语义信息的,为了更好的定位角点,提出使用corner pool来解决。
对于左上角点来说,为了更好的定位左上角点,需要对从左至右的特征和由上至下的“优势”特征进行特征增强。
具体做法:首先需要由backbone输出的featuremap x分别得到垂直方向、竖直方向特征图,命名为ft fl。
在这里插入图片描述
corner pool的过程比较简单,简单来说就是使用maxpool实现优势特征点在对应方向上的延续,以增强左上角特征。
例如ft为
在这里插入图片描述
fl
在这里插入图片描述

将经过corner pool后的ft和fl相加即可得到tl经过corner pool后的特征
在这里插入图片描述
也就是尽可能将大元素集中在feature map的左上部分。论文里实验表明,通过加入cornermap,tl、br的map都有3个点左右的提升。
后面得到tl heat map 、tl offset、tl emb等feature map都是基于cornermap之后的特征图
在这里插入图片描述

如何匹配角点

corner match怎么做也是这篇论文中一个关键点。tl heat map brheatmap确实可以得到所有可能的左上、右下角点,但是哪个左上、右下同属于一个检测框却不得而知。此篇论文的策略是分别预测tl和br的embedding,让同属于一个检测框的embedding值尽可能相近,不同检测框的embedding差值尽可能大。这样在预测时只需要比较tl br embedding的L1距离即可将corner匹配上。

embedding loss设计

embeddding的具体值对于网络来说并不重要,主要原则是同属一个框的tl br的embedding距离要足够近,不同框之间的tl br的embedding距离要足够远。因此设计了Lpull 和Lpush来共同计算embedding的loss
在这里插入图片描述
具体实现

def ae_loss_per_image(tl_preds, br_preds, match):
    """Associative Embedding Loss in one image.

    Associative Embedding Loss including two parts: pull loss and push loss.
    Pull loss makes embedding vectors from same object closer to each other.
    Push loss distinguish embedding vector from different objects, and makes
        the gap between them is large enough.

    During computing, usually there are 3 cases:
        - no object in image: both pull loss and push loss will be 0.
        - one object in image: push loss will be 0 and pull loss is computed
            by the two corner of the only object.
        - more than one objects in image: pull loss is computed by corner pairs
            from each object, push loss is computed by each object with all
            other objects. We use confusion matrix with 0 in diagonal to
            compute the push loss.

    Args:
        tl_preds (tensor): Embedding feature map of left-top corner.
        br_preds (tensor): Embedding feature map of bottim-right corner.
        match (list): Downsampled coordinates pair of each ground truth box.
    """

    tl_list, br_list, me_list = [], [], []
    if len(match) == 0:  # no object in image
        pull_loss = tl_preds.sum() * 0.
        push_loss = tl_preds.sum() * 0.
    else:
        for m in match:
            [tl_y, tl_x], [br_y, br_x] = m
            tl_e = tl_preds[:, tl_y, tl_x].view(-1, 1)
            br_e = br_preds[:, br_y, br_x].view(-1, 1)
            tl_list.append(tl_e)
            br_list.append(br_e)
            me_list.append((tl_e + br_e) / 2.0)

        tl_list = torch.cat(tl_list)
        br_list = torch.cat(br_list)
        me_list = torch.cat(me_list)

        assert tl_list.size() == br_list.size()

        # N is object number in image, M is dimension of embedding vector
        N, M = tl_list.size()

        pull_loss = (tl_list - me_list).pow(2) + (br_list - me_list).pow(2)
        pull_loss = pull_loss.sum() / N

        margin = 1  # exp setting of CornerNet, details in section 3.3 of paper

        # confusion matrix of push loss
        conf_mat = me_list.expand((N, N, M)).permute(1, 0, 2) - me_list
        conf_weight = 1 - torch.eye(N).type_as(me_list)
        conf_mat = conf_weight * (margin - conf_mat.sum(-1).abs())

        if N > 1:  # more than one object in current image
            push_loss = F.relu(conf_mat).sum() / (N * (N - 1))
        else:
            push_loss = tl_preds.sum() * 0.

    return pull_loss, push_loss

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值