OpenPCDet の全体構造図:
PointPillarScatter モジュール
PillarVFEエンコード後、このときのbatch_dict更新は以下のようになり、各ボクセルの特徴を示すpillar_featuresフィールドが追加され、その後Map_to_BEVモジュールが処理される。
Map_to_BEV 構造の、対応する __init__ ファイルの下で、すべてのオプション モジュールを見つけて、PointPillars アルゴリズムで使用される PointPillarScatter モジュールを選択することもできます。
# 根据MODEL中的MAP_TO_BEV确定选择的模块
__all__ = {
'HeightCompression': HeightCompression,
'PointPillarScatter': PointPillarScatter,
'Conv2DCollapse': Conv2DCollapse
}
1.PointPillarScatterの初期化
PointPillarScatter モジュールの初期化部分は比較的単純で、関連する yaml 設定と点群シーンの平面ネットワークのグリッド サイズを保存するだけです。PointPillar は点群シーン全体を平面グリッドに分割するため、ここでの Z 次元は 1 である必要があります。つまり、ネットワークは Z 軸上でセグメント化されていません。
self.model_cfg = model_cfg
self.num_bev_features = self.model_cfg.NUM_BEV_FEATURES
self.nx, self.ny, self.nz = grid_size # PointPillar将整个点云场景切分为平面网格,所以这里的z维度一定是1
assert self.nz == 1
2.PointPillarScatter 順伝播
batch_dict から、点と座標が点群フレーム シーンを区別するために各次元に依存していることがわかります。
map2bev モジュールで行う必要があるのは、抽出されたボクセル特徴を元の空間に復元して、擬似画像特徴を形成することです。
具体的な方法としては、例えば、現在抽出されているボクセル特徴量がNx64であるとする。最初の選択は、擬似空間全体に対して 0 行列を構築することです。ここでは、2 点のグリッド サイズが [1, 432, 496] であるため、[64, 1x432x496] の空の行列が構築されます。対応する寸法を持つ点群フレーム シーンを順次取得し、バッチ マスクを構築します。このマスクによれば、ある点群フレームの柱特徴量と位置座標特徴量を得ることができる。次に、coord はボクセルの特定のグリッドを格納するため、1 次元空間のインデックスを構築でき、そのインデックスに従って空の行列の対応する位置のペアにボクセルの特徴を埋めることができます。次に、元の空間に再形成して、擬似画像の特徴行列を構築します。
完全な操作プロセスは次のとおりです。
def forward(self, batch_dict, **kwargs):
"""
Args:
pillar_features:(31530,64)
voxels:(31530,32,4) --> (x,y,z,intensity)
voxel_coords:(31530,4) --> (batch_index,z,y,x) 在dataset.collate_batch中增加了batch索引
voxel_num_points:(31530,)
Returns:
batch_spatial_features:(4, 64, 496, 432)
"""
pillar_features, coords = batch_dict['pillar_features'], batch_dict['voxel_coords'] # (102483, 64) / (102483, 4)
batch_spatial_features = []
batch_size = coords[:, 0].max().int().item() + 1 # 16
# 依次对每个点云帧场景进行处理
for batch_idx in range(batch_size):
spatial_feature = torch.zeros( # 构建[64, 1x432x496]的0矩阵
self.num_bev_features, # 64
self.nz * self.nx * self.ny, # 1x432x496
dtype=pillar_features.dtype,
device=pillar_features.device)
batch_mask = coords[:, 0] == batch_idx # 构建batch掩码
this_coords = coords[batch_mask, :] # 用来挑选出当前真个batch数据中第batch_idx的点云帧场景
# this_coords: [7857, 4] 4个维度的含义分别为:(batch_index,z,y,x) 由于pointpillars只有一层,所以计算索引的方法如下所示
indices = this_coords[:, 1] + this_coords[:, 2] * self.nx + this_coords[:, 3] # 网格的一维展开索引
indices = indices.type(torch.long)
pillars = pillar_features[batch_mask, :] # 根据mask提取pillar_features [7857, 64]
pillars = pillars.t() # 矩阵转置 [64, 7857]
spatial_feature[:, indices] = pillars # 在索引位置填充pillars
batch_spatial_features.append(spatial_feature) # 将空间特征加入list,每个元素为(64,214272)
batch_spatial_features = torch.stack(batch_spatial_features, 0) # 堆叠拼接 (16, 64, 214272)
# reshape回原空间(伪图像)--> (16, 64, 496, 432), 再保存结果
batch_spatial_features = batch_spatial_features.view(batch_size, self.num_bev_features * self.nz, self.ny, self.nx) # (16, 64, 496, 432)
batch_dict['spatial_features'] = batch_spatial_features
return batch_dict
最終的に構築された spatial_features 次元は (16, 64, 496, 432) です。ここでの 16 はbatch_sizeで、点群フレームシーン情報が16個あることを示します。496x432 は偽画像のグリッド サイズを表し、64 は各グリッド上の特徴の寸法を表します。ボクセル上の特徴はpillar_featuerによって埋められ、他の非ボクセルインデックス上の位置特徴は0であるため、特徴行列全体はまだ比較的疎です。
最後に、PointPillarScatter モジュールによる処理後、1 次元で保存されたボクセル フィーチャは、比較的疎ではありますが、1 次元の bev パースペクティブ フィーチャに変換できます。batch_dict データの更新は次のとおりです。