SiamFC论文解读及代码实现

论文链接:https://arxiv.org/pdf/1606.09549.pdf
论文代码:复现中

摘要:传统上,任意目标跟踪的问题是通过专门在线学习目标外观的模型来解决的,使用视频本身作为唯一的训练数据。尽管这些方法取得了成功,但他们的纯在线方法固有地限制了他们可以学习的模型的丰富性。最近,有人试图利用深层卷积网络的表达能力。然而,当要跟踪的目标事先未知时,需要在线执行随机梯度下降以适应网络的权重,这严重影响了系统的速度。在本文中,我们在ILSVRC15数据集上为视频中的目标检测配备了一个基本的跟踪算法和一个新的端到端训练的孪生神经网络。我们的跟踪器以超过实时的帧速率运行,尽管极其简单,但在多个基准测试中实现了最先进的性能。

1. 论文精华

1.1 Introduction

在单目标跟踪任意对象的问题上,其中对象仅仅由第一帧给框出来,通过算法完成后续的跟踪。由于该算法可能被要求跟踪任意任何对象看,因此不可能已经收集了数据并训练特定的检测器。

最近的几项工作旨在通过使用预训练的深度卷积网络来克服这一限制,该网络是为一项不同但相关的任务学习的。这些方法要么应用“浅层”方法(如相关滤波器),将网络的内部表示作为特征,要么执行SGD(随机梯度下降)来微调网络的多层。各有利弊,使用浅层方法无法充分利用端到端学习,应用SGD以获得最先进结果的方法无法实时运行。

我们提倡另一种方法,即在初始离线阶段训练深度卷积网络来解决更一般的相似性学习问题,然后在跟踪过程中在线简单地评估该函数。本文的主要贡献在于证明,这种方法在现代跟踪基准测试中,以远远超过帧速率要求的速度实现了非常有竞争力的性能。具体来说,我们训练孪生神经网络在更大的搜索图像中定位样本图像。另一个贡献是一种新的连体结构,它与搜索图像完全卷积:通过计算其两个输入的互相关的双线性层实现密集而高效的滑动窗口评估。

我们认为,相似性学习方法已相对被忽视,因为追踪社区无法访问大量标记的数据集。事实上,直到最近,可用的数据集只包含几百个带注释的视频。然而,我们认为,用于视频中目标检测的ILSVRC数据集[10](此后称为ImageNet视频)的出现,使训练这样一个模型成为可能。此外,train和test使用同域视频进行跟踪的深度模型的公平性是一个争议点,VOT委员会最近禁止了这种做法。我们的模型从ImageNet视频域推广到ALOV/OTB/VOT域,使得跟踪基准的视频可以用于测试。

1.2 用于跟踪的深度相似性学习

使用相似性学习可以解决学习跟踪任意对象的问题。我们建议学习一个函数 f ( z , x ) {f(z,x)} f(z,x),该函数将样本图像z与相同大小的候选图像x进行比较,如果两个图像描述相同的对象,则返回高分,否则返回低分。为了在新图像中找到物体的位置,我们可以彻底测试所有可能的位置,并选择与物体过去外观最相似的候选位置。在实验中,我们将简单地使用对象的初始外观作为示例。函数f将从带有标记对象轨迹的视频数据集中学习。

image-20220301194125028

图1 全卷积孪生结构。我们的结构相对于搜索图像X是全卷积的。输出是一个标量分数映射,其维度取决于搜索图像的大小。这使得可以在一次评估中得到所有搜索子窗口的相似性。4在这个例子中,输出图中红色和蓝色的像素包含对应子窗口的相似性。

整体可以用此公式表示:

f ( z , x ) = g ( φ ( z ) , φ ( x ) ) {f(z,x)=g(\varphi(z),\varphi(x))} f(z,x)=g(φ(z),φ(x))

当函数g是一个简单的距离或相似性度量时,函数 φ {\varphi} φ可以被视为嵌入

1.3 全卷积孪生网络结构

采用卷积嵌入函数 φ {\varphi} φ,采用互相关层结合输出特征图

f ( z , x ) = γ φ ( z ) ∗ φ ( x ) + b 1 {f(z,x)=\gamma\varphi(z)*{\varphi(x)}+b\mathbb{1}} f(z,x)=γφ(z)φ(x)+b1

我们采用了一种判别性方法,对网络进行正负配对训练,并采用logistic loss作为损失函数。

2. 说人话环节

2.1 单目标跟踪

单目标跟踪中,通常对第一帧待跟踪目标框出来,算法后续自动框出当前帧目标。SiamFC就是属于这种。

image-20220301194125028

2.2 网络结构

  1. 首先,对于第一帧的待跟踪目标,我们在目标中心将其crop出来,得到 255 × 255 × 3 255\times255\times3 255×255×3的search image和 127 × 127 × 3 127\times127\times3 127×127×3的exemplar image。
  2. 网络仅有一个backbone,即不要全连接层的Alexnet。当Alexnet输入图像为 255 × 255 × 3 255\times255\times3 255×255×3时,输出特征图就是 22 × 22 × 128 22\times22\times128 22×22×128;当Alexnet输入图像为 127 × 127 × 3 127\times127\times3 127×127×3时,输出特征图就是 6 × 6 × 128 6\times6\times128 6×6×128因此网络是分两次分别输入search image和exemplar image。这也就是文章所说的权值共享,根本上就只有一个网络。
  3. 对于得到的search image的特征图和exemplar image的特征图,进行互卷积操作。我们都知道,卷积操作就是利用卷积核去提取和自己相似的特征,是一个模板匹配的过程,而当卷积核为exemplar image时,那其意义就变成了:在图像中找到和自己相似的区域,提取出来。
  4. 卷积出来得到了一张 17 × 17 × 1 17\times17\times1 17×17×1的特征图,称为响应图,卷积后,若区域和自己很相似,那么在数值上体现出来就是更大,如果两个区域描述相同的对象,则高分,否则低分。那么我们就可以通过这个特征图上的最大值去映射到原图,从而找到待跟踪目标并框出来。

2.3 数学描述

  1. 网络提取特征:我们得到search image和exemplar image后,用 z z z表示exemplar image,用 x x x表示search image,用 φ \varphi φ表示网络Alexnet,数学表示为

M a p x = φ ( x ) Map_{x}=\varphi(x) Mapx=φ(x)

M a p z = φ ( z ) Map_{z}=\varphi(z) Mapz=φ(z)

  1. 互卷积操作:对特征图进行互卷积操作,是 M a p z [ 128 , 6 , 6 ] Map_{z}[128,6,6] Mapz[128,6,6]作为卷积核, M a p x [ 128 , 22 , 22 ] Map_{x}[128,22,22] Mapx[128,22,22]作为待卷积图。卷积用 ∗ * 表示,输出响应图用 f ( z , x ) f(z,x) f(z,x)表示,数学表示为

f ( z , x ) = φ ( z ) ∗ φ ( x ) {f(z,x)=\varphi(z)*{\varphi(x)}} f(z,x)=φ(z)φ(x)

  1. 响应图调整:在卷积之后为了让loss function得到更高的值,在输出响应图之后,统一调整响应图的大小。当特征图统一乘以或加上某一个数时,对预测响应图中的最大值没有影响,但是对loss的计算——这是作者的原话。数学表示为

image-20220310140520719

f ( z , x ) = γ ( φ ( z ) ∗ φ ( x ) ) + b 1 {f(z,x)=\gamma(\varphi(z)*{\varphi(x)})+b\mathbb{1}} f(z,x)=γ(φ(z)φ(x))+b1

即响应图同时乘以一个数 γ \gamma γ,同时加上一个数 b 1 b\mathbb{1} b1,对输出结果做压缩或放大。在代码中,这里的 γ \gamma γ b 1 b\mathbb{1} b1则用 1 × 1 1\times1 1×1的卷积核实现,即input_channels=1,output_channels=1,stride=[1,1],没有padding。初始化时,将卷积核的值初始化为1e-3,bias初始化为0,即 γ = 1 e − 3 \gamma=1e-3 γ=1e3 b 1 = 0 b\mathbb{1}=0 b1=0。这也是原文的设置方法。

2.4 网络结构——pytorch实现

class SiamFCNet(nn.Module):
    def __init__(self, cfg):
        super(SiamFCNet, self).__init__()
        self.fea_extract = Backbone(cfg)
        self.xcorr = XCorr()
        self.adjust = nn.Conv2d(1, 1, kernel_size = (1, 1), stride = (1, 1))

    def forward(self, x):
        img_x, img_z = x
        # 1. 网络提取特征
        fea_z = self.fea_extract(img_z)
        fea_x = self.fea_extract(img_x)
        # 2. 互卷积操作
        score_map = self.xcorr(fea_x, fea_z)
        # 3. 响应图调整
        score_map = self.adjust(score_map)
        return score_map

    def init_weights(self):
        for idx, m in enumerate(self.modules()):
            if isinstance(m, nn.Conv2d):
                tmp_layer_idx = idx + 1
                if tmp_layer_idx < 6:
                    nn.init.kaiming_normal_(m.weight.data, mode = 'fan_out', nonlinearity = 'relu')
                else:
                    # 4. 初始化adjust layer
                    m.weight.data.fill_(1e-3)
                    m.bias.data.zero_()
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()
                
class XCorr(nn.Module):
    def __init__(self):
        super(XCorr, self).__init__()

    def forward(self, fea_x, fea_z):
        N, C, H, W = fea_x.shape
        fea_x = fea_x.view(1, -1, H, W)
        score_map = F.conv2d(fea_x, fea_z, groups = N)
        return score_map.transpose(0, 1)

3. 复现细节及注意事项

3.1 数据处理阶段:

  1. search image和exemplar image是从物体中心提取出的,需要在训练时通过groundtruth提取出图像中的目标。此网络是为了得到两张图片的相似情况,因此目标类别可以忽视。
  2. exemplar image为[127, 127, 3]大小,search image为[255, 255, 3]大小。
  3. 如何crop出exemplar image:crop目标前,我们有目标当前帧image和bbox。
    1. 根据bbox得到目标中心cx,cy,长宽w,h
    2. 依据公式 s ( w + 2 p ) × s ( h + 2 p ) = A , p = ( w + h ) / 4 s(w+2p)\times{s(h+2p)}=A,p=(w+h)/4 s(w+2p)×s(h+2p)=A,p=(w+h)/4
    3. 从cx,cy处中心裁剪,其中 A = 12 7 2 A=127^2 A=1272 ( w + 2 p ) ( h + 2 p ) \sqrt{(w+2p)(h+2p)} (w+2p)(h+2p) 表示目标crop出的size
    4. 将crop出的图像resize到127*127的大小,那么s表示缩放因子, s = ( w + 2 p ) ( h + 2 p ) A s=\cfrac{\sqrt{(w+2p)(h+2p)}}{\sqrt{A}} s=A (w+2p)(h+2p)
    5. 先计算,后crop,再resize,若超出图像边界,填充各通道平均值
  4. 如何crop出search image:crop目标前,我们有目标当前帧image和bbox,以及缩放因子s
    1. search image最终需要resize到255*255,为了保持缩放比例一致,因此有 c r o p s i z e 255 = s = ( w + 2 p ) ( h + 2 p ) 127 \cfrac{cropsize}{255}=s=\cfrac{\sqrt{(w+2p)(h+2p)}}{127} 255cropsize=s=127(w+2p)(h+2p) ,那么search image需要crop的size为 255 × s 255\times{s} 255×s
    2. 先计算,后crop,再resize,若超出图像边界,填充各通道平均值

3.2 训练阶段

loss采用pytorch中带权重的BCEWithLogitsLoss,并除以batch size,个人理解除以batch size是为了控制反向传播的大小。loss输入为网络输出的score map和label。

label输出如下

image-20220310150534550

权重输出如下

image-20220310150804748

响应图输出如下类似

image-20220310151250343

或者类似这样:

image-20220310151334195

可以看到

  1. label只在中心出现,这是由于我们的图像都是从目标中心crop的
  2. 带权重的loss保证loss兼顾正负样本
  3. 输出响应图可以看到有不同的响应区域,值越大的区域越有可能出现目标。

3.3. 跟踪阶段

3.3.1 响应图上采样

跟踪阶段需要将得到的响应图映射回272272大小的响应图,采用双三次插值方法。问:为啥不映射到255255的大小?

We found that upsampling the score map using bicubic interpolation, from 17 × 17 to 272 × 272, results in more accurate localization since the original map is relatively coarse

因为输出响应图比较粗糙的缘故,我们发现,将响应图利用双三次插值方法上采样到272*272可以获得更精确的定位

3.3.2 图像金字塔

在跟踪时,为了处理比例变化,搜索五个比例的search image,即得到search image的crop size后,搜索五个比例的search image

C r o p S i z e = c r o p s i z e × 1.02 5 { − 2 , − 1 , 0 , 1 , 2 } CropSize=cropsize\times1.025^{\{-2,-1,0,1,2\}} CropSize=cropsize×1.025{ 2,1,0,1,2}共五个尺度

3.3.3 连续跟踪

  1. 第一帧手动框出图像后,得到第一帧的exemplar image,在后续的论文中也叫做模板。
    在这里插入图片描述

  2. 根据上一帧的物体的cx,cy和w,h,得到当前帧的多个尺度的search image
    在这里插入图片描述

  3. 将search image和exemplar image送入网络,得到响应图
    在这里插入图片描述

  4. 根据响应图的响应位置,改变cx,cy,w,h沿用上一帧,这样第二帧的cx,cy,w,h都有了
    在这里插入图片描述

  5. 重复2-4步骤

4. 优点和不足

4.1优点

  1. 将跟踪方法从以往的在线更新网络参数,转变为一对图片的相似性比较问题,siamese network in VOT的开山之作!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2. 跟踪迅速,网络全卷积,轻量
  3. 端到端实现跟踪

4.2 不足

  1. 模板仅用第一帧,未更新模板。时间尺度下由于光照、畸变、角度等原因,目标会发生变化(DSiam、UpdateNet等后续论文正在做的事)

  2. 跟踪边框大小仅用第一帧,未更新w,h。由于目标离摄像头的远近,目标的大小也会发生变化。

  3. 网络得到的响应图还需要自己上采样并得到cx,cy,能不能用统一的框架直接输出目标和边框(siamFC++、SiamRPN等后续论文正在做的事)

  4. 采用图像金字塔,运行慢,在目前的技术看来,能不能采用特征金字塔方式(C-RPN、SiamRPN++等后续论文正在做的事)

5. 发展

从现在看来,后续的论文依据此范式,在模板更新、网络一体化、以及加入anchor based、anchor free方法、提高网络提取特征能力上都做足了改进。并且仍然有很大的发展空间。

猜你喜欢

转载自blog.csdn.net/weixin_43913124/article/details/123403727
今日推荐