Gromov-Wasserstein distance by ncourty · Pull Request #23 · PythonOT/POT

Conversation

@ncourty

Hi everyone,

This is a new implementation of the Gromov-Wasserstein distance, mostly programmed by Erwan Vautier and myself. In the next commit, I will add a new example on how to compute barycenters and also tests for this new functionality.

rflamary

* Joint OT matrix and mapping estimation [8].
* Wasserstein Discriminant Analysis [11] (requires autograd + pymanopt).

* Gromov-Wasserstein distances [12]

Choose a reason for hiding this comment

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

and barycenters

agramfort


[11] Flamary, R., Cuturi, M., Courty, N., & Rakotomamonjy, A. (2016). [Wasserstein Discriminant Analysis](https://arxiv.org/pdf/1608.08063.pdf). arXiv preprint arXiv:1608.08063.

[12] Peyré, Gabriel, Marco Cuturi, and Justin Solomon, [Gromov-Wasserstein averaging of kernel and distance matrices](http://proceedings.mlr.press/v48/peyre16.html) International Conference on Machine Learning (ICML). 2016.

Choose a reason for hiding this comment

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

Gabriel Peyré to be consistent

agramfort

"""
====================
Gromov-Wasserstein example
====================

Choose a reason for hiding this comment

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

not enough ===

agramfort

import numpy as np

import ot
import matplotlib.pylab as pl

Choose a reason for hiding this comment

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

import pl before ot

agramfort


"""
Sample two Gaussian distributions (2D and 3D)
====================

Choose a reason for hiding this comment

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

not enough ===

it won't render well in sphinx

agramfort

For demonstration purpose, we sample two Gaussian distributions in 2- and 3-dimensional spaces.
"""

n = 30 # nb samples

Choose a reason for hiding this comment

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

n -> n_samples

you won't need to write # nb samples :)

agramfort

Returns the value of L(a,b)=(1/2)*|a-b|^2
"""

return (1 / 2) * (a - b)**2

Choose a reason for hiding this comment

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

1 / 2 will be 0 python 2

agramfort

return b

tens = -np.dot(h1(C1), T).dot(h2(C2).T)
tens = tens - tens.min()

Choose a reason for hiding this comment

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

tens -= tens.min()

agramfort


Parameters
----------
C1 : np.ndarray(ns,ns)

Choose a reason for hiding this comment

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

C1 : ndarray, shape (ns, ns)

is the standard of numpydoc

agramfort

cpt = 0
err = 1

while (err > stopThr and cpt < numItermax):

Choose a reason for hiding this comment

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

avoid while loops. Use for with break. It's much safer to avoid infinite loops

you can use for else syntax to capture the absence of a break

Choose a reason for hiding this comment

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

Ok for this one I will keep the consistency with the rest of the optimization method (especially those in Bregman module)

agramfort

"""


def smacof_mds(C, dim, maxIter=3000, eps=1e-9):

Choose a reason for hiding this comment

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

maxIter -> max_iter

agramfort


Parameters
----------
C : np.ndarray(ns,ns)

Choose a reason for hiding this comment

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

C : ndarray, shape (ns , ns)

agramfort

----------
C : np.ndarray(ns,ns)
dissimilarity matrix
dim : Integer

Choose a reason for hiding this comment

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

Integer -> int

agramfort

dissimilarity matrix
dim : Integer
dimension of the targeted space
maxIter : Maximum number of iterations of the SMACOF algorithm for a single run

Choose a reason for hiding this comment

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

max_iter : int
   Maximum number of iterations of the SMACOF algorithm for a single run

agramfort

Ct01 = [0 for i in range(2)]
for i in range(2):
Ct01[i] = ot.gromov.gromov_barycenters(N, [Cs[0], Cs[1]], [
ps[0], ps[1]], p, lambdast[i], 'square_loss', 5e-4, numItermax=100, stopThr=1e-3)

Choose a reason for hiding this comment

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

numItermax -> max_iter?

agramfort

triangle = spi.imread('../data/triangle.png').astype(np.float64) / 256
fleche = spi.imread('../data/coeur.png').astype(np.float64) / 256

shapes = [carre, rond, triangle, fleche]

Choose a reason for hiding this comment

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

I guess you meant : square, circle, triangle and arrow :)

@agramfort

@ncourty please go over the full diff about docstrings and naming. If you're ok with me bugging you :) I'll do one more pass when you did it.

agramfort

'It.', 'Err') + '\n' + '-' * 19)
print('{:5d}|{:8e}|'.format(cpt, err))

cpt = cpt + 1

Choose a reason for hiding this comment

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

cpt += 1

Nicolas Courty added 2 commits

September 1, 2017 15:37

agramfort

square = spi.imread('../data/carre.png').astype(np.float64) / 256
circle = spi.imread('../data/rond.png').astype(np.float64) / 256
triangle = spi.imread('../data/triangle.png').astype(np.float64) / 256
arrow = spi.imread('../data/coeur.png').astype(np.float64) / 256

Choose a reason for hiding this comment

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

can you rename maybe the png files? also I see arrow = coeur. Is this a bug?

agramfort


xs = ot.datasets.get_2D_samples_gauss(n_samples, mu_s, cov_s)

xt = xs[::-1]

Choose a reason for hiding this comment

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

I would have written:

xt = xs[::-1].copy()

and removed the array below

agramfort

npos : ndarray, shape (R, dim)
Embedded coordinates of the interpolated point cloud (defined with one isometry)


Choose a reason for hiding this comment

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

remove unnecessary empty lines here and one before Returns

agramfort

"""
Sample two Gaussian distributions (2D and 3D)
=============================================
The Gromov-Wasserstein distance allows to compute distances with samples that do not belong to the same metric space.

Choose a reason for hiding this comment

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

line too long

agramfort

tens : ndarray, shape (ns, nt)
\mathcal{L}(C1,C2) \otimes T tensor-matrix multiplication result


Choose a reason for hiding this comment

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

remove empty lines

agramfort

=====================================
Gromov-Wasserstein Barycenter example
=====================================
This example is designed to show how to use the Gromov-Wassertsein distance

Choose a reason for hiding this comment

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

Wassertsein -> Wasserstein

agramfort


def smacof_mds(C, dim, max_iter=3000, eps=1e-9):
"""
Returns an interpolated point cloud following the dissimilarity matrix C using SMACOF

Choose a reason for hiding this comment

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

agramfort

Embedded coordinates of the interpolated point cloud (defined with one isometry)
"""

rng = np.random.RandomState(seed=3)

Choose a reason for hiding this comment

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

you should expose the random_state and use check_random_state like sklearn does.

Choose a reason for hiding this comment

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

wait it's an example maybe it's not necessary...

agramfort

----------
p : ndarray, shape (N,)
weights in the targeted barycenter
lambdas : list of the S spaces' weights

Choose a reason for hiding this comment

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

bad format

agramfort

sample weights in the S spaces
p : ndarray, shape(N,)
weights in the targeted barycenter
lambdas : list of the S spaces' weights

Choose a reason for hiding this comment

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

bad format

agramfort

lambdas = np.asarray(lambdas, dtype=np.float64)

# Initialization of C : random SPD matrix
xalea = np.random.randn(N, 2)

Choose a reason for hiding this comment

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

expose random_state to make results deterministic if one wants

agramfort

@ncourty

Thanks for the careful reading @agramfort . And congrats for your NIPS paper :) See you in LA ?

@rflamary

Hello @ncourty ,

I think we should merge shortly since it has converged, could you please update from master ?

@agramfort

rflamary

Choose a reason for hiding this comment

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

This looks good to me, you have taken into account all comments and the contribution is very nice for the toolbox.

I think we can merge.

Labels