README.md 9.47 KB
Newer Older
rusty1s's avatar
rusty1s committed
1
2
[pypi-image]: https://badge.fury.io/py/torch-sparse.svg
[pypi-url]: https://pypi.python.org/pypi/torch-sparse
rusty1s's avatar
rusty1s committed
3
4
5
6
[testing-image]: https://github.com/rusty1s/pytorch_sparse/actions/workflows/testing.yml/badge.svg
[testing-url]: https://github.com/rusty1s/pytorch_sparse/actions/workflows/testing.yml
[linting-image]: https://github.com/rusty1s/pytorch_sparse/actions/workflows/linting.yml/badge.svg
[linting-url]: https://github.com/rusty1s/pytorch_sparse/actions/workflows/linting.yml
rusty1s's avatar
rusty1s committed
7
8
[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
9

rusty1s's avatar
rusty1s committed
10
# PyTorch Sparse
rusty1s's avatar
rusty1s committed
11
12

[![PyPI Version][pypi-image]][pypi-url]
rusty1s's avatar
rusty1s committed
13
14
[![Testing Status][testing-image]][testing-url]
[![Linting Status][linting-image]][linting-url]
rusty1s's avatar
rusty1s committed
15
16
17
[![Code Coverage][coverage-image]][coverage-url]

--------------------------------------------------------------------------------
rusty1s's avatar
rusty1s committed
18

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

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

All included operations work on varying data types and are implemented both for CPU and GPU.
rusty1s's avatar
rusty1s committed
28
29
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
30
31
32

## Installation

rusty1s's avatar
rusty1s committed
33
34
### Anaconda

rusty1s's avatar
rusty1s committed
35
**Update:** You can now install `pytorch-sparse` via [Anaconda](https://anaconda.org/pyg/pytorch-sparse) for all major OS/PyTorch/CUDA combinations 🤗
rusty1s's avatar
rusty1s committed
36
37
38
Given that you have [`pytorch >= 1.8.0` installed](https://pytorch.org/get-started/locally/), simply run

```
rusty1s's avatar
rusty1s committed
39
conda install pytorch-sparse -c pyg
rusty1s's avatar
rusty1s committed
40
41
```

rusty1s's avatar
rusty1s committed
42
43
### Binaries

rusty1s's avatar
rusty1s committed
44
We alternatively provide pip wheels for all major OS/PyTorch/CUDA combinations, see [here](https://data.pyg.org/whl).
rusty1s's avatar
rusty1s committed
45

rusty1s's avatar
rusty1s committed
46
#### PyTorch 1.10.0
rusty1s's avatar
rusty1s committed
47

rusty1s's avatar
rusty1s committed
48
To install the binaries for PyTorch 1.10.0, simply run
rusty1s's avatar
rusty1s committed
49
50

```
rusty1s's avatar
rusty1s committed
51
pip install torch-scatter torch-sparse -f https://data.pyg.org/whl/torch-1.10.0+${CUDA}.html
rusty1s's avatar
rusty1s committed
52
53
```

rusty1s's avatar
rusty1s committed
54
where `${CUDA}` should be replaced by either `cpu`, `cu102`, or `cu113` depending on your PyTorch installation.
rusty1s's avatar
rusty1s committed
55

rusty1s's avatar
rusty1s committed
56
|             | `cpu` | `cu102` | `cu113` |
rusty1s's avatar
rusty1s committed
57
58
59
60
|-------------|-------|---------|---------|
| **Linux**   | ✅    | ✅      | ✅      |
| **Windows** | ✅    | ✅      | ✅      |
| **macOS**   | ✅    |         |         |
rusty1s's avatar
rusty1s committed
61

rusty1s's avatar
rusty1s committed
62
#### PyTorch 1.9.0/1.9.1
rusty1s's avatar
rusty1s committed
63

rusty1s's avatar
rusty1s committed
64
To install the binaries for PyTorch 1.9.0 and 1.9.1, simply run
rusty1s's avatar
rusty1s committed
65
66

```
rusty1s's avatar
rusty1s committed
67
pip install torch-scatter torch-sparse -f https://data.pyg.org/whl/torch-1.9.0+${CUDA}.html
rusty1s's avatar
rusty1s committed
68
69
```

rusty1s's avatar
rusty1s committed
70
where `${CUDA}` should be replaced by either `cpu`, `cu102`, or `cu111` depending on your PyTorch installation.
rusty1s's avatar
rusty1s committed
71

rusty1s's avatar
rusty1s committed
72
73
74
75
76
|             | `cpu` | `cu102` | `cu111` |
|-------------|-------|---------|---------|
| **Linux**   | ✅    | ✅      | ✅      |
| **Windows** | ✅    | ✅      | ✅      |
| **macOS**   | ✅    |         |         |
rusty1s's avatar
rusty1s committed
77

rusty1s's avatar
rusty1s committed
78
**Note:** Binaries of older versions are also provided for PyTorch 1.4.0, PyTorch 1.5.0, PyTorch 1.6.0, PyTorch 1.7.0/1.7.1 and PyTorch 1.8.0/1.8.1 (following the same procedure).
rusty1s's avatar
rusty1s committed
79
80
81

### From source

rusty1s's avatar
rusty1s committed
82
Ensure that at least PyTorch 1.7.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
83
84

```
rusty1s's avatar
rusty1s committed
85
$ python -c "import torch; print(torch.__version__)"
rusty1s's avatar
rusty1s committed
86
>>> 1.7.0
rusty1s's avatar
rusty1s committed
87

rusty1s's avatar
rusty1s committed
88
$ echo $PATH
rusty1s's avatar
rusty1s committed
89
>>> /usr/local/cuda/bin:...
rusty1s's avatar
rusty1s committed
90
91

$ echo $CPATH
rusty1s's avatar
rusty1s committed
92
>>> /usr/local/cuda/include:...
rusty1s's avatar
rusty1s committed
93
94
```

rusty1s's avatar
rusty1s committed
95
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
96
Note that METIS needs to be installed with 64 bit `IDXTYPEWIDTH` by changing `include/metis.h`.
rusty1s's avatar
rusty1s committed
97
Afterwards, set the environment variable `WITH_METIS=1`.
rusty1s's avatar
rusty1s committed
98

rusty1s's avatar
rusty1s committed
99
100
101
Then run:

```
rusty1s's avatar
rusty1s committed
102
pip install torch-scatter torch-sparse
rusty1s's avatar
rusty1s committed
103
104
```

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

```
rusty1s's avatar
rusty1s committed
109
export TORCH_CUDA_ARCH_LIST="6.0 6.1 7.2+PTX 7.5+PTX"
rusty1s's avatar
rusty1s committed
110
111
112
```

## Functions
rusty1s's avatar
links  
rusty1s committed
113

rusty1s's avatar
rusty1s committed
114
### Coalesce
rusty1s's avatar
rusty1s committed
115

rusty1s's avatar
docs  
rusty1s committed
116
```
rusty1s's avatar
rusty1s committed
117
torch_sparse.coalesce(index, value, m, n, op="add") -> (torch.LongTensor, torch.Tensor)
rusty1s's avatar
docs  
rusty1s committed
118
119
```

120
Row-wise sorts `index` and removes duplicate entries.
rusty1s's avatar
rusty1s committed
121
122
123
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
124
#### Parameters
rusty1s's avatar
rusty1s committed
125
126
127

* **index** *(LongTensor)* - The index tensor of sparse matrix.
* **value** *(Tensor)* - The value tensor of sparse matrix.
wang-ps's avatar
wang-ps committed
128
129
* **m** *(int)* - The first dimension of sparse matrix.
* **n** *(int)* - The second dimension of sparse matrix.
rusty1s's avatar
docs  
rusty1s committed
130
* **op** *(string, optional)* - The scatter operation to use. (default: `"add"`)
rusty1s's avatar
rusty1s committed
131

rusty1s's avatar
rusty1s committed
132
#### Returns
rusty1s's avatar
rusty1s committed
133

rusty1s's avatar
docs  
rusty1s committed
134
135
* **index** *(LongTensor)* - The coalesced index tensor of sparse matrix.
* **value** *(Tensor)* - The coalesced value tensor of sparse matrix.
rusty1s's avatar
rusty1s committed
136

rusty1s's avatar
rusty1s committed
137
#### Example
rusty1s's avatar
docs  
rusty1s committed
138
139

```python
ekka's avatar
ekka committed
140
import torch
rusty1s's avatar
rusty1s committed
141
142
143
144
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
145
value = torch.Tensor([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7]])
rusty1s's avatar
docs  
rusty1s committed
146

rusty1s's avatar
rusty1s committed
147
index, value = coalesce(index, value, m=3, n=2)
rusty1s's avatar
docs  
rusty1s committed
148
149
```

rusty1s's avatar
rusty1s committed
150
151
152
153
154
```
print(index)
tensor([[0, 1, 1, 2],
        [1, 0, 1, 0]])
print(value)
rusty1s's avatar
rusty1s committed
155
156
157
158
tensor([[6.0, 8.0],
        [7.0, 9.0],
        [3.0, 4.0],
        [5.0, 6.0]])
rusty1s's avatar
rusty1s committed
159
```
rusty1s's avatar
docs  
rusty1s committed
160

rusty1s's avatar
rusty1s committed
161
### Transpose
rusty1s's avatar
rusty1s committed
162

rusty1s's avatar
docs  
rusty1s committed
163
```
rusty1s's avatar
rusty1s committed
164
torch_sparse.transpose(index, value, m, n) -> (torch.LongTensor, torch.Tensor)
rusty1s's avatar
docs  
rusty1s committed
165
166
```

rusty1s's avatar
rusty1s committed
167
168
Transposes dimensions 0 and 1 of a sparse matrix.

rusty1s's avatar
rusty1s committed
169
#### Parameters
rusty1s's avatar
rusty1s committed
170
171
172

* **index** *(LongTensor)* - The index tensor of sparse matrix.
* **value** *(Tensor)* - The value tensor of sparse matrix.
wang-ps's avatar
wang-ps committed
173
174
* **m** *(int)* - The first dimension of sparse matrix.
* **n** *(int)* - The second dimension of sparse matrix.
rusty1s's avatar
typo  
rusty1s committed
175
* **coalesced** *(bool, optional)* - If set to `False`, will not coalesce the output. (default: `True`)
rusty1s's avatar
rusty1s committed
176

rusty1s's avatar
rusty1s committed
177
#### Returns
rusty1s's avatar
rusty1s committed
178

rusty1s's avatar
docs  
rusty1s committed
179
180
* **index** *(LongTensor)* - The transposed index tensor of sparse matrix.
* **value** *(Tensor)* - The transposed value tensor of sparse matrix.
rusty1s's avatar
rusty1s committed
181

rusty1s's avatar
rusty1s committed
182
#### Example
rusty1s's avatar
docs  
rusty1s committed
183
184

```python
ekka's avatar
ekka committed
185
import torch
rusty1s's avatar
rusty1s committed
186
187
188
189
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
190
value = torch.Tensor([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7]])
rusty1s's avatar
docs  
rusty1s committed
191

rusty1s's avatar
docs  
rusty1s committed
192
index, value = transpose(index, value, 3, 2)
rusty1s's avatar
docs  
rusty1s committed
193
194
```

rusty1s's avatar
rusty1s committed
195
196
197
198
199
```
print(index)
tensor([[0, 0, 1, 1],
        [1, 2, 0, 1]])
print(value)
rusty1s's avatar
rusty1s committed
200
201
202
203
tensor([[7.0, 9.0],
        [5.0, 6.0],
        [6.0, 8.0],
        [3.0, 4.0]])
rusty1s's avatar
rusty1s committed
204
```
rusty1s's avatar
docs  
rusty1s committed
205

rusty1s's avatar
rusty1s committed
206
### Sparse Dense Matrix Multiplication
rusty1s's avatar
rusty1s committed
207

rusty1s's avatar
docs  
rusty1s committed
208
```
209
torch_sparse.spmm(index, value, m, n, matrix) -> torch.Tensor
rusty1s's avatar
docs  
rusty1s committed
210
211
```

rusty1s's avatar
rusty1s committed
212
213
Matrix product of a sparse matrix with a dense matrix.

rusty1s's avatar
rusty1s committed
214
#### Parameters
rusty1s's avatar
docs  
rusty1s committed
215

rusty1s's avatar
rusty1s committed
216
217
* **index** *(LongTensor)* - The index tensor of sparse matrix.
* **value** *(Tensor)* - The value tensor of sparse matrix.
wang-ps's avatar
wang-ps committed
218
219
* **m** *(int)* - The first dimension of sparse matrix.
* **n** *(int)* - The second dimension of sparse matrix.
rusty1s's avatar
docs  
rusty1s committed
220
* **matrix** *(Tensor)* - The dense matrix.
rusty1s's avatar
rusty1s committed
221

rusty1s's avatar
rusty1s committed
222
#### Returns
rusty1s's avatar
rusty1s committed
223

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

rusty1s's avatar
rusty1s committed
226
#### Example
rusty1s's avatar
rusty1s committed
227
228

```python
ekka's avatar
ekka committed
229
import torch
rusty1s's avatar
rusty1s committed
230
231
232
233
from torch_sparse import spmm

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

rusty1s's avatar
rusty1s committed
237
out = spmm(index, value, 3, 3, matrix)
rusty1s's avatar
rusty1s committed
238
239
240
241
```

```
print(out)
242
243
244
tensor([[7.0, 16.0],
        [8.0, 20.0],
        [7.0, 19.0]])
rusty1s's avatar
docs  
rusty1s committed
245
```
rusty1s's avatar
rusty1s committed
246

rusty1s's avatar
rusty1s committed
247
### Sparse Sparse Matrix Multiplication
rusty1s's avatar
rusty1s committed
248
249
250
251
252
253

```
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
254
Both input sparse matrices need to be **coalesced** (use the `coalesced` attribute to force).
rusty1s's avatar
rusty1s committed
255

rusty1s's avatar
rusty1s committed
256
#### Parameters
rusty1s's avatar
rusty1s committed
257
258
259
260
261

* **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.
wang-ps's avatar
wang-ps committed
262
263
264
* **m** *(int)* - The first dimension of first sparse matrix.
* **k** *(int)* - The second dimension of first sparse matrix and first dimension of second sparse matrix.
* **n** *(int)* - The second dimension of second sparse matrix.
rusty1s's avatar
typo  
rusty1s committed
265
* **coalesced** *(bool, optional)*: If set to `True`, will coalesce both input sparse matrices. (default: `False`)
rusty1s's avatar
rusty1s committed
266

rusty1s's avatar
rusty1s committed
267
#### Returns
rusty1s's avatar
rusty1s committed
268

rusty1s's avatar
docs  
rusty1s committed
269
270
* **index** *(LongTensor)* - The output index tensor of sparse matrix.
* **value** *(Tensor)* - The output value tensor of sparse matrix.
rusty1s's avatar
rusty1s committed
271

rusty1s's avatar
rusty1s committed
272
#### Example
rusty1s's avatar
rusty1s committed
273
274

```python
ekka's avatar
ekka committed
275
import torch
rusty1s's avatar
docs  
rusty1s committed
276
277
from torch_sparse import spspmm

rusty1s's avatar
rusty1s committed
278
indexA = torch.tensor([[0, 0, 1, 2, 2], [1, 2, 0, 0, 1]])
rusty1s's avatar
rusty1s committed
279
valueA = torch.Tensor([1, 2, 3, 4, 5])
rusty1s's avatar
rusty1s committed
280
281

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

rusty1s's avatar
rusty1s committed
284
285
286
287
indexC, valueC = spspmm(indexA, valueA, indexB, valueB, 3, 3, 2)
```

```
ekka's avatar
ekka committed
288
print(indexC)
rusty1s's avatar
rusty1s committed
289
290
tensor([[0, 1, 2],
        [0, 1, 1]])
ekka's avatar
ekka committed
291
print(valueC)
292
tensor([8.0, 6.0, 8.0])
rusty1s's avatar
docs  
rusty1s committed
293
294
```

rusty1s's avatar
rusty1s committed
295
296
297
298
299
300
301
302
303
304
305
306
307
## 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
308
309
310
311
312
## Running tests

```
python setup.py test
```