【DETR 论文精读【论文精读】-哔哩哔哩】 https://b23.tv/Iy9k4O2
摘要:
将目标检测看作一个集合预测的问题
任务:给定一张图片,预测一组框,每个框需要得到坐标信息和包含的物体类别信息,将框可以视为集合,不同图片所对应的框不同,则所对应的集合就不同
去除:NMS、生成anchor
创新:
①提出一个目标函数,通过二分图匹配的方式强制模型输出一组独一无二的预测(去除冗余框,每个物体的理想状态下就会生成一个框)
②使用Transformer 的encoder、decoder架构:
(1)在Transformer解码器中提出learned object query,它可以和全局图像信息结合,通过不停做注意力操作,让模型直接输出一组预测框
(2)并行出框
导言:
背景:
大部分目标检测器采用间接方式预测,或用回归和分类替代目标检测问题
性能受限于后处理(NMS)操作,处理大量冗余框
流程:
①用卷积神经网络提取特征
②将特征拉直,送入Transformer的encoder、decoder,进一步学习全局信息,将每一个点的信息与全局做交互
③生成框输出,通过object query限制框的个数
④使用二分图匹配计算Loss,计算预测框和GT Box的matching loss决定预测框中对应GT Box的框;选择后计算分类损失、Bounding Box Loss;没有匹配上的框被标记为背景
相关工作:
两阶段目标检测:proposal
单阶段目标检测:anchor、center
基于集合:
关系型网络、Learnable NMS利用类似于自注意力的方法去处理物体间联系
无需后处理
性能低,使用了人工干预
基于Encoder Decoder:
得到更全局的信息
并行输出目标框,时效性增强
改进后的Encoder Decoder:
解码器部分的第一部分用到的是Multi-Head Self-Attention ,而第二部分用到的则是Multi-Head Attention
原因:
Queries 内部先进行协同工作(通过 MHSA)。
然后再与图像特征交互提取有用的信息(通过 MHA)。
DETR:
基于集合的目标函数:
使用cost matrix:类似于三个工人分配三个工作,使每个工人被分配其最擅长的工作
使用scipy包中提供的linear-sum-assignment函数,将cost matrix作为函数输入
a、b、c看作100个框,x、y、z看作GT框
损失函数:
包含分类Loss和出框Loss
为了使两个Loss在相近的取值空间,将log去除,得到更好的效果
在Bounding Box中,使用L_1 Loss可能会产生问题,于是加入了genralized IoU Loss(与框大小无关)
细节:为了让模型收敛更快,训练的更稳定,在Decoder后加入很多auxiliary loss(额外的目标函数);在6个(重复六次)Decoder后都加了FFN(共享参数),去得到目标检测输出从而得到Loss
网络框架:
模型创建:
python
detr = DETR(num_classes=91, hidden_dim=256, nheads=8, num_encoder_layers=6, num_decoder_layers=6)
前向过程:
①输入图像[3*800*1066],通过卷积网络得到一些特征
python
# 模型定义
self.backbone = nn.Sequential(*list(resnet50(pretrained=True).children())[:-2])
python
# 前向传播
x = self.backbone(inputs)
② 走到卷积网络最后一层(conv5)时得到[2048*25*34],而25和34分别为800和1066的1/32,2048为对应的通道数
③输入Transformer时需要一个降维操作,通过[1*1*256]的卷积核降维得到[256*25*34]
python
# 投射层 将2048变为256
self.conv = nn.Conv2d(2048, hidden_dim, 1)
python
# 前向传播
h = self.conv(x)
④Transformer无位置信息,为其加入位置编码,固定位置编码大小为[256*25*34],保持维度一致
python
# 模型定义
self.row_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))
self.col_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))
python
# 前向传播
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与w拉直变为一个数值,变为[850*256],850为序列长度,256为head dimension
python
# 拉直
h = self.transformer(pos + h.flatten(2).permute(2, 0, 1),self.query_pos.unsqueeze(1))
⑥进入Transformer Encoder层,输入为[850,256],输出也为[850*256],在DETR中使用了6个Encoder进行叠加
python
# 进入Transformer进行一系列操作
# 最终得到100*256
self.transformer = nn.Transformer(hidden_dim, nheads,num_encoder_layers,num_decoder_layers)
⑦进入Transformer Decoder层,进行框的输出,将输入1和输入2反复做自注意力操作,得到[100*256]的特征;在DETR中使用了6个Decoder进行叠加
python
# 前向传播时叠加两个输入
h = self.transformer(pos + h.flatten(2).permute(2, 0, 1),self.query_pos.unsqueeze(1))
输入1:创新点object queries,它是一个learnable positional embedding,维度[100*256],其中的256是与encoder中的256相互对应,便于一起做乘法,100代表模型最终为100输出(条件)
python
# object queries设置为100 最终出100个框
self.query_pos = nn.Parameter(torch.rand(100, hidden_dim))
细节:但是在第一层Decoder中没有做object queries自注意力机制,为了移除冗余框
输入2:图像端得出的全局特征,维度[850*256]
⑧ 将特征给全连接层,全连接层做物体类别的预测和出框的预测:
类别若是COCO则为91类:
python
self.linear_class = nn.Linear(hidden_dim, num_classes + 1)
框为4个值(x、y、w、h):
python
self.linear_bbox = nn.Linear(hidden_dim, 4)
⑨将得到的100个框与GT框进行匈牙利匹配
python
logits, bboxes = detr(inputs)
实验:
与Faster-RCNN对比:
训练策略的改变对模型提升效果很大,DETR对大物体检测效果较好,但小物体处理效果一般
Transformer Encoder:
Encoder主要学习的是全局特征,尽可能让物体和物体之间分得开
自注意力的可视化,使用Transformer Encoder让图片里的物体分的很开,在此基础上做目标检测和分割相对而言就会简单很多
随着Transformer编码器层数增加,学到的全局特征越多,性能一直在提升,但带来了参数增长和速度变慢
Transformer Decoder:
Decoder将注意力分给学习边缘,更好的区分物体和解决遮挡问题
Object Queries:
每一个正方形代表一个object queries,绿色的点代表小的Bounding Box,红色的点代表大的横向的Bounding Box,蓝色的点代表大的纵向的Bounding Box
object queries 与anchor类似:
anchor:提前定义好一些Bounding Box,最后将预测和提前订好的Bounding Box做对比
object queries:可学习;类似于问问题的"人",用图片自己的方式去问,得到答案,而答案就是对应的Bounding Box,而未找到答案就无结果
每次学习后看到一张图片都会问左下角是否看到一些小物体,中间是否看到大的横向物体
每次学习后看到一张图片都会问右边是否看到一些小物体,中间是否看到大的横向或纵向物体
总结:
优点:
提出了一个全新的用于目标检测的DETR框架
利用了Transformer和二分图匹配,使框架是一个端到端可学习网络
在COCO数据集和全景分割上达到了很好的效果
自注意力带来的全局信息使之在大物体上效果更好
缺点:
训练时间长
不好优化
小物体性能差