Occupancy 代码--mmdet3dSurroundOcc_head代码详解

为什么要选择mmdet3d?

在这里插入图片描述
现在很多最新的领域上都是基于mmdet3d上面制作,所以我们要利用好的工具,减少自己的研究时间,不要再制造轮子了。

因为mmdet3d,是在 mmdetection里面上面改的房子,所以我们先来熟悉一下mmdetection的操作
在这里插入图片描述

register 机制 和 hook 机制

在这里插入图片描述
MMDetection的函数注册机制:

  1. 创建自定义类:首先,用户需创建一个类,该类实现了所需的自定义功能。
  2. 注册类:将新建的类注册到一个特定的查询表中,使用register_module实现这一步骤。
  3. 配置初始化参数:在MMDetection的配置文件中明确指定该类模块的初始化参数。
  4. 实例化模块:利用build_from_cfg函数,根据配置参数对该模块进行实例化操作。
  5. 执行功能:使用实例化后的对象执行定义的功能函数,完成特定任务。

MMDetection的Hook机制:

  1. 定义Hook类:定义一个类,该类继承自Hook基类,以便使用Hook机制。
  2. 重写函数:根据自定 义Hook的需求,选择性地重写Hook基类中的一些函数,以实现特定的逻辑处理。
  3. 注册Hook模块:将自定义的Hook类注册到HOOKS查询表中,使用register_module完成注册。
  4. 实例化并注册Hook:实例化自定义的Hook模块,并将其注册到Runner中,这一步骤通过register_hook函数完成。
  5. 调用Hook函数:在适当的时机,使用回调函数调用之前重写的Hook函数,以执行预定的逻辑。

参考地址: https://blog.csdn.net/qq_16137569/article/details/121316235

在这里插入图片描述

SurroundOcc Occ-head 代码

在这里插入图片描述

SurroundOcc代码库的整体架构提供了一个清晰的框架,旨在处理BEV(鸟瞰视图)/Occupancy(占用)等任务,其结构设计允许用户快速理解和应用到其他相关代码库中。以下是对其主要组成部分的详细解读:

  1. docs(文档)

    • 该文件夹包含了一系列说明文档,目的是为了帮助用户理解项目的整体设计、功能以及如何使用各种功能。
  2. projects(项目)

    • 主要包含各种配置文件(config),这些配置文件定义了训练和测试任务的pipeline。通过这些配置文件,用户可以轻松设定和调整实验的参数、模型结构以及数据处理流程等。
  3. mmdet3d_plugin(插件)

    • 这是一种典型的实现方法,旨在通过插件方式实现代码的模块化和可插拔性。这种设计使得用户可以在不干扰mmdet3d原始代码库的基础上,加入新的功能实现。具体而言,插件中定义了一系列基于mmdet3d的新实现,例如:
      • 数据集的Pipeline和Samplers:根据特定任务需求对数据预处理和采样策略进行定制化改动。
      • 模型的Backbone和Hooks:引入新的网络结构或调整训练过程中的特定行为。
      • SurroundOcc任务的Head/Loss/Hooks等新增内容:为SurroundOcc任务特别设计的模型头、损失函数以及钩子函数等。
  4. tools(工具)

    • 包含了一系列实用脚本,如数据分析、数据转换、模型转换和可视化等。这个文件夹下的工具主要是用来处理工程中的一些辅助任务,使得项目管理更加方便高效。

通过上述组成部分的协同工作,SurroundOcc代码库不仅为用户提供了一个灵活、可扩展的研究和开发环境,同时也展示了在BEV/Occupancy等视觉任务中应用深度学习的一种有效方法。

提取2D 特征

采用卷积的方式,通过FPN将图像特征提取出来

self.transfer_conv = nn.ModuleList()  # 创建一个可以存储神经网络模块的容器

norm_cfg = dict(type='GN', num_groups=16, requires_grad=True)  # 归一化配置 (Group Normalization)
conv_cfg = dict(type='Conv2d', bias=True)  # 卷积层配置

for i in range(self.fpn_level):  # 遍历FPN的层数
    transfer_layer = build_conv_layer(
        conv_cfg,
        in_channels=self.img_channels[i],  # 输入通道数
        out_channels=self.embed_dims[i],   # 输出通道数
        kernel_size=1,  # 卷积核大小
        stride=1       # 卷积步长
    )  # 构建 1x1 卷积层

    transfer_block = nn.Sequential(transfer_layer,  # 构建转换块
                                   nn.ReLU(inplace=True))  # ReLU 激活函数

    self.transfer_conv.append(transfer_block)  # 将转换块加入容器

将2D的特征转化为3D的特征

采用了deformer-able transform的方式

def _init_layers(self): 
    self.transformer = nn.ModuleList()  # 创建一个存储 Transformer 模块的容器 
    for i in range(self.fpn_level):
        transformer = copy.deepcopy(self.transformer_template)  # 深拷贝一份 Transformer 模板

        # 调整 embedding 维度
        transformer.embed_dims = transformer.embed_dims[i]  

        # 调整可变形注意力层的采样点数
        transformer.encoder.transformerlayers.attn_cfgs[0].deformable_attention.num_points = \
            self.transformer_template.encoder.transformerlayers.attn_cfgs[0].deformable_attention.num_points[i]

       # 调整前馈神经网络的通道数
        transformer.encoder.transformerlayers.feedforward_channels = \
            self.transformer_template.encoder.transformerlayers.feedforward_channels[i]

        # 调整其他 embedding 维度 (重复多次) ...

        # 调整编码器中的 Transformer 层数
        transformer.encoder.num_layers = self.transformer_template.encoder.num_layers[i]

        transformer_i = build_transformer(transformer)  # 构建 Transformer 实例
        self.transformer.append(transformer_i)  # 将 Transformer 添加到容器 

Surroundocc 流程图里的 3D volume features生成的部分

volume_embed_reshape = []  # 创建一个空列表,用于存储重塑后的 volume_embed
for i in range(self.fpn_level):
    volume_h = self.volume_h[i]  # 获取 volume_h, volume_w, volume_z
    volume_w = self.volume_w[i]
    volume_z = self.volume_z[i]

    # 重塑 volume_embed,并转换维度顺序,之后加入列表
    volume_embed_reshape_i = volume_embed[i].reshape(bs, volume_z, volume_h, volume_w, -1).permute(0, 4, 3, 2, 1)
    volume_embed_reshape.append(volume_embed_reshape_i)

outputs = []  # 创建空列表,存储解码块的输出
result = volume_embed_reshape.pop()  # 弹出重塑后的 volume_embed 的最后一个元素
for i in range(len(self.deblocks)):
    result = self.deblocks[i](result)  # 使用解码块处理 result

    if i in self.out_indices: 
        outputs.append(result)  # 将 result 添加到 outputs 列表
    elif i < len(self.deblocks) - 2:  
        volume_embed_temp = volume_embed_reshape.pop()  # 弹出重塑后的 volume_embed 元素
        result = result + volume_embed_temp  # 将 result 与 volume_embed_temp 相加

# 预测占用率(occupancy)
occ_preds = []
for i in range(len(outputs)):
    occ_pred = self.occ[i](outputs[i])  # 使用 self.occ 进行占用率预测
    occ_preds.append(occ_pred)

outs = {
    'volume_embed': volume_embed,
    'occ_preds': occ_preds,
}  # 构造输出字典

代码具体位置

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值