BEVFormer组件分析

BEVFormerEncoder中的get_reference_points


@staticmethod
    def get_reference_points(H, W, Z=8, num_points_in_pillar=4, dim='3d', bs=1, device='cuda', dtype=torch.float):
        """Get the reference points used in SCA and TSA.
        Args:
            H, W: spatial shape of bev.
            Z: hight of pillar.
            D: sample D points uniformly from each pillar.
            device (obj:`device`): The device where
                reference_points should be.
        Returns:
            Tensor: reference points used in decoder, has \
                shape (bs, num_keys, num_levels, 2).
        """

        # reference points in 3D space, used in spatial cross-attention (SCA)
        if dim == '3d':
            zs = torch.linspace(0.5, Z - 0.5, num_points_in_pillar, dtype=dtype,
                                device=device).view(-1, 1, 1).expand(num_points_in_pillar, H, W) / Z
            xs = torch.linspace(0.5, W - 0.5, W, dtype=dtype,
                                device=device).view(1, 1, W).expand(num_points_in_pillar, H, W) / W
            ys = torch.linspace(0.5, H - 0.5, H, dtype=dtype,
                                device=device).view(1, H, 1).expand(num_points_in_pillar, H, W) / H
            ref_3d = torch.stack((xs, ys, zs), -1)
            ref_3d = ref_3d.permute(0, 3, 1, 2).flatten(2).permute(0, 2, 1)
            ref_3d = ref_3d[None].repeat(bs, 1, 1, 1)
            return ref_3d

        # reference points on 2D bev plane, used in temporal self-attention (TSA).
        elif dim == '2d':
            ref_y, ref_x = torch.meshgrid(
                torch.linspace(
                    0.5, H - 0.5, H, dtype=dtype, device=device),
                torch.linspace(
                    0.5, W - 0.5, W, dtype=dtype, device=device)
            )
            ref_y = ref_y.reshape(-1)[None] / H
            ref_x = ref_x.reshape(-1)[None] / W
            ref_2d = torch.stack((ref_x, ref_y), -1)
            ref_2d = ref_2d.repeat(bs, 1, 1).unsqueeze(2)
            return ref_2d

根据上面的代码可以看出来,如果输入的是3d, 则是
按照:

  • X方向: 从0.5, 到W-0.5分成W份.
  • Y方向: 从0.5, 到H-0.5分成H份.
  • Z方向: 从0.5, 到Z-0.5, 分成 num_points_in_pillar份.
    其中num_points_in_pillar 默认给的是4.

配置文件里面给的其实也是4.
在这里插入图片描述

BEVFormerEncoder中的point_sampling

  # This function must use fp32!!!
    @force_fp32(apply_to=('reference_points', 'img_metas'))
    def point_sampling(self, reference_points, pc_range,  img_metas):
        lidar2img = []
        for img_meta in img_metas:
            lidar2img.append(img_meta['lidar2img'])
        lidar2img = np.asarray(lidar2img)
        lidar2img = reference_points.new_tensor(lidar2img)  # (B, N, 4, 4)
        reference_points = reference_points.clone()

        # 变换到点云的范围内. 这也是为何get_reference_points中会/H, /W, /Z, 先化到[0, 1]变成ratio.
        reference_points[..., 0:1] = reference_points[..., 0:1] * \
            (pc_range[3] - pc_range[0]) + pc_range[0]
        reference_points[..., 1:2] = reference_points[..., 1:2] * \
            (pc_range[4] - pc_range[1]) + pc_range[1]
        reference_points[..., 2:3] = reference_points[..., 2:3] * \
            (pc_range[5] - pc_range[2]) + pc_range[2]

        # 由(x, y, z) 变成(x, y, z, 1) 便于与4*4的参数矩阵相乘.
        reference_points = torch.cat(
            (reference_points, torch.ones_like(reference_points[..., :1])), -1)
        # 此时reference_points可以当成是点云的点了.

        reference_points = reference_points.permute(1, 0, 2, 3)
        # num_query等于H*W*Z. 等于grid_points的数量.
        D, B, num_query = reference_points.size()[:3]
        num_cam = lidar2img.size(1)

        # 要往每个相机上去投影. 因此先申请num_cam份.
        # reference_points的shape就变成了, (D, b, num_cam, num_query, 4, 1) 便于和4*4的矩阵做matmul.
        reference_points = reference_points.view(
            D, B, 1, num_query, 4).repeat(1, 1, num_cam, 1, 1).unsqueeze(-1)

        # 相机参数由(b,num_cam, 4, 4) 变成(1, b, num_cam, 1, 4, 4) 再变成(D,b,num_cam,num_query,4,4)
        lidar2img = lidar2img.view(
            1, B, num_cam, 1, 4, 4).repeat(D, 1, 1, num_query, 1, 1)

        reference_points_cam = torch.matmul(lidar2img.to(torch.float32),
                                            reference_points.to(torch.float32)).squeeze(-1)
        eps = 1e-5

        # 把每个相机后面的点mask掉. 因为相机后面的点投过来之后第三位是负的.
        bev_mask = (reference_points_cam[..., 2:3] > eps)
        # 再做齐次化. 得到像素坐标.
        reference_points_cam = reference_points_cam[..., 0:2] / torch.maximum(
            reference_points_cam[..., 2:3], torch.ones_like(reference_points_cam[..., 2:3]) * eps)

        # 由像素坐标转成相对于图像的ratio..
        # NOTE 这里如果不同相机size不一样的话.要除以对应的相机的size
        reference_points_cam[..., 0] /= img_metas[0]['img_shape'][0][1]
        reference_points_cam[..., 1] /= img_metas[0]['img_shape'][0][0]

        # 再把超出图像fov范围的点给去掉.
        bev_mask = (bev_mask & (reference_points_cam[..., 1:2] > 0.0)
                    & (reference_points_cam[..., 1:2] < 1.0)
                    & (reference_points_cam[..., 0:1] < 1.0)
                    & (reference_points_cam[..., 0:1] > 0.0))
        if digit_version(TORCH_VERSION) >= digit_version('1.8'):
            bev_mask = torch.nan_to_num(bev_mask)
        else:
            bev_mask = bev_mask.new_tensor(
                np.nan_to_num(bev_mask.cpu().numpy()))

        # 由(D, b, num_cam, num_query, 2) 变成 (num_cam, b, num_query, D, 2)
        reference_points_cam = reference_points_cam.permute(2, 1, 3, 0, 4)
        bev_mask = bev_mask.permute(2, 1, 3, 0, 4).squeeze(-1)

        # 至此. reference_points_cam代表的就是像素点相对于各个相机的ratio.
        # bev_mask就代表哪些点是有效的
        return reference_points_cam, bev_mask

SpatialCrossAttention

个人理解SpatialCrossAttention其实就是正常的Deformable Attention, 只不过原始Deformable Attention中的
refer points是由网络产生的,
而现在的refer points 是由 虚拟的grid points往图像上投影得到的. 在相机参数固定的情况下, 此时的refer points是固定的.

下面是 SpatialCrossAttention这个模块的forward函数的部分代码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

问题: 给固定的这些refer points 的收益是多大? 文章好像并没有提. 这一块儿感觉不充分.

另外, 显然这样虚拟的grid points 是不合理的, 因为有些地方可能就没有点, 但是还是能够投影到图像上的. 这里用真值的点应该会更好,
比如用lidar的points. 但是BEVFormer paper里面没有对比加入lidar后的效果.

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/26827.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【IMX6ULL驱动开发学习】02.IMX6ULL烧写Linux系统

由于我买的是正点原子的IMX6ULL阿尔法开发板&#xff0c;但是我是看韦东山老师视频学习的驱动 所以这里我烧录的方法是按照韦东山老师的课程来的 这里给出烧写Linux系统用到的工具 链接&#xff1a;https://pan.baidu.com/s/1bD-xxn3K8xQAVkJSaJmTzQ 提取码&#xff1a;af6w …

Keysight是德MSOS604A高清晰度示波器1 GH

Keysight是德MSOS604A S系列示波器配备 6 GHz 存储器、15 英寸 XGA 电容触摸屏和 10 位模数转换器。主要特性与技术指标 1 GHz带宽和平坦的频率响应确保高信号保真度 20 GSa/s 最大采样率 10 位模数转换器&#xff08;ADC&#xff09;保证高垂直分辨率 低噪声前端&#xff…

EDA数字钟(三)

文章目录 前言一、设计内容二、模块结构三、代码编写1、顶层模块Digclk2、状态控制模块Ctrl3、按键消抖模块Filter4、计时模块Time5、闹钟模块Alarm6、显示模块Display7、数码管驱动模块Smg 四、测试文件五、波形仿真总结 前言 再次编写数字钟Verilog程序&#xff0c;使其符合…

Mysql的事务

MySQL中的事务是一组数据库操作&#xff0c;这些操作被视为单个逻辑单元并且被当做原子操作执行&#xff0c;这意味着它们要么全部成功&#xff0c;要么全部失败&#xff0c;没有中间状态。事务通常用于确保数据库中的数据完整性和一致性。 在MySQL中&#xff0c;事务可以使用以…

玩转css逐帧动画,努力成为更优质的Ikun~

&#x1f389; 一、前言 css3的animation想必大家都知道吧&#xff0c;那 steps 逐帧动画你知道吗&#xff1f;对于我来说&#xff0c;实际工作及练习中也很少用到这种跳跃式变化的动画&#xff0c;而它start和end的解释又比较“不说人话”&#xff0c;以前用到steps动画的时候…

Linux - 第23节 - Linux高级IO(一)

目录 1.IO的基本概念 2.钓鱼五人组 3.五种IO模型 3.1.阻塞IO 3.2.非阻塞IO 3.3.信号驱动IO 3.4.IO多路转接 3.5.异步IO 4.高级IO重要概念 4.1.同步通信 VS 异步通信 4.2.阻塞 VS 非阻塞 5.其他高级IO 6.阻塞IO 7.非阻塞IO 7.1.fcntl函数介绍 7.2.fcntl函数的使…

MobPush 推送查询API

IP绑定 工作台可以绑定服务器IP地址&#xff0c;未绑定之前所有IP均可进行REST API的调用&#xff0c;绑定后进仅绑定的IP才有调用权限。 设备信息查询接口 根据RegistrationId查询设备信息 接口地址 http://api.push.mob.com/device-v3/getById/{registrationId} 请求方式…

三种编码方式(费诺曼编码,霍夫曼编码,哈夫曼树编码)的简单解释和介绍

一. 费诺曼(Fano)编码是一种前缀编码&#xff0c;其基本原理是将出现频率较高的符号用短的编码表示&#xff0c;而出现频率较低的符号则用长的编码表示。通过这种方式进行编码&#xff0c;可以达到更好的压缩效果。 费诺曼编码的具体过程如下&#xff1a; 将要编码的符号按照…

一个小时入门 Android Compose 动画

0. 前言 前段时间对于Android中的Compose动画做了系统性的学习&#xff0c;相关文章发布在 Compose 动画 专栏里。系统性学完Compose动画后&#xff0c;又对此做了系统性的回顾&#xff0c;抽取其比较重要的部分&#xff0c;希望能帮助大家快速入门Compose动画&#xff0c;所…

ChatGPT新突破:打造自己的智能机器人控制系统

&#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是Zeeland&#xff0c;全栈领域优质创作者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 我的博客&#xff1a;Zeeland&#x1f4da; Github主页: Undertone0809 (Zeeland) (github.com)&…

【论文速览】根据人脑fMRI信号重建图像 Image Reconstruction from human brain activity

文章目录 前言文章一研究背景主要方法部分实验结果总结与思考参考资料 文章二研究背景主要方法部分实验结果总结与思考 前言 人类的视觉神经系统对于真实世界的视觉刺激有着非凡的感知与理解能力&#xff0c;比如我们能够准确地识别物体距离和三维几何关系等&#xff0c;这是当…

三维数字沙盘交互大数据可视化GIS地理信息系统第十课

三维电子沙盘交互无人机倾斜摄影大数据可视化GIS地理信息系统第十课 设置system.ini 如下内容 Server122.112.229.220 userGisTest Passwordchinamtouch.com 该数据库中只提供 成都市火车南站附近的数据请注意&#xff0c;104.0648,30.61658 在SDK中自带了一个自定义的基础面…

pycharm和virtualBox虚拟机的安装(包括本地环境和远程环境配置)

目录 一、安装时需要的软件二、安装virtualBox三、安装pycharm四、创建pycharm本地环境五、创建pycharm远程环境 一、安装时需要的软件 Pycharm&#xff0c;jetbrains-agent-latest破解包&#xff08;破解pycharm&#xff09;;镜像文件ubuntu20&#xff0c;虚拟机virtualBox …

Zellij – 颜值爆表,比tmux、screen更好用的多窗口终端

如果你曾经使用过多窗口终端&#xff0c;如tmux、screen&#xff0c;那么你可能对Zellij上手会更快。下面将介绍这个惊艳出众的多窗口终端利器。 一、Zellij 特点 Zellij最大的特点是支持插件&#xff0c;与WebAssembly编译兼容。与screen和tmux相比&#xff0c;Zellij是以细…

Linux 之Python 定制篇-APT 软件管理和远程登录

Linux 之Python 定制篇-APT 软件管理和远程登录 apt 介绍 apt 是Advanced Packaging Tool 的简称&#xff0c;是一款安装包管理工具。在Ubuntu 下&#xff0c;我们可以使用apt 命令进行软件包的安装、删除、清理等&#xff0c;类似于Windows 中的软件管理工具。 unbuntu 软件…

LVS-DR负载群集的优势和部署实例(我们都会在各自喜欢的事情里变得可爱)

文章目录 一、DR模式数据包流向分析二、DR模式的特点三、DR模式中需要解决的问题问题1解决方式 问题2解决方式 四、LVS-DR部署实例1.配置NFS共享存储器2.配置节点web服务&#xff08;两台的配置相同&#xff09;3.配置LVS负载调度器 一、DR模式数据包流向分析 1.Client 客户端…

《计算机网络——自顶向下方法》精炼——3.7(2)

读书有三到&#xff1a;谓心到&#xff0c;眼到&#xff0c;口到。——明朱熹 文章目录 对链接吞吐量的简化描述高带宽路径的TCP公平性 对链接吞吐量的简化描述 为了简化对一条TCP连接吞吐量的描述&#xff0c;我们首先忽略连接过程中处于慢启动状态的时间&#xff0c;因为这一…

chatgpt赋能python:Python将yyyymmdd转换成yyyy-mm-dd的方法

Python将yyyymmdd转换成yyyy-mm-dd的方法 Python语言不仅易于学习&#xff0c;而且是一种功能强大的语言&#xff0c;广泛应用于数据分析、人工智能和Web开发等领域。在实际开发过程中&#xff0c;我们经常遇到需要将日期格式转换为其他格式的需求。本文将介绍如何使用Python将…

Nginx rewrite

目录 一、location 1.location 匹配规则介绍 2. 实际网站使用中匹配规则 2.1第一个必选规则 2.2第二个必选规则是处理静态文件请求&#xff0c;这是nginx作为http服务器的强项 2.3第三个规则就是通用规则 3.location 匹配规则演示 2.1一般前缀匹配 2.2正则匹配 2.3正则…

电池状态估计 | Matlab实现利用卡尔曼滤波器估计电池充电状态

文章目录 效果一览文章概述研究内容程序设计参考资料效果一览 文章概述 电池状态估计 | Matlab实现利用卡尔曼滤波器估计电池充电状态 研究内容 目前,常用的电池模型有:数