首页 > 其他分享 >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-24 16:34:01浏览次数:8  
标签:768 Tracking OSTrack features Stream inplace attn 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):
        x = self.proj(x)  
        if self.flatten:
            x = x.flatten(2).transpose(1, 2) 
        x = self.norm(x) 
        return x

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

# 展平完加token
        if self.add_cls_token:
            cls_tokens = self.cls_token.expand(B, -1, -1)
            cls_tokens = cls_tokens + self.cls_pos_embed

        # 加位置编码
        z += self.pos_embed_z
        x += self.pos_embed_x

⑤将图像嵌入连接并馈送到Transformer编码器层中,以进行联合特征提取和关系建模;

        # 拼接
        x = combine_tokens(z, x, mode=self.cat_mode)
        if self.add_cls_token:
            x = torch.cat([cls_tokens, x], dim=1)

模型可以包含多个编码器层,每个层都可能包含一个早期淘汰模块

# 前向
        for i, blk in enumerate(self.blocks):
            x = blk(x)  # vit 12个layer层

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

 已淘汰的模块:

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

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

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

 

⑦经过编码器层处理后的特征被重塑(序列token拼回块状布局)

# 一维转二维得到特征图
        opt = (enc_opt.unsqueeze(-1)).permute((0, 3, 2, 1)).contiguous()

通过一个头部网络来预测目标的位置

# OSTrack使用corner Cenner_Predictor
center_head = CenterPredictor(inplanes=in_channel, channel=out_channel,
                                      feat_sz=feat_sz, stride=stride)
return center_head

得到位置信息和分数信息

def forward(self, x, gt_score_map=None):
   """ Forward pass with input x. """
   # 调用self.get_score_map方法来处理输入数据x,得到中心得分图score_map_ctr、尺寸图size_map和偏移图offset_map
   score_map_ctr, size_map, offset_map = self.get_score_map(x)

   if gt_score_map is None:
        bbox = self.cal_bbox(score_map_ctr, size_map, offset_map)
   else:
        bbox = self.cal_bbox(gt_score_map.unsqueeze(1), size_map, offset_map)

   return score_map_ctr, bbox, size_map, offset_map
    def cal_bbox(self, score_map_ctr, size_map, offset_map, return_score=False):
        # 在score_map_ctr中找到最大得分及其对应的索引
        max_score, idx = torch.max(score_map_ctr.flatten(1), dim=1, keepdim=True)
        # 计算出索引idx对应的y和x坐标
        idx_y = idx // self.feat_sz
        idx_x = idx % self.feat_sz

        # 将索引idx扩展为三维张量
        idx = idx.unsqueeze(1).expand(idx.shape[0], 2, 1)
        # 从size_map和offset_map中使用索引idx获取对应的尺寸和偏移值
        size = size_map.flatten(2).gather(dim=2, index=idx)
        offset = offset_map.flatten(2).gather(dim=2, index=idx).squeeze(-1)

        # 计算边界框的坐标
        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)

        # 返回边界框和最大得分
        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的批大小bs和头数hn
    lens_s = attn.shape[-1] - lens_t
    bs, hn, _, _ = attn.shape

    # 根据保留比例keep_ratio计算需要保留的搜索区域令牌数量lens_keep
    lens_keep = math.ceil(keep_ratio * lens_s)
    if lens_keep == lens_s:
        return tokens, global_index, None

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

    # 如果提供了模板掩码box_mask_z,则使用它来过滤注意力权重,然后计算每个搜索区域令牌的平均注意力权重
    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)

    # separate template and search tokens
    # 从令牌张量tokens中分离出模板令牌tokens_t和搜索区域令牌tokens_s
    tokens_t = tokens[:, :lens_t]
    tokens_s = tokens[:, lens_t:]

    B, L, C = tokens_s.shape
    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,attn,True,out
From: https://blog.csdn.net/m0_61595251/article/details/143838238

相关文章

  • 『玩转Streamlit』--布局与容器组件
    在Streamlit中,布局类组件扮演着至关重要的角色。它们不仅决定了应用程序的视觉呈现和用户体验,也极大地增强了页面内容的组织性和可读性。通过这些组件,开发者可以灵活地划分页面空间,创建出清晰、有条理的布局结构。本篇主要介绍3种构建StreamlitApp时常用的3种布局类组件:st.c......
  • Java的Stream流编程的排序sorted方法里参数o1,o2分别代表什么?
    先说结论:在sorted方法中,o1是最后面的元素,o2是倒数第二个元素,以此类推,流是处理元素是从后面开始取值。  packagecom.br.itwzhangzx02.learn;     importorg.junit.Test;   importjava.util.ArrayList; importjava.util.List;......
  • Production Tracking是什么 ?
    【大家好,我是唐Sun,唐Sun的唐,唐Sun的Sun。一站式数智工厂解决方案服务商】ProductionTracking,即生产跟踪,是对生产过程进行全面、实时监控和记录的一种管理手段。它涵盖了从原材料采购、生产计划制定、生产工序执行,到产品最终完成的整个生产流程。通过各种技术手段,如传感器、......
  • Gstreamer系列(5):Gstreamer在arm平台(Nano, Orin, Xavier等)使用硬编码对视频进行保存mp
            在工程实践中,通常使用使用英伟达版板卡作为图像处理的控制器,常见的有xavier,TX2,orin,Nano等,这些控制器使用Gstreamer进行硬件编码的插件通常为omxh264enc,nvv4l2h264enc。本文将基于这两个插件进行介绍区别,并给出使用示例本。本系列其他文章有:Gstreamer系......
  • Centos Stream 9 换yum源(图文详细教程)
    打开centosStream9进入终端输入cd/etc/yum.repos.d进入到yum.repos.d目录输入命令vimupdate_mirror.pl进入vim编辑模式,输入i插入文本把下面文本复制粘贴到虚拟机创建update_mirror.pl的文件中#!/usr/bin/perl usestrict;usewarnings;useautodie; my......
  • Gstreamer系列(2):gstreamer的视频编解码及不同平台编解码插件
    GStreamer是一个强大的多媒体框架,可以用于视频编码、解码和处理。视频编码的基础知识涉及到如何将原始视频数据转换为压缩格式以便于存储和传输。在GStreamer中,视频编码可以通过软编码(软件编码)和硬编码(硬件编码)两种方式实现。以下是GStreamer视频编码的基本概念,涵盖了这两......
  • 实现与PDF进行聊天!(利用 Pinata、OpenAI 和 Streamlit等技术)
    最近在GitHub上发现一个有趣的项目,由用户@Jagroop2001开发的【chat-with-pdf】这个project!我为此项目写了一个介绍和readme,感兴趣的可以点击链接:https://github.com/Hyone-soul/chat-with-pdf/在本教程中,我们将构建一个简单的聊天界面,允许用户上传PDF文件,使用OpenAI的AP......
  • 什么是Streamlit
    最近,我在数据分析的一些任务中尝试了闻名已久的Streamlit,再一次感受到Python的强大之处。于是,准备根据自己的掌握情况,写一个介绍Streamlit的系列。本文作为第一篇,先介绍介绍Streamlit是什么,以及它和Jupyter和传统Web应用的区别。1.是什么Streamlit是一个用于快速构建数据科......
  • 阿里云服务器ECS,CentOS Stream 9使用nrm管理 Node.js 包的下载源
    首先确保你的服务器上已经安装了Node.js。如果没安装,先安装...阿里云服务器ECS,CentOSStream9安装nodejs步骤_centos9nodejs-CSDN博客第一步:安装 nrm 工具用于管理npm源,终端输入:npmi-gnrm第二步:配置nrm查看当前使用的源,终端输入:nrmls切换下载源,例如淘宝,终端......
  • Java Stream介绍
    JavaStreamAPI是Java8引入的一项强大功能,旨在简化集合数据的处理。它允许开发者以更简洁和声明性的方式执行复杂的数据操作。以下是对JavaStreamAPI的详细介绍,包括其核心概念、常见操作、性能优化以及最佳实践。一核心概念1.1流(Stream):流是一种对数据序列的抽......