DETR系列文章之–DETR
文章目录
前言
Transformer应用于目标检测的开山之作,将目标检测转换为集合预测问题,利用匈牙利匹配进行一对一匹配预测。
代码地址
论文地址
CSDN解读
一、DETR框架
首先,CNN的backbone,transformer的encoder-decoder,预测层FFN。特征提取-特征加强-特征查询-预测结果
Backbone-特征提取
目标检测特征图较大,transformer计算吃不消!CNN(resnet)提取特征得到特征集合。通过backbone获得特征层,然后在高度维度展平成特征序列,划分为不同patch,为每个图像patch添加上位置编码作为encoder的输入。
Encoder-进行特征加强
输出一个加强的有效特征层为decoder提供k,v
Decoder-特征查询
利用可学习query对加强后的有效特征进行查询,获得预测结果
prediction heads是DETR的分类器与回归器
对decoder获得的预测结果进行全连接(FFN),两次全连接分别代表种类和回归参数。
二、网络结构解析
2.1 位置编码
简单讲就是为特征添加位置信息,使得网络有区分不同区域的能力。DETR包括正余弦编码和可学习位置编码
可学习位置编码
直接随机初始化和x1一样shape的随机变量。
正余弦位置编码
使用正余弦函数为二维特征图x和y方向各自计算一个位置编码,每个维度位置编码长度num_pos_feats(hidden_him/2),对于x和y,奇数位置计算正弦,偶数位置计算余弦。然后通过permute()变成NDHW(D=hidden_him=输入向量维度=输出特征图的维度) 正余弦编码参考
transformer将正余弦函数的值加到embedding向量中,embedding向量和位置编码相加(两个矩阵加法),将pos_x和pos_y拼接得到NHWD数组
正余弦位置编码代码:
class PositionEmbeddingSine(nn.Module):
"""
这是一个更标准的位置嵌入版本,按照sine进行分布
"""
def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None):
super().__init__()
self.num_pos_feats = num_pos_feats
self.temperature = temperature
self.normalize = normalize
if scale is not None and normalize is False:
raise ValueError("normalize should be True if scale is passed")
if scale is None:
scale = 2 * math.pi
self.scale = scale
def forward(self, tensor_list: NestedTensor):
x = tensor_list.tensors
mask = tensor_list.mask
assert mask is not None
not_mask = ~mask
y_embed = not_mask.cumsum(1, dtype=torch.float32)
x_embed = not_mask.cumsum(2, dtype=torch.float32)
if self.normalize:
eps = 1e-6
y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale
x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale
dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device)
dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats)
pos_x = x_embed[:, :, :, None] / dim_t
pos_y = y_embed[:, :, :, None] / dim_t
pos_x = torch.