README.md 9.84 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.11
rusty1s's avatar
rusty1s committed
47

rusty1s's avatar
rusty1s committed
48
To install the binaries for PyTorch 1.11.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.11.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`, `cu113`, or `cu115` depending on your PyTorch installation.
rusty1s's avatar
rusty1s committed
55

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

rusty1s's avatar
rusty1s committed
62
#### PyTorch 1.10
rusty1s's avatar
rusty1s committed
63

rusty1s's avatar
rusty1s committed
64
To install the binaries for PyTorch 1.10.0, PyTorch 1.10.1 and PyTorch 1.10.2, 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.10.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`, `cu111`, or `cu113` depending on your PyTorch installation.
rusty1s's avatar
rusty1s committed
71

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

rusty1s's avatar
rusty1s committed
78
79
80
**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, PyTorch 1.8.0/1.8.1 and PyTorch 1.9.0 (following the same procedure).
For older versions, you might need to explicitly specify the latest supported version number in order to prevent a manual installation from source.
You can look up the latest supported version number [here](https://data.pyg.org/whl).
rusty1s's avatar
rusty1s committed
81
82
83

### From source

rusty1s's avatar
rusty1s committed
84
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
85
86

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

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

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

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

rusty1s's avatar
rusty1s committed
101
102
103
Then run:

```
rusty1s's avatar
rusty1s committed
104
pip install torch-scatter torch-sparse
rusty1s's avatar
rusty1s committed
105
106
```

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

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

## Functions
rusty1s's avatar
links  
rusty1s committed
115

rusty1s's avatar
rusty1s committed
116
### Coalesce
rusty1s's avatar
rusty1s committed
117

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

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

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

rusty1s's avatar
rusty1s committed
134
#### Returns
rusty1s's avatar
rusty1s committed
135

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

rusty1s's avatar
rusty1s committed
139
#### Example
rusty1s's avatar
docs  
rusty1s committed
140
141

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

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

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

rusty1s's avatar
rusty1s committed
163
### Transpose
rusty1s's avatar
rusty1s committed
164

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

rusty1s's avatar
rusty1s committed
169
170
Transposes dimensions 0 and 1 of a sparse matrix.

rusty1s's avatar
rusty1s committed
171
#### Parameters
rusty1s's avatar
rusty1s committed
172
173
174

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

rusty1s's avatar
rusty1s committed
179
#### Returns
rusty1s's avatar
rusty1s committed
180

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

rusty1s's avatar
rusty1s committed
184
#### Example
rusty1s's avatar
docs  
rusty1s committed
185
186

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

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

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

rusty1s's avatar
rusty1s committed
208
### Sparse Dense Matrix Multiplication
rusty1s's avatar
rusty1s committed
209

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

rusty1s's avatar
rusty1s committed
214
215
Matrix product of a sparse matrix with a dense matrix.

rusty1s's avatar
rusty1s committed
216
#### Parameters
rusty1s's avatar
docs  
rusty1s committed
217

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

rusty1s's avatar
rusty1s committed
224
#### Returns
rusty1s's avatar
rusty1s committed
225

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

rusty1s's avatar
rusty1s committed
228
#### Example
rusty1s's avatar
rusty1s committed
229
230

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

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

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

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

rusty1s's avatar
rusty1s committed
249
### Sparse Sparse Matrix Multiplication
rusty1s's avatar
rusty1s committed
250
251
252
253
254
255

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

rusty1s's avatar
rusty1s committed
258
#### Parameters
rusty1s's avatar
rusty1s committed
259
260
261
262
263

* **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
264
265
266
* **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
267
* **coalesced** *(bool, optional)*: If set to `True`, will coalesce both input sparse matrices. (default: `False`)
rusty1s's avatar
rusty1s committed
268

rusty1s's avatar
rusty1s committed
269
#### Returns
rusty1s's avatar
rusty1s committed
270

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

rusty1s's avatar
rusty1s committed
274
#### Example
rusty1s's avatar
rusty1s committed
275
276

```python
ekka's avatar
ekka committed
277
import torch
rusty1s's avatar
docs  
rusty1s committed
278
279
from torch_sparse import spspmm

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

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

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

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

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

```
rusty1s's avatar
rusty1s committed
313
pytest
rusty1s's avatar
rusty1s committed
314
```