nystrom-ncut 0.1.3__py3-none-any.whl → 0.1.5__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/distance_utils.py +3 -3
- nystrom_ncut/nystrom/distance_realization.py +1 -1
- nystrom_ncut/nystrom/normalized_cut.py +22 -10
- nystrom_ncut/sampling_utils.py +4 -1
- {nystrom_ncut-0.1.3.dist-info → nystrom_ncut-0.1.5.dist-info}/METADATA +1 -1
- nystrom_ncut-0.1.5.dist-info/RECORD +15 -0
- nystrom_ncut-0.1.3.dist-info/RECORD +0 -15
- {nystrom_ncut-0.1.3.dist-info → nystrom_ncut-0.1.5.dist-info}/LICENSE +0 -0
- {nystrom_ncut-0.1.3.dist-info → nystrom_ncut-0.1.5.dist-info}/WHEEL +0 -0
- {nystrom_ncut-0.1.3.dist-info → nystrom_ncut-0.1.5.dist-info}/top_level.txt +0 -0
nystrom_ncut/distance_utils.py
CHANGED
@@ -38,14 +38,14 @@ def distance_from_features(
|
|
38
38
|
elif distance == "euclidean":
|
39
39
|
D = torch.cdist(features, features_B, p=2)
|
40
40
|
elif distance == "rbf":
|
41
|
-
D = torch.cdist(features, features_B, p=2) ** 2
|
41
|
+
D = 0.5 * torch.cdist(features, features_B, p=2) ** 2
|
42
42
|
|
43
43
|
# Outlier-robust scale invariance using quantiles to estimate standard deviation
|
44
44
|
c = 2.0
|
45
45
|
p = torch.erf(torch.tensor((-c, c), device=features.device) * (2 ** -0.5))
|
46
46
|
stds = torch.quantile(features, q=(p + 1) / 2, dim=0)
|
47
|
-
stds = (stds[1] - stds[0]) / 2
|
48
|
-
D = D / (
|
47
|
+
stds = (stds[1] - stds[0]) / (2 * c)
|
48
|
+
D = D / (torch.linalg.norm(stds) ** 2)
|
49
49
|
else:
|
50
50
|
raise ValueError("distance should be 'cosine' or 'euclidean', 'rbf'")
|
51
51
|
return D
|
@@ -98,8 +98,8 @@ class DistanceRealization(OnlineNystromSubsampleFit):
|
|
98
98
|
def __init__(
|
99
99
|
self,
|
100
100
|
n_components: int = 100,
|
101
|
-
sample_config: SampleConfig = SampleConfig(),
|
102
101
|
distance: DistanceOptions = "cosine",
|
102
|
+
sample_config: SampleConfig = SampleConfig(),
|
103
103
|
eig_solver: EigSolverOptions = "svd_lowrank",
|
104
104
|
chunk_size: int = 8192,
|
105
105
|
):
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import einops
|
1
2
|
import torch
|
2
3
|
import torch.nn.functional as Fn
|
3
4
|
|
@@ -21,10 +22,12 @@ class LaplacianKernel(OnlineKernel):
|
|
21
22
|
self,
|
22
23
|
affinity_focal_gamma: float,
|
23
24
|
distance: DistanceOptions,
|
25
|
+
adaptive_scaling: bool,
|
24
26
|
eig_solver: EigSolverOptions,
|
25
27
|
):
|
26
28
|
self.affinity_focal_gamma = affinity_focal_gamma
|
27
29
|
self.distance: DistanceOptions = distance
|
30
|
+
self.adaptive_scaling: bool = adaptive_scaling
|
28
31
|
self.eig_solver: EigSolverOptions = eig_solver
|
29
32
|
|
30
33
|
# Anchor matrices
|
@@ -53,13 +56,25 @@ class LaplacianKernel(OnlineKernel):
|
|
53
56
|
self.a_r = torch.sum(self.A, dim=-1) # [n]
|
54
57
|
self.b_r = torch.zeros_like(self.a_r) # [n]
|
55
58
|
|
56
|
-
def
|
59
|
+
def _affinity(self, features: torch.Tensor) -> torch.Tensor:
|
57
60
|
B = affinity_from_features(
|
58
61
|
self.anchor_features, # [n x d]
|
59
62
|
features, # [m x d]
|
60
63
|
affinity_focal_gamma=self.affinity_focal_gamma,
|
61
64
|
distance=self.distance,
|
62
65
|
) # [n x m]
|
66
|
+
if self.adaptive_scaling:
|
67
|
+
diagonal = (
|
68
|
+
einops.rearrange(B, "n m -> m 1 n") # [m x 1 x n]
|
69
|
+
@ self.Ainv # [n x n]
|
70
|
+
@ einops.rearrange(B, "n m -> m n 1") # [m x n x 1]
|
71
|
+
).squeeze(1, 2) # [m]
|
72
|
+
adaptive_scale = diagonal ** -0.5 # [m]
|
73
|
+
B = B * adaptive_scale
|
74
|
+
return B # [n x m]
|
75
|
+
|
76
|
+
def update(self, features: torch.Tensor) -> torch.Tensor:
|
77
|
+
B = self._affinity(features) # [n x m]
|
63
78
|
b_r = torch.sum(B, dim=-1) # [n]
|
64
79
|
b_c = torch.sum(B, dim=-2) # [m]
|
65
80
|
self.b_r = self.b_r + b_r # [n]
|
@@ -75,12 +90,7 @@ class LaplacianKernel(OnlineKernel):
|
|
75
90
|
B = self.A # [n x n]
|
76
91
|
col_sum = row_sum # [n]
|
77
92
|
else:
|
78
|
-
B =
|
79
|
-
self.anchor_features, # [n x d]
|
80
|
-
features, # [m x d]
|
81
|
-
affinity_focal_gamma=self.affinity_focal_gamma,
|
82
|
-
distance=self.distance,
|
83
|
-
) # [n x m]
|
93
|
+
B = self._affinity(features)
|
84
94
|
b_c = torch.sum(B, dim=-2) # [m]
|
85
95
|
col_sum = b_c + B.mT @ self.Ainv @ self.b_r # [m]
|
86
96
|
scale = (row_sum[:, None] * col_sum) ** -0.5 # [n x m]
|
@@ -94,8 +104,9 @@ class NCut(OnlineNystromSubsampleFit):
|
|
94
104
|
self,
|
95
105
|
n_components: int = 100,
|
96
106
|
affinity_focal_gamma: float = 1.0,
|
97
|
-
sample_config: SampleConfig = SampleConfig(),
|
98
107
|
distance: DistanceOptions = "cosine",
|
108
|
+
adaptive_scaling: bool = True,
|
109
|
+
sample_config: SampleConfig = SampleConfig(),
|
99
110
|
eig_solver: EigSolverOptions = "svd_lowrank",
|
100
111
|
chunk_size: int = 8192,
|
101
112
|
):
|
@@ -104,16 +115,17 @@ class NCut(OnlineNystromSubsampleFit):
|
|
104
115
|
n_components (int): number of top eigenvectors to return
|
105
116
|
affinity_focal_gamma (float): affinity matrix temperature, lower t reduce the not-so-connected edge weights,
|
106
117
|
smaller t result in more sharp eigenvectors.
|
118
|
+
distance (str): distance metric for affinity matrix, ['cosine', 'euclidean', 'rbf'].
|
119
|
+
adaptive_scaling (bool): whether to scale off-diagonal affinity vectors so extended diagonal equals 1
|
107
120
|
sample_config (str): subgraph sampling, ['farthest', 'random'].
|
108
121
|
farthest point sampling is recommended for better Nystrom-approximation accuracy
|
109
|
-
distance (str): distance metric for affinity matrix, ['cosine', 'euclidean', 'rbf'].
|
110
122
|
eig_solver (str): eigen decompose solver, ['svd_lowrank', 'lobpcg', 'svd', 'eigh'].
|
111
123
|
chunk_size (int): chunk size for large-scale matrix multiplication
|
112
124
|
"""
|
113
125
|
OnlineNystromSubsampleFit.__init__(
|
114
126
|
self,
|
115
127
|
n_components=n_components,
|
116
|
-
kernel=LaplacianKernel(affinity_focal_gamma, distance, eig_solver),
|
128
|
+
kernel=LaplacianKernel(affinity_focal_gamma, distance, adaptive_scaling, eig_solver),
|
117
129
|
distance=distance,
|
118
130
|
sample_config=sample_config,
|
119
131
|
eig_solver=eig_solver,
|
nystrom_ncut/sampling_utils.py
CHANGED
@@ -82,4 +82,7 @@ def fpsample(
|
|
82
82
|
U, S, V = torch.pca_lowrank(features, q=config.fps_dim)
|
83
83
|
features = U * S
|
84
84
|
|
85
|
-
|
85
|
+
try:
|
86
|
+
return sample_farthest_points(features[None], K=config.num_sample)[1][0]
|
87
|
+
except RuntimeError:
|
88
|
+
return sample_farthest_points(features[None].cpu(), K=config.num_sample)[1][0].to(features.device)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: nystrom_ncut
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.5
|
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,15 @@
|
|
1
|
+
__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
nystrom_ncut/__init__.py,sha256=HifrTcqX2-hYjBDe6xIThHvuIBYMPBA3EzjR8-qPMUM,512
|
3
|
+
nystrom_ncut/common.py,sha256=_PGJoImSk_Fb_5Ri-e_IsFoCcSfbGS8CxYUUHVoNM50,2036
|
4
|
+
nystrom_ncut/distance_utils.py,sha256=p-pYdpRrJsIhzxM_IxUqja7N8okngx52WGXD9pu_Aec,3129
|
5
|
+
nystrom_ncut/sampling_utils.py,sha256=oMmhFcd_N_D15Ht7F0rCGPSgLeitJszAKMD3ICKwHNU,3105
|
6
|
+
nystrom_ncut/visualize_utils.py,sha256=RsQVjPhxoIdxDOQ2PI7ifFDuEL23YXpZBdJ0wjjafek,22970
|
7
|
+
nystrom_ncut/nystrom/__init__.py,sha256=4EpxD3Cmc8Fif4vo8DG-6FpTfCnNanD5zCZxK3WrMwQ,121
|
8
|
+
nystrom_ncut/nystrom/distance_realization.py,sha256=YaKEzuiiJfS6tdOTuJ4Ce1jqOWIfrVGb8ilvhzKeW9w,5789
|
9
|
+
nystrom_ncut/nystrom/normalized_cut.py,sha256=N-M5wkTo59vpbBfIx8evkSQBxlo4j80qCtuoifxQa_A,7578
|
10
|
+
nystrom_ncut/nystrom/nystrom_utils.py,sha256=Wq364xlxBhr74lqyCkPWLBxq5YSt2zr-DSfYUHpYfgE,12989
|
11
|
+
nystrom_ncut-0.1.5.dist-info/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
|
12
|
+
nystrom_ncut-0.1.5.dist-info/METADATA,sha256=7gO_GxpjbitbEBB9juaha7W4e7SWs-hYqgkYfaGmuIg,6058
|
13
|
+
nystrom_ncut-0.1.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
14
|
+
nystrom_ncut-0.1.5.dist-info/top_level.txt,sha256=gM8IWWHYysIRTCvCTcdS4RShOyl9pxpylgSwPUZR2XM,22
|
15
|
+
nystrom_ncut-0.1.5.dist-info/RECORD,,
|
@@ -1,15 +0,0 @@
|
|
1
|
-
__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
nystrom_ncut/__init__.py,sha256=HifrTcqX2-hYjBDe6xIThHvuIBYMPBA3EzjR8-qPMUM,512
|
3
|
-
nystrom_ncut/common.py,sha256=_PGJoImSk_Fb_5Ri-e_IsFoCcSfbGS8CxYUUHVoNM50,2036
|
4
|
-
nystrom_ncut/distance_utils.py,sha256=xSMKL-sFGrz0EL106vhVx0qSk3iSdSLRFhGL0KmAOnU,3121
|
5
|
-
nystrom_ncut/sampling_utils.py,sha256=7zCneqmkaA_fUkaZcykFjHtn7pxdZdsjAbKxJplegc0,2960
|
6
|
-
nystrom_ncut/visualize_utils.py,sha256=RsQVjPhxoIdxDOQ2PI7ifFDuEL23YXpZBdJ0wjjafek,22970
|
7
|
-
nystrom_ncut/nystrom/__init__.py,sha256=4EpxD3Cmc8Fif4vo8DG-6FpTfCnNanD5zCZxK3WrMwQ,121
|
8
|
-
nystrom_ncut/nystrom/distance_realization.py,sha256=9GX_XSISTvsEWUu8bG5AxtlkYYNItFspcH5wXiwSOKY,5789
|
9
|
-
nystrom_ncut/nystrom/normalized_cut.py,sha256=ZxFV8Sckp6wtpNyoA15DS7Vfu9QLvzNpwrwY0n9_GNs,6953
|
10
|
-
nystrom_ncut/nystrom/nystrom_utils.py,sha256=Wq364xlxBhr74lqyCkPWLBxq5YSt2zr-DSfYUHpYfgE,12989
|
11
|
-
nystrom_ncut-0.1.3.dist-info/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
|
12
|
-
nystrom_ncut-0.1.3.dist-info/METADATA,sha256=tK9gbt1b0c5mGNm2e0OdAKQm7rFUWCuhn9myh_Vf408,6058
|
13
|
-
nystrom_ncut-0.1.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
14
|
-
nystrom_ncut-0.1.3.dist-info/top_level.txt,sha256=gM8IWWHYysIRTCvCTcdS4RShOyl9pxpylgSwPUZR2XM,22
|
15
|
-
nystrom_ncut-0.1.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|