README.md 9.13 KB
Newer Older
rusty1s's avatar
rusty1s committed
1
2
3
4
5
6
[pypi-image]: https://badge.fury.io/py/torch-sparse.svg
[pypi-url]: https://pypi.python.org/pypi/torch-sparse
[build-image]: https://travis-ci.org/rusty1s/pytorch_sparse.svg?branch=master
[build-url]: https://travis-ci.org/rusty1s/pytorch_sparse
[coverage-image]: https://codecov.io/gh/rusty1s/pytorch_sparse/branch/master/graph/badge.svg
[coverage-url]: https://codecov.io/github/rusty1s/pytorch_sparse?branch=master
rusty1s's avatar
rusty1s committed
7

rusty1s's avatar
rusty1s committed
8
# PyTorch Sparse
rusty1s's avatar
rusty1s committed
9
10
11
12
13
14

[![PyPI Version][pypi-image]][pypi-url]
[![Build Status][build-image]][build-url]
[![Code Coverage][coverage-image]][coverage-url]

--------------------------------------------------------------------------------
rusty1s's avatar
rusty1s committed
15

rusty1s's avatar
rusty1s committed
16
This package consists of a small extension library of optimized sparse matrix operations with autograd support.
rusty1s's avatar
typos  
rusty1s committed
17
This package currently consists of the following methods:
rusty1s's avatar
rusty1s committed
18

rusty1s's avatar
rusty1s committed
19
20
21
* **[Coalesce](#coalesce)**
* **[Transpose](#transpose)**
* **[Sparse Dense Matrix Multiplication](#sparse-dense-matrix-multiplication)**
rusty1s's avatar
docs  
rusty1s committed
22
* **[Sparse Sparse Matrix Multiplication](#sparse-sparse-matrix-multiplication)**
rusty1s's avatar
rusty1s committed
23
24

All included operations work on varying data types and are implemented both for CPU and GPU.
rusty1s's avatar
rusty1s committed
25
26
To avoid the hazzle of creating [`torch.sparse_coo_tensor`](https://pytorch.org/docs/stable/torch.html?highlight=sparse_coo_tensor#torch.sparse_coo_tensor), this package defines operations on sparse tensors by simply passing `index` and `value` tensors as arguments ([with same shapes as defined in PyTorch](https://pytorch.org/docs/stable/sparse.html)).
Note that only `value` comes with autograd support, as `index` is discrete and therefore not differentiable.
rusty1s's avatar
rusty1s committed
27
28
29

## Installation

rusty1s's avatar
rusty1s committed
30
31
### Binaries

rusty1s's avatar
rusty1s committed
32
We provide pip wheels for all major OS/PyTorch/CUDA combinations, see [here](https://pytorch-geometric.com/whl).
rusty1s's avatar
rusty1s committed
33

rusty1s's avatar
rusty1s committed
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#### PyTorch 1.8.0

To install the binaries for PyTorch 1.8.0, simply run

```
pip install torch-scatter torch-sparse -f https://pytorch-geometric.com/whl/torch-1.8.0+${CUDA}.html
```

where `${CUDA}` should be replaced by either `cpu`, `cu101`, `cu102`, or `cu111` depending on your PyTorch installation.

|             | `cpu` | `cu101` | `cu102` | `cu111` |
|-------------|-------|---------|---------|---------|
| **Linux**   | ✅    | ✅      | ✅      | ✅      |
| **Windows** | ✅    | ✅      | ✅      | ✅      |
| **macOS**   | ✅    |         |         |         |

rusty1s's avatar
rusty1s committed
50
#### PyTorch 1.7.0
rusty1s's avatar
rusty1s committed
51

rusty1s's avatar
rusty1s committed
52
To install the binaries for PyTorch 1.7.0, simply run
rusty1s's avatar
rusty1s committed
53
54

```
55
pip install torch-scatter torch-sparse -f https://pytorch-geometric.com/whl/torch-1.7.0+${CUDA}.html
rusty1s's avatar
rusty1s committed
56
57
```

rusty1s's avatar
rusty1s committed
58
where `${CUDA}` should be replaced by either `cpu`, `cu92`, `cu101`, `cu102`, or `cu110` depending on your PyTorch installation.
rusty1s's avatar
rusty1s committed
59

rusty1s's avatar
rusty1s committed
60
61
62
63
64
|             | `cpu` | `cu92` | `cu101` | `cu102` | `cu110` |
|-------------|-------|--------|---------|---------|---------|
| **Linux**   | ✅    | ✅     | ✅      | ✅      | ✅      |
| **Windows** | ✅    | ❌     | ✅      | ✅      | ✅      |
| **macOS**   | ✅    |        |         |         |         |
rusty1s's avatar
rusty1s committed
65

rusty1s's avatar
rusty1s committed
66
**Note:** Binaries of older versions are also provided for PyTorch 1.4.0, PyTorch 1.5.0 and PyTorch 1.6.0 (following the same procedure).
rusty1s's avatar
rusty1s committed
67
68
69

### From source

rusty1s's avatar
rusty1s committed
70
Ensure that at least PyTorch 1.4.0 is installed and verify that `cuda/bin` and `cuda/include` are in your `$PATH` and `$CPATH` respectively, *e.g.*:
rusty1s's avatar
rusty1s committed
71
72

```
rusty1s's avatar
rusty1s committed
73
$ python -c "import torch; print(torch.__version__)"
rusty1s's avatar
rusty1s committed
74
>>> 1.4.0
rusty1s's avatar
rusty1s committed
75

rusty1s's avatar
rusty1s committed
76
$ echo $PATH
rusty1s's avatar
rusty1s committed
77
>>> /usr/local/cuda/bin:...
rusty1s's avatar
rusty1s committed
78
79

$ echo $CPATH
rusty1s's avatar
rusty1s committed
80
>>> /usr/local/cuda/include:...
rusty1s's avatar
rusty1s committed
81
82
```

rusty1s's avatar
rusty1s committed
83
If you want to additionally build `torch-sparse` with METIS support, *e.g.* for partioning, please download and install the [METIS library](http://glaros.dtc.umn.edu/gkhome/metis/metis/download) by following the instructions in the `Install.txt` file.
rusty1s's avatar
rusty1s committed
84
Note that METIS needs to be installed with 64 bit `IDXTYPEWIDTH` by changing `include/metis.h`.
rusty1s's avatar
rusty1s committed
85
Afterwards, set the environment variable `WITH_METIS=1`.
rusty1s's avatar
rusty1s committed
86

rusty1s's avatar
rusty1s committed
87
88
89
Then run:

```
rusty1s's avatar
rusty1s committed
90
pip install torch-scatter torch-sparse
rusty1s's avatar
rusty1s committed
91
92
```

rusty1s's avatar
rusty1s committed
93
When running in a docker container without NVIDIA driver, PyTorch needs to evaluate the compute capabilities and may fail.
rusty1s's avatar
rusty1s committed
94
95
96
In this case, ensure that the compute capabilities are set via `TORCH_CUDA_ARCH_LIST`, *e.g.*:

```
rusty1s's avatar
rusty1s committed
97
export TORCH_CUDA_ARCH_LIST="6.0 6.1 7.2+PTX 7.5+PTX"
rusty1s's avatar
rusty1s committed
98
99
100
```

## Functions
rusty1s's avatar
links  
rusty1s committed
101

rusty1s's avatar
rusty1s committed
102
### Coalesce
rusty1s's avatar
rusty1s committed
103

rusty1s's avatar
docs  
rusty1s committed
104
```
rusty1s's avatar
rusty1s committed
105
torch_sparse.coalesce(index, value, m, n, op="add") -> (torch.LongTensor, torch.Tensor)
rusty1s's avatar
docs  
rusty1s committed
106
107
```

108
Row-wise sorts `index` and removes duplicate entries.
rusty1s's avatar
rusty1s committed
109
110
111
Duplicate entries are removed by scattering them together.
For scattering, any operation of [`torch_scatter`](https://github.com/rusty1s/pytorch_scatter) can be used.

rusty1s's avatar
rusty1s committed
112
#### Parameters
rusty1s's avatar
rusty1s committed
113
114
115

* **index** *(LongTensor)* - The index tensor of sparse matrix.
* **value** *(Tensor)* - The value tensor of sparse matrix.
116
117
* **m** *(int)* - The first dimension of corresponding dense matrix.
* **n** *(int)* - The second dimension of corresponding dense matrix.
rusty1s's avatar
docs  
rusty1s committed
118
* **op** *(string, optional)* - The scatter operation to use. (default: `"add"`)
rusty1s's avatar
rusty1s committed
119

rusty1s's avatar
rusty1s committed
120
#### Returns
rusty1s's avatar
rusty1s committed
121

rusty1s's avatar
docs  
rusty1s committed
122
123
* **index** *(LongTensor)* - The coalesced index tensor of sparse matrix.
* **value** *(Tensor)* - The coalesced value tensor of sparse matrix.
rusty1s's avatar
rusty1s committed
124

rusty1s's avatar
rusty1s committed
125
#### Example
rusty1s's avatar
docs  
rusty1s committed
126
127

```python
ekka's avatar
ekka committed
128
import torch
rusty1s's avatar
rusty1s committed
129
130
131
132
from torch_sparse import coalesce

index = torch.tensor([[1, 0, 1, 0, 2, 1],
                      [0, 1, 1, 1, 0, 0]])
rusty1s's avatar
rusty1s committed
133
value = torch.Tensor([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7]])
rusty1s's avatar
docs  
rusty1s committed
134

rusty1s's avatar
rusty1s committed
135
index, value = coalesce(index, value, m=3, n=2)
rusty1s's avatar
docs  
rusty1s committed
136
137
```

rusty1s's avatar
rusty1s committed
138
139
140
141
142
```
print(index)
tensor([[0, 1, 1, 2],
        [1, 0, 1, 0]])
print(value)
rusty1s's avatar
rusty1s committed
143
144
145
146
tensor([[6.0, 8.0],
        [7.0, 9.0],
        [3.0, 4.0],
        [5.0, 6.0]])
rusty1s's avatar
rusty1s committed
147
```
rusty1s's avatar
docs  
rusty1s committed
148

rusty1s's avatar
rusty1s committed
149
### Transpose
rusty1s's avatar
rusty1s committed
150

rusty1s's avatar
docs  
rusty1s committed
151
```
rusty1s's avatar
rusty1s committed
152
torch_sparse.transpose(index, value, m, n) -> (torch.LongTensor, torch.Tensor)
rusty1s's avatar
docs  
rusty1s committed
153
154
```

rusty1s's avatar
rusty1s committed
155
156
Transposes dimensions 0 and 1 of a sparse matrix.

rusty1s's avatar
rusty1s committed
157
#### Parameters
rusty1s's avatar
rusty1s committed
158
159
160

* **index** *(LongTensor)* - The index tensor of sparse matrix.
* **value** *(Tensor)* - The value tensor of sparse matrix.
161
162
* **m** *(int)* - The first dimension of corresponding dense matrix.
* **n** *(int)* - The second dimension of corresponding dense matrix.
rusty1s's avatar
typo  
rusty1s committed
163
* **coalesced** *(bool, optional)* - If set to `False`, will not coalesce the output. (default: `True`)
rusty1s's avatar
rusty1s committed
164

rusty1s's avatar
rusty1s committed
165
#### Returns
rusty1s's avatar
rusty1s committed
166

rusty1s's avatar
docs  
rusty1s committed
167
168
* **index** *(LongTensor)* - The transposed index tensor of sparse matrix.
* **value** *(Tensor)* - The transposed value tensor of sparse matrix.
rusty1s's avatar
rusty1s committed
169

rusty1s's avatar
rusty1s committed
170
#### Example
rusty1s's avatar
docs  
rusty1s committed
171
172

```python
ekka's avatar
ekka committed
173
import torch
rusty1s's avatar
rusty1s committed
174
175
176
177
from torch_sparse import transpose

index = torch.tensor([[1, 0, 1, 0, 2, 1],
                      [0, 1, 1, 1, 0, 0]])
rusty1s's avatar
rusty1s committed
178
value = torch.Tensor([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7]])
rusty1s's avatar
docs  
rusty1s committed
179

rusty1s's avatar
docs  
rusty1s committed
180
index, value = transpose(index, value, 3, 2)
rusty1s's avatar
docs  
rusty1s committed
181
182
```

rusty1s's avatar
rusty1s committed
183
184
185
186
187
```
print(index)
tensor([[0, 0, 1, 1],
        [1, 2, 0, 1]])
print(value)
rusty1s's avatar
rusty1s committed
188
189
190
191
tensor([[7.0, 9.0],
        [5.0, 6.0],
        [6.0, 8.0],
        [3.0, 4.0]])
rusty1s's avatar
rusty1s committed
192
```
rusty1s's avatar
docs  
rusty1s committed
193

rusty1s's avatar
rusty1s committed
194
### Sparse Dense Matrix Multiplication
rusty1s's avatar
rusty1s committed
195

rusty1s's avatar
docs  
rusty1s committed
196
```
197
torch_sparse.spmm(index, value, m, n, matrix) -> torch.Tensor
rusty1s's avatar
docs  
rusty1s committed
198
199
```

rusty1s's avatar
rusty1s committed
200
201
Matrix product of a sparse matrix with a dense matrix.

rusty1s's avatar
rusty1s committed
202
#### Parameters
rusty1s's avatar
docs  
rusty1s committed
203

rusty1s's avatar
rusty1s committed
204
205
* **index** *(LongTensor)* - The index tensor of sparse matrix.
* **value** *(Tensor)* - The value tensor of sparse matrix.
206
207
* **m** *(int)* - The first dimension of corresponding dense matrix.
* **n** *(int)* - The second dimension of corresponding dense matrix.
rusty1s's avatar
docs  
rusty1s committed
208
* **matrix** *(Tensor)* - The dense matrix.
rusty1s's avatar
rusty1s committed
209

rusty1s's avatar
rusty1s committed
210
#### Returns
rusty1s's avatar
rusty1s committed
211

rusty1s's avatar
docs  
rusty1s committed
212
* **out** *(Tensor)* - The dense output matrix.
rusty1s's avatar
rusty1s committed
213

rusty1s's avatar
rusty1s committed
214
#### Example
rusty1s's avatar
rusty1s committed
215
216

```python
ekka's avatar
ekka committed
217
import torch
rusty1s's avatar
rusty1s committed
218
219
220
221
from torch_sparse import spmm

index = torch.tensor([[0, 0, 1, 2, 2],
                      [0, 2, 1, 0, 1]])
rusty1s's avatar
rusty1s committed
222
223
value = torch.Tensor([1, 2, 4, 1, 3])
matrix = torch.Tensor([[1, 4], [2, 5], [3, 6]])
rusty1s's avatar
rusty1s committed
224

rusty1s's avatar
rusty1s committed
225
out = spmm(index, value, 3, 3, matrix)
rusty1s's avatar
rusty1s committed
226
227
228
229
```

```
print(out)
230
231
232
tensor([[7.0, 16.0],
        [8.0, 20.0],
        [7.0, 19.0]])
rusty1s's avatar
docs  
rusty1s committed
233
```
rusty1s's avatar
rusty1s committed
234

rusty1s's avatar
rusty1s committed
235
### Sparse Sparse Matrix Multiplication
rusty1s's avatar
rusty1s committed
236
237
238
239
240
241

```
torch_sparse.spspmm(indexA, valueA, indexB, valueB, m, k, n) -> (torch.LongTensor, torch.Tensor)
```

Matrix product of two sparse tensors.
rusty1s's avatar
typo  
rusty1s committed
242
Both input sparse matrices need to be **coalesced** (use the `coalesced` attribute to force).
rusty1s's avatar
rusty1s committed
243

rusty1s's avatar
rusty1s committed
244
#### Parameters
rusty1s's avatar
rusty1s committed
245
246
247
248
249

* **indexA** *(LongTensor)* - The index tensor of first sparse matrix.
* **valueA** *(Tensor)* - The value tensor of first sparse matrix.
* **indexB** *(LongTensor)* - The index tensor of second sparse matrix.
* **valueB** *(Tensor)* - The value tensor of second sparse matrix.
250
251
252
* **m** *(int)* - The first dimension of first corresponding dense matrix.
* **k** *(int)* - The second dimension of first corresponding dense matrix and first dimension of second corresponding dense matrix.
* **n** *(int)* - The second dimension of second corresponding dense matrix.
rusty1s's avatar
typo  
rusty1s committed
253
* **coalesced** *(bool, optional)*: If set to `True`, will coalesce both input sparse matrices. (default: `False`)
rusty1s's avatar
rusty1s committed
254

rusty1s's avatar
rusty1s committed
255
#### Returns
rusty1s's avatar
rusty1s committed
256

rusty1s's avatar
docs  
rusty1s committed
257
258
* **index** *(LongTensor)* - The output index tensor of sparse matrix.
* **value** *(Tensor)* - The output value tensor of sparse matrix.
rusty1s's avatar
rusty1s committed
259

rusty1s's avatar
rusty1s committed
260
#### Example
rusty1s's avatar
rusty1s committed
261
262

```python
ekka's avatar
ekka committed
263
import torch
rusty1s's avatar
docs  
rusty1s committed
264
265
from torch_sparse import spspmm

rusty1s's avatar
rusty1s committed
266
indexA = torch.tensor([[0, 0, 1, 2, 2], [1, 2, 0, 0, 1]])
rusty1s's avatar
rusty1s committed
267
valueA = torch.Tensor([1, 2, 3, 4, 5])
rusty1s's avatar
rusty1s committed
268
269

indexB = torch.tensor([[0, 2], [1, 0]])
rusty1s's avatar
rusty1s committed
270
valueB = torch.Tensor([2, 4])
rusty1s's avatar
docs  
rusty1s committed
271

rusty1s's avatar
rusty1s committed
272
273
274
275
indexC, valueC = spspmm(indexA, valueA, indexB, valueB, 3, 3, 2)
```

```
ekka's avatar
ekka committed
276
print(indexC)
rusty1s's avatar
rusty1s committed
277
278
tensor([[0, 1, 2],
        [0, 1, 1]])
ekka's avatar
ekka committed
279
print(valueC)
280
tensor([8.0, 6.0, 8.0])
rusty1s's avatar
docs  
rusty1s committed
281
282
```

rusty1s's avatar
rusty1s committed
283
284
285
286
287
288
289
290
291
292
293
294
295
## C++ API

`torch-sparse` also offers a C++ API that contains C++ equivalent of python models.

```
mkdir build
cd build
# Add -DWITH_CUDA=on support for the CUDA if needed
cmake ..
make
make install
```

rusty1s's avatar
rusty1s committed
296
297
298
299
300
## Running tests

```
python setup.py test
```