RepPoint:可形變卷積生成的目標(biāo)輪廓點(diǎn)集

論文題目為:
RepPoints: Point Set Representation for Object Detection

idea總結(jié):

  1. 改變目標(biāo)檢測(cè)領(lǐng)域中對(duì)于目標(biāo)用矩形框的表現(xiàn)形式,而是采用點(diǎn)集的形式來表現(xiàn)一個(gè)物體的輪廓
  2. 特征抽取后,配合deformable convolution來進(jìn)對(duì)物體中心點(diǎn)的偏移量學(xué)習(xí),得到其點(diǎn)集的位置.
  3. 提出deformable RoI pooling.
  4. 提出三種轉(zhuǎn)換方式,將點(diǎn)集轉(zhuǎn)化為矩形框方便評(píng)測(cè)該目標(biāo)檢測(cè)算法的指標(biāo)

respoints 表示

傳統(tǒng)目標(biāo)檢測(cè)采用一個(gè)4-D的向量來表示一個(gè)物體B=(x,y,w,h),其分別代表了物體的中心點(diǎn)(x,y)坐標(biāo),物體框的寬與高.

respoint則是用一組點(diǎn)集來表示,其中n代表了取樣點(diǎn)的數(shù)量(文中設(shè)置為9).建議為某個(gè)數(shù)的平方
R=\{(x_{k},y_{k})\}^{n}_{k=1}

如圖表示,respints在backbone骨干網(wǎng)絡(luò)抽取特征后,通過其RepPointsHead結(jié)構(gòu)轉(zhuǎn)化成9個(gè)物體的輪廓點(diǎn),然后,這9個(gè)點(diǎn)形成物體邊框的pseudo box,然后再轉(zhuǎn)化為傳統(tǒng)目標(biāo)檢測(cè)的bbox.

image

回顧傳統(tǒng)的多階段目標(biāo)檢測(cè)

傳統(tǒng)的兩階段目標(biāo)檢測(cè)流程:

  1. 通過預(yù)設(shè)的錨點(diǎn)(anchor)來覆蓋一定范圍的邊界框比例和縱橫比.
  2. 對(duì)于錨點(diǎn),將其中心點(diǎn)處的圖像特征作為對(duì)象特征,生成有關(guān)錨點(diǎn)是否為目標(biāo)對(duì)象的置信度得分,并通過邊界框回歸生成精煉的邊界框(bbox proposals)
  3. 在第二階段,通過 RoI-pooling 或 RoI-Align從(2)中獲得的邊界框建議提取對(duì)象特征.
  4. 經(jīng)過改進(jìn)的特征將通過邊界框回歸產(chǎn)生最終的邊界框目標(biāo)莽使。
  5. 對(duì)于多階段方法茎辐,還通過邊界框回歸委造,使用改進(jìn)的特征來生成中間的改進(jìn)的邊界框建議(S2)。在生成最終的邊界框目標(biāo)之前,可以多次重復(fù)此步驟,用以修正目標(biāo)框邊界.

邊界框與點(diǎn)集回歸對(duì)比

逐步完善邊界框定位和特征提取對(duì)于多階段目標(biāo)檢測(cè)方法的成功至關(guān)重要。

對(duì)于bbox表現(xiàn)形式:

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)

對(duì)于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)

對(duì)于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}是預(yù)測(cè)點(diǎn)的offset.

所以我們只需要學(xué)習(xí)其offset,然后加到原始點(diǎn)坐標(biāo)即可.

RPDet:anchor free的respoint 檢測(cè)器

其流程如下圖所示:

image
  1. 使用中心點(diǎn)作為對(duì)象的初始表示.
  2. 基于中心點(diǎn),通過deformable convolution 來學(xué)習(xí)每個(gè)中心點(diǎn)的偏移量,如9個(gè)點(diǎn)偏移量來表示物體,則用一個(gè)3 X 3的可變形卷積.然后利用偏移量對(duì)物體位置進(jìn)行回歸.
  3. 經(jīng)過兩次deformable convolution的offset偏移量回歸矯正,形成respints object

其RPDet的head主要算法結(jié)構(gòu)如圖所示:

image

其中l(wèi)ocate subnet 與class subnet兩個(gè)子網(wǎng)絡(luò)的輸入都是通過rpn主干網(wǎng)絡(luò)抽取的相同圖像特征.

我們看到通過center point生成respoint的奧秘在于locate subnet中那個(gè) 3 X 3 的可變形卷積自動(dòng)學(xué)習(xí)得到的關(guān)于物體的感受野位置

respoint 生成bbox的三種方法:

  1. Min-max function.在RepPoints上執(zhí)行兩個(gè)軸上的Min-max操作以確定Bp,等效于所有采樣點(diǎn)上的邊界框值.
  2. Partial min-max function.在兩個(gè)軸上分別對(duì)樣本點(diǎn)的子集進(jìn)行最小-最大運(yùn)算向图,以獲得矩形框值.
  3. Moment-based function.RepPoints的平均值和標(biāo)準(zhǔn)偏差用于計(jì)算矩形框Bp的中心點(diǎn)和比例,其中比例與全球共享的可學(xué)習(xí)乘數(shù)λx和λy相乘标沪。(代碼中默認(rèn)使用這種方式)

loss的計(jì)算:

  1. location loss:先將respoint轉(zhuǎn)換為偽框(pseudo box),然后計(jì)算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'))

其主干網(wǎng)絡(luò)采用restnet+fpn的形式,正常的多尺度抽取圖像特征;

下面我們結(jié)合reppoint-head的結(jié)構(gòu)圖,來看兩個(gè)subnet是如何發(fā)揮作用的:
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大小即為定義點(diǎn)的數(shù)量,即用一個(gè)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()
        #兩個(gè)subnet分別都有3個(gè)3X3的卷積進(jìn)行特征抽取工作
        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進(jìn)行offset學(xué)習(xí)部分網(wǎng)絡(luò)定義
        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)
    #網(wǎng)絡(luò)前饋計(jì)算
    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

總結(jié)與tips

這篇論文在我的理解中,更像是將可形變卷積應(yīng)用在了目標(biāo)檢測(cè)領(lǐng)域,通過定位和分類的監(jiān)督loss來監(jiān)督可形變卷積對(duì)于物體偏移量的學(xué)習(xí),使得卷積的學(xué)習(xí)變得可解釋性.啟發(fā)我們可以可以用不同的監(jiān)督信息來使用可形變卷積.

respoint 如何解決同一位置多個(gè)物體的遮擋問題:

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.

作者認(rèn)為通過rpn結(jié)構(gòu)將不同比例對(duì)象分配給不同的圖像特征的方式來解決;

但這種方式能放解決像行人檢測(cè)中多個(gè)行人遮擋問題還有待商榷.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末榄攀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子金句,更是在濱河造成了極大的恐慌檩赢,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件违寞,死亡現(xiàn)場(chǎng)離奇詭異贞瞒,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)趁曼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門军浆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人挡闰,你說我怎么就攤上這事乒融。” “怎么了摄悯?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵赞季,是天一觀的道長。 經(jīng)常有香客問我奢驯,道長申钩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任叨橱,我火速辦了婚禮典蜕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘罗洗。我一直安慰自己,他們只是感情好钢猛,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布伙菜。 她就那樣靜靜地躺著,像睡著了一般命迈。 火紅的嫁衣襯著肌膚如雪贩绕。 梳的紋絲不亂的頭發(fā)上火的,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音淑倾,去河邊找鬼馏鹤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛娇哆,可吹牛的內(nèi)容都是我干的湃累。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼碍讨,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼治力!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起勃黍,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤宵统,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后覆获,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體马澈,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年弄息,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了箭券。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疑枯,死狀恐怖辩块,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荆永,我是刑警寧澤废亭,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站具钥,受9級(jí)特大地震影響豆村,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜骂删,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一掌动、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宁玫,春花似錦粗恢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春妖碉,著一層夾襖步出監(jiān)牢的瞬間涌庭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工欧宜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坐榆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓冗茸,卻偏偏與公主長得像席镀,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚀狰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344