來源:https://markus-enzweiler.de/downloads/publications/ECCV2022-spatial_detr.pdf
代碼:GitHub - cgtuebingen/SpatialDETR: Official implementation of SpatialDETR. The paper will be presented at ECCV 2022
這篇文章繼承了DETR3D的思路,通過多視角的圖像實現3D目標的檢測。
1. 動機&創新點
1.1 動機
- 【為什么使用純視覺?】 盡管雷達刻畫3D物體比較精確,但camera的方法具有高幀率以及價格低廉
- 【DETR3D存在啥問題?】DETR3D 僅利用了3D目標中心點在多視角圖像中像素點的特征,忽略了大目標在image patch上的信息
1.2 創新點
- geometric positional embedding. 顯式利用空間幾何結構信息。
- cross-sensor global attention.能夠利用query刻畫不同view中image patch構成的key之間的相關性。
2. 方法
2.1 框架
整個框架如下圖所示,不同的視角圖像經過CNN的backbone拿到對應的feature map, 這些feature map與相機的內外參結合經過 幾何位置編碼(Geometric Positional Encoding)生成用于cross-attention的特征,而目標檢測過程則遵循detr的框架,輸入是N個可學習的queries,經過多層decoder layer,最終預測3D目標。每一層decoder layer,包含 self-attention,cross-attention,和FFN模塊,每個模塊都跟著LN層。3D框表示時包含(x,y,z, w, h, l, ).回歸
則是在sigmoid空間內進行,目的是為了數值穩定。此處見標準的DeformableDETR的結構。
2.2 Geometric Positional Encoding
傳統的直接使用sin-cos編碼的方式,或者可學習變量的位置編碼方式,首先沒有顯式的刻畫相機的外參,其次,因為3D-2D的射影變換使得grid結構不符合圖像中像素的真實關系,因此將不同view的圖像相對于同一個參考平面進行位置編碼能夠保證對不同外參的相機車輛拖影的魯棒性。
本文方法的具體做法是,給定的相機C,必然已經知道其內參,那么直接計算該相機成像平面上每個像素的單位方向向量, 這樣本質上是不考慮成像目標的depth信息,而只關心射線方向的相似度。然后將單位向量經過FC層 dir2latent進行編碼加到featuremap上。即, k 對應每個camera image經過backbone生成的feature map,用于cross attention時作為keys。
2.3 Spatially-Aware Attention
為了計算query和key之間的相似度,query和key應該在相同的空間內,而key是在2D 圖像空間內, query在3D空間內,因此需要將query投影到不同的camera上進行相似度計算。
第一個式子是先由query轉成預測的3D box,然后拿到3D box的中心點,第二個式子是通過外參矩陣,由該中心點映射到對應camera上,第三個式子相當于對對應的2D點進行geometric position編碼。這里把q和k理解維context embedding更好理解,映射到相同空間上進行幾何位置編碼,然后計算相似度。
關于query的更新,作者認為每個view的value包含的對應相機的外參信息,多個view的value其實對應3D空間的相同目標,因此有必要對value進行外參的解耦,于是
,
第一個式子是為了從2d表觀上拿到深度信息,第二個式子是拿到對應目標在該相機下的坐標,第三個式子是轉到世界坐標系下,第四個式子是由2d 特征加上世界坐標系的編碼獲得目標在3d空間的特征,用于更新query。
因為這里有用到深度信息,所以本質上是可以引入depth監督。
# xs and ys do include "invalid" values at idxs that correspond to padded pixels
xs, ys = torch.meshgrid(
torch.arange(
0, feats_shape[1], device=mask.device, requires_grad=False),
torch.arange(
0, feats_shape[0], device=mask.device, requires_grad=False),
)
xs = xs.float()
ys = ys.float()
# 3 x width x height
cam_embeddings = torch.cat(
[
xs.unsqueeze(dim=0),
ys.unsqueeze(dim=0),
torch.zeros((1, xs.shape[0], xs.shape[1]),
device=xs.device, requires_grad=False),
],
axis=0,
)
for cam_idx in range(len(img_shape)):
for s_id in range(BS):
# TODO refactor as initial check / caching
# allow for different scales via scale_mat @ K
full_img_shape = img_shape[cam_idx]
feature_scale_x = W / full_img_shape[1]
feature_scale_y = H / full_img_shape[0]
if not np.allclose(feature_scale_x, feature_scale_y):
# the feature scale was not the same (due to uneven division)
# padding fixes this -> one side is too long -> too high scale
# to fix we use the smaller feature scale
warnings.warn(
"x/y feature scale diff, double check padding...")
feature_scale = min(feature_scale_x, feature_scale_y)
else:
feature_scale = feature_scale_x
K = img_metas[s_id]["cam_intrinsic"][cam_idx]
# TODO refactor: assumes fx == fy
# scaling can be accounted for by simply scaling focal length and principal point
scale_factor = img_metas[s_id]["scale_factor"]
scale_factor = scale_factor * feature_scale
cx = K[0][2]
cy = K[1][2]
focal_length = K[0][0]
# cx
cam_embeddings[cam_idx, s_id, :, :, 0] -= cx * scale_factor
# cy
cam_embeddings[cam_idx, s_id, :, :, 1] -= cy * scale_factor
# focal length
cam_embeddings[cam_idx, s_id, :, :,
2] = focal_length * scale_factor
3. Experimets
3.1 消融實驗
- Table 4. 從這個表中可以看出 將query映射到sensor-relative空間作用最明顯, 而將value映射到global空間作用并不明顯,而C(Q)是想拿計算量換指標,也沒啥效果。這里P(V)沒啥效果,個人認為是可以理解的,正如我們前面介紹,k和q都可以當作是context embedding,而key進行了幾何位置編碼,因此query的編碼方式必須要映射到相同空間,顯然有效。而從image feature map上取的value,本質上可以認為是和key一樣的context embedding,和query本身就是在相同空間內,
是在對query更新時額外因為了3d 空間的位置編碼某種程度是不合理的
table 4 -
Table 5. 首先相同的decoder結構,900個query數量可能已經飽和,再增加指標不會改善多少,其次相同的query數, layer數少或多都不好,6個比較適合。最后,decoder layer的最后幾層共享參數,類似RNN那種指標有進一步改善。
Table 5
3.2 和已有實驗的對比
具體內容見原論文,相對于DETR3d,BEVDET這些方法,即使不使用multi-scale test的策略,其檢測指標mAP也是有優勢的。但該方法經過多次投影和反投影,感覺時間開銷較大。
4. 總結
- 本文提出的幾何位置編碼,對于非ipm-BEV方式的transformer 方法感覺是合理且有效的;大目標能漲點
- cross-attention內對query更新時value 疊加上對應3d點的位置編碼感覺解釋的不是很合理,且作用不大;
- 本文方法結構還是比較復雜的,投影和反投影的過程耗時較大。
- decoder的后幾層layer采用RNN方式共享參數可以提點,這點可以驗證下使用。