04 感知:3D目標檢測 注意力機制
1. DETR 2020(DEtection TRansformer)End-to-End Object Detection with Transformers
可以將DETR視為一個從圖像序列到一個集合序列的轉換過程。該集合實際上就是一個可學習的位置編碼(文章中也稱為object queries或者output positional encoding,代碼中叫作query_embed)。
1. pos_embed (位置編碼)
transformer位置編碼:
pos是詞向量在序列中的位置,i是channel的索引。
DETR中位置編碼:為二維特征在圖像x和y方向分別編碼,每個維度編碼長度為特征向量長度一半。這樣兩個維度編碼特征拼接后,構成和圖像特征長度相等的向量。
class PositionEmbeddingSine(nn.Module):
"""
This is a more standard version of the position embedding, very similar to the one
used by the Attention is all you need paper, generalized to work on images.
"""
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.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3)
pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3)
pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2)
return pos
2. object queries (query_embed)
這里query_embed的作用表現的和位置編碼類似
# embedding_layer = nn.Embedding(num_embeddings=3, embedding_dim=2)
self.query_embed = nn.Embedding(num_queries, hidden_dim)
object queries在經過decoder的計算以后,會輸出一個形狀為T,N,C的數組,其中T是object queries的序列長度,即100,N是batch size,C是特征channel。
最后通過一個Linear層輸出class預測,通過一個多層感知機結構輸出box預測:
'''
torch.nn.Linear(in_features, out_features, bias=True)
- 輸入形狀:(batch_size, in_features)
- (batch_size, out_features)
'''
# MLP (also called FFN)
class MLP(nn.Module):
""" Very simple multi-layer perceptron (also called FFN)"""
def __init__(self, input_dim, hidden_dim, output_dim, num_layers):
super().__init__()
self.num_layers = num_layers
h = [hidden_dim] * (num_layers - 1)
self.layers = nn.ModuleList(nn.Linear(n, k) for n, k in zip([input_dim] + h, h + [output_dim]))
def forward(self, x):
for i, layer in enumerate(self.layers):
x = F.relu(layer(x)) if i < self.num_layers - 1 else layer(x)
return x
self.class_embed = nn.Linear(hidden_dim, num_classes + 1)
self.bbox_embed = MLP(hidden_dim, hidden_dim, 4, 3)
#forward
hs = self.transformer(self.input_proj(src), mask, self.query_embed.weight, pos[-1])[0]
outputs_class = self.class_embed(hs)
outputs_coord = self.bbox_embed(hs).sigmoid()
out = {'pred_logits': outputs_class[-1], 'pred_boxes': outputs_coord[-1]}
3. 為什么DETR不需要NMS處理
假如有N個目標,那么100個object predictions中就會有N個能夠匹配到這N個ground truth,其他的都會和“no object”匹配成功,這些predictions的類別label就會被分配為num_classes,即表示該prediction是背景。這樣的設計是很不錯的,理論上每個object query都有唯一匹配的目標,不會存在重疊,所以DETR不需要nms進行后處理。
補充:
1. nn.Embedding
- nn.Embedding 是一個預定義的層,專門用于將 離散的整數索引(比如單詞ID、類別ID)轉換為 稠密向量。
- 它內部維護一個可學習的“向量表”(類似字典),通過查表的方式將索引映射成向量。
- 可學習:向量表中的每個向量都是 nn.Parameter,會被優化器更新。
- 專為離散設計:適合處理文本、類別等離散數據。
- nn.Embedding:就像一本字典,每個單詞對應一頁解釋(向量),這本字典的內容會在訓練中不斷優化,讓解釋更準確。
2. 匈牙利匹配算法(帶權二分圖最大匹配 KM算法)
1. 匈牙利匹配算法
交替路和增廣路是用來解決新配對的時候發生沖突的問題。
交替路:就是依次經過非匹配邊、匹配邊的路
- (非匹配邊) (匹配邊) (非匹配邊):B--------------a----------------A-----------------c
- B和c都是沒有被匹配過的點,而它又是這條交替路的起點和終點。這條交替路就是增廣路。
現在我們要做一個取反操作,怎么取呢,就是將上面這條增廣路的匹配邊變成不匹配邊,不匹配邊變成匹配邊。
- (匹配邊) (非匹配邊) (匹配邊):B--------------a----------------A-----------------c
增廣路的核心特點就是“起點終點都是非匹配點”,這樣就導致非匹配邊比匹配邊多了一條。增廣路建立連接時,必須建立在兩者有意向的基礎上。這樣我們取反,也就是交換匹配和非匹配邊的身份。我們就多得到了一條匹配邊。這個取反的過程,就是把原本匹配上的兩個人拆散,給第三個人騰位置。
參考:Raf 1
2. KM算法
參考:Ref 2
2. DAB-DETR (收斂慢因為: 沒有提供位置先驗的 learnable queries)
3. DN-DETR (收斂慢因為:匈牙利匹配的離散性和模型訓練的隨機性,導致了 query 對 gt 的匹配變成了一個動態的、不穩定的過程)
4. Deformable DETR 2021()
Code URL: https://github.com/fundamentalvision/Deformable-DETR
改進:
- 減少訓練時長:將全局attention轉為局部attention
- 提升小物體檢測準確率:采用多尺度特征圖
原始圖片上一個目標物體太小,它在壓縮后的特征圖上可能就幾乎找不到了,因此我們很難將其檢測出來。所以一般情況下,小物體我們需要更大尺寸的特征圖。想法:讓不同尺寸的特征圖都參與訓練,提高一個物體被檢測出來的可能。
1. Deformable attention計算
# ! 此部分代碼不完整,完整代碼解析查看參考資料:Ref 4.
class MSDeformAttn(nn.Module):
def __init__(self, d_model=256, n_levels=4, n_heads=8, n_points=4):
"""
Multi-Scale Deformable Attention Module
:param d_model hidden dimension
:param n_levels number of feature levels (特征圖的數量)
:param n_heads number of attention heads
:param n_points number of sampling points per attention head per feature level
"""
super().__init__()
if d_model % n_heads != 0:
raise ValueError('d_model must be divisible by n_heads, but got {} and {}'.format(d_model, n_heads))
_d_per_head = d_model // n_heads
# you'd better set _d_per_head to a power of 2 which is more efficient in our CUDA implementation
if not _is_power_of_2(_d_per_head):
warnings.warn("You'd better set d_model in MSDeformAttn to make the dimension of each attention head a power of 2 "
"which is more efficient in our CUDA implementation.")
2. Reference points/ off set 如何產生?
3. Corase2Fine如何實現?
Reference
- 簡單理解增廣路與匈牙利算法:https://zhuanlan.zhihu.com/p/208596378
- 從匈牙利算法到KM算法:ttps://zhuanlan.zhihu.com/p/214072424
- 理解DETR:https://zhuanlan.zhihu.com/p/348060767
- 再讀deformable detr:https://zhuanlan.zhihu.com/p/700776674

浙公網安備 33010602011771號