地平线 bev_cft_efficientnetb3 参考算法-v1.2.1
01 概述
在自动驾驶感知算法中 BEV 感知成为热点话题,BEV 感知可以弥补 2D 感知的缺陷构建 3D “世界”,更有利于下游任务和特征融合。
地平线集成了基于 bev 的纯视觉算法,目前已支持 ipm-based 、lss-based、 transformer-based(Geometry-guided Kernel Transformer、detr3d、petr) 的多种 bev 视觉转换方法。
本文为 camera calibration free 的 transformer-based 的 BEV 感知算法的介绍和使用说明。
该示例为参考算法,仅作为在 征程 5 上模型部署的设计参考,非量产算法
02 性能精度指标
模型配置:
性能精度表现:
注:Nuscenes 数据集官方介绍:Nuscenes
03 模型介绍
3.1 模型框架
bev_cft 模型结构图
bev_cft 使用多视图的当前帧的 6 个 RGB 图像作为输入。输出是目标的 3D Box 结果。多视角图像首先使用 2D 主干获取 2D 特征。然后投影到 3D BEV 视角。接着对 BEV feature 编码获取深层 BEV 特征。最后,接上任务特定的 head,输出检测结果。
模型主要包括以下部分:
Part1—2D Image Encoder:图像特征提取层。使用 2D 主干网络(efficientnet)和 FastSCNN 输出不同分辨率的特征图。返回最后一层–上采样至 1/128 原图大小层,用于下一步投影至 3D 坐标系中。
Part2—View transformer:采用 CFT 方式完成 img 2D 到 BEV 3D 的转换。
Part3—Bev transforms:对 BEV 特征做数据增强,仅发生在训练阶段。
Part4—3D BEV Encoder:BEV 特征提取层。
Part5—BEV Decoder:
使用 DepthwiseSeparableCenterPointHead 进行 3D 目标检测任务,检测的类别为 [“car”,“truck”,“bus”,“barrier”,“bicycle”,“pedestrian”]。
3.2 源码说明
config文件
**configs/bev/bev_cft_efficientnetb3_nuscenes.py**
为该模型的配置文件,定义了模型结构、数据集加载,和整套训练流程,所需参数的说明在算子定义中会给出。
配置文件主要内容包括:
#基础参数配置
task_name = "bev_cft_efficientnetb3_nuscenes"
batch_size_per_gpu = 2
device_ids = [0]
#bev参数配置
resize_shape = (3, 792, 1408)
data_shape = (3, 512, 1408)
grid_size = (64, 64)# 模型结构定义
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(
...
)
...
# 数据加载
data_loader = dict(type=torch.utils.data.DataLoader,...
)val_data_loader = dict(...)#不同step的训练策略配置
float_trainer=dict(...)
calibration_trainer=dict(...)
qat_trainer=dict(...)
int_infer_trainer=dict(...)
#不同step的验证
float_predictor=dict(...)
calibration_predictor=dict(...)
qat_predictor=dict(...)
int_infer_predictor=dict(...)
#编译配置
compile_cfg = dict(march=march,...
)
注:如果需要复现精度,config 中的训练策略最好不要修改。否则可能会有意外的训练情况出现。
img_encoder
来自 6 个 view 的 image 作为输入通过共享的 backbone(efficientnet-b3)和 neck(BiFPN)输出经过 encoder 后的 feature,feature_shape 为(6*B,C,1/128H,1/128W)。
encoder 即对多个 view 的 img_feature 做特征提取,过程见下图:
对应代码:**hat/models/backbones/efficientnet.py
** hat/models/necks/bifpn.py
view_transformer
view_transformer 采用 CFT(camera free transformer)映射的方法,把图像视角的 img_features 转换到 bev_features。
BEV_shape 为[H’,W’]为[64,64],其转换过程见下图:
cft 框架图
view_transformer 对应代码:
**hat/models/task_modules/view_fusion/cft_transformer.py
的CFTTransformer
**。
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_viewskey_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
根据框架图,在 view_transformer 流程中可以分为两部分:
- position-Aware Enhancement:对位置编码进行强化,对 BEV 2D 和 content 编码,并通过 PA 网络实现特征增强
- view-Aware Attention:对图像融合坐标位置编码,增强特征
position-Aware Enhancement
Step 1 : postition_embedding
该部分为 BEV 2D 坐标的编码,编码为可学习、参数可更新的**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.shapehw = 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 的编码。根据位置编码 query_pos 来做高度的预测 ref_h ,然后对高度 ref_h 做正弦函数编码。计算公式为:
对应代码为:
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 为一个输出 channel 为 1 的 mlp:
self.ref_h_head = MLP(input_channels=embed_dims,output_channels=1,feedforward_channels=embed_dims,)
**gen_sineembed_for_position
实现在hat/models/task_modules/view_fusion/cft_transformer.py
**。
Step 3:结合 BEV 的 content query,细化目标的 height
为了细化高度,引入 BEV 的 content 来提取目标的高度信息:
BEV 的 content 为预设的 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 经过 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_postgt = 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 经过一个 self-attention 模块做特征增强。
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_viewskey_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
)
详细实现见 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
在公版中,为了减少计算量和内存消耗,在 Decoder 的自注意力计算中做了分组的 Attention,在做 J5 部署时该部分会用到大量的 slice,IO 操作导致带宽资源紧张,因此,地平线版本未做 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_postgt = 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.shapebs = n // self.num_viewsfeat = 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 数据集中,目标的类别一共被分为了 6 个大类,网络给每一个类都分配了一个 head,装在 headlist 中,而每个 head 内部都为预测的参数。
bev_det 的 head 为**DepthwiseSeparableCenterPointHead
**
对应代码:**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 时,经过共享的 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_convfor _ in range(num_conv - 1):conv_layers.append(self._make_conv(...))c_in = head_conv_channels#cls_layerconv_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
在检测任务中使用 CenterPointDecoder,具体实现流程见下图:
对应代码:**hat/models/task_modules/centerpoint/decoder.py
**
04 浮点模型训练
4.1 Before Start
4.1.1 发布物及环境部署***
Step 1:获取发布物
下载 OE 包:
**horizon_j5_open_explorer_v$version$.tar.gz
**,获取方式见地平线开发者社区 OpenExplorer 算法工具链 版本发布
Step 2:解压发布包
tar -xzvf horizon_j5_open_explorer_v$version$.tar.gz
解压后文件结构如下:
|-- 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 基础示例
| `-- scripts #模型配置文件、运行脚本
Step 3:拉取 docker 环境
docker pull openexplorer/ai_toolchain_ubuntu_20_j5_gpu:v$version$
#启动容器,具体参数可根据实际需求配置
#-v 用于将本地的路径挂载到 docker 路径下
nvidia-docker run -it --shm-size="15g" -v `pwd`:/WORKSPACE openexplorer/ai_toolchain_ubuntu_20_j5_gpu:v$version$
4.1.2 数据集准备***
4.1.2.1 数据集下载
进入nuscenes 官网,根据提示完成账户的注册,下载 Full dataset(v1.0)、CAN bus expansion 和 Map expansion(v1.3)这三个项目下的文件。下载后的压缩文件为:
|-- 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)包含多个子数据集,如果不需要进行 v1.0-trainval 数据集的浮点训练和精度验证,可以只下载 v1.0-mini 数据集进行小场景的训练和验证。
将下载完成的 v1.0-trainval01_blobs.tar~v1.0-trainval10_blobs.tar、v1.0-trainval_meta.tar 和 can_bus.zip 进行解压,解压后的目录如下所示:
|--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解压后的数据|-- attribute.json| ...`-- visibility.json
4.1.2.2 数据集打包***
进入 horizon_model_train_sample/scripts
目录,使用以下命令将训练数据集和验证数据集打包,格式为 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 数据集目录;–target-data-dir 为打包后数据集的存储目录;
–version 选项为[“v1.0-trainval”, “v1.0-test”, “v1.0-mini”],如果进行全量训练和验证设置为 v1.0-trainval,如果仅想了解模型的训练和验证过程,则可以使用 v1.0-mini 数据集;
v1.0-test 数据集仅为测试场景,未提供注释。
全量的 nuscenes 数据集较大,打包时间较长。每打包完 100 张会在终端有打印提示,其中 train 打包约 28100 张,val 打包约 6000 张。
数据集打包命令执行完毕后会在**target-data-dir
下生成train_lmdb
和val_lmdb
,train_lmdb
和val_lmdb
就是打包之后的训练数据集和验证数据集为 config 中的data_rootdir
**。
|-- tmp_data
| |-- nuscenes
| | |-- v1.0-trainval
| | | |-- train_lmdb #打包后的train数据集
| | | | |-- data.mdb
| | | | `-- lock.mdb
| | | `-- val_lmdb #打包后的val数据集
| | | | |-- data.mdb
| | | | `-- lock.mdb
4.1.2.3 meta 文件夹构建
在**tmp_data/nuscenes
** 下创建 meta 文件夹,将**v1.0-trainval_meta.tar
压缩包解压至 meta,得到meta/maps
文件夹,再将nuScenes-map-expansion-v1.3.zip
压缩包解压至meta/maps
**文件夹下,解压后的目录结构为:
|-- 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数据集
| | | `-- val_lmdb #打包后的val数据集
4.1.3 config 配置
在进行模型训练和验证之前,需要对 configs 文件中的部分参数进行配置,一般情况下,我们需要配置以下参数:
- device_ids、batch_size_per_gpu:根据实际硬件配置进行 device_ids 和每个 gpu 的 batchsize 的配置;
- ckpt_dir:浮点、calib、量化训练的权重路径配置,权重下载链接在 config 文件夹下的 README 中;
- data_rootdir:2.1.2.2 中打包的数据集路径配置;
- meta_rootdir :2.1.2.3 中创建的 meta 文件夹的路径配置;
- float_trainer 下的 checkpoint_path:浮点训练时 backbone 的预训练权重所在路径,可以使用 README 的# Backbone Pretrained ckpt 中 ckpt download 提供的 float-checkpoint-best.pth.tar 权重文件。
4.2 浮点模型训练
config 文件中的参数配置完成后,使用以下命令训练浮点模型:
python3 tools/train.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage float
float 训练后模型 ckpt 的保存路径为 config 配置的 ckpt_callback 中 save_dir 的值,默认为 ckpt_dir。
4.3 浮点模型精度验证
浮点模型训练完成以后,可以使用以下命令验证已经训练好的浮点模型精度:
python3 tools/predict.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage float
验证完成后,会在终端打印浮点模型在验证集上检测精度,如下所示:
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 模型量化和编译
完成浮点训练后,还需要进行量化训练和编译,才能将定点模型部署到板端。地平线对该模型的量化采用 horizon_plugin 框架,经过 Calibration+QAT 量化训练后,使用**compile
的工具将量化模型编译成可以上板运行的hbm
**文件。
5.1 Calibration
模型完成浮点训练后,便可进行 Calibration。calibration 在 forward 过程中通过统计各处的数据分布情况,从而计算出合理的量化参数。通过运行下面的脚本就可以开启模型的 Calibration 过程:
python3 tools/train.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage calibration
5.2 Calibration 模型精度验证
Calibration 完成以后,可以使用以下命令验证经过 calib 后模型的精度:
python3 tools/predict.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage calibration
验证完成后,会在终端输出 calib 模型在验证集上检测精度,格式见 2.3。
5.3 量化模型训练
Calibration 完成后,就可以加载 calib 权重开启模型的量化训练。量化训练其实是在浮点训练基础上的 finetue,具体配置信息在 config 的 qat_trainer 中定义。
量化训练的时候,初始学习率设置为浮点训练的十分之一,训练的 epoch 次数也大大减少。和浮点训练的方式一样,将 checkpoint_path 指定为训好的 calibration 权重路径。
通过运行下面的脚本就可以开启模型的 qat 训练:
python3 tools/predict.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage qat
5.4 量化模型精度验证
Calibration 完成以后,可以使用以下命令验证经过 calib 后模型的精度:
#qat模型精度验证python3 tools/predict.py --stage qat--config configs/bev/bev_cft_efficientnetb3_nuscenes.py
验证完成后,会在终端输出 calib 模型在验证集上检测精度,格式见 2.3。
5.5 量化模型精度验证
指定 calibration-checkpoint 后,通过运行以下命令进行量化模型的精度验证:
python3 tools/predict.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --stage int_infer
qat 模型的精度验证对象为插入伪量化节点后的模型(float32);quantize 模型的精度验证对象为定点模型(int8),验证的精度是最终的 int8 模型的真正精度,这两个精度应该是十分接近的。
5.6 仿真上板精度验证
除了上述模型验证之外,我们还提供和上板完全一致的精度验证方法,可以通过下面的方式完成:
python3 tools/align_bpu_validation.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py
5.7 量化模型编译
在量化训练完成之后,可以使用**compile_perf.py
脚本将量化模型编译成可以板端运行的hbm
**模型,同时该工具也能预估在 BPU 上的运行性能,compile_perf 脚本使用方式如下:
python3 tools/compile_perf.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --out-dir ./ --opt 3
opt 为优化等级,取值范围为 0~3,数字越大优化等级越高,编译时间更长,但部署性能更好。compile_perf 脚本将生成。html 文件和。hbm 文件(compile 文件目录下),。html 文件为 BPU 上的运行性能,。hbm 文件为上板实测文件。
运行后,ckpt_dir 的 compile 目录下会产出以下文件。
|-- compile | |-- .html #模型在bpu上的静态性能数据 | |-- .json | |-- model.hbm #板端部署的模型| |-- model.hbir #编译过程的中间文件 `-- model.pt #模型的pt文件
06 其他工具
6.1 结果可视化
如果你希望可以看到训练出来的模型对于单帧的检测效果,我们的 tools 文件夹下面同样提供了预测及可视化的脚本,你只需要运行以下脚本即可:
python3 tools/infer.py --config configs/bev/bev_cft_efficientnetb3_nuscenes.py --save-path ./
可视化结果将会在 save-path 路径下输出。

07 板端部署
7.1 上板性能实测
使用**hrt_model_exec perf
工具将生成的。hbm 文件上板做 BPU 性能 FPS 实测,hrt_model_exec perf
**参数如下:
hrt_model_exec perf --model_file {model}.hbm \ --thread_num 8 \--frame_count 2000 \--core_id 0 \--profile_path '.'
相关文章:
地平线 bev_cft_efficientnetb3 参考算法-v1.2.1
01 概述 在自动驾驶感知算法中 BEV 感知成为热点话题,BEV 感知可以弥补 2D 感知的缺陷构建 3D “世界”,更有利于下游任务和特征融合。 地平线集成了基于 bev 的纯视觉算法,目前已支持 ipm-based 、lss-based、 transformer-basedÿ…...
【linux】shell脚本
文章目录 1. jar包启动脚本1.1 方式一1.2 方式二 2. 进程关闭脚本3. 操作mysql4. impala建表语句提取5. 监控磁盘存量6. 清日志脚本7. 替换tomcat的启动端口8. 将一行数据按照空格依次读取 1. jar包启动脚本 1.1 方式一 #!/bin/sh RESOURCE_NAME/usr/local/applications/scre…...
构建一个去中心化的零售生态参与者的商业模型
在数字化和去中心化技术快速发展的背景下,传统零售行业正迎来革命性的转型。去中心化零售生态不仅让消费者、商家和内容创作者在同一平台上共同参与价值的创造和分配,还推动了零售体验、数据控制和社会互动的彻底变革。本文将探讨如何构建一个去中心化的…...
Spring Boot开发实战:从入门到构建高效应用
Spring Boot 是 Java 开发者构建微服务、Web 应用和后端服务的首选框架之一。其凭借开箱即用的特性、大量的自动化配置和灵活的扩展性,极大简化了开发流程。本文将以实战为核心,从基础到高级,全面探讨 Spring Boot 的应用开发。 一、Spring B…...
MyBatis(mybatis_plus)中TypeHandler的使用教程
MyBatis(mybatis_plus)中TypeHandler的使用教程 一.TypeHandler作用及其使用场景 在我们平常开发操作数据库时,查询、插入数据等操作行为,有时会报数据类型不匹配异常,就可以得知数据的类型是不唯一的必然是多种不同…...
【C++】IO库(三):string流
8.3 string 流 sstream 头文件定义了三个类型来支持内存 IO,这些类型可以向 string 写入数据,也可以从 string 读取数据,就像 string 是一个 IO 流一样。 istringstream 从 string 读数据;ostringstream 向 string 写入数据&…...
C# 反射详解
反射是C#中的一个强大特性,允许程序在运行时检查和操作类型和对象的信息。 通过反射,你可以获取类型的属性、方法、构造函数等信息,并可以动态创建对象、调用方法或访问属性,甚至可以实现某些框架或库的核心功能。 反射的基本概念…...
量化交易系统开发-实时行情自动化交易-8.量化交易服务平台(一)
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来会对于收集整理的33个量化交易服…...
【开发商城系统】
在广西开发商城系统,可以按照以下步骤进行: 确定项目需求:与客户沟通,了解商城系统所需的功能和特性,并确定项目的预算和时间限制。 进行市场调研:了解广西地区的电商市场情况,包括竞争对手、消…...
C++设计模式-享元模式
动机(Motivation) 在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价——主要指内存需求方面的代价。如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作…...
Spark——安装步骤详细教程
1、安装步骤 1、上传 cd /opt/modules 2、解压 tar -zxf spark-3.1.2-bin-hadoop3.2.tgz -C /opt/installs 3、重命名 cd /opt/installs mv spark-3.1.2-bin-hadoop3.2 spark-local 4、创建软链接 ln -s spark-local spark 5、配置环境变量: vi /etc/prof…...
摆烂仙君传——深度学习秘境奇缘
第一章:深度学习秘境 在修仙界与科技交织的边缘,八荒六合九天无上摆烂仙君在其高科技修炼室中感应到一股神秘的召唤。这股力量似乎与他的灵魂产生了共鸣,引导他前往传说中的深度学习秘境。在那里,古老的仙法与前沿的算法交织&…...
C++设计模式:桥接模式(Bridge)
什么是桥接模式? 桥接模式(Bridge Pattern)是一个用来解耦的设计模式,它将抽象层和实现层分离开,让它们可以独立变化。用最简单的话来说,就是让你能够改变抽象的功能和具体的实现,而不需要修改…...
c++源码阅读__smart_ptr__正文阅读
文章目录 简介源码解析1. 引用计数的实现方式2. deleter静态方法的赋值时间节点3.make_smart的实现方式 与 好处4. 几种构造函数4.1 空构造函数4.2 接收指针的构造函数4.3 接收指针和删除方法的构造函数 , 以及auto进行模板lambda的编写4.4 拷贝构造函数4.5 赋值运算符 5. rele…...
halcon3D 1:1切片轮廓投影技术,透过像素距离,知实际物体的尺寸
首先说做个什么事儿 对一个物体的横截面进行1:1或者1:10的投影,也就是说世界物体1mm的话,投影到image中占1个或者10个像素值,这样,就可以透过直接计算image中的像素距离,知道实际物体的尺寸 用一张图说明是这样的。物…...
npm库xss依赖的使用方法和vue3 中Web富文本编辑器 wangeditor 使用xss库解决 XSS 攻击的方法
npm库xss依赖的使用方法和vue3 中Web富文本编辑器 wangeditor 使用xss库解决 XSS 攻击的方法 1. npm库xss依赖的使用方法1.1 xss库定义1.2 xss库功能 2. vue3 中 wangeditor 使用xss库解决 XSS 攻击的方法和示例2.1 在终端执行如下命令安装 xss 依赖2.2 在使用 wangeditor 的地…...
计算机网络 实验七 NAT配置实验
一、实验目的 通过本实验理解网络地址转换的原理和技术,掌握扩展NAT/NAPT设计、配置和测试。 二、实验原理 NAT配置实验的原理主要基于网络地址转换(NAT)技术,该技术用于将内部私有网络地址转换为外部公有网络地址,从…...
UI设计-色彩、层级、字体、边距(一)
一.色彩:色彩可以影响人的心理与行动,具有不同的象征意义;有冷暖,轻重,软硬等等。 1.色彩情绪:最直观的视觉感受 一个活动的页面所用的颜色必须要与其内容相适应,让人看起来舒服。有时我们会不…...
【网络安全】
黑客入侵 什么是黑客入侵? “黑客”是一个外来词,是英语单词hacker的中文音译。最初,“黑客”只是一个褒义词,指的是那些尽力挖掘计算机程序最大潜力的点脑精英,他们讨论软件黑客的技巧和态度,以及共享文化…...
c++趣味编程玩转物联网:基于树莓派Pico控制有源蜂鸣器
有源蜂鸣器是一种简单高效的声音输出设备,广泛应用于电子报警器、玩具、计时器等领域。在本项目中,我们结合树莓派Pico开发板,通过C代码控制有源蜂鸣器发出“滴滴”声,并解析其中涉及的关键技术点和硬件知识。 一、项目概述 1. 项…...
【MySQL】MySQL从入门到放弃
文章目录 声明MYSQL一,架构1.1.网络连接层数据库连接池 1.2.系统服务层1.2.1.SQL接口1.2.2.存储过程1.2.3.触发器1.2.4.解析器1.2.5.优化器1.2.6.缓存,缓冲 1.3.存储引擎层1.4.文件系统层1.4.1.日志模块1.4.2.数据模块 二,SQL 执行2.1.执行流程2.2.刷盘2.3.返回 三.库表设计3.1…...
redis-cluster集群搭建
集群节点信息 192.168.222.131:46379 主要节点1 192.168.222.131:46380 从节点1 192.168.222.131:46381 从节点2192.168.222.132:46379 主要节点2 192.168.222.132:46380 从节点1 192.168.222.132:46381 从节点2192.168.222.133:46379 主要节点3 192.168.222.133:46380 从节点…...
C语言解决空瓶换水问题:高效算法与实现
标题:C语言解决空瓶换水问题:高效算法与实现 一、问题描述 在一个饮料促销活动中,你可以通过空瓶换水的方式免费获得更多的水:3个空瓶可以换1瓶水。喝完这瓶水后,空瓶会再次变为空瓶。假设你最初拥有一定数量的空瓶&a…...
单例模式入门
单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 它的运作方式是这样的: 如果你创建了一个对象, 同时过一会儿后你决定再创建一个新对象, 此时你会获得之前已创建的…...
MongoDB快速入门
1 MongoDB 1.1 MongoDB 概念 1.1.1 什么是 MongoDB MongoDB 是在2007年由DoubleClick公司的几位核心成员开发出的一款分布式文档数据库,由C语言编写。 目的是为了解决数据大量增长的时候系统的可扩展性和敏捷性。MongoDB要比传统的关系型数据库简单很多。 在Mo…...
c语言中的extern是什么
在C语言中,extern 是一个关键字,用于声明变量或函数的外部链接。它告诉编译器该变量或函数的定义在其他文件中,编译器在编译当前文件时并不需要知道变量或函数的具体定义,而是将它们视作外部引用。 1. 变量的 extern 声明 当你在…...
CTF之密码学(摩斯密码)
一、历史背景 摩尔斯电码发明于1837年,是一种早期的数字化通信形式。它最初由艾尔菲德维尔和摩尔斯等人构思,通过点、划和中间的停顿,把各个字元以及标点符号彼此独立地发送出去。这种标识不同符号的方案后来被放入摩尔斯的专利中࿰…...
Flink 任务启动脚本-V2(包括ck启动)
#!/bin/bash#crontab时设置,如果依赖其他环境变量配置,可以在脚本执行一下环境变量脚本 source /etc/profile# 进入脚本目录 curdirdirname "$0" curdircd "$curdir"; pwd echo "进入启动脚本目录 $curdir"# 定义应用程序…...
16:00面试,16:08就出来了,问的问题有点变态。。。
从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到8月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…...
selinux和防火墙
SElinux 1、selinux简介 SELinux是Security-Enhanced Linux的缩写,意思是安全强化的linux。 SELinux 主要由美国国家安全局(NSA)开发,当初开发的目的是为了避免资源的误用。 SELinux是对程序、文件等权限设置依据的一个内核模块。…...
Android 13 Aosp Settings Android Studio版本
Android 13 Aosp Settings Android Studio版本 Settings相关源码 Settings https://android.googlesource.com/platform/packages/apps/Settings/+/refs/heads/android13-release SettingsIntelligence https://android.googlesource.com/platform/packages/apps/SettingsIn…...
[241127] Mistral AI 更新 Le Chat,免费提供前沿 AI 助手!| TrendForce 预测 2025 十大科技趋势
目录 Mistral AI 更新 Le Chat,免费提供前沿 AI 助手!TrendForce 预测 2025 十大科技趋势 Mistral AI 更新 Le Chat,免费提供前沿 AI 助手! Mistral AI 宣布对其免费 AI 助手 Le Chat 进行重大更新,新增多项强大功能&…...
go-carbon v2.5.0 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持。 carbon 目前已捐赠给 dromara 开源组织,已被 awesome-go 收录&am…...
linux安全管理-账号口令
文章目录 1 设备密码复杂度策略2 设备密码生存周期、最小长度、更改最小间隔天数和过期前警告天数3 使用 PAM 认证禁止指定组之外的用户使用 su 切换到 root4 制作用户权限对照表 1 设备密码复杂度策略 1、配置内容 检查密码复杂度策略中设置的特殊字符、大写字母、小写字母和…...
uni-app自定义底部tab并且根据字段显示和隐藏
首先将所有tab使用到的页面创建好并且在pages里面配置好,要在pages.json中的"tabBar里面配置"custom": true将自带的tab底部导航关闭 "pages": [{"path": "pages/mine/mine","style": {"navigationBa…...
C#开发合集
用C#轻松搞定m3u8视频下载与合并 嘿,程序员们!今天咱们来聊聊如何用C#写个小程序,轻松下载和合并m3u8视频文件。没错,就是那种分段的流媒体视频。准备好了吗?让我们开始吧! 准备工作 在动手之前…...
Chrome和edge浏览器如何为任何网站强制暗模式
前言 因为我的编辑器是黑色,可能是看的时间长了比较喜欢这种颜色了,感觉白色有些刺眼。尤其是看文章时,两边的空白纯白色,所以强迫症搜素设置了谷歌浏览器和edge如何设置成黑色。 Chrome和edge浏览器如何为任何网站强制暗模式 前…...
第二十章 Java多线程--JUC并发工具-CountDownLatch
目录 一、CountDownLatch基础概念 CountDownLatch 的核心概念 CountDownLatch 的常用方法 场景一:主线程等待多个子线程执行完毕 场景二:实现多个线程同时开始执行任务 场景三:统计报表优化 CountDownLatch 的局限性 结论 二、Count…...
限制对 etcd 的访问范围是确保 Kubernetes 集群安全的一个重要环节。
限制对 etcd 的访问范围是确保 Kubernetes 集群安全的一个重要环节。通常,etcd 只应当对 Kubernetes 控制平面的组件(如 API Server、Controller Manager、Scheduler 等)以及某些维护工具(如备份工具)开放访问权限&…...
shell脚本基础学习_总结篇(完结)
细致观看可以,访问shell脚本学习专栏,对应章节会有配图https://blog.csdn.net/2201_75446043/category_12833287.html?spm1001.2014.3001.5482 导语 一、shell脚本简介 1. 定义: 2. 主要特点: 3. shell脚本的基本结构 4. S…...
Linux之网络基础
网络发展 网络的发展可以从人与人之间的工作模式开始谈起, 人与人的工作模式反应了机器与机器的工作模式: 1. 独立模式: 在网络发展的早期计算机间处于独立模式, 计算机之间相互独立 最开始计算机之间是独立运行的, 数据之间的交互需要人用软盘等存储介质拷贝过去, 一般涉及…...
《Vue零基础入门教程》第十课:属性绑定指令
往期内容 《Vue零基础入门教程》第一课:Vue简介 《Vue零基础入门教程》第二课:搭建开发环境 《Vue零基础入门教程》第三课:起步案例 《Vue零基础入门教程》第四课:应用实例 《Vue零基础入门教程》第五课:挂载 《…...
RabbitMQ 安装延迟队列插件 rabbitmq_delayed_message_exchange
前言: RabbitMQ 延迟队列插件(rabbitmq_delayed_message_exchange)是一个社区开发的插件,它为 RabbitMQ 添加了支持延迟消息的功能。通过这个插件,用户可以创建一种特殊的交换机类型 x-delayed-message,该…...
MATLAB中Simulink的基础知识
Simulink是MATLAB中的一种可视化仿真工具, 是一种基于MATLAB的框图设计环境,是实现动态系统建模、仿真和分析的一个软件包,被广泛应用于线性系统、非线性系统、数字控制及数字信号处理的建模和仿真中。 Simulink提供一个动态系统建模、仿真和…...
Swift——单例模式
单例是软件设计常用的一种模式,它的核心结构中只有一个被称为单例的特殊类,通过单例模式可以保证应用该模式的类只有一个实例化对象,其作用就是能够使类中的一个对象成为系统中的唯一实例。 单例的特点: 某个类只有一个实例化对象…...
百度智能云千帆大模型平台引领企业创新增长
本文整理自百度世界大会 2024——「智能跃迁 产业加速」论坛的同名演讲。 更多大会演讲内容,请访问: https://baiduworld.baidu.com 首先,跟大家分享一张图,这个是我们目前大模型应用落地的场景分布。可以看到,大模型…...
scala统计词频
目标:统计词频 (1)从文件1.tst,读入内容,保存在一个字符串中。 (2)统计字符串中,每个单词出现的频率 (3)对结果进行排序 (4)把最后…...
CTF之密码学(费纳姆密码)
一、作为二进制替换密码的费纳姆密码 定义:费纳姆密码是一种由二进制产生的替换密码,也被称为弗纳姆密码(Vernam cipher)。它采用二进制表示法,将明文转化为二进制数字,并通过与密钥进行模2加法运算来产生密…...
postgresql按照年月日统计历史数据
1.按照日 SELECT a.time,COALESCE(b.counts,0) as counts from ( SELECT to_char ( b, YYYY-MM-DD ) AS time FROM generate_series ( to_timestamp ( 2024-06-01, YYYY-MM-DD hh24:mi:ss ), to_timestamp ( 2024-06-30, YYYY-MM-DD hh24:mi:ss ), 1 days ) AS b GROUP BY tim…...
Python 网络爬虫进阶:动态网页爬取与反爬机制应对
在上一篇文章中,我们学习了如何使用 Python 构建一个基本的网络爬虫。然而,在实际应用中,许多网站使用动态内容加载或实现反爬机制来阻止未经授权的抓取。因此,本篇文章将深入探讨以下进阶主题: 如何处理动态加载的网…...