Spatially Sparse Convolution

导言

为什么需要稀疏化?

在3D表示中,除了点云(Point Cloud)和网格模型(Mesh),我们常常还会使用到一种称为体素(Voxel)的表示方式。类似于像素(Pixel),这种表示方式将空间均匀地切割为一个个方块,TSDF和占据网格(Occupancy Network)都可以视为体素的一种变形。

最朴素的体素表示方式,这是一种稠密(Dense)的表示形式,我们给定一个\(L\times W\times H\)的包围盒,体素尺寸为\(1\times 1\times 1\),那么我们将得到一个\(L\times W\times H\)的\(bool\)矩阵:

\[B(x, y, z) =
\begin{cases}
1 & \text{if voxel } (x, y, z) \text{ is occupied.}, \\
0 & otherwise.
\end{cases}
\\
\text{where } 0 \leq x < L, \ 0 \leq y < W, \ 0 \leq z < H
\]

那么假设我们有一个\(70.4m\times80m\times4m\)的室外点云场景(KITTI点云格式的感知范围),给定每个体素大小为\(0.16m\times0.16m\times4m\)(PointPillar将点云体素化的参数),那么将得到一个大小为\(440\times 500\times1=220,000\)的体素网格,而最终有效的体素数量不会超过\(40,000\)个,即利用率不会超过\(18\%\),稠密表示形式下,有\(80\%\)的存储空间是被浪费的。

我们在模拟器中简单采集一帧点云做个实验就可以看到,当体素大小为\(0.05m\)时,基本保留原始点云的细节,但此时占用率不足千分之一。

所以只表示有效体素的稀疏化表示就这样提出了,这种表示有效降低了内存的冗余,并加速了对体素的处理。

稀疏卷积

最常用的稀疏卷积分为Spatially Sparse Convolution(SparseConv)和Submanifold Sparse Convolution(SubMConv),前者是常规卷积操作的稀疏化版本,后者是保证不破坏特征图稀疏度的卷积操作。

现代通用版本的SparseConv实现出自于SECOND: Sparsely Embedded Convolutional Detection

SubMConv出自于3D Semantic Segmentation with Submanifold Sparse Convolutional Networks

稀疏卷积主要分为四个步骤:

  1. 张量稀疏化
  2. 建立indice pair
  3. 稀疏特征收集
  4. 稀疏卷积计算

稀疏卷积

我们给出一个简单的稀疏卷积例子

如下图所示,P1与P2两个输入分别在SparseConv与SubMConv所关联的输出为A1与A2

张量稀疏化

张量稀疏化就是顾名思义将一个张量从稠密表示形式变换为稀疏表示形式,我们给出常用的COO内存的定义,给定一个张量\(\mathbf X\in \mathbf{R}^{N_1\times N_2\times\cdots \times N_m}\)与稀疏维度\(d\ge1\),得到一个索引\(\mathbf{I}\in\mathbf{R}^{n\times d}\)以及值\(\mathbf{V}\in\mathbf{R}^{n\times N_{d+1}\times\cdots \times N_m}\),其中\(n\ge 0\)为张量中的非\(0\)量的数量

  • 给定\(\mathbf X\in\mathbf{R}^{2\times 2} = \begin{bmatrix} 0 & 2 \\ 3 & 0 \end{bmatrix}\),\(d=2\),得到\(\mathbf I\in{2\times 2} =\text{[[0, 1], [1, 0]]}\)以及\(\mathbf{V}\in\mathbf{R}^{2}=\text{[2., 3.]}\)
  • 给定\(\mathbf X\in\mathbf{R}^{2\times 2\times 2} = \begin{bmatrix} \begin{bmatrix} 0 & 0 \\ 1 & 2 \end{bmatrix} \\ \begin{bmatrix} 0 & 0 \\ 3 & 4 \end{bmatrix} \end{bmatrix}\),\(d=2\),得到\(\mathbf I\in{2\times 2} =\text{[[0, 1], [1, 1]]}\)以及\(\mathbf{V}\in\mathbf{R}^{2\times2}=\text{[[1., 2.],[3., 4.]]}\)

五种内存管理形式

建立indice pair

在输入中,稀疏矩阵中非空量我们称为active input (actIn),那么每个actIn在输出中存在关联的量称为active output (actOut)

indice pair是一个\(k\times n\)的表结构,每个元素是一个索引对\((i, j)\),表示的是\(\text{actIn}[i]\)乘以卷积核中的第\(k\)个权重,其结果输出到\(\text{actOut}[j]\)中,建立indice pair如下进行:

  • 初始化actOut

  • 计算actIn所关联的每个actOut

    给定一个\(\text{actIn}[i]=(x,y)\),可以算出每个输出坐标\((x^\prime,y^\prime)\)以及其对应卷积核位移\(k\)

    在actOut寻找\((x^\prime,y^\prime)\)是否存在,没有就开辟一个新空间,返回其索引\(j\)

    建立索引indicePair[k].append(i,j)

可以如下写成伪代码形式:

vector[K] get_indice_pair(act_in: vector, act_out: vector) {
initialize indice_pair = vector[K];
for i in enumerate(act_in.length()) {
pos_act_In = act_in[i];
for k, {x, y} in get_valid_out_pos(pos_act_In) {
j = act_out.find({x, y});
if(j == -1) {
j = act_out.length();
act_out.append({x, y});
}
indice_pair[k].append({i, j});
}
}
return indice_pair;
}

如果是SubMConv操作,在get_valid_out_pos中检查输出坐标在输入所对应的坐标中是否为actIn,否则过滤掉即可

注意:这里只是为了方便理解把indice pair写成了\(k\times n\)的表,实际indice pair一般都是一张\(2\times k\times n\)的表,其中\(\text{indice_pair}(0,k,n)=i,\ \text{indice_pair}(1,k,n)=j\),这样在特征收集与计算阶段就只需要读入半张表,提高性能

稀疏特征收集

这一步的目的在于通过indice_pair收集读入指定位置的特征feats,用于下一步的卷积计算。我们可以用公式表示:

\[\text{indice_pair}\in\mathbf{R}^{k\times n}\overset{\text{Scatter}}{\rightarrow}\text{feats}\in\mathbf{R}^{k\times n\times f}
\]

稀疏卷积计算

稀疏卷积计算分为两步:相乘与求和

  • 相乘阶段

    相乘阶段的目的在于将特征feats与指定位置的权重相乘

    \[\text{feats}^\prime\in \mathbf{R}^{k\times n\times f} = \text{feats} \in\mathbf{R}^{k\times n\times f} \odot \text{kernal}\in \mathbf{R}^{k}
    \]

    其中$\odot $是逐元素乘积

  • 求和阶段

    将上一阶段相乘的特征进行求和

    \[\mathbf I = \text{actOut},\mathbf{V}(j)=\sum_{k}\text{feats}^\prime(k,n) \\\text{where}\ \text{indice_pair}[n]=\{i, j\}
    \]

    可以如下写成伪代码形式:

    vector[K] sparse_scatter_add_cpu(act_out: vector[N], indice_pair: vector[K], feats: Tensor[k, n, f], kernal[k]) {
    feats = feats * kernal; \\Tensor[k, n, f]
    value = tensor::zeros((act_out.length(), feats.size(2))); \\Initialize a full 0 Tensor with size [N, f]
    for k in range(K) {
    for index in range(indice_pair[k].length()) {
    {i, j} = indice_pair[k, index];
    value[j] += feats[k, index];
    }
    } return value;
    }

并行版本的稀疏卷积

参考文献

目标检测 | Spatially Sparse Convolution的更多相关文章

  1. QueryDet: Cascaded Sparse Query for Accelerating High-Resolution Small Object Detection(QueryDet:用于加速高分辨率小目标检测的级联稀疏查询)

    QueryDet: Cascaded Sparse Query for Accelerating High-Resolution Small Object Detection(QueryDet:用于加 ...

  2. CVPR2020论文解读:3D Object Detection三维目标检测

    CVPR2020论文解读:3D Object Detection三维目标检测 PV-RCNN:Point-Voxel Feature Se tAbstraction for 3D Object Det ...

  3. 目标检测----ImageAI使用

    1.开源项目  github地址  https://github.com/OlafenwaMoses/ImageAI 2.目标检测(Object Detection)入门概要 3.Pycharm中无法 ...

  4. (转)如何用TensorLayer做目标检测的数据增强

    数据增强在机器学习中的作用不言而喻.和图片分类的数据增强不同,训练目标检测模型的数据增强在对图像做处理时,还需要对图片中每个目标的坐标做相应的处理.此外,位移.裁剪等操作还有可能使得一些目标在处理后只 ...

  5. 目标检测网络之 R-FCN

    R-FCN 原理 R-FCN作者指出在图片分类网络中具有平移不变性(translation invariance),而目标在图片中的位置也并不影响分类结果;但是检测网络对目标的位置比较敏感.因此Fas ...

  6. 从YOLOv1到YOLOv3,目标检测的进化之路

    https://blog.csdn.net/guleileo/article/details/80581858 本文来自 CSDN 网站,作者 EasonApp. 作者专栏: http://dwz.c ...

  7. 目标检测算法—YOLO-V1

    为什么会叫YOLO呢? YOLO:you only look once.只需要看一眼,就可以检测识别出目标,主要是突出这个算法 快 的特点.(原文:Yolo系列之前的文章:主要是rcnn系列的,他们的 ...

  8. [转]CNN目标检测(一):Faster RCNN详解

    https://blog.csdn.net/a8039974/article/details/77592389 Faster RCNN github : https://github.com/rbgi ...

  9. [DeeplearningAI笔记]卷积神经网络3.1-3.5目标定位/特征点检测/目标检测/滑动窗口的卷积神经网络实现/YOLO算法

    4.3目标检测 觉得有用的话,欢迎一起讨论相互学习~Follow Me 3.1目标定位 对象定位localization和目标检测detection 判断图像中的对象是不是汽车--Image clas ...

  10. 语义分割(semantic segmentation) 常用神经网络介绍对比-FCN SegNet U-net DeconvNet,语义分割,简单来说就是给定一张图片,对图片中的每一个像素点进行分类;目标检测只有两类,目标和非目标,就是在一张图片中找到并用box标注出所有的目标.

    from:https://blog.csdn.net/u012931582/article/details/70314859 2017年04月21日 14:54:10 阅读数:4369 前言 在这里, ...

随机推荐

  1. 10C++选择结构(4)

    一.switch语句 问题:风之巅小学规定,若测试成绩大于或等于90分为"A",大于或等于70分小于90分为"B",大于或等于60分小于70分为"C& ...

  2. 工作中这样用MQ,很香!

    前言 消息队列(MQ)是分布式系统中不可或缺的技术之一. 对很多小伙伴来说,刚接触MQ时,可能觉得它只是个"传话工具",但用着用着,你会发现它简直是系统的"润滑剂&quo ...

  3. PDFSharp - Graphics

    PDFSharp - Graphics Graphics - PDFsharp and MigraDoc Wiki 所有的 Graphics 类型都设计成模仿来自 System.Drawing 命名空 ...

  4. 【MyBatis】学习笔记14:通过collection解决一对多的映射关系

    MyBatis14:通过collection解决一对多的映射关系 目录 MyBatis14:通过collection解决一对多的映射关系 对象 接口 映射文件 测试 总结 注意事项 已知,一个部门对应 ...

  5. 在 .NET Core 中使用 ActionBlock 实现高效率的多步骤数据处理

    目录 一.引言 二.ActionBlock介绍 什么是 ActionBlock? ActionBlock 的特点 ActionBlock 的使用场景 ActionBlock 的基本用法 三.假设场景 ...

  6. 巧技拾遗 | JavaScript 中 Array.every 和 Array.map 的巧妙结合

    这几天在跟着学一点 vue3 + TypeScript 中表单验证的实例,看到一个实现,觉得非常巧妙. 需求概述 我们有一个列表 funcArr ,里面存放函数,比如 funcArr = [ func ...

  7. windows11使用pycharm连接wsl2开发基于poetry的python项目

    windows11使用pycharm连接wsl2开发基于poetry的python项目 背景:公司开发的python项目用到了某个只提供了Linux版本的包,遂研究了一番如何在windows环境下进行 ...

  8. 【转载】hacker术语

    1.肉鸡 所谓"肉鸡"是一种很形象的比喻,比喻那些可以随意被我们控制的电脑,对方可以是WINDOWS系统,也可以是UNIX/LINUX系统,可以是普通的个人电脑,也可以是大型的服务 ...

  9. 关于存入sessionStorage中boolean值拿出来为字符串

    上面是html部分,然后定义了变量 定义方法 在mounted中获取,然后刷新页面,打印类型为字符串 解决办法

  10. Windows 风格的个人网盘,支持OnlyOffice、支持音视频聊天、支持自动更新

    一年前,我开源了这个网盘,详见Windows风格的个人网盘,支持文档在线编辑,这一年期间,这个网盘进行了大量的更新,具体如下: 新增支持的功能如下: 支持 OnlyOffice (Word.Excel ...