博客專欄

EEPW首頁(yè) > 博客 > 地平線 LiDAR-Camera 融合多任務(wù) BEVFusion 參考算法-V1.0

地平線 LiDAR-Camera 融合多任務(wù) BEVFusion 參考算法-V1.0

發(fā)布人:地平線開(kāi)發(fā)者 時(shí)間:2025-02-08 來(lái)源:工程師 發(fā)布文章

該示例為參考算法,僅作為在 征程 6 上模型部署的設(shè)計(jì)參考,非量產(chǎn)算法。

1.簡(jiǎn)介

激光雷達(dá)天然地具有深度信息,攝像頭可以提供豐富的語(yǔ)義信息,它們是車載視覺(jué)感知系統(tǒng)中兩個(gè)最關(guān)鍵的傳感器。但是,如果激光雷達(dá)或者攝像頭發(fā)生故障,則整個(gè)感知框架不能做出任何預(yù)測(cè),這在根本上限制了實(shí)際自動(dòng)駕駛場(chǎng)景的部署能力。目前主流的感知架構(gòu)選擇在特征層面進(jìn)行多傳感器融合,即中融合,其中比較有代表性的路線就是 BEV 范式。BEVFusion 就是典型的中融合方法,其存在兩個(gè)獨(dú)立流,將來(lái)自相機(jī)和 LiDAR 的原始輸入編碼為同一個(gè) BEV 空間。由于是通用的融合框架,相機(jī)流和 LiDAR 流的方法都可以自由選擇,在 nuScenes 數(shù)據(jù)集表現(xiàn)出了很強(qiáng)的泛化能力。本文將介紹 BEVFusion 在地平線 J6E/M 平臺(tái)上的優(yōu)化部署。


2.性能精度指標(biāo)

模型參數(shù):

模型數(shù)據(jù)集Input shapeLiDAR StreamCamera StreamBEV HeadOcc Head

BEVFusionNuscenes圖像輸入:6x3x512x960點(diǎn)云輸入:1x5x20x40000CenterPointBEVFormerBEVFormerDetDecoderBevformerOccDetDecoder

性能精度表現(xiàn):

浮點(diǎn)**精度** NDS量化精度 NDSJ6E

Latency/msFPS

0.64280.6352135.6430.95


3.公版模型介紹


BEVFusion 主要由相機(jī)流、激光雷達(dá)流、動(dòng)態(tài)融合模塊和檢測(cè)頭組成,下面將逐一進(jìn)行介紹。


3.1 相機(jī)流

相機(jī)流將多視角圖像轉(zhuǎn)到 BEV 空間,由圖像編碼器、視覺(jué)投影模塊、BEV 編碼器組成。


3.1.1 圖像**編碼器**


圖像編碼器旨在將輸入圖像編碼為語(yǔ)義信息豐富的深度特征,它由用于基本特征提取的 2D backbone Dual-Swin-Tiny 和用于多尺度特征提取的 FPN 組成,并采用了一個(gè)簡(jiǎn)單的功能自適應(yīng)模塊 ADP 來(lái)完善上采樣功能,如下圖所示:



3.1.2 視覺(jué)投影模塊


視覺(jué)投影模塊采用 LSS 將圖像特征轉(zhuǎn)換為 3D 自車坐標(biāo),將圖像視圖作為輸入,并通過(guò)分類方式密集地預(yù)測(cè)深度。

然后,根據(jù)相機(jī)外參和預(yù)測(cè)的圖像深度,獲取偽體素。

3.1.3 BEV 編碼模塊

BEV 編碼模塊采用空間到通道(S2C)操作將 4D 偽體素特征編碼到 3D BEV 空間,從而保留語(yǔ)義信息并降低成本。然后又使用四個(gè) 3 × 3 卷積層縮小通道維度,并提取高級(jí)語(yǔ)義信息。


3.2 LiDAR 流

LiDAR 流將激光雷達(dá)點(diǎn)轉(zhuǎn)換為 BEV 空間,BEVFusion 采用 3 種流行的方法,PointPillars、CenterPoint 和 TransFusion 作為激光雷達(dá)流,從而展示模型框架的優(yōu)秀泛化能力。


3.3 動(dòng)態(tài)融合模塊

動(dòng)態(tài)融合模塊的作用是將 concat 后的相機(jī)、 LiDAR 的 BEV 特進(jìn)行有效融合。受 Squeeze-and-Excitation 機(jī)制的啟發(fā), BEVFusion 應(yīng)用一個(gè)簡(jiǎn)單的通道注意力模塊來(lái)選擇重要的融合特征,網(wǎng)絡(luò)結(jié)構(gòu)圖如下所示:



4.地平線部署優(yōu)化

地平線參考算法使用流程請(qǐng)參考附錄《TCJ6007-J6 參考算法使用指南》;對(duì)應(yīng)高效模型設(shè)計(jì)建議請(qǐng)參考附錄《J6 算法平臺(tái)模型設(shè)計(jì)建議


4.1 優(yōu)化點(diǎn)總結(jié)

整體情況:

BEVFusion 參考算法采用 BEVFormer 和 centerpoint 分別生成視覺(jué)和 LiDAR BEV 特征,然后使用 SE 模型融合 BEV 特征,最后將 BEV 特征解碼。

暫時(shí)無(wú)法在飛書(shū)文檔外展示此內(nèi)容

改動(dòng)點(diǎn):

相機(jī)流使用了地平線深度優(yōu)化后的 bevformer 參考算法,并將其轉(zhuǎn)換到 LiDAR 坐標(biāo)系,其相對(duì)于公版的優(yōu)化如下:

使用地平線深度優(yōu)化后的高效 backbone HENet 提取圖像特征;

將 attention 層的 mean 替換為 conv 計(jì)算,使性能上獲得提升;

公版模型中,在 Encoder 的空間融合模塊,會(huì)根據(jù) bev_mask 計(jì)算有效的 query 和 reference_points,輸出 queries_rebatch 和 reference_points_rebatch,作用為減少交互的數(shù)據(jù)量,提升模型運(yùn)行性能。對(duì)于稀疏的 query 做 crossattn 后再將 query 放回到 bev_feature 中。;

修復(fù)了公版模型中時(shí)序融合的 bug,并獲得了精度上的提升,同時(shí)通過(guò)對(duì)關(guān)鍵層做 int16 的量化精度配置以保障 1%以內(nèi)的量化精度損失。

LiDAR 流采用了地平線深度優(yōu)化后的 centerpoint 參考算法,其相對(duì)于公版的優(yōu)化如下:

前處理部分的輸入為 5 維點(diǎn)云并做歸一化處理,對(duì)量化訓(xùn)練更加友好;

PillarFeatutreNet 中的 PFNLayer 使用 Conv2d + BatchNorm2d + ReLU,替換原有的 Linear + BatchNorm1d + ReLU,使該結(jié)構(gòu)可在 BPU 上高效支持,實(shí)現(xiàn)了性能提升;

PillarFeatutreNet 中的 PFNLayer 使用 MaxPool2d,替換公版的 torch.max,便于性能的提升;

Scatter 過(guò)程使用 horizon_plugin_pytorch 優(yōu)化實(shí)現(xiàn)的 point_pillars_scatter,便于模型推理優(yōu)化,邏輯與 torch 公版相同;

對(duì)于耗時(shí)嚴(yán)重的 OP,采用 H、W 維度轉(zhuǎn)換的方式,將較大維數(shù)放到 W 維度,比如 1x5x40000x20 轉(zhuǎn)換為 1x5x20x40000;

相對(duì)于公版,增加了 OCC 任務(wù)頭,實(shí)現(xiàn)了 LiDAR+Camera+OCC 動(dòng)靜態(tài)二網(wǎng)合一;


4.2 性能優(yōu)化4.2.1 相機(jī)流

公版 BEVFusion 使用流行的 Lift-Splat-Shoot(LSS)并適度調(diào)整以提高性能。參考算法直接采用了地平線深度優(yōu)化后的 BEVFormer 參考算法作為相機(jī)流網(wǎng)絡(luò),bev 網(wǎng)格的尺寸配置為 128 x128。

改動(dòng)點(diǎn) 1:

backbone 由公版的 Dual-Swin-Tiny 替換為地平線的高效 backbone HENet,不僅在精度上可與 ResNet50 相媲美,而且在性能上有顯著優(yōu)勢(shì)。

HENet 是針對(duì) 征程 6 平臺(tái)專門設(shè)計(jì)的高效 backbone,其采用了純 CNN 架構(gòu),總體可分為四個(gè) stage,每個(gè) stage 會(huì)進(jìn)行 2 倍下采樣。以下為總體的結(jié)構(gòu)配置:

depth = [4, 3, 8, 6]
block_cls = ["GroupDWCB", "GroupDWCB", "AltDWCB", "DWCB"]
width = [64, 128, 192, 384]
attention_block_num = [0,0,0,0]
mlp_ratios, mlp_ratio_attn = [2, 2, 2, 3], 2
act_layer = ["nn.GELU", "nn.GELU", "nn.GELU", "nn.GELU""]
use_layer_scale = [True,True,True,True]
final_expand_channel, feature_mix_channel = 0,1024
down_cls = ["S2DDown", "S2DDown", "S2DDown", "None"71


模型相關(guān)細(xì)節(jié)可以參考【地平線高效 backbone: HENet】。

代碼路徑:/usr/local/lib/python3.10/dist-packages/hat/models/backbones/henet.py

改動(dòng)點(diǎn) 2:

bevformer 中的Temporal Self-Attention通過(guò)引入時(shí)序信息與當(dāng)前時(shí)刻的 BEV Query 進(jìn)行融合,提高 BEV Query 的建模能力,Temporal Self-Attention中最關(guān)鍵的結(jié)構(gòu)為MultiScaleDeformableAttention。

經(jīng)評(píng)估,該模塊中的 mean 對(duì)性能影響較大,參考算法中將其替換為固定 weight 的 conv 計(jì)算,從而獲取性能上的提升,相關(guān)代碼:


class HorizonTemporalSelfAttention(MultiScaleDeformableAttentionBase):
   """The basic structure of HorizonTemporalSelfAttention.
   Args:
       embed_dims: The embedding dimension of Attention.
       num_heads: Parallel attention heads.
       num_levels: The num of featuremap.
       num_points: The num points for each head sample.
       grid_align_num: The align num for grid, align the grid shape of \
           gridsample operator to \
           [bs * numhead, -1, grid_align_num * numpoints, 2].
       num_bev_queue: The num queue for temporal fusion.
       reduce_align_num: The align num for reduce mean, align the shape to \
           [bs, num_bev_queue * reduce_align_num, -1, num_query].
       dropout: Probability of an element to be zeroed.
       feats_size: The Size of featmaps.
   """
   def
__init__
(
       self,
       embed_dims: int = 256,
       num_heads: int = 8,
       num_levels: int = 4,
       num_points: int = 4,
       grid_align_num: int = 8,
       num_bev_queue: int = 2,
       reduce_align_num: int = 1,
       dropout: float = 0.1,
       feats_size: Sequence[Sequence[int]] = ((128, 128),),
   ) -> None:
       super().
__init__
(
           embed_dims=embed_dims,
           num_heads=num_heads,
           num_levels=num_levels,
           num_points=num_points,
           grid_align_num=grid_align_num,
           feats_size=feats_size,
       )
       self.dropout = nn.Dropout(dropout)
       self.num_bev_queue = num_bev_queue
       self.reduce_align_num = reduce_align_num
       ...
       #將mean計(jì)算替換為conv計(jì)算
       self.query_reduce_mean = nn.Conv2d(
           self.num_bev_queue * self.reduce_align_num,
           self.reduce_align_num,
           1,
           bias=False,
       )
       



代碼路徑:/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/bevformer/attention.py

改動(dòng)點(diǎn) 3:

Spatial Cross-Attention利用 Temporal Self-Attention 模塊輸出的 bev_query, 對(duì)主干網(wǎng)絡(luò)和 Neck 網(wǎng)絡(luò)提取到的多尺度環(huán)視圖像特征進(jìn)行查詢,生成 BEV 空間下的BEV Embedding特征。公版的 BEVFormer 中采用 bevmask 來(lái)減少 camera 的 query 點(diǎn)數(shù)的優(yōu)化,但是由于涉及到 BPU 不支持的動(dòng)態(tài) shape,并且涉及到運(yùn)行效率較低的 gather/scatter 操作(當(dāng)前 gather 算子已經(jīng)支持 BPU 加速)。進(jìn)一步分析發(fā)現(xiàn):

從 bev voxel 的角度來(lái)看,中心點(diǎn)到 multi camera 的映射是稀疏的;

從 bev pillar 的角度來(lái)看,通常每個(gè) pillar 只會(huì)映射到 1-2 個(gè) camera;

基于以上分析以及實(shí)驗(yàn)結(jié)果,參考算法在設(shè)置了virtual_bev_h、virtual_bev_w、max_numcam_overlap這 3 個(gè)參數(shù)對(duì)稀疏率進(jìn)行配置,這 3 個(gè)參數(shù)的具體含義是:

virtual_bev_h:虛擬 bev 的高度,用于計(jì)算將稀疏點(diǎn)集恢復(fù)為密集 bev 的網(wǎng)格,參考算法中配置為 64;

virtual_bev_w:虛擬 bev 的寬度,用于計(jì)算將稀疏點(diǎn)集恢復(fù)為密集 bev 的網(wǎng)格,參考算法中配置為 80;

max_numcam_overlap:每個(gè) bev pillar 映射到的最多 camera 數(shù)量,參考算法中配置為 2;

    view_transformer=dict(
       type="SingleBevFormerViewTransformer",
       bev_h=bev_h_,
       bev_w=bev_w_,
       pc_range=point_cloud_range,
       num_points_in_pillar=2,
       embed_dims=
_dim_
,
       queue_length=1,
       in_indices=(-1,),
       single_bev=True,
       use_lidar2img=use_lidar2img,
       max_camoverlap_num=max_camoverlap_num, #2
       virtual_bev_h=64,
       virtual_bev_w=80,
       positional_encoding=dict(
           type="LearnedPositionalEncoding",
           num_feats=
_pos_dim_
,
           row_num_embed=bev_h_,
           col_num_embed=bev_w_,
       ),

代碼路徑:samples/ai_toolchain/horizon_model_train_sample/scripts/configs/lidar_bevfusion/bevfusion_pointpillar_henet_multisensor_multitask_nuscenes.py


4.2.2 LiDAR 流

公版 BEVFusion 采用了當(dāng)前流行的 3 種激光點(diǎn)云檢測(cè)模型 PointPillars , CenterPoint 和 TransFusion 作為 LiDAR 流來(lái)展示框架的通用性。BEVFusion 參考算法復(fù)用了經(jīng)過(guò)深度優(yōu)化的 centerpoint 參考算法,其相對(duì)于公版主要做了以下性能優(yōu)化,下面將逐一介紹。

改動(dòng)點(diǎn) 1:

為了應(yīng)用 2D 卷積架構(gòu),PillarFeatutreNet 將點(diǎn)云(P,N,5)轉(zhuǎn)換為 2D 偽圖像,整體步驟如下圖所示:


公版模型中 PillarFeatutreNet 中的部分算子在 BPU 運(yùn)行效率比較低,所以參考算法對(duì)其做了替換:

PillarFeatutreNet 中的 PFNLayer 使用 BPU 上運(yùn)行比較高效的 Conv2d + BathNorm2d + ReLU 算子,替換了公版的 Linear + BatchNorm1d + ReLU 結(jié)構(gòu),實(shí)現(xiàn)了性能的提升;

PillarFeatutreNet 中的 PFNLayer 使用 MaxPool2d,替換原有的 torch.max,便于性能的提升,對(duì)應(yīng)代碼:

class PFNLayer(nn.Module):
   def
__init__
(
       self,
       in_channels: int,
       out_channels: int,
       bn_kwargs: dict = None,
       last_layer: bool = False,
       use_conv: bool = True,
       pool_size: Tuple[int, int] = (1, 1),
       hw_reverse: bool = False,
   ):
       """Pillar Feature Net Layer.
       This layer is used to convert point cloud into pseudo-image.
       Can stack multiple to form Pillar Feature Net.
       The original PointPillars paper uses only a single PFNLayer.
       Args:
           in_channels (int): number of input channels.
           out_channels (int): number of output channels.
           bn_kwrags (dict): batch normalization arguments. Defaults to None.
           last_layer (bool, optional): if True, there is no concatenation of
               layers. Defaults to False.
       """
       ...
       if not self.use_conv:
           ...
       else:
           #使用Conv2d + BathNorm2d + ReLU,
           #替換了公版的 Linear + BatchNorm1d + ReLU
           self.linear = nn.Conv2d(
               in_channels, self.units, kernel_size=1, bias=False
           )
           self.norm = nn.BatchNorm2d(self.units, **bn_kwargs)
           self.relu = nn.ReLU(inplace=True)
           #使用 MaxPool2d,替換torch.max
           self.max_pool = nn.MaxPool2d(
               kernel_size=pool_size, stride=pool_size
           )

代碼路徑:/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/lidar/pillar_encoder.py

改動(dòng)點(diǎn) 2:

如上圖所示,Scatter 是實(shí)現(xiàn)偽圖像轉(zhuǎn)換的重要一個(gè)步驟,參考算法使用horizon_plugin_pytorch實(shí)現(xiàn)的point_pillars_scatter,便于模型推理優(yōu)化,邏輯與公版相同。對(duì)應(yīng)代碼:



from horizon_plugin_pytorch.nn.functional import point_pillars_scatter
class PointPillarScatter(nn.Module):
   ...
   def forward(
       ...
       ):
        #input_shape=(coors_range[3:] - coors_range[:3]) / voxel_size
        self.nx = input_shape[0]

        self.ny = input_shape[1]
        if self.use_horizon_pillar_scatter: #對(duì)應(yīng)改動(dòng)4
            if len(voxel_features.shape) == 4:
                P, C = voxel_features.size(2), voxel_features.size(3)
                voxel_features = voxel_features.reshape(P, C)
            out_shape = (batch_size, self.nchannels, self.ny, self.nx)
            #(P, C)-->(batch,C,H,W)
            batch_canvas = point_pillars_scatter(
                voxel_features, coords, out_shape
            )
        else:
            ...
        return batch_canvas  


其中,核心函數(shù)point_pillars_scatter是在horizon_plugin_pytorch中實(shí)現(xiàn)的。

代碼路徑: /usr/local/lib/python3.10/dist-packages/hat/models/task_modules/lidar/pillar_encoder.py


4.2.3 動(dòng)態(tài)融合模塊

相對(duì)于公版的動(dòng)態(tài)融合模塊(參考 3.3 節(jié)),參考算法在 concat 后新增了 1 個(gè) conv1x1,有助于性能的提升,相關(guān)代碼如下:

class BevFuseModule(nn.Module):
   """BevFuseModule fuses features using convolutions and SE block.
   Args:
       input_c: The number of input channels.
       fuse_c: The number of channels after fusion.
   """
   def
__init__
(self, input_c: int, fuse_c: int):
       super().
__init__
()
       self.reduce_conv = ConvModule2d(
           input_c,
           fuse_c,
           kernel_size=1,
           stride=1,
           padding=0,
           norm_layer=nn.BatchNorm2d(fuse_c, eps=1e-3, momentum=0.01),
           act_layer=nn.ReLU(inplace=False),
       ...
   def forward(self, x: torch.Tensor):
       #增加了 conv1x1
       x = self.reduce_conv(x)
       x = self.conv2(x)
       pts_feats = self.seblock(x)
       return pts_feats


代碼路徑: /usr/local/lib/python3.10/dist-packages/hat/models/task_modules/lidar_fusion/fusion_module.py


4.3 浮點(diǎn)精度優(yōu)化4.3.1 旋轉(zhuǎn)增強(qiáng)

在模型訓(xùn)練時(shí),參考算法對(duì) bev 進(jìn)行旋轉(zhuǎn)增強(qiáng),相關(guān)代碼如下:

train_dataset = dict(
   type="NuscenesBevSequenceDataset",
   data_path=os.path.join(data_rootdir, "train_lmdb"),
   ...
   transforms=[
       dict(type="MultiViewsImgResize", size=input_size),
       dict(type="MultiViewsImgFlip"),
       dict(type="MultiViewsImgRotate", rot=(-5.4, 5.4)),
       dict(type="BevBBoxRotation", rotation_3d_range=(-0.3925, 0.3925)),
       dict(type="MultiViewsPhotoMetricDistortion"),
       dict(
           type="MultiViewsImgTransformWrapper",
           transforms=[
               dict(type="PILToTensor"),
               dict(type="BgrToYuv444", rgb_input=True),
               dict(type="Normalize", mean=128, std=128),
           ],
       ),
   ],
)


代碼路徑:

horizon_model_train_sample/scripts/configs/lidar_bevfusion/bevfusion_pointpillar_henet_multisensor_multitask_nuscenes.py
/usr/local/lib/python3.10/dist-packages/hat/data/transforms/multi_views.py


4.3.2 加載預(yù)訓(xùn)練模型

為了提升浮點(diǎn)模型的精度,浮點(diǎn)訓(xùn)練時(shí)相機(jī)流和 LiDAR 流分別加載了預(yù)訓(xùn)練模型,然后再共同訓(xùn)練,對(duì)應(yīng)代碼如下:

float_trainer = dict(
    type="distributed_data_parallel_trainer",
    model=model,
    data_loader=data_loader,
    model_convert_pipeline=dict(
        type="ModelConvertPipeline",
        converters=[
            dict(
                type="LoadCheckpoint",
                #加載相機(jī)流的預(yù)訓(xùn)練模型
                checkpoint_path=os.path.join(
                    camera_ckpt_dir, "float-checkpoint-last.pth.tar"
                ),
                allow_miss=True,
                ignore_extra=True,
                verbose=True,
            ),
            dict(
                type="LoadCheckpoint",
                #加載LiDAR流的預(yù)訓(xùn)練模型
                checkpoint_path=os.path.join(
                    lidar_ckpt_dir, "float-checkpoint-last.pth.tar"
                ),
               ...
    ),

代碼路徑:

horizon_model_train_sample/scripts/configs/lidar_bevfusion/bevfusion_pointpillar_henet_multisensor_multitask_nuscenes.py


4.4 量化精度優(yōu)化4.4.1 全 int8+部分算子配置為 int16

BEVFusion 參考算法采用的量化策略為全 int8+部分敏感算子通過(guò) set_qconfig 配置為 int16,其中敏感算子的集中分布在 bevformer 部分,如下為 bevformer 中將MultiScaleDeformableAttention中對(duì)量化敏感的算子和 Tensor 配置為 int16 的示例代碼:


class MultiScaleDeformableAttentionBase(nn.Module):
    """The basic class for MultiScaleDeformableAttention.
    Args:
        embed_dims: The embedding dimension of Attention.
        num_heads: Parallel attention heads.
        num_levels: The num of featuremap.
        num_points: The num points for each head sample.
        grid_align_num: The align num for grid, align the grid shape of \
            gridsample operator to \
            [bs * numhead, -1, grid_align_num * numpoints, 2].
        feats_size: The Size of featmaps.
    """
    def 
__init__
(
        self,
        embed_dims: int = 256,
        num_heads: int = 8,
        num_levels: int = 4,
        num_points: int = 4,
        grid_align_num: int = 8,
        feats_size: Sequence[Sequence[int]] = ((128, 128),),
    ) -> None:
        super().
__init__
()
        ...
    def set_qconfig(self) -> None:
        """Set the quantization configuration."""
        from hat.utils import qconfig_manager
        int16_module = [
            self.sampling_offsets,
            self.quant_shape,
            self.norm_offset,
            self.add_offset,
            self.add1,
            self.mul1,
        ]
        for m in int16_module:
            m.qconfig = qconfig_manager.get_qconfig(
                activation_qat_qkwargs={"dtype": qint16},
                activation_calibration_qkwargs={
                    "dtype": qint16,
                },
                activation_calibration_observer="mix",
            )

代碼路徑:

/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/bevformer/attention.py


4.5 其它優(yōu)化4.5.1 增加 Occ 任務(wù)頭

除了公版 BEVFusion 就存在的 3D 檢測(cè)頭外,參考算法增加了 Occ 任務(wù)頭做占用預(yù)測(cè),和 3D 檢測(cè)頭共用特征部分,從而極大地節(jié)省了計(jì)算資源。Occ 任務(wù)頭復(fù)用了 FlashOcc 中的 head 進(jìn)行設(shè)計(jì),通過(guò)通道轉(zhuǎn)高度模塊將 BEV 特征沿通道維度執(zhí)行簡(jiǎn)單的重塑操作。相關(guān)代碼如下:

    def forward(self, img_feats: Tensor):
        """Forward mould.
        Args:
            img_feats: (B, C, Dy, Dx)
        Returns:
            occ_pred:tensor
        """
        occ_pred = self.final_conv(img_feats)
        if self.use_upsample is True:
            occ_pred = F.interpolate(
                occ_pred, size=(200, 200), mode="bilinear", align_corners=False
            )
        # (B, C, Dy, Dx) --> (B, Dx, Dy, C)
        occ_pred = occ_pred.permute(0, 3, 2, 1)
        bs, Dx, Dy = occ_pred.shape[:3]
        if self.use_predicter:
            #通道轉(zhuǎn)高度操作
            # (B, Dx, Dy, C) --> (B, Dx, Dy, 2
*C) --> (B, Dx, Dy, Dz*
n_cls)
            occ_pred = self.predicter(occ_pred)
            occ_pred = occ_pred.view(bs, Dx, Dy, self.Dz, self.num_classes)
        return occ_pred

代碼路徑:

/usr/local/lib/python3.10/dist-packages/hat/models/task_modules/flashocc/bev_occ_head.py

Occ label 坐標(biāo)轉(zhuǎn)換

由于 Occ label 是在 ego 坐標(biāo)系中標(biāo)注的,所以需要將其統(tǒng)一到 Lidar 坐標(biāo)系,相關(guān)代碼如下:

class NuscenesBevDataset(NuscenesDataset):
   ...
    def 
__getitem__
(self, item):
        aug_cfg = None
        if isinstance(item, dict):
            idx = item["idx"]
            aug_cfg = item["aug"]
        else:
            idx = item
        sample = self._decode(self.pack_file, self.samples[idx])
        sample = NuscenesSample(sample)
        data = self.sampler(sample)
        if aug_cfg:
            data["scenes_aug"] = aug_cfg
        if self.transforms is not None:
            data = self.transforms(data)
        if self.with_lidar_occ:
            #將Occ label由ego坐標(biāo)系轉(zhuǎn)到lidar坐標(biāo)系
            data["gt_occ_info"] = sample._get_lidar_occ(data["lidar2global"])
        return data

代碼路徑:

/usr/local/lib/python3.10/dist-packages/hat/data/datasets/nuscenes_dataset.py

Bev 特征裁剪

bev 的空間范圍為[51.2,51.2],grid 尺寸為 128x128;而 occ 的空間范圍為[40,40],grid 尺寸為 128x128。為了將 bev 空間范圍對(duì)齊到 Occ,occ_head中根據(jù)比例將 128x128 的 bev feature 從中心裁剪出 100x100 的 roi,從而滿足 40/51.2=100/128。相關(guān)代碼如下:


occ_head = dict(
    type="BevformerOccDetDecoder",
    use_mask=True,
    lidar_input=lidar_input,
    camera_input=camera_input,
    num_classes=num_classes_occ,
    #使用RoiResize做bev feature的裁剪
    roi_resizer=dict(
        type="RoiResize",
        in_strides=[1],
        roi_resize_cfgs=[
            dict(
                in_stride=1,
                roi_box=(14, 14, 114, 114),
            )
        ],
    ),

代碼路徑:

horizon_model_train_sample/scripts/configs/lidar_bevfusion/bevfusion_pointpillar_henet_multisensor_multitask_nuscenes.py


5.總結(jié)與建議5.1 訓(xùn)練建議

建議在浮點(diǎn)訓(xùn)練時(shí)分別加載 Lidar 流和相機(jī)流的預(yù)訓(xùn)練模型,然后再訓(xùn)練整個(gè)網(wǎng)絡(luò);

建議選擇合適的 bev grid size,實(shí)驗(yàn)中發(fā)現(xiàn) bev grid size 配置為 128x128 時(shí)的精度比 50x50 要高;

對(duì)于多任務(wù)模型,建議在量化訓(xùn)練適當(dāng)增加 epoch,即量化訓(xùn)練不一定要嚴(yán)格按照浮點(diǎn)訓(xùn)練的 1/10 epoch 來(lái)訓(xùn)練;

浮點(diǎn)訓(xùn)練時(shí)采用CosineAnnealingLrUpdater策略,量化訓(xùn)練時(shí)采用StepDecayLrUpdater策略,對(duì)于此模型來(lái)說(shuō),采用StepDecayLrUpdater策略對(duì)量化訓(xùn)練精度更友好;


5.2 部署建議

建議在模型架構(gòu)設(shè)計(jì)之初就考慮采用地平線深度優(yōu)化后的 backbone 或者網(wǎng)絡(luò)作為 base model;

在注意力機(jī)制中存在一些 add、sum 等 ElementWise 操作,對(duì)于導(dǎo)致性能瓶頸的可以考慮 conv 替換,對(duì)于造成量化風(fēng)險(xiǎn)的可以根據(jù)敏感度分析結(jié)果合理選擇更高的量化精度,以確保注意力機(jī)制的部署;

建議在選擇 bev size 時(shí)考慮性能影響。征程 6 相比于 征程 5 帶寬增大,但仍需注意 bev size 過(guò)大導(dǎo)致訪存時(shí)間過(guò)長(zhǎng)對(duì)性能的影響,建議考慮實(shí)際部署情況選擇合適的 bev size;

若出現(xiàn)性能問(wèn)題可以通過(guò)優(yōu)化 backbone 或者減少層數(shù)或者點(diǎn)數(shù)的方式來(lái)提升性能,但要注意以上操作可能會(huì)導(dǎo)致精度損失,請(qǐng)優(yōu)先考慮對(duì)點(diǎn)數(shù)的減少等對(duì)精度的影響較小性能收益最高的操作;


附錄

論文:BEVFusion

公版模型代碼:https://github.com/ADLab-AutoDrive/BEVFusion

參考算法使用指南:J6 參考算法使用指南


*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。




相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉