首页 > 其他分享 >OSTrack:Joint Feature Learning and Relation Modeling for Tracking: A One-Stream Framework

OSTrack:Joint Feature Learning and Relation Modeling for Tracking: A One-Stream Framework

时间:2024-11-19 20:18:22浏览次数:3  
标签:768 Tracking OSTrack features Stream inplace False True out

Abstract

问题:

传统的双流跟踪框架对目标提取的特征不够具体。

特征提取和关系建模是分开进行的,导致算法在区分目标和背景方面的能力有限。

两流、两阶段框架容易受到性能-速度困境的影响。

解决:

提出一种新的单流跟踪框架,OSTrack通过桥接具有双向信息流的模板搜索图像来统一特征学习和关系建模。

提出了一种基于单流框架中计算的强相似先验的网络内候选早期消除模块。

双流/单流

双流框架:

①Track-by-detection:检测流+关联流

②光流:光流流+特征流

③Anchor-free&re-ID:Anchor-free+re-ID

单流框架:单个模型同时检测和目标关联

本文创新点

①结合特征提取和关系建模,提出一种单流、单阶段跟踪框架。

②利用早期获得的目标与搜索区域各部分之间的相似性得分的先验性,提出了一种网络内早期候选消除模块,以减少推理时间。

Introduction

根据特征融合模块的计算量,通常采用两种不同的双流策略

双流两阶段轻关系跟踪框架:

举例:

孪生网络(Siamese networks)跟踪器

判别式(discriminative)跟踪器

过程:

①通过 CNN 主干网分别提取具有相同的结构和参数的模板和搜索区域特征

②采用单个算子,如互相关或判别相关滤波器融合特征用于状态估计

缺点:

效率高,但简单的线性运算导致判别信息丢失,效果差

无信息交互

双流两阶段重关系跟踪框架:

举例:

TransT:堆叠自注意力和交叉注意力层以进行迭代特征融合

STARK:将预先提取的模板和搜索区域特征连接输入自注意力层

缺点:

解决非线性交互造成的信息丢失问题(Transformer),但大量参数和使用迭代细化,效率低。

单流一阶段跟踪框架:

核心思想:

将模板和搜索区域连接,并将它们送到堆叠的自关注层中(Vision Transformer, ViT),生成的搜索区域特征直接用于目标分类和回归,而无需进一步匹配。

stacked self-attention layers:

堆叠多个自注意力层,每个自注意力层对输入序列处理,将输出传给下一个自注意力层。

模板会指导搜索区域的特征提取(让它更加关注目标),而搜索区域的信息也会反过来调整模板特征的表示。

优点:

在性能和速度之间取得了很好的平衡

单流框架提供了目标与搜索区域(即候选区域)的相似性的强先验

如图所示,该模型即使在早期阶段也可以识别背景区域,促使网络内早期候选淘汰模块放入提出。

Method

模型流程:

①输入图像对,包括目标初始框和搜索区域图像

# x:骨干网络的输出特征
# aux_dict:辅助字典,包含中间层特征或注意力权重
x, aux_dict = self.backbone(z=template, x=search,
                                    ce_template_mask=ce_template_mask,
                                    ce_keep_rate=ce_keep_rate,
                                    return_last_attn=return_last_attn, )  
# 跳转到 vit_ce.py---191  x Tensor:(4,320,768)

②将输入的图像送入ViT backbone预处理,切分图像块,将图像展平为一维向量

x = self.patch_embed(x)
z = self.patch_embed(z)

 ③线性投影到高维

    def forward(self, x):
        # allow different input size
        # B, C, H, W = x.shape
        # _assert(H == self.img_size[0], f"Input image height ({H}) doesn't match model ({self.img_size[0]}).")
        # _assert(W == self.img_size[1], f"Input image width ({W}) doesn't match model ({self.img_size[1]}).")
        x = self.proj(x)  # Tensor:(4,768,16,16)
        if self.flatten:
            x = x.flatten(2).transpose(1, 2)  # BCHW -> BNC  # Tensor:(4,256,768)
        x = self.norm(x)  # Tensor:(4,256,768)
        return x

 ④模型为每个包括图块特征和搜索区域的图块特征添加位置嵌入,特征包含图块嵌入和位置编码

⑤将图像嵌入连接并馈送到Transformer编码器层中,以进行联合特征提取和关系建模;模型可以包含多个编码器层,每个层都可能包含一个早期淘汰模块

# 将输入特征x通过线性变换得到QKV的组合表示,将其重新塑形和排列便于在注意力机制中使用
qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)

 已淘汰的模块:

 未淘汰的模块:经过多头注意力机制融合当前块和其他块的信息

⑥ 输入序列的长度需要被填充到一个固定的尺寸,使用令牌填充来确保所有序列具有相同长度。

占位符:是自动填充的,与淘汰的模块不是同一个

 

⑦经过编码器层处理后的特征被重塑(序列token拼回块状布局),通过一个头部网络来预测目标的位置。

    def cal_bbox(self, score_map_ctr, size_map, offset_map, return_score=False):
# 获取最大得分和索引
        max_score, idx = torch.max(score_map_ctr.flatten(1), dim=1, keepdim=True)  # shape都是 Tensor:(4,1) 按 batch 拿出最大的得分和所对应的索引
# 计算索引坐标
        idx_y = idx // self.feat_sz  # Tensor:(4,1)
        idx_x = idx % self.feat_sz  # Tensor:(4,1)
 
# 扩展索引以匹配尺寸和偏移图
        idx = idx.unsqueeze(1).expand(idx.shape[0], 2, 1)  # Tensor:(4,2,1)
# 获取目标尺寸和偏移
        size = size_map.flatten(2).gather(dim=2, index=idx)  # Tensor:(4,2,1)
        offset = offset_map.flatten(2).gather(dim=2, index=idx).squeeze(-1)  # Tensor:(4,2)
 
        # bbox = torch.cat([idx_x - size[:, 0] / 2, idx_y - size[:, 1] / 2,
        #                   idx_x + size[:, 0] / 2, idx_y + size[:, 1] / 2], dim=1) / self.feat_sz
        # cx, cy, w, h
# 计算边界框
        bbox = torch.cat([(idx_x.to(torch.float) + offset[:, :1]) / self.feat_sz,
                          (idx_y.to(torch.float) + offset[:, 1:]) / self.feat_sz,
                          size.squeeze(-1)], dim=1)  # Tensor:(4,4)

# 返回结果 
        if return_score:
            return bbox, max_score
        return bbox

Joint Feature Extraction and Relation Modeling

输入:

模板图像:z\in \mathbb{R}^{3*H_{z}*W_{z}}

搜索区域:x\in \mathbb{R}^{3*H_{x}*W_{x}}

展平:

模板图像:z_{p}\in \mathbb{R}^{N_{z}*(3\cdot P^{2})},P*P为每个小块的分辨率,N_{z}=\frac{H_{z}W_{z}}{P^{2}}为小块数量

搜索区域:x_{p}\in \mathbb{R}^{N_{x}*(3\cdot P^{2})}N_{x}=\frac{H_{x}W_{x}}{P^{2}}

投影:

拼接:

同时用于模板和搜索区域的自注意力操作输出:

W_{z z}:模板区域内不同特征的相似性

W_{x z}:模板区域内和搜索区域内的相似性,W_{x z}与之对称

W_{x x}:搜索区域内部不同特征的相似性

与Transformer对比:

Transformer层仅用于融合提取的特征

OSTrack 在第一阶段直接连接线性投影模板和搜索区域图像,模板和搜索区域相互引导

OSTrack 受益于预训练的 ViT 模型

Early Candidate Elimination

将搜索区域的每个标记视为目标候选,将每个模板标记视为目标对象的一部分。

搜索区域的关注权值突出显示ViT早期(例如,第4层)的前景对象,然后逐步关注目标。

Candidate Elimination

模板token计算:

注意力权重 w_{x}^{i}决定了模板部分h_{z}^{i}与所有搜索区域令牌(候选者)之间的相似度。 

代表性相似度:

w_{x}^{\phi }\phi =\left \lfloor \frac{W_{z}}{2} \right \rfloor+W_{z}\left \lfloor \frac{H_{z}}{2} \right \rfloor

将模板中心部分的权重与搜索区域token的相似度结合起来,作为代表性相似度

对每个头的分数取平均:

 \overline{w_{x}^{\phi }}=\frac{\sum_{m=1}^{M} w_{x}^{\phi }}{M}

如果一个候选区域与目标的相似度相对较小,那么它更有可能是背景区域。因此,只保留k个最大(top-k)元素对应的候选元素(k是一个超参数,我们定义token保留比为\rho =\frac{k}{n}),而剩余的候选元素被淘汰。

在编码器层进行多头注意操作后插入所提出的候选消除模块,如图所示。

此外,所有剩余候选人的原始顺序都被记录下来,以便在最后阶段恢复。

def candidate_elimination(attn: torch.Tensor, tokens: torch.Tensor, lens_t: int, keep_ratio: float, global_index: torch.Tensor, box_mask_z: torch.Tensor):
    lens_s = attn.shape[-1] - lens_t
    bs, hn, _, _ = attn.shape

# 计算保留的候选区域数量:
    lens_keep = math.ceil(keep_ratio * lens_s)
    if lens_keep == lens_s:
        return tokens, global_index, None

# 从注意力张量中提取模板和搜索区域之间的注意力分数:
    attn_t = attn[:, :, :lens_t, lens_t:]

    if box_mask_z is not None:
        box_mask_z = box_mask_z.unsqueeze(1).unsqueeze(-1).expand(-1, attn_t.shape[1], -1, attn_t.shape[-1])
        # attn_t = attn_t[:, :, box_mask_z, :]
        attn_t = attn_t[box_mask_z]
        attn_t = attn_t.view(bs, hn, -1, lens_s)
        attn_t = attn_t.mean(dim=2).mean(dim=1)  # B, H, L-T, L_s --> B, L_s

    else:
        attn_t = attn_t.mean(dim=2).mean(dim=1)  # B, H, L-T, L_s --> B, L_s

# 对注意力分数进行排序并获取索引:
    sorted_attn, indices = torch.sort(attn_t, dim=1, descending=True)
# 选择顶部的 lens_keep 个候选:
    topk_attn, topk_idx = sorted_attn[:, :lens_keep], indices[:, :lens_keep]
    non_topk_attn, non_topk_idx = sorted_attn[:, lens_keep:], indices[:, lens_keep:]

# 收集保留和移除的索引:
    keep_index = global_index.gather(dim=1, index=topk_idx)
    removed_index = global_index.gather(dim=1, index=non_topk_idx)

    tokens_t = tokens[:, :lens_t]
    tokens_s = tokens[:, lens_t:]

    B, L, C = tokens_s.shape
# 收集保留的token:
    attentive_tokens = tokens_s.gather(dim=1, index=topk_idx.unsqueeze(-1).expand(B, -1, C))
    
    tokens_new = torch.cat([tokens_t, attentive_tokens], dim=1)

    return tokens_new, keep_index, removed_index

Candidate Restoration

候选项消除模块破坏了候选项的原始顺序,使得无法将候选项序列重塑回特征映射,因此先恢复剩余候选项的原始顺序,然后填充缺失的位置。

由于丢弃的候选对象属于无关背景区域,因此不会影响分类和回归任务。它们只是作为重塑操作的占位符,只需要首先恢复剩余候选项的顺序,然后在它们之间进行零填充。

Visualization

通过迭代丢弃搜索区域中不相关的标记,OSTrack不仅大大减轻了计算负担,而且避免了噪声背景区域对特征学习的负面影响。

Head and Loss

将填充的搜索区域令牌序列重新解释为二维空间特征图,然后将其馈送到全卷积网络(FCN)中。

使用局部偏移量以补偿因分辨率降低而引起的离散化误差,以及归一化的边界盒大小(即宽度和高度)。将分类得分最高的位置视为目标位置,即最终得到目标边界框

Experiments

网络结构:

OSTrack(
# 主干网络VIT CE代表使用了注意力机制
  (backbone): VisionTransformerCE(
# 将输入图像分割成patch并映射到一个高维特征空间
    (patch_embed): PatchEmbed(
      (proj): Conv2d(3, 768, kernel_size=(16, 16), stride=(16, 16))
      (norm): Identity()
    )
    (pos_drop): Dropout(p=0.0, inplace=False)
# ViT的核心部分block由多个相同的模块组成
    (blocks): Sequential(
      (0): CEBlock(
# 层归一化,用于稳定训练过程
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
# 注意力机制,用于计算不同特征之间的相关性
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
# 正则化,用于在训练过程中随机丢弃某些路径
        (drop_path): Identity()
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
# 多层感知机,用于进一步处理特征
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (1): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.009)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (2): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.018)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (3): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.027)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (4): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.036)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (5): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.045)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (6): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.055)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (7): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.064)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (8): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.073)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (9): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.082)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (10): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.091)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
      (11): CEBlock(
        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (attn): Attention(
          (qkv): Linear(in_features=768, out_features=2304, bias=True)
          (attn_drop): Dropout(p=0.0, inplace=False)
          (proj): Linear(in_features=768, out_features=768, bias=True)
          (proj_drop): Dropout(p=0.0, inplace=False)
        )
        (drop_path): DropPath(drop_prob=0.100)
        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
        (mlp): Mlp(
          (fc1): Linear(in_features=768, out_features=3072, bias=True)
          (act): GELU()
          (drop1): Dropout(p=0.0, inplace=False)
          (fc2): Linear(in_features=3072, out_features=768, bias=True)
          (drop2): Dropout(p=0.0, inplace=False)
        )
      )
    )
# 层归一化
    (norm): LayerNorm((768,), eps=1e-06, elementwise_affine=True)
  )
# 模型的头部,用于预测目标的边界框
# 用于预测中心点(center)
  (box_head): CenterPredictor(
    (conv1_ctr): Sequential(
      (0): Conv2d(768, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
    (conv2_ctr): Sequential(
      (0): Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
    (conv3_ctr): Sequential(
      (0): Conv2d(128, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
    (conv4_ctr): Sequential(
      (0): Conv2d(64, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
# 最后一个卷积层,输出一个特征图,用于预测中心点
    (conv5_ctr): Conv2d(32, 1, kernel_size=(1, 1), stride=(1, 1))
# 用于预测偏移量(offset)
    (conv1_offset): Sequential(
      (0): Conv2d(768, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
    (conv2_offset): Sequential(
      (0): Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
    (conv3_offset): Sequential(
      (0): Conv2d(128, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
    (conv4_offset): Sequential(
      (0): Conv2d(64, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
# 最后一个卷积层,输出两个通道,用于预测目标的偏移量
    (conv5_offset): Conv2d(32, 2, kernel_size=(1, 1), stride=(1, 1))
# 用于预测目标大小(size)
    (conv1_size): Sequential(
      (0): Conv2d(768, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
    (conv2_size): Sequential(
      (0): Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
    (conv3_size): Sequential(
      (0): Conv2d(128, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
    (conv4_size): Sequential(
      (0): Conv2d(64, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (2): ReLU(inplace=True)
    )
# 最后一个卷积层,输出两个通道,用于预测目标的大小
    (conv5_size): Conv2d(32, 2, kernel_size=(1, 1), stride=(1, 1))
  )
)

头部是一个轻量级的FCN,由4个堆叠的convn - bn - relu层组成,用于三个输出中的每个输出。

每个候选消除模块的保持比\rho设为0.7,在ViT的第4层、第7层、第10层共插入3个候选消除模块。

script_name: ostrack.py  config_name: vitb_256_mae_ce_32x4_ep300.yaml

跟踪过程:

    def track(self, image, info: dict = None):
        H, W, _ = image.shape
        self.frame_id += 1
# 以上一帧预测的位置 self.state 为中心裁剪当前帧的搜索区域
        x_patch_arr, resize_factor, x_amask_arr = sample_target(image, self.state, self.params.search_factor,
                                                                output_sz=self.params.search_size)  # (x1, y1, w, h)
#  预处理搜索区域
        search = self.preprocessor.process(x_patch_arr, x_amask_arr)

        with torch.no_grad():
            x_dict = search
# 将模板特征和当前搜索区域特征输入到 Transformer 模型进行特征交互
            out_dict = self.network.forward(
                template=self.z_dict1.tensors, search=x_dict.tensors, ce_template_mask=self.box_mask_z)

# 分类分数图和边界框预测        
        pred_score_map = out_dict['score_map']
# 分数图和汉宁窗 (self.output_window) 相乘以平滑预测,防止目标位置偏移太大
        response = self.output_window * pred_score_map
        pred_boxes = self.network.box_head.cal_bbox(response, out_dict['size_map'], out_dict['offset_map'])
# 选择最终目标框 
        pred_boxes = pred_boxes.view(-1, 4)
        # Baseline: Take the mean of all pred boxes as the final result
        pred_box = (pred_boxes.mean(
            dim=0) * self.params.search_size / resize_factor).tolist()  # (cx, cy, w, h) [0,1]
        # get the final box result
        self.state = clip_box(self.map_box_back(pred_box, resize_factor), H, W, margin=10)

 采用汉宁窗惩罚,按照惯例利用位置先验进行跟踪。具体来说,只需将分类图P与大小相同的汉宁窗口相乘,相乘后得分最高的方框将被选中作为跟踪结果。

Comparison with State-of-the-Arts

GOT-10k.单流跟踪框架可以通过相互引导提取更多未见类的判别特征。

早期候选消除模块对LaSOT, GOT-10k和TrackingNet基准上的推理速度,mac和跟踪性能的影响,w/o和w/分别表示有或没有早期候选消除模块的模型。

损失函数:

Ablation Study and Analysis

早期候选人淘汰模块的影响:

早期候选淘汰模块可以显著减少计算量,提高推理速度,大多数情况下性能略有提升,该模块缓解了噪声背景区域对特征学习的负面影响。

不同的预训练方法:

由于测试集中的对象类别与训练集中的对象类别完全不同,双流框架提取的特征的判别能力是有限的。而通过模板特征与搜索区域的迭代交互,OSTrack可以通过相互引导提取更多的判别特征。

OSTrack在保持联合特征提取和关联建模模块的高并行性的同时,忽略了多余的繁重的关系建模模块。因此,当采用同一骨干网时,所提出的单流框架比STARK(快40.2 FPS)和SwinTrack(快25.6 FPS)要快得多。

判别区域可视化:

OSTrack可以提取有区别的面向目标的特征,因为所提出的早期融合机制使模板和搜索区域之间的关系在第一阶段建模。

标签:768,Tracking,OSTrack,features,Stream,inplace,False,True,out
From: https://blog.csdn.net/m0_61595251/article/details/143838238

相关文章

  • centos9stream 新系统配置IP 设置远程登录 修改国内源
    配置IP.网关.DNS连接互联网vim/etc/NetworkManager/system-connections/ens33.nmconnection###网络配置文件[connection]id=ens33uuid=3c17691d-cccc-xxxx-zzzz-xzxzxczxcczxtype=ethernetautoconnect-priority=-999interface-name=ens33timestamp=1732001143[et......
  • stream detector, m3u8 detector
     https://chromewebstore.google.com/detail/the-stream-detector/iakkmkmhhckcmoiibcfjnooibphlobak EmreYILMAZ Jun30,2024 Doesnntworkwithtwitchanymore.1personfoundthisreviewtobeunhelpful54acDeveloperJun30,2024I'msurprisedi......
  • 第十章 收集Stream流中的结果
    目录一、引言 二、Stream流中的结果到集合中三、Stream流中的结果到数组中 一、引言 上图中,我们针对流操作完成之后,进行了循环遍历输出、统计个数、总数等操作,如果需要将流的结果保存到数组或集合中,我们使用JDK8提供的方法收集流中的数据。二、Stream流中的结果......
  • 第十一章 对Stream流的聚合函数处理
    目录一、对流中数据进行聚合计算二、对流中数据进行分组三、对流中数据进行多级分组四、对流中数据进行分区 4.1.使用方式及代码4.2.分区于分组的区别分区(Partitioning)分组(Grouping)实际应用场景五、对流中数据进行拼接一、对流中数据进行聚合计算当我们使用......
  • Gradio 和 Streamlit 安装与使用教程
    最近SealosDevbox有点火......
  • java day13 Set集合 & Map集合 & Stream流
    目录​编辑1.Set集合: 1.Set集合的特点:  2.HashSet的底层原理:​编辑  3.LinkedHashSet集合的底层原理:  4.TreeSet集合:2.Map集合: 1.Map集合概述: 2.Map集合的常用方法:3.Map集合的遍历方式:  4.Map集合的实现类:3.Stream流:1.获取流的方法:2.流......
  • ORB-SLAM2 ---- Tracking::TrackReferenceKeyFrame()
    文章目录一、函数作用二、函数讲解三、函数代码四、调用的函数1.ORBmatcher::SearchByBoW()1).函数讲解2).函数代码2.Optimizer::PoseOptimization()1).函数讲解2).函数代码五、总结一、函数作用本函数是用参考关键帧的地图点来对当前普通帧进行跟踪,是第一......
  • 『玩转Streamlit』--图像与媒体组件
    Streamlit中的图像与媒体组件,主要是st.image、st.audio和st.video。它们是专为在StreamlitWeb应用程序中嵌入和展示多媒体内容而设计的,这些组件不仅丰富了应用程序的呈现形式,还极大地提升了用户体验和互动性。1.st.imagest.image函数用于在Streamlit应用程序中展示图像内容,增......
  • streamstring类介绍
    std::stringstream是C++标准库中提供的一个类,定义在头文件<sstream>中。它是基于字符串的流(stream),允许像操作输入流(std::cin)或输出流(std::cout)那样,操作字符串内容。std::stringstream是std::iostream的派生类,支持同时进行字符串解析(输入)和字符串构造(输出)。核心概念std:......
  • Stream流统计集合元素出现次数并降序
    使用Arrays.stream()结合Collectors.groupingBy()和Collectors.counting()来统计数组中每个元素出现个数,按照出现次数降序排列后获取前五个元素及其出现次数的示例代码:importjava.util.*;importjava.util.stream.Collectors;publicclassArrayElementCountTopFive{......