ncut-pytorch 3.0.0.dev5__tar.gz → 3.0.0.dev7__tar.gz
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.
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/PKG-INFO +1 -1
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/ncuts/ncut_click.py +0 -1
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/ncuts/ncut_nystrom.py +31 -22
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/utils/math.py +5 -1
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/utils/sample.py +1 -1
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch.egg-info/PKG-INFO +1 -1
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/pyproject.toml +1 -1
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/LICENSE +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/README.md +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/__init__.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/color/__init__.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/color/coloring.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/color/mspace.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/color/mspace_nopl.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/ncut.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/ncuts/__init__.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/ncuts/ncut_kway.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/__init__.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/__init__.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/api.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/dinov3.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/hires_dino.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/lowres_dino.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/patch.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/transform.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino_predictor.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/jafar_predictor.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/predictor.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/vision_predictor.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/utils/__init__.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/utils/device.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/utils/grad.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/utils/sigma.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/utils/torch_mod.py +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch.egg-info/SOURCES.txt +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch.egg-info/dependency_links.txt +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch.egg-info/requires.txt +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch.egg-info/top_level.txt +0 -0
- {ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/setup.cfg +0 -0
|
@@ -9,7 +9,10 @@ from ncut_pytorch.utils.math import rbf_affinity, cosine_affinity
|
|
|
9
9
|
from ncut_pytorch.utils.math import gram_schmidt, normalize_affinity, grad_safe_eig_solve, correct_rotation, keep_topk_per_row, svd_lowrank
|
|
10
10
|
from ncut_pytorch.utils.sample import farthest_point_sampling
|
|
11
11
|
from ncut_pytorch.utils.device import auto_device
|
|
12
|
+
import logging
|
|
12
13
|
|
|
14
|
+
MATMUL_CHUNK_SIZE = 65536
|
|
15
|
+
SMALL_SCALE_THRESHOLD = 8192 # if the number of nodes is less than SMALL_SCALE_THRESHOLD, skip nystrom approximation use exact ncut
|
|
13
16
|
|
|
14
17
|
class NystromConfig:
|
|
15
18
|
"""
|
|
@@ -21,7 +24,6 @@ class NystromConfig:
|
|
|
21
24
|
n_sample2 = 1024 # number of samples for eigenvector propagation, 1024 is large enough for most cases
|
|
22
25
|
n_neighbors = 32 # number of neighbors for eigenvector propagation, 10 is large enough for most cases
|
|
23
26
|
n_neighbors_max_ratio = 1/32 # max ratio of n_neighbors to n_sample2, to avoid over smoothing
|
|
24
|
-
matmul_chunk_size = 65536 # chunk size for matrix multiplication, larger chunk size is faster but requires more memory
|
|
25
27
|
|
|
26
28
|
def update(self, kwargs: dict):
|
|
27
29
|
for key, value in kwargs.items():
|
|
@@ -78,9 +80,11 @@ def ncut_fn(
|
|
|
78
80
|
device = auto_device(X.device, device)
|
|
79
81
|
|
|
80
82
|
# subsample for nystrom approximation
|
|
81
|
-
is_enough_data = X.shape[0] > config.n_sample
|
|
82
83
|
n_sample = min(config.n_sample, int(X.shape[0]*config.n_sample_max_ratio))
|
|
83
|
-
|
|
84
|
+
if X.shape[0] > SMALL_SCALE_THRESHOLD:
|
|
85
|
+
nystrom_indices = farthest_point_sampling(X, n_sample=n_sample, device=device)
|
|
86
|
+
else:
|
|
87
|
+
nystrom_indices = torch.arange(X.shape[0])
|
|
84
88
|
nystrom_X = X[nystrom_indices].to(device)
|
|
85
89
|
|
|
86
90
|
sigma, repulsion_sigma = find_optimal_sigma(nystrom_X, quantile_sigma, quantile_sigma_repulsion, sigma, repulsion_sigma, affinity_fn)
|
|
@@ -95,10 +99,6 @@ def ncut_fn(
|
|
|
95
99
|
if no_propagation:
|
|
96
100
|
return nystrom_eigvec, eigval, nystrom_indices, sigma
|
|
97
101
|
|
|
98
|
-
if not is_enough_data:
|
|
99
|
-
# skip nystrom approximation if not enough data, use exact ncut
|
|
100
|
-
return nystrom_eigvec, eigval
|
|
101
|
-
|
|
102
102
|
# propagate eigenvectors from subgraph to full graph
|
|
103
103
|
eigvec = nystrom_propagate(
|
|
104
104
|
nystrom_eigvec,
|
|
@@ -107,7 +107,6 @@ def ncut_fn(
|
|
|
107
107
|
extrapolation_factor=extrapolation_factor,
|
|
108
108
|
n_neighbors=config.n_neighbors,
|
|
109
109
|
n_sample=config.n_sample2,
|
|
110
|
-
matmul_chunk_size=config.matmul_chunk_size,
|
|
111
110
|
device=device,
|
|
112
111
|
)
|
|
113
112
|
|
|
@@ -117,6 +116,7 @@ def ncut_fn(
|
|
|
117
116
|
|
|
118
117
|
return eigvec, eigval
|
|
119
118
|
|
|
119
|
+
|
|
120
120
|
def find_optimal_sigma(
|
|
121
121
|
X: torch.Tensor,
|
|
122
122
|
quantile_sigma: float = 0.25,
|
|
@@ -137,6 +137,7 @@ def find_optimal_sigma(
|
|
|
137
137
|
raise ValueError(f"`sigma` need to be provided for affinity function {affinity_fn}, (sigma=0.5, repulsion_sigma=0.3)")
|
|
138
138
|
return sigma, repulsion_sigma
|
|
139
139
|
|
|
140
|
+
|
|
140
141
|
def ncut_with_repulsion(
|
|
141
142
|
X: torch.Tensor,
|
|
142
143
|
n_eig: int = 100,
|
|
@@ -197,11 +198,16 @@ def nystrom_propagate(
|
|
|
197
198
|
nystrom_X (torch.Tensor): input features from nystrom sampled nodes, shape (m, D)
|
|
198
199
|
extrapolation_factor (float): control how far can we extrapolate, larger extrapolation_factor means we can extrapolate further, default 1.0
|
|
199
200
|
device (str): device to use for computation, if 'auto', will detect GPU automatically
|
|
200
|
-
|
|
201
|
+
return_indices (bool): whether to return the indices used for propagation
|
|
201
202
|
|
|
202
203
|
Returns:
|
|
203
204
|
torch.Tensor: output propagated by nearest neighbors, shape (N, D)
|
|
204
205
|
"""
|
|
206
|
+
if X.shape[0] <= SMALL_SCALE_THRESHOLD and nystrom_X.shape == X.shape and torch.allclose(nystrom_X.to(X.device), X, atol=1e-6):
|
|
207
|
+
# skip propagation if nystrom_out is the same as X, for small scale graph that don't need nystrom approximation
|
|
208
|
+
if return_indices:
|
|
209
|
+
return nystrom_out, np.arange(X.shape[0])
|
|
210
|
+
return nystrom_out
|
|
205
211
|
|
|
206
212
|
config = NystromConfig()
|
|
207
213
|
config.update(kwargs)
|
|
@@ -217,33 +223,36 @@ def nystrom_propagate(
|
|
|
217
223
|
|
|
218
224
|
D = rbf_affinity(nystrom_X, sigma=sigma).mean(1)
|
|
219
225
|
|
|
220
|
-
all_outs = []
|
|
221
|
-
n_chunk = config.matmul_chunk_size
|
|
222
226
|
n_neighbors = int(min(config.n_neighbors, len(indices)*config.n_neighbors_max_ratio))
|
|
223
227
|
n_neighbors = max(n_neighbors, 4)
|
|
228
|
+
n_chunk = _find_max_chunk_size(X, nystrom_X, device)
|
|
229
|
+
|
|
230
|
+
all_outs = torch.empty((X.shape[0], nystrom_out.shape[-1]), device=output_device, dtype=nystrom_out.dtype)
|
|
224
231
|
for i in range(0, X.shape[0], n_chunk):
|
|
225
232
|
end = min(i + n_chunk, X.shape[0])
|
|
226
233
|
|
|
227
234
|
_Ai = rbf_affinity(X[i:end].to(device), nystrom_X, sigma=sigma)
|
|
228
235
|
_Ai, _indices = keep_topk_per_row(_Ai, n_neighbors) # (n, n_neighbors)
|
|
236
|
+
|
|
229
237
|
_Di = D[_indices].sum(1)
|
|
230
238
|
_Ai = _Ai / _Di[:, None]
|
|
231
239
|
|
|
232
|
-
|
|
233
|
-
neighbors = nystrom_out[_indices.flatten()]
|
|
234
|
-
neighbors = neighbors.reshape(-1, n_neighbors, nystrom_out.shape[-1]) # (n, n_neighbors, d)
|
|
235
|
-
out = weights * neighbors # (n, n_neighbors, d)
|
|
236
|
-
out = out.sum(dim=1) # (n, d)
|
|
237
|
-
|
|
238
|
-
out = out.to(output_device)
|
|
239
|
-
all_outs.append(out)
|
|
240
|
+
out = torch.einsum('nk,nkd->nd', _Ai, nystrom_out[_indices])
|
|
240
241
|
|
|
241
|
-
|
|
242
|
+
all_outs[i:end] = out.to(output_device)
|
|
242
243
|
|
|
243
244
|
if return_indices:
|
|
244
245
|
return all_outs, indices
|
|
245
|
-
|
|
246
246
|
return all_outs
|
|
247
247
|
|
|
248
248
|
|
|
249
|
-
|
|
249
|
+
def _find_max_chunk_size(X: torch.Tensor, nystrom_X: torch.Tensor, device: str):
|
|
250
|
+
max_chunk_size = MATMUL_CHUNK_SIZE
|
|
251
|
+
while max_chunk_size > 1:
|
|
252
|
+
try:
|
|
253
|
+
_ = rbf_affinity(X[:max_chunk_size].to(device), nystrom_X)
|
|
254
|
+
return max_chunk_size
|
|
255
|
+
except RuntimeError as e:
|
|
256
|
+
max_chunk_size = max_chunk_size // 2
|
|
257
|
+
continue
|
|
258
|
+
raise RuntimeError("failed to find max chunk size")
|
|
@@ -45,7 +45,11 @@ def rbf_affinity(
|
|
|
45
45
|
sigma = sigma if gamma is None else check_gamma_deprecated(gamma)
|
|
46
46
|
X2 = X1 if X2 is None else X2
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
try:
|
|
49
|
+
dist2 = torch.cdist(X1, X2, p=2)**2
|
|
50
|
+
except NotImplementedError:
|
|
51
|
+
dist2 = X1.unsqueeze(1) - X2.unsqueeze(0)
|
|
52
|
+
dist2 = dist2.pow(2).sum(dim=-1)
|
|
49
53
|
W = torch.exp(-dist2 / (2.0 * sigma * sigma)) # [N,M]
|
|
50
54
|
if zero_diag and X1 is X2:
|
|
51
55
|
W = W.clone()
|
|
@@ -60,5 +60,5 @@ def _farthest_point_sampling(
|
|
|
60
60
|
assert not torch.any(torch.isnan(X)), "X contains NaN"
|
|
61
61
|
assert not torch.any(torch.isinf(X)), "X contains Inf"
|
|
62
62
|
|
|
63
|
-
samples_idx = sample_idx(X.cpu(), n_sample)
|
|
63
|
+
samples_idx = sample_idx(X.cpu(), n_sample)
|
|
64
64
|
return samples_idx
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/hires_dino.py
RENAMED
|
File without changes
|
{ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/lowres_dino.py
RENAMED
|
File without changes
|
|
File without changes
|
{ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino/transform.py
RENAMED
|
File without changes
|
{ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/dino_predictor.py
RENAMED
|
File without changes
|
{ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/jafar_predictor.py
RENAMED
|
File without changes
|
|
File without changes
|
{ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch/predictor/vision_predictor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ncut_pytorch-3.0.0.dev5 → ncut_pytorch-3.0.0.dev7}/ncut_pytorch.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|