Skip to content
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

much improved NN graph #43

Open
wants to merge 92 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 74 commits
Commits
Show all changes
92 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
f9cc066
add nn support
nperraud Jul 22, 2019
29d6fa6
make test work
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
d933292
Merge branch 'master' into naspert-nn_refactor
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
3212350
Merge branch 'master' into naspert-nn_refactor
mdeff Nov 9, 2019
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 @@ -19,7 +19,8 @@ matrix:
addons:
apt:
packages:
- libqt5gui5 # pyqt5>5.11 fails to load the xcb platform plugin without it
- libqt5gui5 # pyqt5>5.11 otherwise cannot load the xcb platform plugin
- libflann-dev

install:
- pip install -U --upgrade-strategy eager .[alldeps,test,doc]
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ 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://lts2.epfl.ch/gsp>`_ exists.
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,
Expand Down
3 changes: 3 additions & 0 deletions doc/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ History
* 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)

Experimental filter API (to be tested and validated):

Expand Down
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
4 changes: 2 additions & 2 deletions pygsp/filters/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def filter(self, s, method='chebyshev', order=30):
>>> _ = G.plot(s1, ax=axes[0])
>>> _ = G.plot(s2, ax=axes[1])
>>> print('{:.5f}'.format(np.linalg.norm(s1 - s2)))
0.26808
0.26995

Perfect reconstruction with Itersine, a tight frame:

Expand Down Expand Up @@ -449,7 +449,7 @@ def estimate_frame_bounds(self, x=None):
A=1.708, B=2.359
>>> A, B = g.estimate_frame_bounds(G.e)
>>> print('A={:.3f}, B={:.3f}'.format(A, B))
A=1.723, B=2.359
A=1.839, B=2.359

The frame bounds can be seen in the plot of the filter bank as the
minimum and maximum of their squared sum (the black curve):
Expand Down
2 changes: 1 addition & 1 deletion pygsp/graphs/fourier.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def coherence(self):
>>> graph.compute_fourier_basis()
>>> minimum = 1 / np.sqrt(graph.n_vertices)
>>> print('{:.2f} in [{:.2f}, 1]'.format(graph.coherence, minimum))
0.88 in [0.12, 1]
0.91 in [0.12, 1]
>>>
>>> # Plot the most localized eigenvector.
>>> import matplotlib.pyplot as plt
Expand Down
4 changes: 1 addition & 3 deletions pygsp/graphs/nngraphs/bunny.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,5 @@ def __init__(self, **kwargs):
'distance': 8,
}

super(Bunny, self).__init__(Xin=data['bunny'],
epsilon=0.02, NNtype='radius',
center=False, rescale=False,
super(Bunny, self).__init__(data['bunny'], kind='radius', radius=0.02,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want a radius graph by default for the bunny?

Copy link
Collaborator Author

@mdeff mdeff Dec 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That comes from the matlab version. It was however updated to a kNN in version 0.7.0 epfl-lts2/gspbox@6079047. Do you think we should do it here too? If yes, a small PR with justification is best (if you remember why it was radius before and kNN now).

plotting=plotting, **kwargs)
17 changes: 9 additions & 8 deletions pygsp/graphs/nngraphs/cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ class Cube(NNGraph):

Parameters
----------
radius : float
Edge lenght (default = 1)
nb_pts : int
Number of vertices (default = 300)
nb_dim : int
Dimension (default = 3)
length : float
Edge length (default = 1)
sampling : string
Variance of the distance kernel (default = 'random')
(Can now only be 'random')
Expand All @@ -35,20 +35,23 @@ class Cube(NNGraph):
"""

def __init__(self,
radius=1,
nb_pts=300,
nb_dim=3,
length=1,
sampling='random',
seed=None,
**kwargs):

self.radius = radius
self.nb_pts = nb_pts
self.nb_dim = nb_dim
self.length = length
self.sampling = sampling
self.seed = seed
rs = np.random.RandomState(seed)

if length != 1:
raise NotImplementedError('Only length=1 is implemented.')

mdeff marked this conversation as resolved.
Show resolved Hide resolved
if self.nb_dim > 3:
raise NotImplementedError("Dimension > 3 not supported yet!")

Expand Down Expand Up @@ -89,12 +92,10 @@ def __init__(self,
'distance': 9,
}

super(Cube, self).__init__(Xin=pts, k=10,
center=False, rescale=False,
plotting=plotting, **kwargs)
super(Cube, self).__init__(pts, k=10, plotting=plotting, **kwargs)

def _get_extra_repr(self):
attrs = {'radius': '{:.2f}'.format(self.radius),
attrs = {'length': '{:.2e}'.format(self.length),
'nb_pts': self.nb_pts,
'nb_dim': self.nb_dim,
'sampling': self.sampling,
Expand Down
16 changes: 9 additions & 7 deletions pygsp/graphs/nngraphs/imgpatches.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ class ImgPatches(NNGraph):

Extract a feature vector in the form of a patch for every pixel of an
image, then construct a nearest-neighbor graph between these feature
vectors. The feature matrix, i.e. the patches, can be found in :attr:`Xin`.
vectors. The feature matrix, i.e., the patches, can be found in
:attr:`features`.

Parameters
----------
Expand All @@ -35,9 +36,10 @@ class ImgPatches(NNGraph):
>>> from skimage import data, img_as_float
>>> img = img_as_float(data.camera()[::64, ::64])
>>> G = graphs.ImgPatches(img, patch_shape=(3, 3))
>>> print('{} nodes ({} x {} pixels)'.format(G.Xin.shape[0], *img.shape))
>>> N, d = G.patches.shape
>>> print('{} nodes ({} x {} pixels)'.format(N, *img.shape))
64 nodes (8 x 8 pixels)
>>> print('{} features per node'.format(G.Xin.shape[1]))
>>> print('{} features per node'.format(d))
9 features per node
>>> G.set_coordinates(kind='spring', seed=42)
>>> fig, axes = plt.subplots(1, 2)
Expand Down Expand Up @@ -83,16 +85,16 @@ def __init__(self, img, patch_shape=(3, 3), **kwargs):
# Alternative: sklearn.feature_extraction.image.extract_patches_2d.
# sklearn has much less dependencies than skimage.
try:
import skimage
from skimage.util import view_as_windows
except Exception as e:
raise ImportError('Cannot import skimage, which is needed to '
'extract patches. Try to install it with '
'pip (or conda) install scikit-image. '
'Original exception: {}'.format(e))
patches = skimage.util.view_as_windows(img, window_shape=window_shape)
patches = patches.reshape((h * w, r * c * d))
self.patches = view_as_windows(img, window_shape)
self.patches = self.patches.reshape((h * w, r * c * d))

super(ImgPatches, self).__init__(patches, **kwargs)
super(ImgPatches, self).__init__(self.patches, **kwargs)

def _get_extra_repr(self):
attrs = dict(patch_shape=self.patch_shape)
Expand Down
Loading