[BEV]学习笔记之BEVDepth(原理+代码)
文章目錄
- 1、前言
- 2、模型簡介
- 3、代碼解析
- 4、總結
1、前言
繼lift-splat-shoot之后,純視覺BEV感知又有了新的進展,如曠視科技、華中理工和西安交大提出來的BEVDepth。本文首先會對BEVDepth方法進行簡要說明,后面會結合閱讀代碼過程中的理解對整個流程進行詳細的說明,尤其是voxel_pooling的實現。
repo :https://github.com/Megvii-BaseDetection/BEVDepth
paper:https://arxiv.org/pdf/2206.10092
歡迎進入BEV感知交流群,一起解決學習過程發現的問題,可以加v群:Rex1586662742,q群:468713665。
2、模型簡介
常見的自底向上方法的會顯示的估計每個特征點的距離,但是這些距離是隱式學習的,在BEVDepth中會利用lidar的點云來監督預測出來的深度,使得預測的距離更加接近真實值。此外,考慮到相機外參可能會對結果進行干擾,文章增加一個網絡來學習相機參數,作為注意力權重作用于圖像和深度特征。同時,利用cuda實現了高效的體素池化操作。下面為論文中的網絡結構圖。
從左下角出發,一直到右下角結束,大體可以分為四個部分:環視圖片特征提取、深度特征預測、Voxel Pooling和Detection Head,BEVDepth論文的關鍵深度特征提取以及Voxel Pooling這兩個部分,因此下面將會針對這兩個部分的代碼進行說明。
3、代碼解析
下面的代碼是基本上是按照forward的順序進行的,會對關鍵代碼進行解釋以及shape的標注。
1、bevdepth/models/base_bev_depth.py
class BaseBEVDepth(nn.Module):def forward(...):if self.is_train_depth and self.training:# 訓練時 用Lidar的深度來監督 depth_predx, depth_pred = self.backbone(...)preds = self.head(x)else:# x:[1, 160, 128, 128] 關鍵幀+過渡幀的 bev特征x = self.backbone(x, mats_dict, timestamps) # -> bevdepth/layers/backbones/base_lss_fpn.py# 解碼preds = self.head(x) # 參考centerpoint2、bevdepth/layers/backbones/base_lss_fpn.py
class BaseLSSFPN(nn.Module):def __init__(...):...def forward(...):"""Args:sweep_imgs:[1, 2, 6, 3, 256, 704],關鍵幀以及過渡幀圖片mats_dict(dict):sensor2ego_mats:相機坐標系->車輛坐標系intrin_mats:相機內參ida_mats:圖像數據增強矩陣sensor2sensor_mats:key frame camera to sweep frame camera,關鍵幀到過渡幀的變化矩陣bda_mat:bev特征增強矩陣 """# 提取關鍵幀的BEV特征 key_frame_res:[1, 80, 128, 128])key_frame_res = self._forward_single_sweep(...)for sweep_index in range(1, num_sweeps):# 提取過渡幀的bev特征feature_map = self._forward_single_sweep(...)ret_feature_list.append(feature_map)if is_return_depth:return torch.cat(ret_feature_list, 1), key_frame_res[1]return torch.cat(ret_feature_list, 1) def _forward_single_sweep(...):# 提取環視圖片特征# img_feats:[1, 1, 6, 512, 16, 44]img_feats = self.get_cam_feats(sweep_imgs)source_features = img_feats[:, 0, ...]# 提取Depth以及contextdepth_feature = self._forward_depth_net(...)# 預測的距離分布 depth:[6, 112, 16, 44]depth = depth_feature[:, :self.depth_channels].softmax(1)# 對應論文中的 Context Feature * Depth Distribution 操作img_feat_with_depth = ... # # 車輛坐標系下的視錐坐標點 geom_xyz:[1, 6, 112, 16, 44, 3] geom_xyz = self.get_geometry(...)# 將車輛坐標系的原點移動到左下角geom_xyz = ((geom_xyz - (self.voxel_coord - self.voxel_size / 2.0)) /self.voxel_size).int()# 獲得最終BEV特征 [1, 80, 128, 128]feature_map = voxel_pooling(...) # -> bevdepth/ops/voxel_pooling/voxel_pooling.pyif is_return_depth:# 訓練時需要返回預測的深度,用lidar信號進行監督return feature_map.contiguous(), depthreturn feature_map.contiguous()def _forward_depth_net(...):return self.depth_net(feat, mats_dict)def get_geometry(...):"""Transfer points from camera coord to ego coordArgs:rots(Tensor): Rotation matrix from camera to ego.trans(Tensor): Translation matrix from camera to ego.intrins(Tensor): Intrinsic matrix.post_rots_ida(Tensor): Rotation matrix for ida.post_trans_ida(Tensor): Translation matrix for idapost_rot_bda(Tensor): Rotation matrix for bda."""# self.frustum:[112, 16, 44, 4] 視錐 points = self.frustum# 乘以圖像增強的逆矩陣points = ida_mat.inverse().matmul(points.unsqueeze(-1))# lamda * [x,y,1] = [lamda*x,lamda*y,lamda]# 像素坐標系轉相機坐標系points = torch.cat(...)# cam_to_egocombine = sensor2ego_mat.matmul(torch.inverse(intrin_mat))points = combine.view(...)return points # 對應Depth Module,由與論文中沒有給出該模塊的流程圖于是按照代碼邏輯繪制了一個 class DepthNet(nn.Module):def __init__(...):...def forward(...):# 當前幀的相機參數mlp_input = ...# Normmlp_input = self.bn(mlp_input.reshape(-1, mlp_input.shape[-1])) # 相機參數作為 context的注意力系數context_se = self.context_mlp(mlp_input)[..., None, None]# 注意力操作context = self.context_se(x, context_se)# FCcontext = self.context_conv(context)# 相機參數作為 Depth的注意力系數depth_se = self.depth_mlp(mlp_input)[..., None, None]# 注意力操作depth = self.depth_se(x, depth_se)# FCdepth = self.depth_conv(depth)return torch.cat([depth, context], dim=1)Depth Module
3、bevdepth/ops/voxel_pooling/voxel_pooling.py
class VoxelPooling(...):def forward(...):"""Args:geom_xyz:在車輛坐標系下的視錐點,x、y軸的范圍為0~127 input_features:環視圖片特征voxel_num: 128 * 128 * 80"""# 為每個視錐點分配一個thread,將在bev特征下,處于相同位置的特征點對應的特征向量相加,具體可以看下方的核函數voxel_pooling_ext.voxel_pooling_forward_wrapper(...)# -> bevdepth/ops/voxel_pooling/src/voxel_pooling_forward_cuda.cu# 最終就得到BEV特征 output_featuresreturn output_features4、bevdepth/ops/voxel_pooling/src/voxel_pooling_forward_cuda.cu
由于voxel_pooling代碼講解的資料比較少,根據對下面的代碼的理解繪制了voxel_pooling的示意圖,在下方的代碼注釋中會對這個圖進行說明。
4、總結
本次針對BEVDepth的特性進行學習,主要是針對深度預測模塊以及Voxel_pooling模塊進行了分析,了解完BEVDepth之后,就可以對曠視的另一篇論文BEVstereo進行學習了,希望有更多的人加入進來,一起學習、討論。
總結
以上是生活随笔為你收集整理的[BEV]学习笔记之BEVDepth(原理+代码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国家基础地理信息中心行政边界等矢量数据免
- 下一篇: 丢失的相机照片怎么找回来的使用方法分享