当前位置: 首页 > news >正文

2D物体检测学习

DETR

原理

1.提出了一种新的检测思路,将目标检测任务视作为集合预测问题
2.此前的检测器大都先用手工设计的候选框预测方案,例如anchor或滑动框。这些方案也包含了其他先验知识的干涉,例如NMS等后处理方案、anchor的设计、训练时如何将检测结果与ground truth匹配等。这些手工设计的策略让人对其泛化性能会有一些怀疑。
3.DETR通过将transformer融入模型,跳过手工设计的部分,将问题转化为集合预测问题,以端到端的方式直接输出预测的(对象,框)的集合。
4.本文的方法还可以用来做segmentation任务

CNN为ResNet50和Res101

encoder结构不变,位置编码改一下(固定的更好)

decoder输入可学习的object queries,并行计算得到独立输出

FFN边框预测是用ReLU激活的3层感知机,类别预测是一个线性层+softmax预测层

得到预测结果以后,将object predictions和ground truth box之间通过匈牙利算法进行二分匹配:假如有K个目标,那么100个object predictions中就会有K个能够匹配到这K个ground truth,其他的都会和“no object”匹配成功,使其在理论上每个object query都有唯一匹配的目标,不会存在重叠,所以DETR不需要nms进行后处理

实践

https://github.com/facebookresearch/detr

detr_hands_on.ipynb - Colab

可视化了最后一个解码器层的注意力权重,看不同object query的效果

代码

main.py中设定可学习的object queries

parser.add_argument('--num_queries', default=100, type=int,help="Number of query slots")

decoder:

class TransformerDecoder(nn.Module):def __init__(self, decoder_layer, num_layers, norm=None, return_intermediate=False):super().__init__()self.layers = _get_clones(decoder_layer, num_layers)self.num_layers = num_layersself.norm = normself.return_intermediate = return_intermediatedef forward(self, tgt, memory,tgt_mask: Optional[Tensor] = None,memory_mask: Optional[Tensor] = None,tgt_key_padding_mask: Optional[Tensor] = None,memory_key_padding_mask: Optional[Tensor] = None,pos: Optional[Tensor] = None,query_pos: Optional[Tensor] = None):output = tgtintermediate = []for layer in self.layers:output = layer(output, memory, tgt_mask=tgt_mask,memory_mask=memory_mask,tgt_key_padding_mask=tgt_key_padding_mask,memory_key_padding_mask=memory_key_padding_mask,pos=pos, query_pos=query_pos)if self.return_intermediate:intermediate.append(self.norm(output))if self.norm is not None:output = self.norm(output)if self.return_intermediate:intermediate.pop()intermediate.append(output)if self.return_intermediate:return torch.stack(intermediate)return output.unsqueeze(0)
  • query_pos 是可学习的 object queries。
  • output 是解码器每层的输出,使用 query_pos 和 encoder 输出的 memory 进行交互。
  • 所有的object queries会同时输入到解码器的所有层,形成并行计算。

匈牙利算法进行二分匹配:

  1. 获取批量和查询数

    bs, num_queries = outputs["pred_logits"].shape[:2]
    
  2. 展平预测结果

    out_prob = outputs["pred_logits"].flatten(0, 1).softmax(-1)  # [batch_size * num_queries, num_classes]
    out_bbox = outputs["pred_boxes"].flatten(0, 1)  # [batch_size * num_queries, 4]
    
    • out_prob:对分类结果应用 Softmax。
    • out_bbox:展平边界框预测。
  3. 拼接目标数据

    tgt_ids = torch.cat([v["labels"] for v in targets])
    tgt_bbox = torch.cat([v["boxes"] for v in targets])
    
  4. 计算分类成本 代码行

    cost_class = -out_prob[:, tgt_ids]
    
    • 含义:分类成本为 1 - 概率[target class],这里的负号用于最小化目标。
  5. 计算 L1 成本

    cost_bbox = torch.cdist(out_bbox, tgt_bbox, p=1)
    
    • 计算 GIoU 成本

      cost_giou = -generalized_box_iou(box_cxcywh_to_xyxy(out_bbox), box_cxcywh_to_xyxy(tgt_bbox))
      
    • 组合成本矩阵 

      C = self.cost_bbox * cost_bbox + self.cost_class * cost_class + self.cost_giou * cost_giou
      C = C.view(bs, num_queries, -1).cpu()
      
    • 应用匈牙利算法

      sizes = [len(v["boxes"]) for v in targets]
      indices = [linear_sum_assignment(c[i]) for i, c in enumerate(C.split(sizes, -1))]
      return [(torch.as_tensor(i, dtype=torch.int64), torch.as_tensor(j, dtype=torch.int64)) for i, j in indices]
      
      • linear_sum_assignment:解决 Linear Sum Assignment Problem (LSAP),找到最优匹配。

    DINO grounding

    原理

    根据文字描述检测指定目标

    提取:Swin Transformer作为image backbone,BERT作为text backbone

    多模态融合:利用Deformable Self-Attention和Self-Attention来增强image features和text features,然后利用GLIP中的image-to-text 和 text-to-image cross-attention实现特征融合

    选query:,两个模态特征乘起来求最大的前Nq个

    解码:Self-Attention、Image Cross-Attention、Text Cross-Attention组合

    关于text prompt:mask掉不相关类别名之间的联系

    实践

    zero-shot-object-detection-with-grounding-dino.ipynb - Colab

    代码

    生成attention_mask(注意力掩码)、position_ids(位置编码)和cate_to_token_mask_list(类别到token的映射生成掩码列表):

    attention_mask = (torch.eye(num_token, device=input_ids.device).bool().unsqueeze(0).repeat(bs, 1, 1))
    position_ids = torch.zeros((bs, num_token), device=input_ids.device)
    cate_to_token_mask_list = [[] for _ in range(bs)]
    previous_col = 0
    for i in range(idxs.shape[0]):row, col = idxs[i]if (col == 0) or (col == num_token - 1):attention_mask[row, col, col] = Trueposition_ids[row, col] = 0else:attention_mask[row, previous_col + 1 : col + 1, previous_col + 1 : col + 1] = Trueposition_ids[row, previous_col + 1 : col + 1] = torch.arange(0, col - previous_col, device=input_ids.device)c2t_maski = torch.zeros((num_token), device=input_ids.device).bool()c2t_maski[previous_col + 1 : col] = Truecate_to_token_mask_list[row].append(c2t_maski)previous_col = col
    cate_to_token_mask_list = [torch.stack(cate_to_token_mask_listi, dim=0) for cate_to_token_mask_listi in cate_to_token_mask_list]
    return attention_mask, position_ids.to(torch.long), cate_to_token_mask_list

      attention_mask创建了一个单位矩阵作为基本的注意力mask,每个token最初只能关注自身

      position_ids初始化为全 0 张量

      cate_to_token_mask_list创建了一个长度为 bs 的列表,每个元素都是一个空列表,用于后续存储每个 batch 中生成的类别到token的mask

      BERT得到文本特征:

      bert_output = self.bert(**tokenized_for_encoder) 
      encoded_text = self.feat_map(bert_output["last_hidden_state"]) 

      对齐图像端的embedding维度(256)

      Swin Transformer得到图片特征和位置编码:

      def forward(self, tensor_list: NestedTensor):xs = self[0](tensor_list)out: List[NestedTensor] = []pos = []for name, x in xs.items():out.append(x)pos.append(self[1](x).to(x.tensors.dtype))return out, pos

      特征融合:

      def forward(self, v, l, attention_mask_v=None, attention_mask_l=None):v = self.layer_norm_v(v)l = self.layer_norm_l(l)delta_v, delta_l = self.attn(v, l, attention_mask_v=attention_mask_v, attention_mask_l=attention_mask_l)# v, l = v + delta_v, l + delta_lv = v + self.drop_path(self.gamma_v * delta_v)l = l + self.drop_path(self.gamma_l * delta_l)return v, l

      选query:

      output_memory, output_proposals = gen_encoder_output_proposals(memory, mask_flatten, spatial_shapes)output_memory = self.enc_output_norm(self.enc_output(output_memory))if text_dict is not None:enc_outputs_class_unselected = self.enc_out_class_embed(output_memory, text_dict)else:enc_outputs_class_unselected = self.enc_out_class_embed(output_memory)topk_logits = enc_outputs_class_unselected.max(-1)[0]enc_outputs_coord_unselected = (self.enc_out_bbox_embed(output_memory) + output_proposals) topk = self.num_queriestopk_proposals = torch.topk(topk_logits, topk, dim=1)[1]  # bs, nq# gather boxesrefpoint_embed_undetach = torch.gather( enc_outputs_coord_unselected, 1, topk_proposals.unsqueeze(-1).repeat(1, 1, 4)) refpoint_embed_ = refpoint_embed_undetach.detach()init_box_proposal = torch.gather(output_proposals, 1, topk_proposals.unsqueeze(-1).repeat(1, 1, 4)).sigmoid() # gather tgttgt_undetach = torch.gather(output_memory, 1, topk_proposals.unsqueeze(-1).repeat(1, 1, self.d_model))if self.embed_init_tgt:tgt_ = (self.tgt_embed.weight[:, None, :].repeat(1, bs, 1).transpose(0, 1))else:tgt_ = tgt_undetach.detach()if refpoint_embed is not None:refpoint_embed = torch.cat([refpoint_embed, refpoint_embed_], dim=1)tgt = torch.cat([tgt, tgt_], dim=1)else:refpoint_embed, tgt = refpoint_embed_, tgt_

      DINO-X

      接受文本提示、视觉提示和自定义提示作为输入,并且可以生成各个语义层面的表示,包括边界框、分割蒙版、姿势关键点和对象标题

      Pro

      文本提示编码器:CLIP的文本编码器

      视觉提示编码器:采用了来自T-Rex2 的视觉提示编码器,将其整合以利用用户定义的箱形和点形式的视觉提示来增强物体检测。通过正弦-余弦层转换成位置嵌入。模型使用不同的线性投影分离箱形和点提示

      自定义提示:通过提示微调技术覆盖更多的长尾、特定领域或功能特定场景

      给定一张输入图像和用户提供的提示,无论是文本、视觉还是自定义提示嵌入,DINO-X都会在提示与从输入图像中提取的视觉特征之间进行深层特征融合,然后根据不同感知任务应用不同的头。具体实现的头部如下所述:

      框头:遵循Grounding DINO,采用了语言引导的查询选择模块,接着是一个简单的MLP层来预测每个对象查询对应的边界框坐标

      Mask头:遵循Mask2Former和Mask DINO的核心设计,我们通过融合1/4分辨率的主干特征和从Transformer编码器上采样的1/8分辨率特征来构建像素嵌入图。然后,我们计算Transformer解码器中的每个对象查询与像素嵌入图之间的点积以获取查询的掩膜输出

      关键点头:接收DINO-X的相关检测输出,例如人或手,作为输入,并使用单独的解码器来解码物体的关键点。每个检测输出被视为一个查询并扩展为多个关键点,然后发送到多个可变形Transformer解码器层来预测所需的关键点位置及其可见性。这个过程可以视为简化的ED-Pose 算法,不需要考虑物体检测任务,而是专注于关键点检测。在DINO-X中,我们实例化了两个人物和手的关键点头,它们分别有17个和21个预定义的关键点。

      语言头:语言头是一个任务可提示的生成式小型语言模型,用于增强DINO-X理解和执行超出定位任务的感知任务的能力,如物体识别、区域字幕生成、文本识别和基于区域的视觉问答(VQA)。对于DINO-X检测到的任何物体,我们首先使用RoIAlign操作符从DINO-X主干特征中提取其区域特征,结合其查询嵌入形成我们的物体令牌。然后,我们应用一个简单的线性投影以确保它们的维度与文本嵌入对齐。轻量级的语言解码器以自回归方式将这些区域表示与任务令牌集成以生成输出。可学习的任务令牌赋予语言解码器处理各种任务的能力。

      Edge

      更强的文本提示编码器:CLIP文本编码器

      知识蒸馏:从Pro模型使用基于特征的知识蒸馏和基于响应的知识蒸馏以增强Edge模型的性能

      改进的FP16推理:我们采用了一种浮点乘法的归一化技术,使得模型可以量化为FP16而不牺牲精度


      http://www.mrgr.cn/news/98950.html

      相关文章:

    1. C++ `shared_ptr` 多线程使用
    2. 深入理解C++中string的深浅拷贝
    3. day1-小白学习JAVA---JDK安装和环境变量配置(mac版)
    4. 认知觉醒是什么? 如何做到 ? ( 持续更新ing )
    5. cpolar 内网穿透 实现公网可以访问本机
    6. [编程基础] Java · 学习手册
    7. MATLAB 控制系统设计与仿真 - 35
    8. 下拉框select标签类型
    9. 基于linux 设置无线网卡Monitor模式 sniffer抓包
    10. Git-使用教程(新手向)
    11. 向量数据库前沿:Faiss 向量数据库的配置与使用(文中有彩蛋)
    12. 高频面试题:Android MVP/MVVM/MVI这几种架构在实际生产中,各自的优缺点和适用场景是什么
    13. STM32单片机C语言
    14. 《系统分析师-第三阶段—总结(一)》
    15. SQL:聚合函数(Aggregate Functions)
    16. docker.desktop下安装普罗米修斯prometheus、grafana并看服务器信息
    17. 全面解析IPv6:从理论到实践(以H3C配置为例)
    18. 2026《数据结构》考研复习笔记三(C++高级教程)
    19. 浅谈验证(Verification)和确认(Validation)
    20. Ubuntu22.04安装QT、px4安装环境