Skip to content

Add a graph learning module #57

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 134 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
1ee85b5
attempt to refactor nn graph building
naspert Mar 19, 2018
4bacd5c
update tests
naspert Mar 19, 2018
00bbcdd
fix typo
naspert Mar 19, 2018
b822333
fix tests (avoiding not implemented combinations)
naspert Mar 19, 2018
38aebd0
- fix missing space after colon in dictionary
naspert Mar 19, 2018
524c60f
fix (matlab) GSP url
naspert Mar 19, 2018
ae83814
throw exception when using FLANN + max_dist (produces incorrect results)
naspert Mar 19, 2018
62fc0ce
update test case to fit FLANN & max_dist exception
naspert Mar 19, 2018
6f473fa
implement nn graph using pdist using radius
naspert Mar 20, 2018
25ec6d2
implement radius nn graph with flann
naspert Mar 20, 2018
96b628e
flann returns the squared distance when called with 'euclidean' dista…
naspert Mar 20, 2018
09bbff4
compute sqrt of list properly
naspert Mar 20, 2018
27b9a03
use cyflann instead of pyflann (radius search not working)
naspert Mar 20, 2018
8a1f9b9
check nn graphs building against pdist reference
naspert Mar 20, 2018
6e9e2ac
cyflann needs the flann library to be installed on the system
naspert Mar 20, 2018
811de06
check nn graphs building against pdist reference
naspert Mar 20, 2018
813fe39
backport stuff from cyflann branch
naspert Mar 20, 2018
4a4d597
flann should (mostly) work for knn graphs
naspert Mar 20, 2018
53dffc1
fix pdist warnings
naspert Mar 21, 2018
1309e92
implement and use scipy-ckdtree as default (faster than kdtree)
naspert Mar 21, 2018
90ae9a8
Merge remote-tracking branch 'origin-nas/nn_cyflann' into nn_refactor
naspert Mar 22, 2018
648fa91
backport README changes from master
naspert Mar 22, 2018
96fa5f6
Merge branch 'master' of https://github.com/epfl-lts2/pygsp into nn_r…
naspert Mar 22, 2018
c26e449
Merge branch 'master' into nn_refactor
naspert Mar 22, 2018
8e7c553
add nmslib
naspert Mar 23, 2018
b83e467
test flann when not on windows
naspert Mar 26, 2018
28b7858
use the same code to build sparse matrix for knn and radius
naspert Mar 29, 2018
188c4a6
building the graph with rescale/center=False should also work
naspert Mar 29, 2018
59c131a
Merge pull request #1 from naspert/nmslib
naspert Mar 29, 2018
8e98b77
update doc for nmslib
naspert Mar 29, 2018
08ae29f
enable multithreading with ckdtree/nmslib
naspert Apr 9, 2018
57e9661
Merge branch 'master' into nn_refactor
naspert Jun 20, 2018
a562896
fix _get_extra_repr
naspert Jun 20, 2018
f69c694
Merge branch 'nn_refactor' of https://github.com/naspert/pygsp into n…
mdeff Feb 8, 2019
441341f
Merge branch 'master' into naspert-nn_refactor
mdeff Feb 13, 2019
8a51649
NNGraph: clean and doc (PR #21)
mdeff Feb 14, 2019
9b5d8c0
python 2.7 doesn't support keyword-only args
mdeff Feb 14, 2019
720646e
simplify test_nngraph (PR #21)
mdeff Feb 15, 2019
172d83f
python 2.7 doesn't support dict unpacking
mdeff Feb 15, 2019
be16da9
correct number of edges (PR #21)
mdeff Feb 15, 2019
a879818
order=3 by default (order=0 is not supported by all backends)
mdeff Feb 15, 2019
719d397
avoid deprecation warning
mdeff Feb 15, 2019
eb2ab0b
deal with empty neighborhood
mdeff Feb 15, 2019
b2bfb51
nngraph: don't store features
mdeff Feb 15, 2019
e1879ee
nngraph: further cleanup
mdeff Feb 15, 2019
bf7427f
nngraph: standardize instead of center and rescale
mdeff Feb 15, 2019
ec74ed7
nngraph: simplify default kernel_width
mdeff Feb 16, 2019
c1e1148
nngraph: test empty graph
mdeff Feb 16, 2019
57ce98c
no assertLogs in python 2.7
mdeff Feb 16, 2019
695272b
nngraph: fix symmetrization
mdeff Feb 16, 2019
505e456
nngraph: fix radius cKDTree (PR #21)
mdeff Feb 16, 2019
204ad19
compact code
mdeff Feb 19, 2019
2b25337
NNGraph: allow user to pass parameters to backends
mdeff Feb 19, 2019
8cc3539
fix flann distances
mdeff Feb 19, 2019
ebc5c05
NNGraph: test consistency across backends
mdeff Feb 19, 2019
1167f52
python 2.7 dict unpacking
mdeff Feb 19, 2019
3638cfd
pdist accepts no parameters
mdeff Feb 19, 2019
9b663aa
NNGraph: test distance on a circle
mdeff Feb 20, 2019
4af4118
NNGraph pdist: don't sort twice
mdeff Feb 20, 2019
624af23
NNGraph: fuse knn and radius implementations
mdeff Feb 20, 2019
043579e
nmslib: number of thread is automatically set to max
mdeff Feb 20, 2019
1d22376
order consistent with metric
mdeff Feb 20, 2019
0763076
cleaner error handling
mdeff Feb 20, 2019
3f0c2b5
nngraph: test standardization
mdeff Feb 20, 2019
26e12e3
nngraph: radius estimation
mdeff Feb 20, 2019
080bb5c
fix others uses of radius
mdeff Feb 21, 2019
dad4105
nngraph: check shape of features
mdeff Feb 24, 2019
f544e1e
nngraph: fix definition of gaussian kernel
mdeff Feb 24, 2019
9c8e86e
nngraph: allow users to choose the similarity kernel
mdeff Feb 24, 2019
bfef548
nngraph: fix attributes
mdeff Feb 24, 2019
5c2e856
nngraph: fix intermittent test failure of nmslib
mdeff Feb 24, 2019
af5aeca
nngraph: width = radius / 2
mdeff Feb 24, 2019
0fc8fd1
nngraph: doc and examples
mdeff Feb 25, 2019
cbb2537
nngraph: update history
mdeff Feb 25, 2019
1da0e55
Update nngraph.py
nperraud Feb 25, 2019
17dc1c6
nngraph: only warn for similarity > 1
mdeff Mar 1, 2019
ad5caee
show original exception if nmslib cannot be imported
mdeff Mar 13, 2019
fc043fe
backup commit
nperraud Jul 18, 2019
bb8133c
working sparse solution
nperraud Jul 18, 2019
f9cc066
add nn support
nperraud Jul 22, 2019
29d6fa6
make test work
nperraud Jul 22, 2019
8913359
Merge branch 'naspert-nn_refactor' into learngraphnew
nperraud Jul 22, 2019
5818eb0
backup commit
nperraud Jul 22, 2019
280ae3c
fix tests
nperraud Jul 22, 2019
0b1242b
make k=4 to pass tests
nperraud Jul 22, 2019
ddc290e
test
nperraud Jul 25, 2019
9ad6bff
making test pass -- not very clean nn function
nperraud Jul 26, 2019
17e24a7
update tests
nperraud Aug 16, 2019
d8d8903
Merge branch 'naspert-nn_refactor' into learngraphnew
nperraud Aug 16, 2019
d933292
Merge branch 'master' into naspert-nn_refactor
nperraud Aug 17, 2019
b308bfa
going further
nperraud Aug 17, 2019
b25b3ba
small fix
nperraud Aug 17, 2019
8e2ff0e
fix doc
nperraud Aug 17, 2019
74ea306
fix test
nperraud Aug 17, 2019
cc78ff2
fix test
nperraud Aug 17, 2019
92b6fbb
fix test_graphs
nperraud Aug 17, 2019
152bfae
update reduction
nperraud Aug 19, 2019
4df48c8
Merge branch 'naspert-nn_refactor' into learngraphnew
nperraud Aug 19, 2019
8a0f869
move files
nperraud Aug 19, 2019
594e048
first version
nperraud Aug 19, 2019
b6f9da6
update graph
nperraud Aug 19, 2019
8596081
updates
nperraud Aug 19, 2019
ec3d535
fix bugs
nperraud Aug 19, 2019
33e5b8e
update doc
nperraud Aug 19, 2019
5015731
update history
nperraud Aug 19, 2019
0d0aff7
small fix
nperraud Aug 19, 2019
e37171a
update doc
nperraud Aug 19, 2019
b3c8efe
add code to test each module separatly
nperraud Aug 19, 2019
3ed33f9
fix doc
nperraud Aug 19, 2019
af9845e
fix some doc
nperraud Aug 19, 2019
57269fc
fix tests
nperraud Aug 19, 2019
9e2b382
fix compat python 2.7
nperraud Aug 19, 2019
5af2527
fix compat python 2.7
nperraud Aug 19, 2019
0b14b4a
fix compat python 2.7
nperraud Aug 19, 2019
3e7daa2
fix random test
nperraud Aug 19, 2019
c0ee54c
Update learngraph.py
nperraud Sep 26, 2019
3212350
Merge branch 'master' into naspert-nn_refactor
mdeff Nov 9, 2019
28c85fb
update test and remove useless files
nperraud Nov 10, 2019
97ab20c
small fix in import
nperraud Nov 10, 2019
1f83d68
update seed
nperraud Nov 10, 2019
3c18c10
update seed
nperraud Nov 10, 2019
3bdbfc0
minor fix in playground.ipynb
kalofolias Nov 11, 2019
4842e91
Merge remote-tracking branch 'origin/naspert-nn_refactor' into learng…
nperraud Nov 15, 2019
23d51d9
rename
nperraud Nov 15, 2019
84613ef
hack my way through renaming
nperraud Nov 15, 2019
27ed937
fix import
nperraud Nov 15, 2019
264ea39
Merge branch 'learngraphnew' of github.com:epfl-lts2/pygsp into learn…
kalofolias Nov 16, 2019
7b732b6
Big bug in graph learning: Z needs **squared** Euclidean distances
kalofolias Nov 17, 2019
60f8e5f
Allow to set manually edge_mask in LearnedFromSmoothSignals
kalofolias Mar 29, 2020
2e80742
fix square bug
nperraud May 14, 2020
6005c13
Update learned.py
nperraud May 15, 2020
e69158c
minor exception fix
kalofolias Jun 21, 2020
2e28767
solve merge conflict: kept my version that is more detailed
kalofolias Jun 21, 2020
309f304
Merge branch 'master' into learngraphnew
nperraud Jun 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ addons:
- ubuntu-toolchain-r-test
- sourceline: 'deb http://downloads.skewed.de/apt/trusty trusty universe'
packages:
- libqt5gui5 # pyqt5>5.11 otherwise cannot load the xcb platform plugin
- libflann-dev
- python3-graph-tool
- python-graph-tool
- libqt5gui5 # pyqt5>5.11 fails to load the xcb platform plugin without it

install:
- pip install --upgrade pip setuptools wheel # install with latest tools
Expand Down
9 changes: 9 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ A (mostly unmaintained) `Matlab version <https://epfl-lts2.github.io/gspbox-html
.. |conda| image:: https://anaconda.org/conda-forge/pygsp/badges/installer/conda.svg
:target: https://anaconda.org/conda-forge/pygsp


The PyGSP is a Python package to ease
`Signal Processing on Graphs <https://arxiv.org/abs/1211.0053>`_.
The documentation is available on
`Read the Docs <https://pygsp.readthedocs.io>`_
and development takes place on
`GitHub <https://github.com/epfl-lts2/pygsp>`_.
A (mostly unmaintained) `Matlab version <https://epfl-lts2.github.io/gspbox-html>`_ exists.

The PyGSP facilitates a wide variety of operations on graphs, like computing
their Fourier basis, filtering or interpolating signals, plotting graphs,
signals, and filters. Its core is spectral graph theory, and many of the
Expand Down
5 changes: 5 additions & 0 deletions doc/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,17 @@ Unreleased
* New implementation of the Sensor graph that is simpler and scales better.
* A new learning module with three functions to solve standard semi-supervised
classification and regression problems.
* A much improved, fixed, documented, and tested NNGraph. The user can now
select the backend and similarity kernel. The radius can be estimated and
features standardized. (PR #43)
* Import and export graphs and their signals to NetworkX and graph-tool.
* Save and load graphs and theirs signals to / from GraphML, GML, and GEXF.
* Documentation: path graph linked to DCT, ring graph linked to DFT.
* We now have a gallery of examples! That is convenient for users to get a
taste of what the library can do, and to start working from a code snippet.
* Merged all the extra requirements in a single dev requirement.
* A function to learn the graph from the signal has been added with doc and tests.
This function can be used simply using the graph ``LearnGraph``

Experimental filter API (to be tested and validated):

Expand Down
17 changes: 17 additions & 0 deletions doc/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,20 @@ @article{grassi2018timevertex
year={2018},
journal={IEEE Transactions on Signal Processing},
}

@inproceedings{
kalofolias2018large,
title={Large Scale Graph Learning From Smooth Signals},
author={Vassilis Kalofolias and Nathanaël Perraudin},
booktitle={International Conference on Learning Representations},
year={2019},
url={https://openreview.net/forum?id=ryGkSo0qYm},
}

@inproceedings{kalofolias2016learn,
title={How to learn a graph from smooth signals},
author={Kalofolias, Vassilis},
booktitle={Artificial Intelligence and Statistics},
pages={920--929},
year={2016}
}
139 changes: 139 additions & 0 deletions doc/tutorials/graph_learning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import numpy as np
import pygsp
from matplotlib import pyplot as plt

#%%
n_signals = 4
def f1(x, y): return (-np.sin((2-x-y)**2)/2 + np.cos(y*3))/2
def f2(x, y): return np.cos((x+y)**2);
def f3(x, y): return ((x-.5)**2 + (y-.5)**3 + x - y)*3;
def f4(x, y): return np.sin(3*((x-.5)**2+(y-.5)**2));



#%%
n_nodes = 300
coords = np.random.uniform(size=(n_nodes, 2))

# the vectors of smooth signals will be stored as columns of X
X = np.zeros((n_nodes, n_signals))
for i, f in enumerate((f1, f2, f3, f4)):
X[:, i] = f(coords[:, 0], coords[:, 1])



#%%
plt.figure(figsize=(16, 10))
for i, f in enumerate((f1, f2, f3, f4)):
plt.subplot(2, 2, i+1);
plt.scatter(coords[:, 0], coords[:, 1], 500, X[:, i], '.');
plt.title('smooth signal {}'.format(i+1));
plt.axis('off');
plt.colorbar();


#%%

k = 5
param_opt = {'maxit':2000}

G1 = pygsp.graphs.LearnedFromSmoothSignals(X[:, 0], coords=coords, k=k, param_opt=param_opt)
G2 = pygsp.graphs.LearnedFromSmoothSignals(X[:, 1], coords=coords, k=k, param_opt=param_opt)
G3 = pygsp.graphs.LearnedFromSmoothSignals(X[:, 2], coords=coords, k=k, param_opt=param_opt)
G4 = pygsp.graphs.LearnedFromSmoothSignals(X[:, 3], coords=coords, k=k, param_opt=param_opt)

#%%


# G1.set_coordinates()
plt.figure(figsize=(18, 16))
for i, G in enumerate((G1, G2, G3, G4)):
_, _, weights = G.get_edge_list()
ax = plt.subplot(2, 2, i+1);
G.plot(vertex_size=50, edge_width=weights, ax=ax)
plt.xticks([])
plt.yticks([])
plt.title('n_vertices = {}, n_edges = {}, k = {:.1f}'.format(G.n_vertices, G.n_edges, G.n_edges * 2 / G.n_vertices))



#%%

G_all = pygsp.graphs.LearnedFromSmoothSignals(X, coords=coords, k=k, param_opt=param_opt)
plt.figure(figsize=(8, 6))
ax = plt.axes()
G_all.plot(vertex_size=0, ax=ax)
plt.xticks([]), plt.yticks([])
plt.title('n_vertices = {}, n_edges = {}, k = {:.1f}'.format(G_all.n_vertices, G_all.n_edges, G_all.n_edges * 2 / G_all.n_vertices))



#%%

G_coords = pygsp.graphs.LearnedFromSmoothSignals(coords, coords=coords, k=k, param_opt=param_opt)
plt.figure(figsize=(8, 6))
ax = plt.axes()
G_coords.plot(vertex_size=0, ax=ax, edges=True)




#%%


import scipy
Z = scipy.spatial.distance_matrix(X, X)**2
plt.imshow(Z)
print(np.count_nonzero(Z))
edge_mask = (Z < 1 / np.sqrt(n_nodes)).astype(np.int)
np.fill_diagonal(edge_mask, 0)
print(np.count_nonzero(edge_mask))
edge_mask[:3,:3]



#%%

G_all = pygsp.graphs.LearnedFromSmoothSignals(X, coords=coords, k=k,
param_opt=param_opt,
sparse=True, edge_mask=edge_mask)
plt.figure(figsize=(8, 6))
ax = plt.axes()
G_all.plot(vertex_size=0, ax=ax)
plt.xticks([]), plt.yticks([])
plt.title('n_vertices = {}, n_edges = {}, k = {:.1f}'.format(G_all.n_vertices, G_all.n_edges, G_all.n_edges * 2 / G_all.n_vertices))




#%%






#%%






#%%






#%%






#%%


4 changes: 2 additions & 2 deletions doc/tutorials/optimization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ We start with the graph TV regularization. We will use the :class:`pyunlocbox.so
>>> prob1 = pyunlocbox.solvers.solve([d, r, f], solver=solver,
... x0=x0, rtol=0, maxit=1000)
Solution found after 1000 iterations:
objective function f(sol) = 2.250584e+02
objective function f(sol) = 2.256055e+02
stopping criterion: MAXIT
>>>
>>> fig, ax = G.plot(prob1['sol'])
Expand All @@ -107,7 +107,7 @@ This figure shows the label signal recovered by graph total variation regulariza
>>> prob2 = pyunlocbox.solvers.solve([r, f], solver=solver,
... x0=x0, rtol=0, maxit=1000)
Solution found after 1000 iterations:
objective function f(sol) = 6.504290e+01
objective function f(sol) = 4.376481e+01
stopping criterion: MAXIT
>>>
>>> fig, ax = G.plot(prob2['sol'])
Expand Down
24 changes: 21 additions & 3 deletions playground.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"source": [
"G = graphs.Logo()\n",
"G.estimate_lmax()\n",
"g = filters.Heat(G, tau=100)"
"g = filters.Heat(G, scale=100)"
]
},
{
Expand Down Expand Up @@ -117,7 +117,25 @@
]
}
],
"metadata": {},
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
"nbformat_minor": 4
}
Loading