README.md 5.5 KB
Newer Older
rusty1s's avatar
rusty1s committed
1
2
3
4
5
6
7
[pypi-image]: https://badge.fury.io/py/torch-cluster.svg
[pypi-url]: https://pypi.python.org/pypi/torch-cluster
[build-image]: https://travis-ci.org/rusty1s/pytorch_cluster.svg?branch=master
[build-url]: https://travis-ci.org/rusty1s/pytorch_cluster
[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
8
# PyTorch Cluster
rusty1s's avatar
rusty1s committed
9

rusty1s's avatar
rusty1s committed
10
11
12
13
[![PyPI Version][pypi-image]][pypi-url]
[![Build Status][build-image]][build-url]
[![Code Coverage][coverage-image]][coverage-url]

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

rusty1s's avatar
rusty1s committed
16
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
17
The package consists of the following clustering algorithms:
rusty1s's avatar
rusty1s committed
18

rusty1s's avatar
credit  
rusty1s committed
19
* **[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
20
* **[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
21
22
* **[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
23
* Clustering based on **[Nearest](#nearest)** points
rusty1s's avatar
rusty1s committed
24
* **[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
25
26
27
28
29

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

## Installation

rusty1s's avatar
rusty1s committed
30
Ensure that at least PyTorch 1.1.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
31
32
33

```
$ python -c "import torch; print(torch.__version__)"
rusty1s's avatar
rusty1s committed
34
>>> 1.1.0
rusty1s's avatar
rusty1s committed
35
36
37
38
39

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

$ echo $CPATH
rusty1s's avatar
rusty1s committed
40
>>> /usr/local/cuda/include:...
rusty1s's avatar
rusty1s committed
41
42
```

rusty1s's avatar
rusty1s committed
43
44
45
Then run:

```
rusty1s's avatar
rusty1s committed
46
pip install torch-cluster
rusty1s's avatar
rusty1s committed
47
48
```

rusty1s's avatar
rusty1s committed
49
If you are running into any installation problems, please create an [issue](https://github.com/rusty1s/pytorch_cluster/issues).
rusty1s's avatar
rusty1s committed
50
Be sure to import `torch` first before using this package to resolve symbols the dynamic linker must see.
rusty1s's avatar
rusty1s committed
51

rusty1s's avatar
rusty1s committed
52
53
54
## Graclus

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
55
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
56
57
58
59
60

```python
import torch
from torch_cluster import graclus_cluster

rusty1s's avatar
rusty1s committed
61
62
row = torch.tensor([0, 1, 1, 2])
col = torch.tensor([1, 0, 2, 1])
rusty1s's avatar
new api  
rusty1s committed
63
weight = torch.Tensor([1, 1, 1, 1])  # Optional edge weights.
rusty1s's avatar
rusty1s committed
64
65
66
67
68
69

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

```
print(cluster)
rusty1s's avatar
rusty1s committed
70
tensor([0, 0, 1])
rusty1s's avatar
rusty1s committed
71
72
```

rusty1s's avatar
rusty1s committed
73
74
75
## VoxelGrid

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
76
77
78
79
80

```python
import torch
from torch_cluster import grid_cluster

rusty1s's avatar
new api  
rusty1s committed
81
82
pos = torch.Tensor([[0, 0], [11, 9], [2, 8], [2, 2], [8, 3]])
size = torch.Tensor([5, 5])
rusty1s's avatar
rusty1s committed
83
84
85
86
87
88

cluster = grid_cluster(pos, size)
```

```
print(cluster)
rusty1s's avatar
rusty1s committed
89
tensor([0, 5, 3, 0, 1])
rusty1s's avatar
rusty1s committed
90
```
rusty1s's avatar
rusty1s committed
91

rusty1s's avatar
rusty1s committed
92
93
## FarthestPointSampling

rusty1s's avatar
rusty1s committed
94
A sampling algorithm, which iteratively samples the most distant point with regard to the rest points.
rusty1s's avatar
rusty1s committed
95
96
97
98
99
100
101

```python
import torch
from torch_cluster import fps

x = torch.Tensor([[-1, -1], [-1, 1], [1, -1], [1, 1]])
batch = torch.tensor([0, 0, 0, 0])
rusty1s's avatar
rusty1s committed
102
index = fps(x, batch, ratio=0.5, random_start=False)
rusty1s's avatar
rusty1s committed
103
104
105
106
107
108
109
110
111
```

```
print(sample)
tensor([0, 3])
```

## kNN-Graph

rusty1s's avatar
rusty1s committed
112
Computes graph edges to the nearest *k* points.
rusty1s's avatar
rusty1s committed
113
114
115
116
117
118
119
120
121
122
123
124

```python
import torch
from torch_cluster import knn_graph

x = torch.Tensor([[-1, -1], [-1, 1], [1, -1], [1, 1]])
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
125
126
tensor([[1, 2, 0, 3, 0, 3, 1, 2],
        [0, 0, 1, 1, 2, 2, 3, 3]])
rusty1s's avatar
rusty1s committed
127
128
129
130
```

## Radius-Graph

rusty1s's avatar
rusty1s committed
131
Computes graph edges to all points within a given distance.
rusty1s's avatar
rusty1s committed
132
133
134
135
136
137
138
139
140
141
142
143

```python
import torch
from torch_cluster import radius_graph

x = torch.Tensor([[-1, -1], [-1, 1], [1, -1], [1, 1]])
batch = torch.tensor([0, 0, 0, 0])
edge_index = radius_graph(x, r=1.5, batch=batch, loop=False)
```

```
print(edge_index)
Matthias Fey's avatar
Matthias Fey committed
144
145
tensor([[1, 2, 0, 3, 0, 3, 1, 2],
        [0, 0, 1, 1, 2, 2, 3, 3]])
rusty1s's avatar
rusty1s committed
146
147
```

rusty1s's avatar
rusty1s committed
148
149
## Nearest

rusty1s's avatar
rusty1s committed
150
Clusters points in *x* together which are nearest to a given query point in *y*.
rusty1s's avatar
rusty1s committed
151
152
153
154
155
156

```python
import torch
from torch_cluster import nearest

x = torch.Tensor([[-1, -1], [-1, 1], [1, -1], [1, 1]])
rusty1s's avatar
rusty1s committed
157
158
159
160
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
161
162
163
164
165
166
167
```

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

rusty1s's avatar
rusty1s committed
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
## RandomWalk-Sampling

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
185
tensor([[0, 1, 2, 4],
rusty1s's avatar
rusty1s committed
186
        [1, 3, 4, 2],
Maurits's avatar
Maurits committed
187
188
189
        [2, 4, 2, 1],
        [3, 4, 2, 4],
        [4, 3, 1, 0]])
rusty1s's avatar
rusty1s committed
190
191
```

rusty1s's avatar
rusty1s committed
192
193
194
195
196
## Running tests

```
python setup.py test
```