High Performance Visual Tracking With Siamese Region Proposal Network(SiamRPN)阅读笔记

前言

SiamRPN是在孪生网络的基础上增加了RPN模块,即可以让tracker对在检测帧中选择的proposals进行学习,并对目标进行回归,从而检测帧中使用更慢的selective search。SiamRPN速度很快,但未在在线跟踪中对模型进行fine-tuning,因此其精确度较之后能进行online learning的tracker还是差了些。

模块

孪生网络

孪生网络(Siamese)在近年来是tracker模型的主流,得益于其通过将目标帧与模板帧中的目标进行特征提取,再对两者进行相似度比较(cross correlation),从而判断在检测帧中该目标是否为我们所跟踪的目标。

在实际跟踪中,tracker可能跟踪的是任意一个模型训练中未曾见到过的物体,由于传统的基于相关滤波的tracker在训练集中从未见过该类目标,则因此tracker对这类目标的跟踪性能并不好。

而Siamese则是根据相似度匹配的原则来进行跟踪,因此即是出现训练集中未出现的目标,根据比较检测帧和模板帧中目标的相似度,也能进行跟踪。

实施细节


在孪生网络模块中,有两个分支,分别对应检测帧和模板帧。两个分支分别通过CNN进行特征提取。CNN使用基于已经训练好的AlexNet进行改进。

 self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=11, stride=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(64, 192, kernel_size=5),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(192, 384, kernel_size=3),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3),
        )

其中包括以RELU为激励函数和池化层Max pooling用来保证不变性以及降低特征维度。但该CNN中没有使用padding,忽略了边界信息,可能是因为模板帧与检测帧中的目标都在中间。阅读SiamRPN++的论文后发现,无padding也是为了满足空间不变性。

RPN

Region proposal network通过将proposals的选取加入到学习过程中,从而能够得到更加精确的proposal。RPN的核心是基于anchor以及bounding box regression,其中两个分支一个是分类分支,用于计算输出与Ground Truth的IoU,根据IoU是否大于一个阈值,从而判断proposal是否为目标;第二个分支即为回归分支,即将得到的输出框进行微调,使其更加接近Ground Truth。
在这里插入图片描述

实施细节

RPN中有两个分支,分别为classfication branch以及regression branch。由于在检测帧中存在k个anchor,代码中k=5,因此为了给每个anchor都有一个对应的分类得分,并且回归这组anchor,因此需要将模板分支,经孪生网络出来后的φ(z)通过卷积将通道数分别对分类分支和回归分支提升2k和4k倍。充当卷积核。最后将卷积核与检测帧做卷积操作。代码中将卷积核转换为可以训练的卷积层的参数:

self.cconv.weight = nn.Parameter(ckernal)
self.rconv.weight = nn.Parameter(rkernal)

最终的结果是:
A w × h × 2 k c l s = [ φ ( x ) ] c l s ⋆ [ φ ( z ) ] c l s A_{w×h×2k}^{cls}=[φ(x)]_{cls}\star[φ(z)]_{cls} Aw×h×2kcls=[φ(x)]cls[φ(z)]cls

A w × h × 4 k r e g = [ φ ( x ) ] r e g ⋆ [ φ ( z ) ] r e g A_{w×h×4k}^{reg}=[φ(x)]_{reg}\star[φ(z)]_{reg} Aw×h×4kreg=[φ(x)]reg[φ(z)]reg

A w × h × 2 k c l s A_{w×h×2k}^{cls} Aw×h×2kcls代表了每个anchor的正负样本概率,而 A w × h × 4 k r e g A_{w×h×4k}^{reg} Aw×h×4kreg则代表了anchor到groundtruth的距离dx,dy,dw,dh。

Loss

对于分类分支的loss,采用常用于分类的交叉熵损失函数(cross-entropy loss):
L c l s = − 1 n ∑ x [ y l n a + ( 1 − y ) l n ( 1 − a ) ] L_{cls}=-\frac{1}{n}\displaystyle\sum_{x}[ylna+(1-y)ln(1-a)] Lcls=n1x[ylna+(1y)ln(1a)]
对于回归分支的loss,采用的是smooth L 1 L_1 L1 loss,这种loss对于处理有四个偏移点的bounding box regression具有很好的鲁棒性。
根据bounding box regression:

δ [ 0 ] = T x − A x A w \delta[0]=\frac{T_x-A_x}{A_w} δ[0]=AwTxAx δ [ 1 ] = T y − A y A h \delta[1]=\frac{T_y-A_y}{A_h} δ[1]=AhTyAy δ [ 2 ] = l n T w A w \delta[2]=ln\frac{T_w}{A_w} δ[2]=lnAwTw δ [ 3 ] = l n T h A h \delta[3]=ln\frac{T_h}{A_h} δ[3]=lnAhTh

T x T_x Tx T y T_y Ty T w T_w Tw T h T_h Th分别代表ground truth的中心坐标以及形状大小,而 A x A_x Ax A y A_y Ay A w A_w Aw A h A_h Ah则代表的是anchor的中心坐标及形状大小。 δ \delta δ则为回归目标dx,dy,dw,dh。

smooth L1 loss公式为:
s m o o t h L 1 ( x , σ ) = { 0.5 σ 2 x 2 , ∣ x ∣ < 1 σ 2 ∣ x ∣ − 1 2 σ 2 , ∣ x ∣ ≥ 1 σ 2 smooth_{L1}(x,\sigma)=\left\{ \begin{array}{c}0.5\sigma^2x^2,|x|<\frac{1}{\sigma^2}\\ |x|-\frac{1}{2\sigma^2},|x|≥\frac{1}{\sigma^2} \end{array}\right. smoothL1(x,σ)={0.5σ2x2,x<σ21x2σ21,xσ21
最终的回归分支loss为:
L r e g = ∑ i = 0 3 s m o o t h L 1 ( δ [ i ] , σ ) L_{reg}=\displaystyle\sum_{i=0}^3smooth_{L1}(\delta[i],\sigma) Lreg=i=03smoothL1(δ[i],σ)
总体loss为:
l o s s = L c l s + λ L r e g loss=L_{cls}+\lambda L_{reg} loss=Lcls+λLreg

anchor

anchor为检测帧中的预定框。而anchor的生成由三个参数决定:anchor scale,anchor ratio以及anchor stride。anchor ratio即为anchor的高宽比,文中给出的ratio为:[0.33,0.5,1,2,3];而anchor scale则为anchor的大小,代码中设定的是8。anchor stride,根据代码中的用途,是一个预定的size,而最终anchor的size则是在这个预定大小的size上再乘以anchor scale,文中的anchor scale同样为8.可以得出最终生成的anchor接近64*64。

Tracking

tracking中,使用了one-shot learning的方法,将模板分支用来预测检测分支中卷积核的参数.
tracking的过程为:
首先根据上一帧中所得到bounding box,得到target的中心以及size,并通过:
( w + p ) × ( h + p ) = s 2 , p = w + h 2 (w+p)×(h+p)=s^2,p=\frac{w+h}{2} (w+p)×(h+p)=s2,p=2w+h
来得到要从当前帧中截取的正方形图片原始大小s,并且将s resize到预设大小255,如果resize后已经超过img的范围,则将对边界进行padding,对超出部分pad的值为整个图片所有通道的平均值。

w_z = self.size[0] + cfg.TRACK.CONTEXT_AMOUNT * np.sum(self.size) # w+p/2   self.size = traget's size
h_z = self.size[1] + cfg.TRACK.CONTEXT_AMOUNT * np.sum(self.size) # h+p/2
s_z = np.sqrt(w_z * h_z) # last frame proposal size
scale_z = cfg.TRACK.EXEMPLAR_SIZE / s_z #
s_x = s_z * (cfg.TRACK.INSTANCE_SIZE / cfg.TRACK.EXEMPLAR_SIZE) #
x_crop = self.get_subwindow(img, self.center_pos, cfg.TRACK.INSTANCE_SIZE,    # resize round(s_x)->instance_size
    round(s_x), self.channel_average)  # channel h w  # crop from this frame

get_subwindow 即为从检测帧中划分出crop的函数,输出的crop的值为(channel,height,width)。然后再将crop进行追踪,得到分类得分以及预测的bounding box。

Proposals selection

在得到由anchor所生成的bounding box之后,要从这些bounding box中选出候选区proposal。文章中采取了两种策略来筛选proposals。

首先将proposals的选取集中在离上一帧目标中心一个邻近范围内的anchor上,而那些距离中心很远的anchor生成的bounding box则不考虑。原因是,在连续的两帧中,目标的变化不会太大。

第二个策略则是添加尺度变化penalty和余弦窗,然后再对所选取的proposals进行re-rank。
添加penalty的目的,是为了对两帧之间相差太大的形状或大小进行抑制。
p e n a l t y = e k ∗ m a x ( r r ′ , r ′ r ) ∗ m a x ( s s ′ , s ′ s ) penalty=e^{k*max(\frac{r}{r'},\frac{r'}{r})*max(\frac{s}{s'},\frac{s'}{s})} penalty=ekmax(rr,rr)max(ss,ss)
其中r,s分别为proposal的ratio以及scale,而 r ′ r' r s ′ s' s则分别为上一帧中的ratio与scale。得到penalty后,再将penalty与proposal的分类得分相乘。

然后对其使用cosine window。生成cosine window的代码如下:

 hanning = np.hanning(self.score_size)
 window = np.outer(hanning, hanning)

经过这两行代码,可以生成一个高斯矩阵,用于突出中心位置目标,而忽略边缘化信息。添加cosine window penalty的目的就在于抑制边缘信息。

>>> hanning=np.hanning(5)
>>> hanning
array([0. , 0.5, 1. , 0.5, 0. ])
>>> window=np.outer(hanning,hanning)
>>> window
array([[0.  , 0.  , 0.  , 0.  , 0.  ],
       [0.  , 0.25, 0.5 , 0.25, 0.  ],
       [0.  , 0.5 , 1.  , 0.5 , 0.  ],
       [0.  , 0.25, 0.5 , 0.25, 0.  ],
       [0.  , 0.  , 0.  , 0.  , 0.  ]])

对经过scale change penalty后得到的score再进行window penalty,

pscore = pscore * (1 - cfg.TRACK.WINDOW_INFLUENCE) + \
                self.window * cfg.TRACK.WINDOW_INFLUENCE

可以看到余弦窗与原先得分分别乘上一个影响因子后再进行相加,得到各proposal的最终得分。然后将这些得分进行重拍,选出最大的那一个作为最终选定的proposal。在经过平滑处理以及剪裁边界后,得到最终的输出。

关于裁剪边界以及平滑bounding box部分还存在疑惑。

lr = penalty[best_idx] * score[best_idx] * cfg.TRACK.LR
        
cx = bbox[0] + self.center_pos[0]
cy = bbox[1] + self.center_pos[1]

# smooth bbox
width = self.size[0] * (1 - lr) + bbox[2] * lr
height = self.size[1] * (1 - lr) + bbox[3] * lr

# clip boundary
cx, cy, width, height = self._bbox_clip(cx, cy, width, height, img.shape[:2])

RPN模块代码剖析

SiamRPN中采用的是up-channel RPN。整个RPN模块的网络结构为:

self.template_cls_conv = nn.Conv2d(feature_in, 
                feature_in * cls_output, kernel_size=3)
self.template_loc_conv = nn.Conv2d(feature_in, 
                feature_in * loc_output, kernel_size=3)

self.search_cls_conv = nn.Conv2d(feature_in, 
                feature_in * cls_output, kernel_size=3)
self.search_loc_conv = nn.Conv2d(feature_in, 
                feature_in * loc_output, kernel_size=3)

模板分支和检测分支分别通过一层卷积层后,通道数从256分别变为256×2k与256×4k,对应分类与回归。通过卷积后,再将模板与检测分支做cross correlation。

def xcorr_fast(x, kernel): # n c w h    x: 1 256 20 20    kernel:1 256*2k 4 4
    """group conv2d to calculate cross correlation, fast version
    """
    batch = kernel.size()[0] # mini batch=1
    pk = kernel.view(-1, x.size()[1], kernel.size()[2], kernel.size()[3])  #(2k,256,4,4)
    px = x.view(1, -1, x.size()[2], x.size()[3]) # (1,256,20,20)
    po = F.conv2d(px, pk, groups=batch) # (2k,1,17,17)
    po = po.view(batch, -1, po.size()[2], po.size()[3]) # (1,2k,17,17) 
    return po

总结

本文将RPN网络与Siamese Network相结合,提高了追踪准确度,但存在的问题是其没有online learning,模板始终用的是第一帧,这种方式虽然在速度上很快,但性能上却还有待提高。

本文是本人对SiamRPN算法的一点自己的总结与分析,文中的代码段均来源于https://github.com/zkisthebest/Siamese-RPN 以及https://github.com/STVIR/pysot 图片截自High Performance Visual Tracking With Siamese Region Proposal Network

总结尚未完善,若文中有出错的地方,还请指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值