Skip to content

Commit c1c9a66

Browse files
author
Emmanuelle Gouillart
committed
spectral_embedding: corrected bug in the computation of the Laplacian
+ minor changes (API, etc.)
1 parent 4a687ad commit c1c9a66

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

diffusions.py

+37-6
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,34 @@ def _make_weights_3d(edges, data, beta=130, eps=1.e-6):
170170
weights = np.exp(- beta*gradients / (10*data.std())) + eps
171171
return weights
172172

173+
def _make_distances_3d(edges, data):
174+
lx, ly, lz = data.shape
175+
gradients = np.abs(data[edges[0]/(ly*lz), \
176+
(edges[0] % (ly*lz))/lz, \
177+
(edges[0] % (ly*lz))%lz] - \
178+
data[edges[1]/(ly*lz), \
179+
(edges[1] % (ly*lz))/lz, \
180+
(edges[1] % (ly*lz)) % lz])
181+
return gradients
182+
183+
def _make_adaptive_weights(edges, data):
184+
print "adaptive"
185+
pixel_nb = len(np.unique(edges.ravel()))
186+
gradients = _make_distances_3d(edges, data)
187+
i_indices = np.hstack((edges[0], edges[1]))
188+
j_indices = np.hstack((edges[1], edges[0]))
189+
w = np.hstack((gradients, gradients))
190+
nb = np.bincount(i_indices).astype(np.float)
191+
total_weight = np.bincount(i_indices, weights=w)
192+
sigmas = total_weight / nb
193+
sigma_of_edges = np.array([sigmas[edges[0]], sigmas[edges[1]]])
194+
return _make_weights_adaptative(gradients, sigma_of_edges)
195+
196+
def _make_weights_adaptative(gradients, sigma_of_edges, eps=1.e-10):
197+
sigma_i, sigma_j = sigma_of_edges
198+
weights = np.exp(- gradients**2 / (sigma_i * sigma_j)) + eps
199+
return weights
200+
173201
def _make_laplacian_sparse(edges, weights):
174202
"""
175203
Sparse implementation
@@ -190,19 +218,19 @@ def _make_normed_laplacian(edges, weights):
190218
"""
191219
Sparse implementation
192220
"""
193-
tol = 1.e-8
194-
eps = 1.e-5
221+
eps = 0
195222
pixel_nb = len(np.unique(edges.ravel()))
196223
diag = np.arange(pixel_nb)
197224
i_indices = np.hstack((edges[0], edges[1]))
198225
j_indices = np.hstack((edges[1], edges[0]))
199226
data = np.hstack((-weights, -weights))
200227
lap = coo_matrix((data, (i_indices, j_indices)), shape=(pixel_nb, pixel_nb))
201228
w = -np.ravel(lap.sum(axis=1))
229+
print w.min(), w.max()
202230
data *= 1. / (np.sqrt(w[i_indices]*w[j_indices]))
203-
data = np.hstack((data, eps*np.ones_like(diag)))
204-
i_indices = np.hstack((i_indices, diag))
205-
j_indices = np.hstack((j_indices, diag))
231+
#data = np.hstack((data, eps*np.ones_like(diag)))
232+
#i_indices = np.hstack((i_indices, diag))
233+
#j_indices = np.hstack((j_indices, diag))
206234
lap = coo_matrix((-data, (i_indices, j_indices)),\
207235
shape=(pixel_nb, pixel_nb))
208236
return lap.tocsc(), w
@@ -245,7 +273,10 @@ def _trim_edges_weights(edges, weights, mask):
245273
def _build_laplacian(data, mask=None, normed=False, beta=50):
246274
lx, ly, lz = data.shape
247275
edges = _make_edges_3d(lx, ly, lz)
248-
weights = _make_weights_3d(edges, data, beta=beta, eps=1.e-10)
276+
if beta==None:
277+
weights = _make_adaptive_weights(edges, data)
278+
else:
279+
weights = _make_weights_3d(edges, data, beta=beta, eps=1.e-10)
249280
if mask is not None:
250281
edges, weights = _trim_edges_weights(edges, weights, mask)
251282
if not normed:

spectral_embedding.py

+28-8
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ def spectral_embedding_sparse(adjacency, k_max=14, mode='amg', take_first=True):
4343
print 'amg'
4444
sh = adjacency.shape[0]
4545
adjacency = adjacency.copy()
46-
diag = sparse.coo_matrix((diag_weights.ravel(), (range(sh), range(sh))))
46+
#diag = sparse.coo_matrix((diag_weights.ravel(), (range(sh), range(sh))))
47+
diag = sparse.eye(sh, sh)
4748
adjacency = - adjacency + diag
4849
ml = smoothed_aggregation_solver(adjacency.tocsr())
4950
X = scipy.rand(adjacency.shape[0], k_max)
50-
X[:, 0] = 1. / np.sqrt(adjacency.shape[0])
51+
#X[:, 0] = 1. / np.sqrt(adjacency.shape[0])
52+
X[:, 0] = 1. / dd.ravel()
5153
M = ml.aspreconditioner()
5254
lambdas, diffusion_map = lobpcg(adjacency, X, M=M, tol=1.e-12, largest=False)
5355
print lambdas
@@ -145,14 +147,32 @@ def q_score(adjacency, labels):
145147
#q -= (weights[label == labels].sum()/total_weights)**2
146148
return 2 * q
147149

150+
def n_cut(adjacency, labels):
151+
""" Returns the Q score of a clustering.
152+
"""
153+
q = 0
154+
"""
155+
if isinstance(adjacency, sparse.csc.csc_matrix):
156+
adjacency = np.array(adjacency.todense())
157+
"""
158+
weights = adjacency
159+
total_weights = 0.5 * weights.sum()
160+
for label in np.unique(labels):
161+
inds = np.nonzero(labels == label)[0]
162+
a = (weights[inds][:, inds]).sum()
163+
b = weights[inds].sum()
164+
q += (b - a)/b
165+
return - q
166+
148167

149168
def best_k_means(k, maps, adjacency, n_bst=10):
150169
from nipy.neurospin.clustering.clustering import _kmeans
151170
best_score = -np.inf
152171
for _ in range(n_bst):
153172
print "doing kmeans"
154173
_, labels, _ = _kmeans(maps, nbclusters=k)
155-
score = q_score(adjacency, labels)
174+
#score = q_score(adjacency, labels)
175+
score = n_cut(adjacency, labels)
156176
if score > best_score:
157177
best_score = score
158178
best_labels = labels
@@ -196,12 +216,12 @@ def communities_clustering_sparse(adjacency, k_best=None, k_min=2, k_max=8, n_bs
196216
this_maps = maps[:k_best - 1].T.copy()
197217
res, scores = best_k_means(k_best, this_maps, adjacency,
198218
n_bst=4*n_bst)
199-
print 'Final : k=%i, score=%s' % (k_best, score)
219+
print 'Final : k=%i, score=%s' % (k_best, scores)
200220
return res, scores
201221

202222
def separate_in_regions(data, mask, k_best=None, k_min=2, k_max=8, \
203-
center=None, only_connex=True, \
204-
take_first=True, beta=10, mode='bf'):
223+
center=None, only_connex=True, n_times=4,\
224+
take_first=True, beta=10, mode='bf'):
205225
labs, nb_labels = ndimage.label(mask)
206226
if nb_labels > 1:
207227
if center is None:
@@ -212,10 +232,10 @@ def separate_in_regions(data, mask, k_best=None, k_min=2, k_max=8, \
212232
mask = labs == ind_max
213233
lap, w = _build_laplacian(np.atleast_3d(data), mask=np.atleast_3d(mask), \
214234
normed=True, beta=beta)
215-
return lap, w
216235
print lap.shape
217236
res, scores = communities_clustering_sparse(lap, k_best=k_best, \
218-
k_min=k_min, k_max=k_max, take_first=take_first, mode=mode)
237+
k_min=k_min, k_max=k_max, n_bst=n_times, \
238+
take_first=take_first, mode=mode)
219239
if not only_connex:
220240
if k_best==None:
221241
labels = dict()

0 commit comments

Comments
 (0)