色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          "); //-->

          博客專欄

          EEPW首頁 > 博客 > 地平線 bev_cft_efficientnetb3 參考算法-v1.2.1

          地平線 bev_cft_efficientnetb3 參考算法-v1.2.1

          發(fā)布人:地平線開發(fā)者 時(shí)間:2024-11-24 來源:工程師 發(fā)布文章
          01 概述


          在自動(dòng)駕駛感知算法中 BEV 感知成為熱點(diǎn)話題,BEV 感知可以彌補(bǔ) 2D 感知的缺陷構(gòu)建 3D “世界”,更有利于下游任務(wù)和特征融合。


          地平線集成了基于 bev 的純視覺算法,目前已支持 ipm-based 、lss-based、 transformer-based(Geometry-guided Kernel Transformer、detr3d、petr) 的多種 bev 視覺轉(zhuǎn)換方法。


          本文為 camera calibration free 的 transformer-based 的 BEV 感知算法的介紹和使用說明。


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



          02 性能精度指標(biāo)


          模型配置:

          圖片


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


          圖片


          注:Nuscenes 數(shù)據(jù)集官方介紹:Nuscenes



          03 模型介紹


          3.1 模型框架


          圖片


          bev_cft 模型結(jié)構(gòu)圖


          bev_cft 使用多視圖的當(dāng)前幀的 6 個(gè) RGB 圖像作為輸入。輸出是目標(biāo)的 3D Box 結(jié)果。多視角圖像首先使用 2D 主干獲取 2D 特征。然后投影到 3D BEV 視角。接著對 BEV feature 編碼獲取深層 BEV 特征。最后,接上任務(wù)特定的 head,輸出檢測結(jié)果。


          模型主要包括以下部分:


          • Part1—2D Image Encoder:圖像特征提取層。使用 2D 主干網(wǎng)絡(luò)(efficientnet)和 FastSCNN 輸出不同分辨率的特征圖。返回最后一層–上采樣至 1/128 原圖大小層,用于下一步投影至 3D 坐標(biāo)系中。


          • Part2—View transformer:采用 CFT 方式完成 img 2D 到 BEV 3D 的轉(zhuǎn)換。


          • Part3—Bev transforms:對 BEV 特征做數(shù)據(jù)增強(qiáng),僅發(fā)生在訓(xùn)練階段。


          • Part4—3D BEV Encoder:BEV 特征提取層。


          • Part5—BEV Decoder

            使用 DepthwiseSeparableCenterPointHead 進(jìn)行 3D 目標(biāo)檢測任務(wù),檢測的類別為 [“car”,“truck”,“bus”,“barrier”,“bicycle”,“pedestrian”]。


          3.2 源碼說明config文件

          **configs/bev/bev_cft_efficientnetb3_nuscenes.py** 為該模型的配置文件,定義了模型結(jié)構(gòu)、數(shù)據(jù)集加載,和整套訓(xùn)練流程,所需參數(shù)的說明在算子定義中會(huì)給出。

          配置文件主要內(nèi)容包括:

          #基礎(chǔ)參數(shù)配置
          task_name = "bev_cft_efficientnetb3_nuscenes"
          batch_size_per_gpu = 2
          device_ids = [0]
          #bev參數(shù)配置
          resize_shape = (3, 792, 1408)
          data_shape = (3, 512, 1408)
          grid_size = (64, 64)

          # 模型結(jié)構(gòu)定義
          model = dict(
             type="ViewFusion",
             backbone=dict(
                 type="efficientnet",
                 model_type="b3",
                 ...
             ),
             neck=dict(
                 type="BiFPN",
                 ...
             ),
             view_transformer=dict(
                 type="CFTTransformer", #cft transform
                 ...
             ),
             bev_transforms=[...],
             bev_encoder=dict(
                 type="BevEncoder",
                 ...
             ),
             bev_decoders=[
                  dict(
                     type="BevDetDecoder",
                     ...
                 )
             ],
          )

          deploy_model = dict(
          ...
          )
          ...
          # 數(shù)據(jù)加載
          data_loader = dict(
             type=torch.utils.data.DataLoader,
             ...
          )

          val_data_loader = dict(...)

          #不同step的訓(xùn)練策略配置
          float_trainer=dict(...)
          calibration_trainer=dict(...)
          qat_trainer=dict(...)
          int_infer_trainer=dict(...)
          #不同step的驗(yàn)證
          float_predictor=dict(...)
          calibration_predictor=dict(...)
          qat_predictor=dict(...)
          int_infer_predictor=dict(...)
          #編譯配置
          compile_cfg = dict(
             march=march,
             ...
          )

          注:如果需要復(fù)現(xiàn)精度,config 中的訓(xùn)練策略最好不要修改。否則可能會(huì)有意外的訓(xùn)練情況出現(xiàn)。

          img_encoder


          來自 6 個(gè) view 的 image 作為輸入通過共享的 backbone(efficientnet-b3)和 neck(BiFPN)輸出經(jīng)過 encoder 后的 feature,feature_shape 為(6*B,C,1/128H,1/128W)。


          encoder 即對多個(gè) view 的 img_feature 做特征提取,過程見下圖:


          圖片


          對應(yīng)代碼:hat/models/backbones/efficientnet.py hat/models/necks/bifpn.py

          view_transformer


          view_transformer 采用 CFT(camera free transformer)映射的方法,把圖像視角的 img_features 轉(zhuǎn)換到 bev_features。


          BEV_shape 為[H’,W’]為[64,64],其轉(zhuǎn)換過程見下圖:


          圖片


          cft 框架圖


          view_transformer 對應(yīng)代碼:

          hat/models/task_modules/view_fusion/cft_transformer.pyCFTTransformer。

          class CFTTransformer(ViewTransformer):
             ...
             def forward(self, feats: Tensor, data: Tensor,...):
                 query_pos, key_pos, ref_h_embed, ref_h = self._position_embed(feats)

                 bs = feats.shape[0] // self.num_views
                 key_pos = key_pos.repeat(bs, 1, 1, 1)
                 tgt = (
                     self.query_embed.weight.view(
                         self.grid_size[0], self.grid_size[1], -1
                     )
                     .repeat(bs, 1, 1, 1)
                     .permute(0, 3, 1, 2)
                     .contiguous()
                 )

                 key_pos = self.key_pos_quant(key_pos)
                 feats = self.encoder(feats, pos=key_pos)
                 tgt = self.tgt_quant(tgt)
                 query_pos = self.query_pos_quant(query_pos)
                 ref_h_embed = self.ref_h_quant(ref_h_embed)
                 feats = self.decoder(
                     feats,
                     tgt=tgt,
                     query_pos=query_pos,
                     key_pos=key_pos,
                     ref_h_embed=ref_h_embed,
                 )
                 return feats, ref_h


          根據(jù)框架圖,在 view_transformer 流程中可以分為兩部分:

          • position-Aware Enhancement:對位置編碼進(jìn)行強(qiáng)化,對 BEV 2D 和 content 編碼,并通過 PA 網(wǎng)絡(luò)實(shí)現(xiàn)特征增強(qiáng)

          • view-Aware Attention:對圖像融合坐標(biāo)位置編碼,增強(qiáng)特征


          position-Aware Enhancement


          Step 1 : postition_embedding


          該部分為 BEV 2D 坐標(biāo)的編碼,編碼為可學(xué)習(xí)、參數(shù)可更新的PositionEmbeddingLearned2D


          class PositionEmbeddingLearned2D(nn.Module):
             ...
             def forward(self, patch: Tensor) -> Tensor:
                 """
                 Forward pass of the PositionEmbeddingLearned2D module.

                 Args:
                     patch: Input tensor.

                 Returns:
                     pos: Output tensor.
                 """
                 hw, _ = patch.shape
                 hw = torch.tensor(hw)
                 h = w = torch.sqrt(hw).int()
                 i = torch.arange(h, device=patch.device)
                 j = torch.arange(w, device=patch.device)
                 x_emb = self. col_embed(i)
                 y_emb = self.row_embed(j)
                 pos = x_emb.unsqueeze(1).repeat(1, w, 1) + y_emb.unsqueeze(0).repeat(
                     h, 1, 1
                 )
                 return pos.permute(2, 0, 1).contiguous().unsqueeze(0)


          Step 2 : reference height embedding


          該步驟為對高度 reference height 的編碼。根據(jù)位置編碼 query_pos 來做高度的預(yù)測 ref_h ,然后對高度 ref_h 做正弦函數(shù)編碼。計(jì)算公式為:

          圖片

          對應(yīng)代碼為:

          def _position_embed(
                 self, feats: Tensor
             ) -> Tuple[Tensor, Tensor, Tensor, Tensor]:
                 ...        
                 height_range = [self.position_range[2], self.position_range[5]]
                 ref_h = self.ref_h_head(query_pos)
                 ref_h = (
                     ref_h.sigmoid() * (height_range[1] - height_range[0])
                     + height_range[0]
                 )
                 ref_h_embed = gen_sineembed_for_position(
                     ref_h, height_range, self.embed_dims
                 )


          ref_h_head 為一個(gè)輸出 channel 為 1 的 mlp:

          self.ref_h_head = MLP(
                     input_channels=embed_dims,
                     output_channels=1,
                     feedforward_channels=embed_dims,
                 )

          gen_sineembed_for_position實(shí)現(xiàn)在hat/models/task_modules/view_fusion/cft_transformer.py。


          Step 3:結(jié)合 BEV 的 content query,細(xì)化目標(biāo)的 height


          圖片


          為了細(xì)化高度,引入 BEV 的 content 來提取目標(biāo)的高度信息:


          圖片


          BEV 的 content 為預(yù)設(shè)的 query。num_query 為 bevsize 大小。

          num_queries = self.grid_size[0] * self.grid_size[1]
          self.query_embed = nn.Embedding(num_queries, self.embed_dims)

          tgt = (
             self.query_embed.weight.view(
                 self.grid_size[0], self.grid_size[1], -1
             )
             .repeat(bs, 1, 1, 1)
             .permute(0, 3, 1, 2)
             .contiguous()
          )


          Content query 經(jīng)過 MLP 后與 Ref_h 做 mul,然后與 query_pos 做 add。代碼:

          class Decoder(nn.Module):
             ...
             def forward(
                 self,
                 x: Tensor,
                 tgt: Tensor,
                 query_pos: Tensor,
                 key_pos: Tensor,
                 ref_h_embed: Tensor,
             ) -> Tensor:
                 ...
                 for i, decoder in enumerate(self.decoders):
                     if i > 0:
                         pos_transformation = self.query_trans_pos(tgt)
                         ref_h_embed = self.mul.mul(ref_h_embed, pos_transformation)
                     ref_h_embed = ref_h_embed + query_pos
                     tgt = decoder(
                         x,
                         tgt=tgt,
                         query_pos=query_pos,
                         key_pos=key_pos,
                         ref_h_embed=ref_h_embed,
                     )
                 return tgtclass Decoder(nn.Module):    ...    def forward(        self,        x: Tensor,        tgt: Tensor,        query_pos: Tensor,        key_pos: Tensor,        ref_h_embed: Tensor,    ) -> Tensor:        ...        for i, decoder in enumerate(self.decoders):            if i > 0:                pos_transformation = self.query_trans_pos(tgt)                ref_h_embed = self.mul.mul(ref_h_embed, pos_transformation)            ref_h_embed = ref_h_embed + query_pos            tgt = decoder(                x,                tgt=tgt,                query_pos=query_pos,                key_pos=key_pos,                ref_h_embed=ref_h_embed,            )        return tgt


          view-Aware Attention

          該層對圖像做 encoder。融合 position 經(jīng)過一個(gè) self-attention 模塊做特征增強(qiáng)。

          class CFTTransformer(ViewTransformer):
             ...
             def forward(self, feats: Tensor, data: Tensor,...):
                 ...
                 query_pos, key_pos, ref_h_embed, ref_h = self._position_embed(feats)
                 bs = feats.shape[0] // self.num_views
                 key_pos = key_pos.repeat(bs, 1, 1, 1)
                 ...
                 key_pos = self.key_pos_quant(key_pos)        
                 feats = self.encoder(feats, pos=key_pos)
                 ...


          其中位置編碼 key_pos 的方式為:

          self.pos_embedding = PositionEmbeddingLearned(
             num_pos_feats=[100, 100, 56], num_pos=num_pos
          )

          詳細(xì)實(shí)現(xiàn)見 PositionEmbeddingLearned。


          圖像的 encoder 操作為:

          class Encoderlayer(nn.Module):
             ...    
             def forward(self, x: Tensor, pos: Tensor) -> Tensor:
                 x = self.norm1(x)
                 q = k = self.pos_add.add(x, pos)
                 tgt, _ = self.self_attns(query=q, key=k, value=x)
                 tgt = self.dropout1_add.add(x, self.dropout1(tgt))
                 tgt2 = self.norm2(tgt)
                 tgt2 = self.ffn(tgt2)
                 tgt2 = self.dropout2_add.add(tgt, self.dropout2(tgt2))
                 return tgt2


          在公版中,為了減少計(jì)算量和內(nèi)存消耗,在 Decoder 的自注意力計(jì)算中做了分組的 Attention,在做 J5 部署時(shí)該部分會(huì)用到大量的 slice,IO 操作導(dǎo)致帶寬資源緊張,因此,地平線版本未做 part attention。

          class Decoder(nn.Module):
             ...
             def forward(
                 self,
                 x: Tensor,
                 tgt: Tensor,
                 query_pos: Tensor,
                 key_pos: Tensor,
                 ref_h_embed: Tensor,
             ) -> Tensor:

                 for i, decoder in enumerate(self.decoders):
                     if i > 0:
                         pos_transformation = self.query_trans_pos(tgt)
                         ref_h_embed = self.mul.mul(ref_h_embed, pos_transformation)
                     ref_h_embed = ref_h_embed + query_pos
                     tgt = decoder(
                         x,
                         tgt=tgt,
                         query_pos=query_pos,
                         key_pos=key_pos,
                         ref_h_embed=ref_h_embed,
                     )
                 return tgt


          decoder 為 cross-attention 操作,num_layers 為 2:

          class Decoderlayer(nn.Module):
             ...
             def forward(
                 self,
                 feat: Tensor,
                 tgt: Tensor,
                 query_pos: Tensor,
                 key_pos: Tensor,
                 ref_h_embed: Tensor,
             ):

                 n, c, h, w = feat.shape
                 bs = n // self.num_views
                 feat = feat.view(-1, self.num_views, c, h, w)
                 key_pos = key_pos.view(-1, self.num_views, c, h, w)

                 feat = feat.permute(0, 2, 1, 3, 4).contiguous().view(bs, c, -1, w)
                 key_pos = (
                     key_pos.permute(0, 2, 1, 3, 4).contiguous().view(bs, c, -1, w)
                 )
                 query = self.Qadd.add(tgt, query_pos)

                 query = self.Qadd2.add(query, ref_h_embed)
                 key = self.Kadd.add(feat, key_pos)
                 tgt2, _ = self.cross_attns(query=query, key=key, value=feat)

                 tgt = self.dropout1_add.add(tgt, self.dropout1(tgt2))
                 tgt = self.norm1(tgt)
                 tgt2 = self.ffn(tgt)
                 tgt = self.dropout2_add.add(tgt, self.dropout2(tgt2))
                 tgt = self.norm2(tgt)
                 return tgt


          bev_head


          檢測為多 task 檢測,主要分為:

          tasks = [
             dict(
                 name="bbos",
                 num_class=10,
                 class_names=[
                     "car",
                     "truck",
                     "construction_vehicle",
                     "bus",
                     "trailer",
                     "barrier",
                     "motorcycle",
                     "bicycle",
                     "pedestrian",
                     "traffic_cone",
                 ],
             )
          ]


          在 nuscenes 數(shù)據(jù)集中,目標(biāo)的類別一共被分為了 6 個(gè)大類,網(wǎng)絡(luò)給每一個(gè)類都分配了一個(gè) head,裝在 headlist 中,而每個(gè) head 內(nèi)部都為預(yù)測的參數(shù)。

          bev_det 的 head 為DepthwiseSeparableCenterPointHead


          對應(yīng)代碼:hat/models/task_modules/centerpoint/head.py


          class DepthwiseSeparableCenterPointHead(CenterPointHead):
             def _make_conv(
                 self,
                 ...
             ):
                 pw_norm_layer = nn.BatchNorm2d(in_channels, **self.bn_kwargs)
                 pw_act_layer = nn.ReLU(inplace=True)

                 return SeparableConvModule2d(
                     in_channels=in_channels,
                     ...
                 )

             def _make_task(self, **kwargs):
                 return DepthwiseSeparableTaskHead(**kwargs)

          class CenterPointHead(nn.Module):
             def __init__(self,...):
                 self.shared_conv = nn.Sequential(
                     *(
                         self._make_conv(
                             in_channels=in_channels if i == 0 else share_conv_channels,
                             ...
                         )
                         for i in range(share_conv_num)
                     )
                 )  
                 #head module  
                 for num_cls in num_classes:
                     heads = copy.deepcopy(common_heads)
                     heads.update({"heatmap": (num_cls, num_heatmap_convs)})
                     task_head = self._make_task(
                         ...,
                     )
                     self.task_heads.append(task_head)

             def forward(self, feats):
                 rets = []
                 feats = feats[0]
                 feats = self.shared_conv(feats)
                 for task in self.task_heads:
                     rets.append(task(feats))


          forward 時(shí),經(jīng)過共享的 SeparableConv 后,將 feature 再分別傳入 task_heads 做 task_pred。

          hat/models/task_modules/centerpoint/head.py的 TaskHead 對不同的 task 定義 conv_layers:

          class DepthwiseSeparableTaskHead(TaskHead):
             def _make_conv(
                 self,
                 in_channels,
                 ...
             ):
                 return SeparableConvModule2d(
                     in_channels=in_channels,
                     ...
                 )

          class TaskHead(nn.Module):
             def __init__(...):
                  ...    
                  for head in self.heads:
                     classes, num_conv = self.heads[head]
                     ...
                     #head_conv
                     for _ in range(num_conv - 1):
                         conv_layers.append(
                             self._make_conv(
                             ...
                             )
                         )
                         c_in = head_conv_channels
                     #cls_layer
                     conv_layers.append(
                         ConvModule2d(
                             in_channels=head_conv_channels,
                             out_channels=classes,
                             ...
                         )
                     )
                     conv_layers = nn.Sequential(*conv_layers)
             
             def forward(self, x):
                 ret_dict = {}
                 for head in self.heads:
                     ret_dict[head] = self.dequant(self.__getattr__(head)(x))
                 return ret_dict


          bev_decoder

          在檢測任務(wù)中使用 CenterPointDecoder,具體實(shí)現(xiàn)流程見下圖:


          圖片

          對應(yīng)代碼:hat/models/task_modules/centerpoint/decoder.py



          04 浮點(diǎn)模型訓(xùn)練


          4.1 Before Start


          4.1.1 發(fā)布物及環(huán)境部署***


          Step 1:獲取發(fā)布物

          下載 OE 包:

          horizon_j5_open_explorer_v$version$.tar.gz,獲取方式見地平線開發(fā)者社區(qū) OpenExplorer 算法工具鏈 版本發(fā)布


          Step 2:解壓發(fā)布包

          tar -xzvf horizon_j5_open_explorer_v$version$.tar.gz


          解壓后文件結(jié)構(gòu)如下:

          |-- bsp
          |-- ddk
          |   |-- package
          |   `-- samples
          |       |-- ai_benchmark
          |       |-- ai_forward_view_sample
          |       |-- ai_toolchain
          |       |   |-- ...
          |       |   |-- horizon_model_train_sample
          |       |   `-- model_zoo
          |       |-- model_zoo
          |       `-- vdsp_rpc_sample
          |-- README-CN
          |-- README-EN
          |-- resolve_all.sh
          `-- run_docker.sh


          其中horizon_model_train_sample為參考算法模塊,包含以下模塊:

          |-- horizon_model_train_sample  #參考算法示例
          |   |-- plugin_basic  #qat 基礎(chǔ)示例
          |   `-- scripts  #模型配置文件、運(yùn)行腳本


          Step 3:拉取 docker 環(huán)境

          docker pull openexplorer/ai_toolchain_ubuntu_20_j5_gpu:v$version$
          #啟動(dòng)容器,具體參數(shù)可根據(jù)實(shí)際需求配置
          #-v 用于將本地的路徑掛載到 docker 路徑下
          nvidia-docker run -it --shm-size="15g" -v `pwd`:/WORKSPACE openexplorer/ai_toolchain_ubuntu_20_j5_gpu:v$version$


          4.1.2 數(shù)據(jù)集準(zhǔn)備***4.1.2.1 數(shù)據(jù)集下載

          進(jìn)入nuscenes 官網(wǎng),根據(jù)提示完成賬戶的注冊,下載 Full dataset(v1.0)、CAN bus expansion 和 Map expansion(v1.3)這三個(gè)項(xiàng)目下的文件。下載后的壓縮文件為:

          |-- nuScenes-map-expansion-v1.3.zip
          |-- can_bus.zip
          |-- v1.0-mini.tar
          |-- v1.0-trainval01_blobs.tar
          |-- ...
          |-- v1.0-trainval10_blobs.tar
          `-- v1.0-trainval_meta.tar

          Full dataset(v1.0)包含多個(gè)子數(shù)據(jù)集,如果不需要進(jìn)行 v1.0-trainval 數(shù)據(jù)集的浮點(diǎn)訓(xùn)練和精度驗(yàn)證,可以只下載 v1.0-mini 數(shù)據(jù)集進(jìn)行小場景的訓(xùn)練和驗(yàn)證。


          將下載完成的 v1.0-trainval01_blobs.tar~v1.0-trainval10_blobs.tar、v1.0-trainval_meta.tar 和 can_bus.zip 進(jìn)行解壓,解壓后的目錄如下所示:

          |--nuscenes
             |-- can_bus #can_bus.zip解壓后的目錄
             |-- samples #v1.0-trainvalXX_blobs.tar解壓后的目錄
             |   |-- CAM_BACK
             |   |-- ...
             |   |-- CAM_FRONT_RIGHT
             |   |--  ...
             |   `-- RADAR_FRONT_RIGHT
             |-- sweeps
             |   |-- CAM_BACK
             |   |-- ...
             |   |-- CAM_FRONT_RIGHT
             |   |--  ...
             |   `-- RADAR_FRONT_RIGHT
             |-- v1.0-trainval #v1.0-trainval_meta.tar解壓后的數(shù)據(jù)
                 |-- attribute.json
                 |    ...
                 `-- visibility.json



          4.1.2.2 數(shù)據(jù)集打包***


          進(jìn)入 horizon_model_train_sample/scripts 目錄,使用以下命令將訓(xùn)練數(shù)據(jù)集和驗(yàn)證數(shù)據(jù)集打包,格式為 lmdb:

          #pack train_Set
          python3 tools/datasets/nuscenes_packer.py --src-data-dir /WORKSPACE/nuscenes/ --pack-type lmdb --target-data-dir /WORKSPACE/tmp_data/nuscenes/v1.0-trainval --version v1.0-trainval --split-name train
          #pack val_Set
          python3 tools/datasets/nuscenes_packer.py --src-data-dir /WORKSPACE/nuscenes/ --pack-type lmdb --target-data-dir /WORKSPACE/tmp_data/nuscenes/v1.0-trainval --version v1.0-trainval --split-name val

          –src-data-dir 為解壓后的 nuscenes 數(shù)據(jù)集目錄;–target-data-dir 為打包后數(shù)據(jù)集的存儲(chǔ)目錄;

          –version 選項(xiàng)為[“v1.0-trainval”, “v1.0-test”, “v1.0-mini”],如果進(jìn)行全量訓(xùn)練和驗(yàn)證設(shè)置為 v1.0-trainval,如果僅想了解模型的訓(xùn)練和驗(yàn)證過程,則可以使用 v1.0-mini 數(shù)據(jù)集;

          v1.0-test 數(shù)據(jù)集僅為測試場景,未提供注釋。

          全量的 nuscenes 數(shù)據(jù)集較大,打包時(shí)間較長。每打包完 100 張會(huì)在終端有打印提示,其中 train 打包約 28100 張,val 打包約 6000 張。


          數(shù)據(jù)集打包命令執(zhí)行完畢后會(huì)在target-data-dir下生成train_lmdbval_lmdb,train_lmdbval_lmdb就是打包之后的訓(xùn)練數(shù)據(jù)集和驗(yàn)證數(shù)據(jù)集為 config 中的data_rootdir

          |-- tmp_data 
          |   |-- nuscenes
          |   |   |-- v1.0-trainval
          |   |   |   |-- train_lmdb  #打包后的train數(shù)據(jù)集
          |   |   |   |   |-- data.mdb
          |   |   |   |   `-- lock.mdb
          |   |   |   `-- val_lmdb   #打包后的val數(shù)據(jù)集
          |   |   |   |   |-- data.mdb
          |   |   |   |   `-- lock.mdb

          ####

          4.1.2.3 meta 文件夾構(gòu)建


          tmp_data/nuscenes 下創(chuàng)建 meta 文件夾,將v1.0-trainval_meta.tar壓縮包解壓至 meta,得到meta/maps文件夾,再將nuScenes-map-expansion-v1.3.zip壓縮包解壓至meta/maps文件夾下,解壓后的目錄結(jié)構(gòu)為:

          |-- tmp_data 
          |   |-- nuscenes
          |   |   |-- meta
          |   |   |   |-- maps        #nuScenes-map-expansion-v1.3.zip解壓后的目錄
          |   |   |   |   |-- 36092f0b03a857c6a3403e25b4b7aab3.png
          |   |   |   |   |-- ...
          |   |   |   |   |-- 93406b464a165eaba6d9de76ca09f5da.png
          |   |   |   |   |-- prediction
          |   |   |   |   |-- basemap
          |   |   |   |   |-- expansion
          |   |   |   |-- v1.0-trainval  #v1.0-trainval_meta.tar解壓后的目錄
          |   |   |       |-- attribute.json
          |   |   |           ...
          |   |   |       |-- visibility.json
          |   |   `-- v1.0-trainval
          |   |   |   |-- train_lmdb  #打包后的train數(shù)據(jù)集
          |   |   |   `-- val_lmdb   #打包后的val數(shù)據(jù)集


          4.1.3 config 配置


          在進(jìn)行模型訓(xùn)練和驗(yàn)證之前,需要對 configs 文件中的部分參數(shù)進(jìn)行配置,一般情況下,我們需要配置以下參數(shù):


          • device_ids、batch_size_per_gpu:根據(jù)實(shí)際硬件配置進(jìn)行 device_ids 和每個(gè) gpu 的 batchsize 的配置;

          • ckpt_dir:浮點(diǎn)、calib、量化訓(xùn)練的權(quán)重路徑配置,權(quán)重下載鏈接在 config 文件夾下的 README 中;

          • data_rootdir:2.1.2.2 中打包的數(shù)據(jù)集路徑配置;

          • meta_rootdir :2.1.2.3 中創(chuàng)建的 meta 文件夾的路徑配置;

          • float_trainer 下的 checkpoint_path:浮點(diǎn)訓(xùn)練時(shí) backbone 的預(yù)訓(xùn)練權(quán)重所在路徑,可以使用 README 的# Backbone Pretrained ckpt 中 ckpt download 提供的 float-checkpoint-best.pth.tar 權(quán)重文件。



          4.2 浮點(diǎn)模型訓(xùn)練


          config 文件中的參數(shù)配置完成后,使用以下命令訓(xùn)練浮點(diǎn)模型:

          python3 tools/train.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage float

          float 訓(xùn)練后模型 ckpt 的保存路徑為 config 配置的 ckpt_callback 中 save_dir 的值,默認(rèn)為 ckpt_dir。


          4.3 浮點(diǎn)模型精度驗(yàn)證


          浮點(diǎn)模型訓(xùn)練完成以后,可以使用以下命令驗(yàn)證已經(jīng)訓(xùn)練好的浮點(diǎn)模型精度:

          python3 tools/predict.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage float


          驗(yàn)證完成后,會(huì)在終端打印浮點(diǎn)模型在驗(yàn)證集上檢測精度,如下所示:

          Per-class results:
          Object Class    AP      ATE     ASE     AOE     AVE     AAE
          car     0.458   0.552   0.157   0.188   1.263   0.230
          ...
          2023-12-19 17:47:02,796 INFO [nuscenes_metric.py:349] Node[0] NDS: 0.3280, mAP:0.2481
          ...
          2023-06-06 18:24:10,513 INFO [mean_iou.py:170] Node[0] ~~~~ MeanIOU Summary metrics ~~~~
          car_AP: [0.5]:0.1182  [1.0]:0.3794  [2.0]:0.6097  [4.0]:0.7232
          ...
          2023-12-19 17:47:03,046 INFO [metric_updater.py:360] Node[0] Epoch[0] Validation bev_cft_efficientnetb3_nuscenes: NDS[0.3280]
          2023-12-19 17:47:03,058 INFO [logger.py:176] Node[0] ==================================================END PREDICT==================================================
          2023-12-19 17:47:03,058 INFO [logger.py:176] Node[0] ==================================================END FLOAT PREDICT==================================================



          05 模型量化和編譯


          完成浮點(diǎn)訓(xùn)練后,還需要進(jìn)行量化訓(xùn)練和編譯,才能將定點(diǎn)模型部署到板端。地平線對該模型的量化采用 horizon_plugin 框架,經(jīng)過 Calibration+QAT 量化訓(xùn)練后,使用compile的工具將量化模型編譯成可以上板運(yùn)行的hbm文件。


          5.1 Calibration


          模型完成浮點(diǎn)訓(xùn)練后,便可進(jìn)行 Calibration。calibration 在 forward 過程中通過統(tǒng)計(jì)各處的數(shù)據(jù)分布情況,從而計(jì)算出合理的量化參數(shù)。通過運(yùn)行下面的腳本就可以開啟模型的 Calibration 過程:

          python3 tools/train.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage calibration


          5.2 Calibration 模型精度驗(yàn)證


          Calibration 完成以后,可以使用以下命令驗(yàn)證經(jīng)過 calib 后模型的精度:

          python3 tools/predict.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage calibration


          驗(yàn)證完成后,會(huì)在終端輸出 calib 模型在驗(yàn)證集上檢測精度,格式見 2.3。



          5.3 量化模型訓(xùn)練


          Calibration 完成后,就可以加載 calib 權(quán)重開啟模型的量化訓(xùn)練。量化訓(xùn)練其實(shí)是在浮點(diǎn)訓(xùn)練基礎(chǔ)上的 finetue,具體配置信息在 config 的 qat_trainer 中定義。

          量化訓(xùn)練的時(shí)候,初始學(xué)習(xí)率設(shè)置為浮點(diǎn)訓(xùn)練的十分之一,訓(xùn)練的 epoch 次數(shù)也大大減少。和浮點(diǎn)訓(xùn)練的方式一樣,將 checkpoint_path 指定為訓(xùn)好的 calibration 權(quán)重路徑。

          通過運(yùn)行下面的腳本就可以開啟模型的 qat 訓(xùn)練:

          python3 tools/predict.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage qat



          5.4 量化模型精度驗(yàn)證


          Calibration 完成以后,可以使用以下命令驗(yàn)證經(jīng)過 calib 后模型的精度:

          #qat模型精度驗(yàn)證python3 tools/predict.py --stage qat--config configs/bev/bev_cft_efficientnetb3_nuscenes.py


          驗(yàn)證完成后,會(huì)在終端輸出 calib 模型在驗(yàn)證集上檢測精度,格式見 2.3。



          5.5 量化模型精度驗(yàn)證


          指定 calibration-checkpoint 后,通過運(yùn)行以下命令進(jìn)行量化模型的精度驗(yàn)證:

          python3 tools/predict.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage int_infer

          qat 模型的精度驗(yàn)證對象為插入偽量化節(jié)點(diǎn)后的模型(float32);quantize 模型的精度驗(yàn)證對象為定點(diǎn)模型(int8),驗(yàn)證的精度是最終的 int8 模型的真正精度,這兩個(gè)精度應(yīng)該是十分接近的。



          5.6 仿真上板精度驗(yàn)證


          除了上述模型驗(yàn)證之外,我們還提供和上板完全一致的精度驗(yàn)證方法,可以通過下面的方式完成:

          python3 tools/align_bpu_validation.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py


          5.7 量化模型編譯


          在量化訓(xùn)練完成之后,可以使用compile_perf.py腳本將量化模型編譯成可以板端運(yùn)行的hbm模型,同時(shí)該工具也能預(yù)估在 BPU 上的運(yùn)行性能,compile_perf 腳本使用方式如下:

          python3 tools/compile_perf.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --out-dir ./ --opt 3

          opt 為優(yōu)化等級,取值范圍為 0~3,數(shù)字越大優(yōu)化等級越高,編譯時(shí)間更長,但部署性能更好。compile_perf 腳本將生成。html 文件和。hbm 文件(compile 文件目錄下),。html 文件為 BPU 上的運(yùn)行性能,。hbm 文件為上板實(shí)測文件。


          運(yùn)行后,ckpt_dir 的 compile 目錄下會(huì)產(chǎn)出以下文件。

          |-- compile 

          |   |-- .html #模型在bpu上的靜態(tài)性能數(shù)據(jù)

          |   |-- .json  

          |   |-- model.hbm  #板端部署的模型

          |   |-- model.hbir #編譯過程的中間文件

          ?   `-- model.pt   #模型的pt文件




          06 其他工具


          6.1 結(jié)果可視化


          如果你希望可以看到訓(xùn)練出來的模型對于單幀的檢測效果,我們的 tools 文件夾下面同樣提供了預(yù)測及可視化的腳本,你只需要運(yùn)行以下腳本即可:

          python3 tools/infer.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --save-path ./


          可視化結(jié)果將會(huì)在 save-path 路徑下輸出。

          avatar



          07 板端部署


          7.1 上板性能實(shí)測


          使用hrt_model_exec perf工具將生成的。hbm 文件上板做 BPU 性能 FPS 實(shí)測,hrt_model_exec perf參數(shù)如下:


          hrt_model_exec perf --model_file {model}.hbm \     
                              --thread_num 8 \
                              --frame_count 2000 \
                              --core_id 0 \
                              --profile_path '.'


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



          關(guān)鍵詞: 算法 自動(dòng)駕駛

          相關(guān)推薦

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

          關(guān)閉