论文题目:End-to-End Object Detection with Transformers
代码:facebookresearch/detr: End-to-End Object Detection with Transformers (github.com)
端到端:通常指的是一种设计和实现方式,它将输入数据直接映射到期望的输出结果,而不需要或者很少需要人为地定义中间步骤或特征。这种算法在机器学习和人工智能领域尤为常见,尤其是在自然语言处理(NLP)、计算机视觉和其他需要复杂数据处理的领域。
端到端算法的一个典型例子是深度学习模型,如卷积神经网络(CNN)和循环神经网络(RNN),它们在图像识别、语音识别和机器翻译等任务中取得了显著的成功。这些模型通过多层的非线性变换,自动从原始数据中学习到复杂的特征表示。
然而,端到端算法也有其局限性,例如可能需要大量的计算资源和数据,以及模型的可解释性可能较差。
端到端的目标监测解决了痛点,即不需要proposal,也不需要anchor。不需要nms进行后处理(NMS(Non-Maximum Suppression,非极大值抑制)是目标检测算法中的一个重要后处理步骤。在目标检测任务中,尤其是在使用基于锚点(anchor-based)的方法时,如Faster R-CNN、SSD、YOLO等,模型通常会为每个类别生成多个候选边界框(bounding boxes),这些框可能包含对同一目标的多次检测,即存在重叠的边界框。NMS的目的是减少这些重叠的边界框,确保对于每个检测到的目标,只保留一个最有可能的边界框。这样做可以提高检测的准确性,避免重复检测同一个目标,并且使得最终的检测结果更加清晰和准确。)
摘要:目标是给定一个图片预测集合(框)。
- 提出了新的目标函数,通过二分图匹配的方式能够强制模型输出一组独一无二的预测框
- 使用transformer encoder和decoder的架构
- 并行化(实时性好)
- 简单性
- 能够简单的扩展到别的领域(eg.全景分割、目标追踪、姿态预测、语义分割)
论文DETR结构图(简洁)
步骤:
- step1.使用卷积神经网络提取特征
- step2.transformer encoder 进一步学习全局的信息,帮助后面做检测
- step3.transformer decoder生成预测的框
- step4.将预测的框和ground truth框做匹配,在匹配的框上面算目标检测的loss
论文提到在COCO数据集上达到了与Faster R-CNN模型差不多的效果,且DETR对大物体的检测效果好。在小物体上效果不是很好,需要不断的进化 ,且训练速度慢。(为解决这些问题,不到半年Deformable DETR出现了,通过多尺度的特征解决小物体问题。)DETR不仅可以作为一个方法也可以作为一个框架,设计理念为了能够适用于更多复杂任务。
相关工作:大部分的目标检测分类器都是根据已有的猜测做的预测(eg.Two-stage detector初始猜测是proposals、Single-stage初始猜测是anchor/物体中心点)
Recurrent detector(15、16年的工作):使用的全是RNN,也就是自回归模型(时效性和性能会比较差)
The DETR model:
- 基于集合的目标函数
模型最后的输出是一个固定的集合,n个输出(100)
使用二分图匹配
将abc看成目标检测的100个框,xyz看成groundtruth框。cost matrix 就说loss,一旦拥有loss就可以用scipy.linear_sum_assignment(匈牙利算法)得到最优解。
LOSS公式如下:
由于使用了transformer提取全局的特征会导致loss很大,作者使用了L_1 loss和generalized iou loss(和框大小无关的目标函数)合体算bounding box loss
如下所示为DETR结构图(细节)
代码实现
import torch
from torch import nn
from torchvision.models import resnet50
class DETR(nn.Module):
def __init__(self,num_classes, hidden_dim, nheads, num_encoder_layers, num_decoder_layers):
super().__init__()
self.backbone = nn.Sequential(*list(resnet50(pretrained=True).children())[:2])
self.conv = nn.Conv2d(2048, hidden_dim, 1)
self.transformer = nn.Transformer(hidden_dim, nheads, num_encoder_layer, num_decoder_layers)
self.linear_class = nn.Linear(hidden_dim, num_classes +1)
self.iinear_bbox = nn.Linear(hidden_dim, 4)
self.query_pos = nn.Parameter(torch.rand(100, hidden_dim))
self.row_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))
self.col_embed = nn.Parameter(torch.rand(50, hidden_dim //2))
def forward(self, inputs):
x = self.backbone(inputs)
h = self.conv(x)
H, W = h.shape[-2:]
pos = torch.cat([
self.col_embed[:W].unsqueeze(0).repeat(H, 1, 1),
self.row_embed[:H].unsqueeze(1).repeat(1, W, 1),
], dim=-1).flatten(0,1).unsqueeze(1)
h = self.transformer(pos + h.flatten(2).permute(2, 0, 1),
self.query_pos.unsqueeze(1))
return self.linear_class(h), self.linear_bbox(h).sigmoid()
# num_classes 为类别数量
detr = DETR(num_classes=91, hidden_dim=256, nheads=8, num_encoder_layers=6, num_decoder_layers=6)
detr.eval()
inputs = torch.randn(1, 3, 800, 1200)
logits, bboxes = detr(inputs)
编码器的层数越深,学到的特征越好。encoder尽可能的将物体和物体分离开。decoder去学边缘来跟好的处理遮挡的物体。
如下图所示为20个object query可视化
绿色点为小的bounding box,红色为大的横向的bounding box,蓝色的代表竖向的大的bounding box。