README.md 7.61 KB
Newer Older
traveller59's avatar
traveller59 committed
1
2
# SpConv: PyTorch Spatially Sparse Convolution Library

tusimple's avatar
tusimple committed
3
4
[![Build Status](https://github.com/traveller59/spconv/workflows/build/badge.svg)](https://github.com/traveller59/spconv/actions?query=workflow%3Abuild)

traveller59's avatar
traveller59 committed
5
6
This is a spatially sparse convolution library like [SparseConvNet](https://github.com/facebookresearch/SparseConvNet) but faster and easy to read. This library provide sparse convolution/transposed, submanifold convolution, inverse convolution and sparse maxpool.

traveller59's avatar
traveller59 committed
7
8
The GPU Indice Generation algorithm is a unofficial implementation of paper [SECOND](http://www.mdpi.com/1424-8220/18/10/3337). That algorithm (don't include GPU SubM indice generation algorithm) may be protected by patent.

traveller59's avatar
traveller59 committed
9
10
11
This project only support CUDA 9.0+ or CPU only. If you are using cuda 8.0, please update it to 9.0.

This project only support tensors with spatial volume less than ```std::numeric_limits<int>::max()``` (~2e9). if someone really need very large space, open an issue.
12

13
14
## News:

traveller59's avatar
traveller59 committed
15
2019-5-24: spconv v1.1 released, now indice generation will use hash table as default (CPU code only support hash table). you can use ```use_hash=False``` to use dense table when using CUDA. In addition, add CPU only build support.
16

tusimple's avatar
tusimple committed
17
18
19
20
## Docker:

```docker pull scrin/dev-spconv```, contains python 3.8, cuda 10.1, fish shell, newest pytorch and tensorflow.

traveller59's avatar
traveller59 committed
21
## Install on Ubuntu 16.04/18.04
traveller59's avatar
traveller59 committed
22

Yan Yan's avatar
Yan Yan committed
23
24
* if you are using pytorch 1.4+ and encounter "nvcc fatal: unknown -Wall", you need to go to torch package dir and remove flags contains "-Wall" in INTERFACE_COMPILE_OPTIONS in Caffe2Targets.cmake. This problem can't be fixed in this project (to avoid this, I need to remove all torch dependency in cuda sources and drop half support).

traveller59's avatar
traveller59 committed
25
26
0. Use ```git clone xxx.git --recursive``` to clone this repo.

Mohammad Shahedul Islam's avatar
Mohammad Shahedul Islam committed
27
1. Install boost headers to your system include path, you can use either ```sudo apt-get install libboost-all-dev``` or download compressed files from boost official website and copy headers to include path.
traveller59's avatar
traveller59 committed
28

29
2. Download cmake >= 3.13.2, then add cmake executables to PATH.
traveller59's avatar
traveller59 committed
30

traveller59's avatar
traveller59 committed
31
3. Ensure you have installed pytorch 1.0+ in your environment, run ```python setup.py bdist_wheel``` (don't use ```python setup.py install```).
traveller59's avatar
traveller59 committed
32
33
34
35
36
37
38

4. Run ```cd ./dist```, use pip to install generated whl file.

## Install on Windows 10 with CUDA 10 and python 3.6 (python 3.7 may have problem, see [this](https://github.com/pytorch/pytorch/issues/17233))

Since install newest driver and CUDA is very simple on windows, please use CUDA 10 on windows. 

traveller59's avatar
traveller59 committed
39
0. Install Visual Studio 2017. Use ```git clone xxx.git --recursive``` to clone this repo.
traveller59's avatar
traveller59 committed
40
41
42
43
44
45

1. Download compressed files from boost official website and copy headers (i.e. boost_1_69/boost) to spconv/include.

2. Download and install cmake >= 3.13.2, select add cmake to User or System PATH.

3. Ensure you have installed pytorch 1.0 in your environment, run ```python setup.py bdist_wheel``` (don't use ```python setup.py install```).
traveller59's avatar
traveller59 committed
46
47

4. Run ```cd ./dist```, use pip to install generated whl file.
traveller59's avatar
traveller59 committed
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

## Compare with SparseConvNet

### Features

* SparseConvNet's Sparse Convolution don't support padding and dilation, spconv support this.

* spconv only contains sparse convolutions, the batchnorm and activations can directly use layers from torch.nn, SparseConvNet contains lots of their own implementation of layers such as batchnorm and activations.

### Speed

* spconv is faster than SparseConvNet due to gpu indice generation and gather-gemm-scatter algorithm. SparseConvNet use hand-written gemm which is slow.

## Usage

### SparseConvTensor

```Python
features = # your features with shape [N, numPlanes]
indices = # your indices/coordinates with shape [N, ndim + 1], batch index must be put in indices[:, 0]
spatial_shape = # spatial shape of your sparse tensor.
batch_size = # batch size of your sparse tensor.
x = spconv.SparseConvTensor(features, indices, spatial_shape, batch_size)
traveller59's avatar
traveller59 committed
71
x_dense_NCHW = x.dense() # convert sparse tensor to dense NCHW tensor.
traveller59's avatar
traveller59 committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
print(x.sparity) # helper function to check sparity. 
```

### Sparse Convolution

```Python
import spconv
from torch import nn
class ExampleNet(nn.Module):
    def __init__(self, shape):
        super().__init__()
        self.net = spconv.SparseSequential(
            spconv.SparseConv3d(32, 64, 3), # just like nn.Conv3d but don't support group and all([d > 1, s > 1])
            nn.BatchNorm1d(64), # non-spatial layers can be used directly in SparseSequential.
            nn.ReLU(),
            spconv.SubMConv3d(64, 64, 3, indice_key="subm0"),
            nn.BatchNorm1d(64),
            nn.ReLU(),
            # when use submanifold convolutions, their indices can be shared to save indices generation time.
            spconv.SubMConv3d(64, 64, 3, indice_key="subm0"),
            nn.BatchNorm1d(64),
            nn.ReLU(),
            spconv.SparseConvTranspose3d(64, 64, 3, 2),
            nn.BatchNorm1d(64),
            nn.ReLU(),
            spconv.ToDense(), # convert spconv tensor to dense and convert it to NCHW format.
            nn.Conv3d(64, 64, 3),
            nn.BatchNorm1d(64),
            nn.ReLU(),
        )
        self.shape = shape

    def forward(self, features, coors, batch_size):
        coors = coors.int() # unlike torch, this library only accept int coordinates.
        x = spconv.SparseConvTensor(features, coors, self.shape, batch_size)
        return self.net(x)# .dense()
```

### Inverse Convolution

Inverse sparse convolution means "inv" of sparse convolution. the output of inverse convolution contains same indices as input of sparse convolution.

Inverse convolution usually used in semantic segmentation.

```Python
class ExampleNet(nn.Module):
    def __init__(self, shape):
        super().__init__()
        self.net = spconv.SparseSequential(
            spconv.SparseConv3d(32, 64, 3, 2, indice_key="cp0"),
122
            spconv.SparseInverseConv3d(64, 32, 3, indice_key="cp0"), # need provide kernel size to create weight
traveller59's avatar
traveller59 committed
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
        )
        self.shape = shape

    def forward(self, features, coors, batch_size):
        coors = coors.int()
        x = spconv.SparseConvTensor(features, coors, self.shape, batch_size)
        return self.net(x)
```

### Utility functions

* convert point cloud to voxel

```Python

voxel_generator = spconv.utils.VoxelGenerator(
    voxel_size=[0.1, 0.1, 0.1], 
    point_cloud_range=[-50, -50, -3, 50, 50, 1],
    max_num_points=30,
    max_voxels=40000
)

points = # [N, 3+] tensor.
voxels, coords, num_points_per_voxel = voxel_generator.generate(points)
```

## Implementation Details

This implementation use gather-gemm-scatter framework to do sparse convolution.

## Projects using spconv:

* [second.pytorch](https://github.com/traveller59/second.pytorch): Point Cloud Object Detection in KITTI Dataset.

## Authors

* **Yan Yan** - *Initial work* - [traveller59](https://github.com/traveller59)

traveller59's avatar
traveller59 committed
161
* **Bo Li** - *gpu indice generation idea, owner of patent of the sparse conv gpu indice generation algorithm (don't include subm)* - [prclibo](https://github.com/prclibo)
traveller59's avatar
traveller59 committed
162

traveller59's avatar
traveller59 committed
163
164
165
166
167
168
169
170
171
172
## Third party libraries

* [CUDPP](https://github.com/cudpp/cudpp): A cuda library. contains a cuda hash implementation.

* [robin-map](https://github.com/Tessil/robin-map): A fast c++ hash library. almost 2x faster than std::unordered_map in this project.

* [pybind11](https://github.com/pybind/pybind11): A head-only python c++ binding library.

* [prettyprint](https://github.com/louisdx/cxx-prettyprint): A head-only library for container print.

traveller59's avatar
traveller59 committed
173
174
175
## License

This project is licensed under the Apache license 2.0 License - see the [LICENSE.md](LICENSE.md) file for details
traveller59's avatar
traveller59 committed
176
177
178

The [CUDPP](https://github.com/cudpp/cudpp) hash code is licensed under BSD License.

Mohammad Shahedul Islam's avatar
Mohammad Shahedul Islam committed
179
The [robin-map](https://github.com/Tessil/robin-map) code is licensed under MIT license.