一. 前言
稀疏卷积: regular output definition,就像普通的卷积一样,只要kernel 覆盖一个 active input site,就可以计算出output site。对应论文:SECOND: Sparsely Embedded Convolutional Detection
子流形卷积:、submanifold output definition。只有当kernel的中心覆盖一个 active input site时,卷积输出才会被计算。对应论文:3D Semantic Segmentation with Submanifold Sparse Convolutional Networks
卷积神经网络已经被证明对于二维图像信号处理是非常有效的,而在自动驾驶和机器人领域,点云数据是3维的,额外的维数 z 显著增加了计算量。另一方面,与普通图像不同的是,大多数三维点云的体素是空的,这使得三维体素中的点云数据通常是稀疏信号。如下图所示(其中深灰色像素全为零,浅灰色像素代表非零数据点):


对于稀疏的3D grid,我们是否只能有效地计算稀疏数据的卷积,而不是扫描所有的图像像素或空间体素?否则这些空白区域带来的计算量太多余了。这就是 sparse convolution 提出的motivation。
二. 定义
为了逐步解释稀疏卷积的概念,使其更易于理解,本文以二维稀疏图像处理为例。由于稀疏信号采用数据列表和索引列表表示,二维和三维稀疏信号没有本质区别。
1. 输入定义
使用以下稀疏图像作为输入:

如上图所示,我们有一个5 × 5的3通道图像。除了 P1和 P2两点外,所有像素都是(0,0,0) (虽然0这个假设也很不严谨)。P1和 P2,这种非零元素也称为active input sites。
在稀疏格式中,数据列表是0.1,0.1,0.1 ,0.2,0.2,0.2 ,索引列表是1,2 ,2,3 ,并且是 YX 顺序。
2. kernel 定义
假设使用以下参数进行卷积操作:

稀疏卷积的卷积核与传统的卷积核相同。上图是一个例子,其内核大小为3x3。深色和浅色代表两种滤镜。
conv2D(kernel_size=3, out_channels=2, stride=1, padding=0)
3. 输出的定义
稀疏卷积的输出与传统的卷积有很大的不同。对于稀疏卷积的发展,上述有两篇很重要的论文对应的地址,所以对应的,稀疏卷积也有两种输出。
一种是 regular output definition,就像普通的卷积一样,只要kernel 覆盖一个 active input site,就可以计算出output site。
另一个称为submanifold output definition。只有当kernel的中心覆盖一个 active input site时,卷积输出才会被计算。

上图说明了这两种输出之间的区别。
A1代表 active site,即 P1产生的卷积结果。类似地,A2代表从 P2计算出的 active site。A1A2代表 active site,它是 P1和 P2输出的总和。深色和浅色代表不同的输出通道。
三. 稀疏卷积的计算过程
1. 构建 Input Hash Table 和 Output Hash Table
现在要把 input 和 Output 都表示成 hash table 的形式。

input hash table和output hash table 对应上图的 Hash_in 和 Hash_out。
对于 Hash_in:v_in 是下标,key_ in 表示value在input matrix中的位置。
现在的input一共两个元素 P1和P2,P1在input matrxi的(2, 1)位置, P2在 input matrix 的(3,2)的位置,并且是 YX 顺序。
是的没错,这里只记录一下p1的位置 ,先不管 p1代表的数字。所以其实可以把这个input hash table命名为 input position hash table。

input hash tabel的构建完成了,接下来构建 output hash table。先来看一下卷积过程中 P1是怎么向下传导的:
用一个kernel去进行卷积操作:

但是,并不是每次卷积kernel都可以刚好碰到P1。所以,从第7次开始,输出的这个矩阵就不再变化了。

然后记录每个元素的位置。

上面说的只是操作P1,当然P2也是同样的操作:

然后把P1, P2的结果结合起来(主要是消除掉重复元素),得到了一张位置表。是的没错,此处记录的还是位置。
然后编号,就得到了 output hash table。
2.构建 Rulebook
建立规则手册------rulebook。这是稀疏卷积的关键部分!!!
规则手册的目的类似于 im2col ,它将卷积从数学形式转化为有效的可编程形式。
但是与 im2col 不同的是,rulebook集合了卷积中所有涉及到的原子运算,然后将它们关联到相应的核元素上。

上图就是如何构建 rulebook 的例子。
rulebook的每一行都是一个 atomic operation(这个的定义看下面的列子就知道了)。
rulebook一共有四列:
第一列是一个索引(代表有作用的卷积核位置,跟左边的GetOffset一一对应)。
第二列是一个计数器count,相当于把同个位置的卷积核有作用的堆叠到一起,并编序号,如(0,-1)位置分别跟P1和P2都有计算。
第三、四列 v_in和 v_ out 分别是atomic operation的 input hash table 的 index和 output hash tabel的index。(没错,到现在为止,依然是index,而没有用到真实的数据。)
展开来讲:
这是上文提到的hash表位置构建。

这个表示卷积核每个元素的位置,坐标表示(列,行),正中心位置为(0,0),左边为(-1,0)。

GetOffset是表示得到Pout是卷积核的哪个位置起作用。

比如P1卷积得到这灰色A1,位置为(1,1),卷积核作用位置为(0,-1):

P1卷积得到这灰色A1,位置为(2,2),卷积核作用位置为(0,-1):

因为这个时候(0, -1) 是第二次被遍历到,所以count+1。
3. Computation Pipeline
现在有输入(3*5*5)对它进行卷积操作:

conv2D(kernel_size=3, out_channels=2, stride=1, padding=0)

深色和浅色的kernel表示2个不同的kernel,即output channel=2。
则,程序里的稀疏卷积过程是:

现在展开说明
计算过程就是hash_in、hash_out、rulebook、卷积核计算得到卷积后结果。
根据rulebook可以实现并行计算
1、遍历或者并行逐一取出rulebook的列表,以第一行为例
2、(i,j)指向卷积核(-1,-1)的位置,也就是取出F0;
3、v_in指向0,也就是对应hash_in表格,取出0位置的P1值(2,1),因为输入是一个3通道数值,所以得到输入P1(0.1,0.1,0.1),卷积核值F0,F0,F0;
4、v_out指向5,查hash_out表对应为(2,1)位置,也就是新的特征图位置为第2行第3列。
同理对于rulebook黑色框所选的卷积核位置(0,0)也按照以上步骤,最终也同样得到hash_out表对应为(2,1)位置,也就是新的特征图位置为第2行第3列。
那么最终得到特征这个图的位置就是将两者直接相加就可以了。

以上也就解释整个稀疏卷积的过程,虽然构建 rulebook 也是需要额外的计算开销的,但是这个构建过程也是可以在GPU上并行处理的,所以能加快计算速度。
论文中的表述如下,可以按照上述解释简单看下流程:
-
将稀疏的输入特征 通过gather操作获得密集的gather特征,对比Hash_in;
-
然后使用GEMM对密集的gather特征 进行卷积操作,获得密集的输出特征,GEMM对比如何得到Hash_out值;
-
通过预先构建的输入-输出索引规则矩阵 ,将密集的输出特征 映射到稀疏的输出特征,这个相当于查表,将结果映射回特征图中。

四. 引用:
1 Graham, Benjamin, Martin Engelcke, and Laurens Van Der Maaten. "3d semantic segmentation with submanifold sparse convolutional networks."Proceedings of the IEEE conference on computer vision and pattern recognition. 2018.
2 Yan, Yan, Yuxing Mao, and Bo Li. "Second: Sparsely embedded convolutional detection."_Sensors_18.10 (2018): 3337.
3 Li, Xuesong, et al. "Three-dimensional Backbone Network for 3D Object
4 https://towardsdatascience.com/how-does-sparse-convolution-work-3257a0a8fd1