README.md 9.35 KB
Newer Older
rusty1s's avatar
rusty1s committed
1
2
[pypi-image]: https://badge.fury.io/py/torch-cluster.svg
[pypi-url]: https://pypi.python.org/pypi/torch-cluster
rusty1s's avatar
rusty1s committed
3
4
5
6
[testing-image]: https://github.com/rusty1s/pytorch_cluster/actions/workflows/testing.yml/badge.svg
[testing-url]: https://github.com/rusty1s/pytorch_cluster/actions/workflows/testing.yml
[linting-image]: https://github.com/rusty1s/pytorch_cluster/actions/workflows/linting.yml/badge.svg
[linting-url]: https://github.com/rusty1s/pytorch_cluster/actions/workflows/linting.yml
rusty1s's avatar
rusty1s committed
7
8
9
[coverage-image]: https://codecov.io/gh/rusty1s/pytorch_cluster/branch/master/graph/badge.svg
[coverage-url]: https://codecov.io/github/rusty1s/pytorch_cluster?branch=master

rusty1s's avatar
rusty1s committed
10
# PyTorch Cluster
rusty1s's avatar
rusty1s committed
11

rusty1s's avatar
rusty1s committed
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
[![Code Coverage][coverage-image]][coverage-url]

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

rusty1s's avatar
rusty1s committed
19
This package consists of a small extension library of highly optimized graph cluster algorithms for the use in [PyTorch](http://pytorch.org/).
rusty1s's avatar
typo  
rusty1s committed
20
The package consists of the following clustering algorithms:
rusty1s's avatar
rusty1s committed
21

rusty1s's avatar
credit  
rusty1s committed
22
* **[Graclus](#graclus)** from Dhillon *et al.*: [Weighted Graph Cuts without Eigenvectors: A Multilevel Approach](http://www.cs.utexas.edu/users/inderjit/public_papers/multilevel_pami.pdf) (PAMI 2007)
rusty1s's avatar
rusty1s committed
23
* **[Voxel Grid Pooling](#voxelgrid)** from, *e.g.*, Simonovsky and Komodakis: [Dynamic Edge-Conditioned Filters in Convolutional Neural Networks on Graphs](https://arxiv.org/abs/1704.02901) (CVPR 2017)
rusty1s's avatar
rusty1s committed
24
25
* **[Iterative Farthest Point Sampling](#farthestpointsampling)** from, *e.g.* Qi *et al.*: [PointNet++: Deep Hierarchical Feature Learning on Point Sets in a Metric Space](https://arxiv.org/abs/1706.02413) (NIPS 2017)
* **[k-NN](#knn-graph)** and **[Radius](#radius-graph)** graph generation
rusty1s's avatar
rusty1s committed
26
* Clustering based on **[Nearest](#nearest)** points
rusty1s's avatar
rusty1s committed
27
* **[Random Walk Sampling](#randomwalk-sampling)** from, *e.g.*, Grover and Leskovec: [node2vec: Scalable Feature Learning for Networks](https://arxiv.org/abs/1607.00653) (KDD 2016)
rusty1s's avatar
rusty1s committed
28
29
30
31
32

All included operations work on varying data types and are implemented both for CPU and GPU.

## Installation

rusty1s's avatar
rusty1s committed
33
34
35
### Binaries

We provide pip wheels for all major OS/PyTorch/CUDA combinations, see [here](https://s3.eu-central-1.amazonaws.com/pytorch-geometric.com/whl/index.html).
rusty1s's avatar
rusty1s committed
36

rusty1s's avatar
rusty1s committed
37
#### PyTorch 1.9.0
rusty1s's avatar
rusty1s committed
38

rusty1s's avatar
rusty1s committed
39
To install the binaries for PyTorch 1.9.0, simply run
rusty1s's avatar
rusty1s committed
40
41

```
rusty1s's avatar
rusty1s committed
42
pip install torch-cluster -f https://pytorch-geometric.com/whl/torch-1.9.0+${CUDA}.html
rusty1s's avatar
rusty1s committed
43
44
```

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

rusty1s's avatar
rusty1s committed
47
48
49
50
51
|             | `cpu` | `cu102` | `cu111` |
|-------------|-------|---------|---------|
| **Linux**   | ✅    | ✅      | ✅      |
| **Windows** | ✅    | ✅      | ✅      |
| **macOS**   | ✅    |         |         |
rusty1s's avatar
rusty1s committed
52

rusty1s's avatar
rusty1s committed
53
#### PyTorch 1.8.0/1.8.1
rusty1s's avatar
rusty1s committed
54

rusty1s's avatar
rusty1s committed
55
To install the binaries for PyTorch 1.8.0 and 1.8.1, simply run
rusty1s's avatar
rusty1s committed
56
57

```
rusty1s's avatar
rusty1s committed
58
pip install torch-cluster -f https://pytorch-geometric.com/whl/torch-1.8.0+${CUDA}.html
rusty1s's avatar
rusty1s committed
59
60
```

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

rusty1s's avatar
rusty1s committed
63
64
65
66
67
|             | `cpu` | `cu101` | `cu102` | `cu111` |
|-------------|-------|---------|---------|---------|
| **Linux**   | ✅    | ✅      | ✅      | ✅      |
| **Windows** | ✅    | ❌      | ✅      | ✅      |
| **macOS**   | ✅    |         |         |         |
rusty1s's avatar
rusty1s committed
68

rusty1s's avatar
rusty1s committed
69
**Note:** Binaries of older versions are also provided for PyTorch 1.4.0, PyTorch 1.5.0, PyTorch 1.6.0 and PyTorch 1.7.0/1.7.1 (following the same procedure).
rusty1s's avatar
rusty1s committed
70
71
72
73
74
75
76
77

### From source

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.*:

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

$ python -c "import torch; print(torch.__version__)"
rusty1s's avatar
rusty1s committed
80
>>> 1.1.0
rusty1s's avatar
rusty1s committed
81
82
83
84
85

$ echo $PATH
>>> /usr/local/cuda/bin:...

$ echo $CPATH
rusty1s's avatar
rusty1s committed
86
>>> /usr/local/cuda/include:...
rusty1s's avatar
rusty1s committed
87
88
```

rusty1s's avatar
rusty1s committed
89
90
91
Then run:

```
rusty1s's avatar
rusty1s committed
92
pip install torch-cluster
rusty1s's avatar
rusty1s committed
93
94
```

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

```
export TORCH_CUDA_ARCH_LIST = "6.0 6.1 7.2+PTX 7.5+PTX"
```

## Functions
rusty1s's avatar
rusty1s committed
103

rusty1s's avatar
rusty1s committed
104
### Graclus
rusty1s's avatar
rusty1s committed
105
106

A greedy clustering algorithm of picking an unmarked vertex and matching it with one its unmarked neighbors (that maximizes its edge weight).
rusty1s's avatar
credit  
rusty1s committed
107
The GPU algorithm is adapted from Fagginger Auer and Bisseling: [A GPU Algorithm for Greedy Graph Matching](http://www.staff.science.uu.nl/~bisse101/Articles/match12.pdf) (LNCS 2012)
rusty1s's avatar
rusty1s committed
108
109
110
111
112

```python
import torch
from torch_cluster import graclus_cluster

rusty1s's avatar
rusty1s committed
113
114
row = torch.tensor([0, 1, 1, 2])
col = torch.tensor([1, 0, 2, 1])
rusty1s's avatar
rusty1s committed
115
weight = torch.tensor([1., 1., 1., 1.])  # Optional edge weights.
rusty1s's avatar
rusty1s committed
116
117
118
119
120
121

cluster = graclus_cluster(row, col, weight)
```

```
print(cluster)
rusty1s's avatar
rusty1s committed
122
tensor([0, 0, 1])
rusty1s's avatar
rusty1s committed
123
124
```

rusty1s's avatar
rusty1s committed
125
### VoxelGrid
rusty1s's avatar
rusty1s committed
126
127

A clustering algorithm, which overlays a regular grid of user-defined size over a point cloud and clusters all points within a voxel.
rusty1s's avatar
rusty1s committed
128
129
130
131
132

```python
import torch
from torch_cluster import grid_cluster

rusty1s's avatar
rusty1s committed
133
pos = torch.tensor([[0., 0.], [11., 9.], [2., 8.], [2., 2.], [8., 3.]])
rusty1s's avatar
new api  
rusty1s committed
134
size = torch.Tensor([5, 5])
rusty1s's avatar
rusty1s committed
135
136
137
138
139
140

cluster = grid_cluster(pos, size)
```

```
print(cluster)
rusty1s's avatar
rusty1s committed
141
tensor([0, 5, 3, 0, 1])
rusty1s's avatar
rusty1s committed
142
```
rusty1s's avatar
rusty1s committed
143

rusty1s's avatar
rusty1s committed
144
### FarthestPointSampling
rusty1s's avatar
rusty1s committed
145

rusty1s's avatar
rusty1s committed
146
A sampling algorithm, which iteratively samples the most distant point with regard to the rest points.
rusty1s's avatar
rusty1s committed
147
148
149
150
151

```python
import torch
from torch_cluster import fps

rusty1s's avatar
rusty1s committed
152
x = torch.tensor([[-1., -1.], [-1., 1.], [1., -1.], [1., 1.]])
rusty1s's avatar
rusty1s committed
153
batch = torch.tensor([0, 0, 0, 0])
rusty1s's avatar
rusty1s committed
154
index = fps(x, batch, ratio=0.5, random_start=False)
rusty1s's avatar
rusty1s committed
155
156
157
```

```
JunZe Yu's avatar
JunZe Yu committed
158
print(index)
rusty1s's avatar
rusty1s committed
159
160
161
tensor([0, 3])
```

rusty1s's avatar
rusty1s committed
162
### kNN-Graph
rusty1s's avatar
rusty1s committed
163

rusty1s's avatar
rusty1s committed
164
Computes graph edges to the nearest *k* points.
rusty1s's avatar
rusty1s committed
165

166
167
168
**Args:**

* **x** *(Tensor)*: Node feature matrix of shape `[N, F]`.
luwei0917's avatar
luwei0917 committed
169
* **k** *(int)*: The number of neighbors.
170
171
172
173
174
175
* **batch** *(LongTensor, optional)*: Batch vector of shape `[N]`, which assigns each node to a specific example. `batch` needs to be sorted. (default: `None`)
* **loop** *(bool, optional)*: If `True`, the graph will contain self-loops. (default: `False`)
* **flow** *(string, optional)*: The flow direction when using in combination with message passing (`"source_to_target"` or `"target_to_source"`). (default: `"source_to_target"`)
* **cosine** *(boolean, optional)*: If `True`, will use the Cosine distance instead of Euclidean distance to find nearest neighbors. (default: `False`)
* **num_workers** *(int)*: Number of workers to use for computation. Has no effect in case `batch` is not `None`, or the input lies on the GPU. (default: `1`)

rusty1s's avatar
rusty1s committed
176
177
178
179
```python
import torch
from torch_cluster import knn_graph

rusty1s's avatar
rusty1s committed
180
x = torch.tensor([[-1., -1.], [-1., 1.], [1., -1.], [1., 1.]])
rusty1s's avatar
rusty1s committed
181
182
183
184
185
186
batch = torch.tensor([0, 0, 0, 0])
edge_index = knn_graph(x, k=2, batch=batch, loop=False)
```

```
print(edge_index)
Matthias Fey's avatar
Matthias Fey committed
187
188
tensor([[1, 2, 0, 3, 0, 3, 1, 2],
        [0, 0, 1, 1, 2, 2, 3, 3]])
rusty1s's avatar
rusty1s committed
189
190
```

rusty1s's avatar
rusty1s committed
191
### Radius-Graph
rusty1s's avatar
rusty1s committed
192

rusty1s's avatar
rusty1s committed
193
Computes graph edges to all points within a given distance.
rusty1s's avatar
rusty1s committed
194

195
196
197
198
199
200
**Args:**

* **x** *(Tensor)*: Node feature matrix of shape `[N, F]`.
* **r** *(float)*: The radius.
* **batch** *(LongTensor, optional)*: Batch vector of shape `[N]`, which assigns each node to a specific example. `batch` needs to be sorted. (default: `None`)
* **loop** *(bool, optional)*: If `True`, the graph will contain self-loops. (default: `False`)
rusty1s's avatar
rusty1s committed
201
* **max_num_neighbors** *(int, optional)*: The maximum number of neighbors to return for each element. If the number of actual neighbors is greater than `max_num_neighbors`, returned neighbors are picked randomly. (default: `32`)
202
203
204
* **flow** *(string, optional)*: The flow direction when using in combination with message passing (`"source_to_target"` or `"target_to_source"`). (default: `"source_to_target"`)
* **num_workers** *(int)*: Number of workers to use for computation. Has no effect in case `batch` is not `None`, or the input lies on the GPU. (default: `1`)

rusty1s's avatar
rusty1s committed
205
206
207
208
```python
import torch
from torch_cluster import radius_graph

rusty1s's avatar
rusty1s committed
209
x = torch.tensor([[-1., -1.], [-1., 1.], [1., -1.], [1., 1.]])
rusty1s's avatar
rusty1s committed
210
batch = torch.tensor([0, 0, 0, 0])
rusty1s's avatar
rusty1s committed
211
edge_index = radius_graph(x, r=2.5, batch=batch, loop=False)
rusty1s's avatar
rusty1s committed
212
213
214
215
```

```
print(edge_index)
Matthias Fey's avatar
Matthias Fey committed
216
217
tensor([[1, 2, 0, 3, 0, 3, 1, 2],
        [0, 0, 1, 1, 2, 2, 3, 3]])
rusty1s's avatar
rusty1s committed
218
219
```

rusty1s's avatar
rusty1s committed
220
### Nearest
rusty1s's avatar
rusty1s committed
221

rusty1s's avatar
rusty1s committed
222
Clusters points in *x* together which are nearest to a given query point in *y*.
rusty1s's avatar
rusty1s committed
223
`batch_{x,y}` vectors need to be sorted.
rusty1s's avatar
rusty1s committed
224
225
226
227
228
229

```python
import torch
from torch_cluster import nearest

x = torch.Tensor([[-1, -1], [-1, 1], [1, -1], [1, 1]])
rusty1s's avatar
rusty1s committed
230
231
232
233
batch_x = torch.tensor([0, 0, 0, 0])
y = torch.Tensor([[-1, 0], [1, 0]])
batch_y = torch.tensor([0, 0])
cluster = nearest(x, y, batch_x, batch_y)
rusty1s's avatar
rusty1s committed
234
235
236
237
238
239
240
```

```
print(cluster)
tensor([0, 0, 1, 1])
```

rusty1s's avatar
rusty1s committed
241
### RandomWalk-Sampling
rusty1s's avatar
rusty1s committed
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257

Samples random walks of length `walk_length` from all node indices in `start` in the graph given by `(row, col)`.

```python
import torch
from torch_cluster import random_walk

row = torch.tensor([0, 1, 1, 1, 2, 2, 3, 3, 4, 4])
col = torch.tensor([1, 0, 2, 3, 1, 4, 1, 4, 2, 3])
start = torch.tensor([0, 1, 2, 3, 4])

walk = random_walk(row, col, start, walk_length=3)
```

```
print(walk)
Maurits's avatar
Maurits committed
258
tensor([[0, 1, 2, 4],
rusty1s's avatar
rusty1s committed
259
        [1, 3, 4, 2],
Maurits's avatar
Maurits committed
260
261
262
        [2, 4, 2, 1],
        [3, 4, 2, 4],
        [4, 3, 1, 0]])
rusty1s's avatar
rusty1s committed
263
264
```

rusty1s's avatar
rusty1s committed
265
266
267
268
269
## Running tests

```
python setup.py test
```
rusty1s's avatar
rusty1s committed
270
271
272
273
274
275
276
277
278
279
280
281
282

## C++ API

`torch-cluster` 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
```