nystrom-ncut 0.0.1__py3-none-any.whl → 0.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nystrom_ncut/__init__.py +4 -4
- nystrom_ncut/common.py +20 -0
- nystrom_ncut/ncut_pytorch.py +190 -473
- nystrom_ncut/nystrom.py +4 -2
- nystrom_ncut/propagation_utils.py +19 -61
- nystrom_ncut/visualize_utils.py +11 -100
- {nystrom_ncut-0.0.1.dist-info → nystrom_ncut-0.0.3.dist-info}/METADATA +1 -1
- nystrom_ncut-0.0.3.dist-info/RECORD +11 -0
- nystrom_ncut/new_ncut_pytorch.py +0 -241
- nystrom_ncut-0.0.1.dist-info/RECORD +0 -11
- {nystrom_ncut-0.0.1.dist-info → nystrom_ncut-0.0.3.dist-info}/LICENSE +0 -0
- {nystrom_ncut-0.0.1.dist-info → nystrom_ncut-0.0.3.dist-info}/WHEEL +0 -0
- {nystrom_ncut-0.0.1.dist-info → nystrom_ncut-0.0.3.dist-info}/top_level.txt +0 -0
nystrom_ncut/nystrom.py
CHANGED
@@ -2,6 +2,8 @@ from typing import Literal, Tuple
|
|
2
2
|
|
3
3
|
import torch
|
4
4
|
|
5
|
+
from .common import ceildiv
|
6
|
+
|
5
7
|
|
6
8
|
EigSolverOptions = Literal["svd_lowrank", "lobpcg", "svd", "eigh"]
|
7
9
|
|
@@ -75,7 +77,7 @@ class OnlineNystrom:
|
|
75
77
|
return U[:, :self.n_components], L[:self.n_components] # [n x n_components], [n_components]
|
76
78
|
|
77
79
|
def update(self, features: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
|
78
|
-
n_chunks =
|
80
|
+
n_chunks = ceildiv(len(features), self.chunk_size)
|
79
81
|
if n_chunks > 1:
|
80
82
|
""" Chunked version """
|
81
83
|
chunks = torch.chunk(features, n_chunks, dim=0)
|
@@ -111,7 +113,7 @@ class OnlineNystrom:
|
|
111
113
|
if features is None:
|
112
114
|
VS = self.A @ self.transform_matrix # [n x n_components]
|
113
115
|
else:
|
114
|
-
n_chunks =
|
116
|
+
n_chunks = ceildiv(len(features), self.chunk_size)
|
115
117
|
if n_chunks > 1:
|
116
118
|
""" Chunked version """
|
117
119
|
chunks = torch.chunk(features, n_chunks, dim=0)
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import logging
|
2
|
-
import math
|
3
2
|
from typing import Literal
|
4
3
|
|
5
4
|
import numpy as np
|
6
5
|
import torch
|
7
6
|
import torch.nn.functional as F
|
8
7
|
|
8
|
+
from .common import ceildiv, lazy_normalize
|
9
|
+
|
9
10
|
|
10
11
|
@torch.no_grad()
|
11
12
|
def run_subgraph_sampling(
|
@@ -42,7 +43,7 @@ def run_subgraph_sampling(
|
|
42
43
|
sampled_indices = torch.randperm(features.shape[0])[:num_sample]
|
43
44
|
else:
|
44
45
|
raise ValueError("sample_method should be 'farthest' or 'random'")
|
45
|
-
return sampled_indices
|
46
|
+
return sampled_indices.to(features.device)
|
46
47
|
|
47
48
|
|
48
49
|
def farthest_point_sampling(
|
@@ -60,14 +61,12 @@ def farthest_point_sampling(
|
|
60
61
|
# PCA to reduce the dimension
|
61
62
|
if features.shape[1] > 8:
|
62
63
|
u, s, v = torch.pca_lowrank(features, q=8)
|
63
|
-
_n = features.shape[0]
|
64
|
-
s /= math.sqrt(_n)
|
65
64
|
features = u @ torch.diag(s)
|
66
65
|
|
67
66
|
h = min(h, int(np.log2(features.shape[0])))
|
68
67
|
|
69
68
|
kdline_fps_samples_idx = fpsample.bucket_fps_kdline_sampling(
|
70
|
-
features.
|
69
|
+
features.numpy(force=True), num_sample, h
|
71
70
|
).astype(np.int64)
|
72
71
|
return torch.from_numpy(kdline_fps_samples_idx)
|
73
72
|
|
@@ -76,26 +75,19 @@ def distance_from_features(
|
|
76
75
|
features: torch.Tensor,
|
77
76
|
features_B: torch.Tensor,
|
78
77
|
distance: Literal["cosine", "euclidean", "rbf"],
|
79
|
-
fill_diagonal: bool,
|
80
78
|
):
|
81
79
|
"""Compute affinity matrix from input features.
|
82
80
|
Args:
|
83
81
|
features (torch.Tensor): input features, shape (n_samples, n_features)
|
84
82
|
features_B (torch.Tensor, optional): optional, if not None, compute affinity between two features
|
85
|
-
affinity_focal_gamma (float): affinity matrix parameter, lower t reduce the edge weights
|
86
|
-
on weak connections, default 1.0
|
87
83
|
distance (str): distance metric, 'cosine' (default) or 'euclidean', 'rbf'.
|
88
|
-
normalize_features (bool): normalize input features before computing affinity matrix
|
89
|
-
|
90
84
|
Returns:
|
91
85
|
(torch.Tensor): affinity matrix, shape (n_samples, n_samples)
|
92
86
|
"""
|
93
87
|
# compute distance matrix from input features
|
94
88
|
if distance == "cosine":
|
95
|
-
|
96
|
-
|
97
|
-
if not check_if_normalized(features_B):
|
98
|
-
features_B = F.normalize(features_B, dim=-1)
|
89
|
+
features = lazy_normalize(features, dim=-1)
|
90
|
+
features_B = lazy_normalize(features_B, dim=-1)
|
99
91
|
D = 1 - features @ features_B.T
|
100
92
|
elif distance == "euclidean":
|
101
93
|
D = torch.cdist(features, features_B, p=2)
|
@@ -105,8 +97,6 @@ def distance_from_features(
|
|
105
97
|
else:
|
106
98
|
raise ValueError("distance should be 'cosine' or 'euclidean', 'rbf'")
|
107
99
|
|
108
|
-
if fill_diagonal:
|
109
|
-
D[torch.arange(D.shape[0]), torch.arange(D.shape[0])] = 0
|
110
100
|
return D
|
111
101
|
|
112
102
|
|
@@ -115,7 +105,6 @@ def affinity_from_features(
|
|
115
105
|
features_B: torch.Tensor = None,
|
116
106
|
affinity_focal_gamma: float = 1.0,
|
117
107
|
distance: Literal["cosine", "euclidean", "rbf"] = "cosine",
|
118
|
-
fill_diagonal: bool = True,
|
119
108
|
):
|
120
109
|
"""Compute affinity matrix from input features.
|
121
110
|
|
@@ -125,8 +114,6 @@ def affinity_from_features(
|
|
125
114
|
affinity_focal_gamma (float): affinity matrix parameter, lower t reduce the edge weights
|
126
115
|
on weak connections, default 1.0
|
127
116
|
distance (str): distance metric, 'cosine' (default) or 'euclidean', 'rbf'.
|
128
|
-
normalize_features (bool): normalize input features before computing affinity matrix
|
129
|
-
|
130
117
|
Returns:
|
131
118
|
(torch.Tensor): affinity matrix, shape (n_samples, n_samples)
|
132
119
|
"""
|
@@ -134,12 +121,10 @@ def affinity_from_features(
|
|
134
121
|
|
135
122
|
# if feature_B is not provided, compute affinity matrix on features x features
|
136
123
|
# if feature_B is provided, compute affinity matrix on features x feature_B
|
137
|
-
if features_B is not None:
|
138
|
-
assert not fill_diagonal, "fill_diagonal should be False when feature_B is None"
|
139
124
|
features_B = features if features_B is None else features_B
|
140
125
|
|
141
126
|
# compute distance matrix from input features
|
142
|
-
D = distance_from_features(features, features_B, distance
|
127
|
+
D = distance_from_features(features, features_B, distance)
|
143
128
|
|
144
129
|
# torch.exp make affinity matrix positive definite,
|
145
130
|
# lower affinity_focal_gamma reduce the weak edge weights
|
@@ -154,9 +139,8 @@ def propagate_knn(
|
|
154
139
|
knn: int = 10,
|
155
140
|
distance: Literal["cosine", "euclidean", "rbf"] = "cosine",
|
156
141
|
affinity_focal_gamma: float = 1.0,
|
157
|
-
chunk_size: int =
|
142
|
+
chunk_size: int = 8192,
|
158
143
|
device: str = None,
|
159
|
-
use_tqdm: bool = False,
|
160
144
|
move_output_to_cpu: bool = False,
|
161
145
|
):
|
162
146
|
"""A generic function to propagate new nodes using KNN.
|
@@ -169,8 +153,6 @@ def propagate_knn(
|
|
169
153
|
distance (str): distance metric, 'cosine' (default) or 'euclidean', 'rbf'
|
170
154
|
chunk_size (int): chunk size for matrix multiplication
|
171
155
|
device (str): device to use for computation, if None, will not change device
|
172
|
-
use_tqdm (bool): show progress bar when propagating eigenvectors from subgraph to full graph
|
173
|
-
|
174
156
|
Returns:
|
175
157
|
torch.Tensor: propagated eigenvectors, shape (new_num_samples, D)
|
176
158
|
|
@@ -197,24 +179,16 @@ def propagate_knn(
|
|
197
179
|
# used in nystrom_ncut
|
198
180
|
# propagate eigen_vector from subgraph to full graph
|
199
181
|
subgraph_output = subgraph_output.to(device)
|
200
|
-
V_list = []
|
201
|
-
iterator = range(0, inp_features.shape[0], chunk_size)
|
202
|
-
try:
|
203
|
-
assert use_tqdm
|
204
|
-
from tqdm import tqdm
|
205
|
-
iterator = tqdm(iterator, "propagate by KNN")
|
206
|
-
except (AssertionError, ImportError):
|
207
|
-
pass
|
208
182
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
_v =
|
213
|
-
_A = affinity_from_features(subgraph_features, _v, affinity_focal_gamma, distance
|
183
|
+
n_chunks = ceildiv(inp_features.shape[0], chunk_size)
|
184
|
+
V_list = []
|
185
|
+
for _v in torch.chunk(inp_features, n_chunks, dim=0):
|
186
|
+
_v = _v.to(device)
|
187
|
+
_A = affinity_from_features(subgraph_features, _v, affinity_focal_gamma, distance).mT
|
214
188
|
|
215
189
|
if knn is not None:
|
216
190
|
mask = torch.full_like(_A, True, dtype=torch.bool)
|
217
|
-
mask[torch.arange(
|
191
|
+
mask[torch.arange(len(_v))[:, None], _A.topk(knn, dim=-1, largest=True).indices] = False
|
218
192
|
_A[mask] = 0.0
|
219
193
|
_A = F.normalize(_A, p=1, dim=-1)
|
220
194
|
|
@@ -232,16 +206,14 @@ def propagate_nearest(
|
|
232
206
|
inp_features: torch.Tensor,
|
233
207
|
subgraph_features: torch.Tensor,
|
234
208
|
distance: Literal["cosine", "euclidean", "rbf"] = "cosine",
|
235
|
-
chunk_size: int =
|
209
|
+
chunk_size: int = 8192,
|
236
210
|
device: str = None,
|
237
211
|
move_output_to_cpu: bool = False,
|
238
212
|
):
|
239
213
|
device = subgraph_output.device if device is None else device
|
240
214
|
if distance == 'cosine':
|
241
|
-
|
242
|
-
|
243
|
-
if not check_if_normalized(subgraph_features):
|
244
|
-
subgraph_features = F.normalize(subgraph_features, dim=-1)
|
215
|
+
inp_features = lazy_normalize(inp_features, dim=-1)
|
216
|
+
subgraph_features = lazy_normalize(subgraph_features, dim=-1)
|
245
217
|
|
246
218
|
# used in nystrom_tsne, equivalent to propagate_by_knn with knn=1
|
247
219
|
# propagate tSNE from subgraph to full graph
|
@@ -250,7 +222,7 @@ def propagate_nearest(
|
|
250
222
|
for i in range(0, inp_features.shape[0], chunk_size):
|
251
223
|
end = min(i + chunk_size, inp_features.shape[0])
|
252
224
|
_v = inp_features[i:end].to(device)
|
253
|
-
_A = -distance_from_features(subgraph_features, _v, distance
|
225
|
+
_A = -distance_from_features(subgraph_features, _v, distance).mT
|
254
226
|
|
255
227
|
# keep top1 for each row
|
256
228
|
top_idx = _A.argmax(dim=-1).cpu()
|
@@ -273,7 +245,6 @@ def propagate_eigenvectors(
|
|
273
245
|
sample_method: Literal["farthest", "random"],
|
274
246
|
chunk_size: int,
|
275
247
|
device: str,
|
276
|
-
use_tqdm: bool,
|
277
248
|
):
|
278
249
|
"""Propagate eigenvectors to new nodes using KNN. Note: this is equivalent to the class API `NCUT.tranform(new_features)`, expect for the sampling is re-done in this function.
|
279
250
|
Args:
|
@@ -283,10 +254,8 @@ def propagate_eigenvectors(
|
|
283
254
|
knn (int): number of KNN to propagate eigenvectors, default 3
|
284
255
|
num_sample (int): number of samples for subgraph sampling, default 50000
|
285
256
|
sample_method (str): sample method, 'farthest' (default) or 'random'
|
286
|
-
chunk_size (int): chunk size for matrix multiplication, default
|
257
|
+
chunk_size (int): chunk size for matrix multiplication, default 8192
|
287
258
|
device (str): device to use for computation, if None, will not change device
|
288
|
-
use_tqdm (bool): show progress bar when propagating eigenvectors from subgraph to full graph
|
289
|
-
|
290
259
|
Returns:
|
291
260
|
torch.Tensor: propagated eigenvectors, shape (n_new_samples, num_eig)
|
292
261
|
|
@@ -319,21 +288,10 @@ def propagate_eigenvectors(
|
|
319
288
|
knn=knn,
|
320
289
|
chunk_size=chunk_size,
|
321
290
|
device=device,
|
322
|
-
use_tqdm=use_tqdm,
|
323
291
|
)
|
324
|
-
|
325
292
|
return new_eigenvectors
|
326
293
|
|
327
294
|
|
328
|
-
def check_if_normalized(x, n=1000):
|
329
|
-
"""check if the input tensor is normalized (unit norm)"""
|
330
|
-
n = min(n, x.shape[0])
|
331
|
-
random_indices = torch.randperm(x.shape[0])[:n]
|
332
|
-
_x = x[random_indices]
|
333
|
-
flag = torch.allclose(torch.norm(_x, dim=-1), torch.ones(n, device=x.device))
|
334
|
-
return flag
|
335
|
-
|
336
|
-
|
337
295
|
def quantile_min_max(x, q1=0.01, q2=0.99, n_sample=10000):
|
338
296
|
if x.shape[0] > n_sample:
|
339
297
|
np.random.seed(0)
|
nystrom_ncut/visualize_utils.py
CHANGED
@@ -6,11 +6,11 @@ import torch
|
|
6
6
|
import torch.nn.functional as F
|
7
7
|
from sklearn.base import BaseEstimator
|
8
8
|
|
9
|
+
from .common import lazy_normalize
|
9
10
|
from .propagation_utils import (
|
10
11
|
run_subgraph_sampling,
|
11
12
|
propagate_knn,
|
12
13
|
propagate_eigenvectors,
|
13
|
-
check_if_normalized,
|
14
14
|
quantile_min_max,
|
15
15
|
quantile_normalize
|
16
16
|
)
|
@@ -20,75 +20,6 @@ def _identity(X: torch.Tensor) -> torch.Tensor:
|
|
20
20
|
return X
|
21
21
|
|
22
22
|
|
23
|
-
def eigenvector_to_rgb(
|
24
|
-
eigen_vector: torch.Tensor,
|
25
|
-
method: Literal["tsne_2d", "tsne_3d", "umap_sphere", "umap_2d", "umap_3d"] = "tsne_3d",
|
26
|
-
num_sample: int = 1000,
|
27
|
-
perplexity: int = 150,
|
28
|
-
n_neighbors: int = 150,
|
29
|
-
min_distance: float = 0.1,
|
30
|
-
metric: Literal["cosine", "euclidean"] = "cosine",
|
31
|
-
device: str = None,
|
32
|
-
q: float = 0.95,
|
33
|
-
knn: int = 10,
|
34
|
-
seed: int = 0,
|
35
|
-
):
|
36
|
-
"""Use t-SNE or UMAP to convert eigenvectors (more than 3) to RGB color (3D RGB CUBE).
|
37
|
-
|
38
|
-
Args:
|
39
|
-
eigen_vector (torch.Tensor): eigenvectors, shape (n_samples, num_eig)
|
40
|
-
method (str): method to convert eigenvectors to RGB,
|
41
|
-
choices are: ['tsne_2d', 'tsne_3d', 'umap_sphere', 'umap_2d', 'umap_3d']
|
42
|
-
num_sample (int): number of samples for Nystrom-like approximation, increase for better approximation
|
43
|
-
perplexity (int): perplexity for t-SNE, increase for more global structure
|
44
|
-
n_neighbors (int): number of neighbors for UMAP, increase for more global structure
|
45
|
-
min_distance (float): minimum distance for UMAP
|
46
|
-
metric (str): distance metric, default 'cosine'
|
47
|
-
device (str): device to use for computation, if None, will not change device
|
48
|
-
q (float): quantile for RGB normalization, default 0.95. lower q results in more sharp colors
|
49
|
-
knn (int): number of KNN for propagating eigenvectors from subgraph to full graph,
|
50
|
-
smaller knn result in more sharp colors, default 1. knn>1 will smooth-out the embedding
|
51
|
-
in the t-SNE or UMAP space.
|
52
|
-
seed (int): random seed for t-SNE or UMAP
|
53
|
-
|
54
|
-
Examples:
|
55
|
-
>>> from ncut_pytorch import eigenvector_to_rgb
|
56
|
-
>>> X_3d, rgb = eigenvector_to_rgb(eigenvectors, method='tsne_3d')
|
57
|
-
>>> print(X_3d.shape, rgb.shape)
|
58
|
-
>>> # (10000, 3) (10000, 3)
|
59
|
-
|
60
|
-
Returns:
|
61
|
-
(torch.Tensor): t-SNE or UMAP embedding, shape (n_samples, 2) or (n_samples, 3)
|
62
|
-
(torch.Tensor): RGB color for each data sample, shape (n_samples, 3)
|
63
|
-
"""
|
64
|
-
kwargs = {
|
65
|
-
"num_sample": num_sample,
|
66
|
-
"perplexity": perplexity,
|
67
|
-
"n_neighbors": n_neighbors,
|
68
|
-
"min_distance": min_distance,
|
69
|
-
"metric": metric,
|
70
|
-
"device": device,
|
71
|
-
"q": q,
|
72
|
-
"knn": knn,
|
73
|
-
"seed": seed,
|
74
|
-
}
|
75
|
-
|
76
|
-
if method == "tsne_2d":
|
77
|
-
embed, rgb = rgb_from_tsne_2d(eigen_vector, **kwargs)
|
78
|
-
elif method == "tsne_3d":
|
79
|
-
embed, rgb = rgb_from_tsne_3d(eigen_vector, **kwargs)
|
80
|
-
elif method == "umap_sphere":
|
81
|
-
embed, rgb = rgb_from_umap_sphere(eigen_vector, **kwargs)
|
82
|
-
elif method == "umap_2d":
|
83
|
-
embed, rgb = rgb_from_umap_2d(eigen_vector, **kwargs)
|
84
|
-
elif method == "umap_3d":
|
85
|
-
embed, rgb = rgb_from_umap_3d(eigen_vector, **kwargs)
|
86
|
-
else:
|
87
|
-
raise ValueError("method should be 'tsne_2d', 'tsne_3d' or 'umap_sphere'")
|
88
|
-
|
89
|
-
return embed, rgb
|
90
|
-
|
91
|
-
|
92
23
|
def _rgb_with_dimensionality_reduction(
|
93
24
|
features: torch.Tensor,
|
94
25
|
num_sample: int,
|
@@ -126,7 +57,7 @@ def _rgb_with_dimensionality_reduction(
|
|
126
57
|
move_output_to_cpu=True,
|
127
58
|
))
|
128
59
|
rgb = rgb_func(X_nd, q)
|
129
|
-
return X_nd
|
60
|
+
return X_nd, rgb
|
130
61
|
|
131
62
|
|
132
63
|
def rgb_from_tsne_2d(
|
@@ -138,7 +69,6 @@ def rgb_from_tsne_2d(
|
|
138
69
|
seed: int = 0,
|
139
70
|
q: float = 0.95,
|
140
71
|
knn: int = 10,
|
141
|
-
**kwargs: Any,
|
142
72
|
):
|
143
73
|
"""
|
144
74
|
Returns:
|
@@ -169,7 +99,6 @@ def rgb_from_tsne_2d(
|
|
169
99
|
"perplexity": perplexity,
|
170
100
|
},
|
171
101
|
)
|
172
|
-
|
173
102
|
return x2d, rgb
|
174
103
|
|
175
104
|
|
@@ -182,7 +111,6 @@ def rgb_from_tsne_3d(
|
|
182
111
|
seed: int = 0,
|
183
112
|
q: float = 0.95,
|
184
113
|
knn: int = 10,
|
185
|
-
**kwargs: Any,
|
186
114
|
):
|
187
115
|
"""
|
188
116
|
Returns:
|
@@ -213,7 +141,6 @@ def rgb_from_tsne_3d(
|
|
213
141
|
"perplexity": perplexity,
|
214
142
|
},
|
215
143
|
)
|
216
|
-
|
217
144
|
return x3d, rgb
|
218
145
|
|
219
146
|
|
@@ -225,7 +152,6 @@ def rgb_from_cosine_tsne_3d(
|
|
225
152
|
seed: int = 0,
|
226
153
|
q: float = 0.95,
|
227
154
|
knn: int = 10,
|
228
|
-
**kwargs: Any,
|
229
155
|
):
|
230
156
|
"""
|
231
157
|
Returns:
|
@@ -272,7 +198,6 @@ def rgb_from_cosine_tsne_3d(
|
|
272
198
|
"perplexity": perplexity,
|
273
199
|
},
|
274
200
|
)
|
275
|
-
|
276
201
|
return x3d, rgb
|
277
202
|
|
278
203
|
|
@@ -286,7 +211,6 @@ def rgb_from_umap_2d(
|
|
286
211
|
seed: int = 0,
|
287
212
|
q: float = 0.95,
|
288
213
|
knn: int = 10,
|
289
|
-
**kwargs: Any,
|
290
214
|
):
|
291
215
|
"""
|
292
216
|
Returns:
|
@@ -310,7 +234,6 @@ def rgb_from_umap_2d(
|
|
310
234
|
"min_dist": min_dist,
|
311
235
|
},
|
312
236
|
)
|
313
|
-
|
314
237
|
return x2d, rgb
|
315
238
|
|
316
239
|
|
@@ -324,7 +247,6 @@ def rgb_from_umap_sphere(
|
|
324
247
|
seed: int = 0,
|
325
248
|
q: float = 0.95,
|
326
249
|
knn: int = 10,
|
327
|
-
**kwargs: Any,
|
328
250
|
):
|
329
251
|
"""
|
330
252
|
Returns:
|
@@ -357,7 +279,6 @@ def rgb_from_umap_sphere(
|
|
357
279
|
},
|
358
280
|
transform_func=transform_func
|
359
281
|
)
|
360
|
-
|
361
282
|
return x3d, rgb
|
362
283
|
|
363
284
|
|
@@ -371,7 +292,6 @@ def rgb_from_umap_3d(
|
|
371
292
|
seed: int = 0,
|
372
293
|
q: float = 0.95,
|
373
294
|
knn: int = 10,
|
374
|
-
**kwargs: Any,
|
375
295
|
):
|
376
296
|
"""
|
377
297
|
Returns:
|
@@ -395,7 +315,6 @@ def rgb_from_umap_3d(
|
|
395
315
|
"min_dist": min_dist,
|
396
316
|
},
|
397
317
|
)
|
398
|
-
|
399
318
|
return x3d, rgb
|
400
319
|
|
401
320
|
|
@@ -417,13 +336,11 @@ def rotate_rgb_cube(rgb, position=1):
|
|
417
336
|
torch.Tensor: RGB color space, shape (n_samples, 3)
|
418
337
|
"""
|
419
338
|
assert position in range(0, 7), "position should be 0, 1, 2, 3, 4, 5, 6"
|
420
|
-
rotation_matrix = torch.tensor(
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
]
|
426
|
-
).float()
|
339
|
+
rotation_matrix = torch.tensor((
|
340
|
+
(0., 1., 0.),
|
341
|
+
(0., 0., 1.),
|
342
|
+
(1., 0., 0.),
|
343
|
+
))
|
427
344
|
n_mul = position % 3
|
428
345
|
rotation_matrix = torch.matrix_power(rotation_matrix, n_mul)
|
429
346
|
rgb = rgb @ rotation_matrix
|
@@ -503,9 +420,8 @@ def propagate_rgb_color(
|
|
503
420
|
knn: int = 10,
|
504
421
|
num_sample: int = 1000,
|
505
422
|
sample_method: Literal["farthest", "random"] = "farthest",
|
506
|
-
chunk_size: int =
|
423
|
+
chunk_size: int = 8192,
|
507
424
|
device: str = None,
|
508
|
-
use_tqdm: bool = False,
|
509
425
|
):
|
510
426
|
"""Propagate RGB color to new nodes using KNN.
|
511
427
|
Args:
|
@@ -515,10 +431,8 @@ def propagate_rgb_color(
|
|
515
431
|
knn (int): number of KNN to propagate RGB color, default 1
|
516
432
|
num_sample (int): number of samples for subgraph sampling, default 50000
|
517
433
|
sample_method (str): sample method, 'farthest' (default) or 'random'
|
518
|
-
chunk_size (int): chunk size for matrix multiplication, default
|
434
|
+
chunk_size (int): chunk size for matrix multiplication, default 8192
|
519
435
|
device (str): device to use for computation, if None, will not change device
|
520
|
-
use_tqdm (bool): show progress bar when propagating RGB color from subgraph to full graph
|
521
|
-
|
522
436
|
Returns:
|
523
437
|
torch.Tensor: propagated RGB color for each data sample, shape (n_new_samples, 3)
|
524
438
|
|
@@ -538,7 +452,6 @@ def propagate_rgb_color(
|
|
538
452
|
sample_method=sample_method,
|
539
453
|
chunk_size=chunk_size,
|
540
454
|
device=device,
|
541
|
-
use_tqdm=use_tqdm,
|
542
455
|
)
|
543
456
|
|
544
457
|
|
@@ -627,9 +540,7 @@ def get_mask(
|
|
627
540
|
"""
|
628
541
|
|
629
542
|
# normalize the eigenvectors to unit norm, to compute cosine similarity
|
630
|
-
|
631
|
-
all_eigvecs = F.normalize(all_eigvecs, p=2, dim=-1)
|
632
|
-
|
543
|
+
all_eigvecs = lazy_normalize(all_eigvecs, p=2, dim=-1)
|
633
544
|
prompt_eigvec = F.normalize(prompt_eigvec, p=2, dim=-1)
|
634
545
|
|
635
546
|
# compute the cosine similarity
|
@@ -642,7 +553,7 @@ def get_mask(
|
|
642
553
|
heatmap = _transform_heatmap(heatmap, gamma=gamma)
|
643
554
|
|
644
555
|
masks = heatmap > threshold
|
645
|
-
masks = masks.
|
556
|
+
masks = masks.numpy(force=True).astype(np.uint8)
|
646
557
|
|
647
558
|
if denoise:
|
648
559
|
cleaned_masks = []
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: nystrom_ncut
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.3
|
4
4
|
Summary: Normalized Cut and Nyström Approximation
|
5
5
|
Author-email: Huzheng Yang <huze.yann@gmail.com>, Wentinn Liao <wentinn.liao@gmail.com>
|
6
6
|
Project-URL: Documentation, https://github.com/JophiArcana/Nystrom-NCUT/
|
@@ -0,0 +1,11 @@
|
|
1
|
+
nystrom_ncut/__init__.py,sha256=Cww-_OsyQHLKpgw_Wh28_tUOvIMMr7Ey8w-tH7v99xQ,452
|
2
|
+
nystrom_ncut/common.py,sha256=qdR_JwknT9H1Cv5LopwdwZfORFx-O8MLiRI6ZF1Qohc,558
|
3
|
+
nystrom_ncut/ncut_pytorch.py,sha256=8LfznDwhq-WL_vQxbFBFLSzymg9SEDti_zzf9QQLnrA,11651
|
4
|
+
nystrom_ncut/nystrom.py,sha256=Jo-P-2vnYk8yEZinGZnN3jHMiiB5AueoaLAYK4OmRqE,8604
|
5
|
+
nystrom_ncut/propagation_utils.py,sha256=pigecB0rAmlbCoMNb8zhCyyNwh3QzkxXEnaBsDRE_ns,12136
|
6
|
+
nystrom_ncut/visualize_utils.py,sha256=oNaDz_Xn12g3knEZZTb-QWVN-wTrnCNE5gn9cu8Xl_U,18569
|
7
|
+
nystrom_ncut-0.0.3.dist-info/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
|
8
|
+
nystrom_ncut-0.0.3.dist-info/METADATA,sha256=yh1pDFHUL2Z4WPVnuQyeHjgSEokUtpB6OPzPMxEClsM,6058
|
9
|
+
nystrom_ncut-0.0.3.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
|
10
|
+
nystrom_ncut-0.0.3.dist-info/top_level.txt,sha256=j7g_j0S048EvguFFnGgD5Ewd3r2H6klsxd5A4dd-wHw,13
|
11
|
+
nystrom_ncut-0.0.3.dist-info/RECORD,,
|