torch-molecule 0.1.0.dev2__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.
- torch_molecule/__init__.py +70 -0
- torch_molecule/base/__init__.py +8 -0
- torch_molecule/base/base.py +396 -0
- torch_molecule/base/encoder.py +44 -0
- torch_molecule/base/generator.py +24 -0
- torch_molecule/base/old_encoder.py +322 -0
- torch_molecule/base/old_predictor.py +904 -0
- torch_molecule/base/old_predictor2.py +436 -0
- torch_molecule/base/predictor.py +112 -0
- torch_molecule/encoder/attrmask/__init__.py +3 -0
- torch_molecule/encoder/attrmask/model.py +113 -0
- torch_molecule/encoder/attrmask/modeling_attrmask.py +304 -0
- torch_molecule/encoder/constant.py +13 -0
- torch_molecule/encoder/contextpred/__init__.py +3 -0
- torch_molecule/encoder/contextpred/model.py +207 -0
- torch_molecule/encoder/contextpred/modeling_contextpred.py +299 -0
- torch_molecule/encoder/contextpred/utils.py +206 -0
- torch_molecule/encoder/edgepred/__init__.py +3 -0
- torch_molecule/encoder/edgepred/model.py +104 -0
- torch_molecule/encoder/edgepred/modeling_edgepred.py +285 -0
- torch_molecule/encoder/graphmae/__init__.py +3 -0
- torch_molecule/encoder/graphmae/dataloader.py +206 -0
- torch_molecule/encoder/graphmae/model.py +137 -0
- torch_molecule/encoder/graphmae/modeling_graphmae.py +323 -0
- torch_molecule/encoder/infograph/__init__.py +3 -0
- torch_molecule/encoder/infograph/loss_function.py +128 -0
- torch_molecule/encoder/infograph/model.py +92 -0
- torch_molecule/encoder/infograph/modeling_infograph.py +301 -0
- torch_molecule/encoder/infograph/module.py +31 -0
- torch_molecule/encoder/moama/__init__.py +3 -0
- torch_molecule/encoder/moama/model.py +131 -0
- torch_molecule/encoder/moama/modeling_moama.py +307 -0
- torch_molecule/encoder/moama/utils.py +143 -0
- torch_molecule/encoder/pretrained/__init__.py +3 -0
- torch_molecule/encoder/pretrained/modeling_pretrained.py +274 -0
- torch_molecule/encoder/supervised/__init__.py +3 -0
- torch_molecule/encoder/supervised/model.py +97 -0
- torch_molecule/encoder/supervised/modeling_supervised.py +354 -0
- torch_molecule/generator/digress/__init__.py +3 -0
- torch_molecule/generator/digress/diffusion.py +194 -0
- torch_molecule/generator/digress/modeling_digress.py +503 -0
- torch_molecule/generator/digress/transformer.py +360 -0
- torch_molecule/generator/digress/utils.py +196 -0
- torch_molecule/generator/gdss/__init__.py +3 -0
- torch_molecule/generator/gdss/layers.py +257 -0
- torch_molecule/generator/gdss/model.py +204 -0
- torch_molecule/generator/gdss/modeling_gdss.py +474 -0
- torch_molecule/generator/gdss/sde.py +334 -0
- torch_molecule/generator/gdss/solver.py +227 -0
- torch_molecule/generator/gdss/toremove/ScoreNetworkA.py +167 -0
- torch_molecule/generator/gdss/toremove/ScoreNetworkX.py +85 -0
- torch_molecule/generator/gdss/utils.py +240 -0
- torch_molecule/generator/graph_dit/__init__.py +3 -0
- torch_molecule/generator/graph_dit/diffusion.py +188 -0
- torch_molecule/generator/graph_dit/modeling_graph_dit.py +581 -0
- torch_molecule/generator/graph_dit/transformer.py +207 -0
- torch_molecule/generator/graph_dit/utils.py +220 -0
- torch_molecule/generator/graph_ga/__init__.py +3 -0
- torch_molecule/generator/graph_ga/crossover.py +182 -0
- torch_molecule/generator/graph_ga/modeling_graph_ga.py +310 -0
- torch_molecule/generator/graph_ga/mutate.py +136 -0
- torch_molecule/generator/graph_ga/oracle.py +95 -0
- torch_molecule/generator/jtvae/__init__.py +3 -0
- torch_molecule/generator/jtvae/jtnn/chemutils.py +450 -0
- torch_molecule/generator/jtvae/jtnn/datautils.py +127 -0
- torch_molecule/generator/jtvae/jtnn/jtmpn.py +140 -0
- torch_molecule/generator/jtvae/jtnn/jtnn_dec.py +350 -0
- torch_molecule/generator/jtvae/jtnn/jtnn_enc.py +131 -0
- torch_molecule/generator/jtvae/jtnn/mol_tree.py +111 -0
- torch_molecule/generator/jtvae/jtnn/mpn.py +129 -0
- torch_molecule/generator/jtvae/jtnn/nnutils.py +66 -0
- torch_molecule/generator/jtvae/jtnn/vocab.py +31 -0
- torch_molecule/generator/jtvae/jtnn_vae.py +246 -0
- torch_molecule/generator/jtvae/modeling_jtvae.py +247 -0
- torch_molecule/generator/lstm/__init__.py +3 -0
- torch_molecule/generator/lstm/action_sampler.py +91 -0
- torch_molecule/generator/lstm/lstm.py +59 -0
- torch_molecule/generator/lstm/modeling_lstm.py +263 -0
- torch_molecule/generator/lstm/smiles_char_dict.py +123 -0
- torch_molecule/generator/lstm/utils.py +62 -0
- torch_molecule/generator/molgpt/__init__.py +3 -0
- torch_molecule/generator/molgpt/dataset.py +87 -0
- torch_molecule/generator/molgpt/gpt.py +251 -0
- torch_molecule/generator/molgpt/modeling_molgpt.py +427 -0
- torch_molecule/generator/pretrained/modeling_pretrained.py +1 -0
- torch_molecule/nn/__init__.py +16 -0
- torch_molecule/nn/attention.py +63 -0
- torch_molecule/nn/embedder.py +183 -0
- torch_molecule/nn/gnn.py +631 -0
- torch_molecule/nn/mlp.py +34 -0
- torch_molecule/predictor/bfgnn/__init__.py +3 -0
- torch_molecule/predictor/bfgnn/model.py +116 -0
- torch_molecule/predictor/bfgnn/modeling_bfgnn.py +81 -0
- torch_molecule/predictor/dir/__init__.py +3 -0
- torch_molecule/predictor/dir/model.py +235 -0
- torch_molecule/predictor/dir/modeling_dir.py +161 -0
- torch_molecule/predictor/dir/utils.py +40 -0
- torch_molecule/predictor/gnn/__init__.py +3 -0
- torch_molecule/predictor/gnn/model.py +114 -0
- torch_molecule/predictor/gnn/modeling_gnn.py +706 -0
- torch_molecule/predictor/gnn/old_modeling_gnn.py +707 -0
- torch_molecule/predictor/grea/__init__.py +3 -0
- torch_molecule/predictor/grea/model.py +190 -0
- torch_molecule/predictor/grea/modeling_grea.py +107 -0
- torch_molecule/predictor/grea/old1_features.py +229 -0
- torch_molecule/predictor/grea/old1_modeling_grea.py +493 -0
- torch_molecule/predictor/grea/utils.py +97 -0
- torch_molecule/predictor/grin/__init__.py +3 -0
- torch_molecule/predictor/grin/model.py +116 -0
- torch_molecule/predictor/grin/modeling_grin.py +91 -0
- torch_molecule/predictor/irm/__init__.py +3 -0
- torch_molecule/predictor/irm/model.py +127 -0
- torch_molecule/predictor/irm/modeling_irm.py +179 -0
- torch_molecule/predictor/lstm/__init__.py +3 -0
- torch_molecule/predictor/lstm/model.py +145 -0
- torch_molecule/predictor/lstm/modeling_lstm.py +627 -0
- torch_molecule/predictor/lstm/token_from_smiles.py +85 -0
- torch_molecule/predictor/old_modeling_graph.py +650 -0
- torch_molecule/predictor/rpgnn/__init__.py +3 -0
- torch_molecule/predictor/rpgnn/model.py +185 -0
- torch_molecule/predictor/rpgnn/modeling_rpgnn.py +76 -0
- torch_molecule/predictor/sgir/__init__.py +3 -0
- torch_molecule/predictor/sgir/modeling_sgir.py +260 -0
- torch_molecule/predictor/sgir/strategy.py +266 -0
- torch_molecule/predictor/smiles_transformer/__init__.py +3 -0
- torch_molecule/predictor/smiles_transformer/model.py +424 -0
- torch_molecule/predictor/smiles_transformer/modeling_transformer.py +252 -0
- torch_molecule/predictor/ssr/__init__.py +3 -0
- torch_molecule/predictor/ssr/model.py +283 -0
- torch_molecule/predictor/ssr/modeling_ssr.py +267 -0
- torch_molecule/predictor/ssr/utils.py +185 -0
- torch_molecule/utils/__init__.py +31 -0
- torch_molecule/utils/checker.py +158 -0
- torch_molecule/utils/checkpoint.py +294 -0
- torch_molecule/utils/format.py +140 -0
- torch_molecule/utils/generic/metrics.py +530 -0
- torch_molecule/utils/generic/pseudo_tasks.py +11 -0
- torch_molecule/utils/generic/weights.py +30 -0
- torch_molecule/utils/graph/features.py +178 -0
- torch_molecule/utils/graph/graph_from_smiles.py +134 -0
- torch_molecule/utils/graph/graph_to_smiles.py +312 -0
- torch_molecule/utils/hf.py +232 -0
- torch_molecule/utils/search.py +64 -0
- torch_molecule-0.1.0.dev2.dist-info/METADATA +243 -0
- torch_molecule-0.1.0.dev2.dist-info/RECORD +148 -0
- torch_molecule-0.1.0.dev2.dist-info/WHEEL +5 -0
- torch_molecule-0.1.0.dev2.dist-info/licenses/LICENSE +21 -0
- torch_molecule-0.1.0.dev2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import torch
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
def get_score_fn(sde, model, train=True, continuous=True):
|
|
6
|
+
if not train:
|
|
7
|
+
model.eval()
|
|
8
|
+
model_fn = model
|
|
9
|
+
if isinstance(sde, VPSDE) or isinstance(sde, subVPSDE):
|
|
10
|
+
def score_fn(x, adj, flags, t):
|
|
11
|
+
# Scale neural network output by standard deviation and flip sign
|
|
12
|
+
if continuous:
|
|
13
|
+
score = model_fn(x, adj, flags)
|
|
14
|
+
std = sde.marginal_prob(torch.zeros_like(adj), t)[1]
|
|
15
|
+
else:
|
|
16
|
+
raise NotImplementedError(f"Discrete not supported")
|
|
17
|
+
score = -score / std[:, None, None]
|
|
18
|
+
return score
|
|
19
|
+
|
|
20
|
+
elif isinstance(sde, VESDE):
|
|
21
|
+
def score_fn(x, adj, flags, t):
|
|
22
|
+
if continuous:
|
|
23
|
+
score = model_fn(x, adj, flags)
|
|
24
|
+
else:
|
|
25
|
+
raise NotImplementedError(f"Discrete not supported")
|
|
26
|
+
return score
|
|
27
|
+
else:
|
|
28
|
+
raise NotImplementedError(f"SDE class {sde.__class__.__name__} not supported.")
|
|
29
|
+
return score_fn
|
|
30
|
+
|
|
31
|
+
def load_sde(sde_type, beta_min, beta_max, num_scales):
|
|
32
|
+
if sde_type == "VP":
|
|
33
|
+
sde = VPSDE(beta_min=beta_min, beta_max=beta_max, N=num_scales)
|
|
34
|
+
elif sde_type == "VE":
|
|
35
|
+
sde = VESDE(sigma_min=beta_min, sigma_max=beta_max, N=num_scales)
|
|
36
|
+
elif sde_type == "subVP":
|
|
37
|
+
sde = subVPSDE(beta_min=beta_min, beta_max=beta_max, N=num_scales)
|
|
38
|
+
else:
|
|
39
|
+
raise NotImplementedError(f"SDE class {sde_type} not yet supported.")
|
|
40
|
+
return sde
|
|
41
|
+
|
|
42
|
+
class SDE(abc.ABC):
|
|
43
|
+
"""SDE abstract class. Functions are designed for a mini-batch of inputs."""
|
|
44
|
+
|
|
45
|
+
def __init__(self, N):
|
|
46
|
+
"""Construct an SDE.
|
|
47
|
+
Args:
|
|
48
|
+
N: number of discretization time steps.
|
|
49
|
+
"""
|
|
50
|
+
super().__init__()
|
|
51
|
+
self.N = N
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
@abc.abstractmethod
|
|
55
|
+
def T(self):
|
|
56
|
+
"""End time of the SDE."""
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
@abc.abstractmethod
|
|
60
|
+
def sde(self, x, t):
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
@abc.abstractmethod
|
|
64
|
+
def marginal_prob(self, x, t):
|
|
65
|
+
"""Parameters to determine the marginal distribution of the SDE, $p_t(x)$."""
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
@abc.abstractmethod
|
|
69
|
+
def prior_sampling(self, shape):
|
|
70
|
+
"""Generate one sample from the prior distribution, $p_T(x)$."""
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
@abc.abstractmethod
|
|
74
|
+
def prior_logp(self, z):
|
|
75
|
+
"""Compute log-density of the prior distribution.
|
|
76
|
+
Useful for computing the log-likelihood via probability flow ODE.
|
|
77
|
+
Args:
|
|
78
|
+
z: latent code
|
|
79
|
+
Returns:
|
|
80
|
+
log probability density
|
|
81
|
+
"""
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
def discretize(self, x, t):
|
|
85
|
+
"""Discretize the SDE in the form: x_{i+1} = x_i + f_i(x_i) + G_i z_i.
|
|
86
|
+
Useful for reverse diffusion sampling and probabiliy flow sampling.
|
|
87
|
+
Defaults to Euler-Maruyama discretization.
|
|
88
|
+
Args:
|
|
89
|
+
x: a torch tensor
|
|
90
|
+
t: a torch float representing the time step (from 0 to `self.T`)
|
|
91
|
+
Returns:
|
|
92
|
+
f, G
|
|
93
|
+
"""
|
|
94
|
+
dt = 1 / self.N
|
|
95
|
+
drift, diffusion = self.sde(x, t)
|
|
96
|
+
f = drift * dt
|
|
97
|
+
G = diffusion * torch.sqrt(torch.tensor(dt, device=t.device))
|
|
98
|
+
return f, G
|
|
99
|
+
|
|
100
|
+
def reverse(self, score_fn, probability_flow=False):
|
|
101
|
+
"""Create the reverse-time SDE/ODE.
|
|
102
|
+
Args:
|
|
103
|
+
score_fn: A time-dependent score-based model that takes x and t and returns the score.
|
|
104
|
+
probability_flow: If `True`, create the reverse-time ODE used for probability flow sampling.
|
|
105
|
+
"""
|
|
106
|
+
N = self.N
|
|
107
|
+
T = self.T
|
|
108
|
+
sde_fn = self.sde
|
|
109
|
+
discretize_fn = self.discretize
|
|
110
|
+
|
|
111
|
+
# -------- Build the class for reverse-time SDE --------
|
|
112
|
+
class RSDE(self.__class__):
|
|
113
|
+
def __init__(self):
|
|
114
|
+
self.N = N
|
|
115
|
+
self.probability_flow = probability_flow
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def T(self):
|
|
119
|
+
return T
|
|
120
|
+
|
|
121
|
+
def sde(self, feature, x, flags, t, is_adj=True):
|
|
122
|
+
"""Create the drift and diffusion functions for the reverse SDE/ODE."""
|
|
123
|
+
drift, diffusion = sde_fn(x, t) if is_adj else sde_fn(feature, t)
|
|
124
|
+
score = score_fn(feature, x, flags, t)
|
|
125
|
+
drift = drift - diffusion[:, None, None] ** 2 * score * (
|
|
126
|
+
0.5 if self.probability_flow else 1.0
|
|
127
|
+
)
|
|
128
|
+
# -------- Set the diffusion function to zero for ODEs. --------
|
|
129
|
+
diffusion = 0.0 if self.probability_flow else diffusion
|
|
130
|
+
return drift, diffusion
|
|
131
|
+
|
|
132
|
+
def discretize(self, feature, x, flags, t, is_adj=True):
|
|
133
|
+
"""Create discretized iteration rules for the reverse diffusion sampler."""
|
|
134
|
+
f, G = discretize_fn(x, t) if is_adj else discretize_fn(feature, t)
|
|
135
|
+
score = score_fn(feature, x, flags, t)
|
|
136
|
+
rev_f = f - G[:, None, None] ** 2 * score * (
|
|
137
|
+
0.5 if self.probability_flow else 1.0
|
|
138
|
+
)
|
|
139
|
+
rev_G = torch.zeros_like(G) if self.probability_flow else G
|
|
140
|
+
return rev_f, rev_G
|
|
141
|
+
|
|
142
|
+
return RSDE()
|
|
143
|
+
|
|
144
|
+
class VPSDE(SDE):
|
|
145
|
+
def __init__(self, beta_min=0.1, beta_max=20, N=1000):
|
|
146
|
+
"""Construct a Variance Preserving SDE.
|
|
147
|
+
Args:
|
|
148
|
+
beta_min: value of beta(0)
|
|
149
|
+
beta_max: value of beta(1)
|
|
150
|
+
N: number of discretization steps
|
|
151
|
+
"""
|
|
152
|
+
super().__init__(N)
|
|
153
|
+
self.beta_0 = beta_min
|
|
154
|
+
self.beta_1 = beta_max
|
|
155
|
+
self.N = N
|
|
156
|
+
self.discrete_betas = torch.linspace(beta_min / N, beta_max / N, N)
|
|
157
|
+
self.alphas = 1.0 - self.discrete_betas
|
|
158
|
+
self.alphas_cumprod = torch.cumprod(self.alphas, dim=0)
|
|
159
|
+
self.sqrt_alphas_cumprod = torch.sqrt(self.alphas_cumprod)
|
|
160
|
+
self.sqrt_1m_alphas_cumprod = torch.sqrt(1.0 - self.alphas_cumprod)
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def T(self):
|
|
164
|
+
return 1
|
|
165
|
+
|
|
166
|
+
def sde(self, x, t):
|
|
167
|
+
beta_t = self.beta_0 + t * (self.beta_1 - self.beta_0)
|
|
168
|
+
drift = -0.5 * beta_t[:, None, None] * x
|
|
169
|
+
diffusion = torch.sqrt(beta_t)
|
|
170
|
+
return drift, diffusion
|
|
171
|
+
|
|
172
|
+
# -------- mean, std of the perturbation kernel --------
|
|
173
|
+
def marginal_prob(self, x, t):
|
|
174
|
+
log_mean_coeff = (
|
|
175
|
+
-0.25 * t**2 * (self.beta_1 - self.beta_0) - 0.5 * t * self.beta_0
|
|
176
|
+
)
|
|
177
|
+
mean = torch.exp(log_mean_coeff[:, None, None]) * x
|
|
178
|
+
std = torch.sqrt(1.0 - torch.exp(2.0 * log_mean_coeff))
|
|
179
|
+
return mean, std
|
|
180
|
+
|
|
181
|
+
def prior_sampling(self, shape):
|
|
182
|
+
return torch.randn(*shape)
|
|
183
|
+
|
|
184
|
+
def prior_sampling_sym(self, shape):
|
|
185
|
+
x = torch.randn(*shape).triu(1)
|
|
186
|
+
return x + x.transpose(-1, -2)
|
|
187
|
+
|
|
188
|
+
def prior_logp(self, z):
|
|
189
|
+
shape = z.shape
|
|
190
|
+
N = np.prod(shape[1:])
|
|
191
|
+
logps = -N / 2.0 * np.log(2 * np.pi) - torch.sum(z**2, dim=(1, 2)) / 2.0
|
|
192
|
+
return logps
|
|
193
|
+
|
|
194
|
+
def discretize(self, x, t):
|
|
195
|
+
"""DDPM discretization."""
|
|
196
|
+
timestep = (t * (self.N - 1) / self.T).long()
|
|
197
|
+
beta = self.discrete_betas.to(x.device)[timestep]
|
|
198
|
+
alpha = self.alphas.to(x.device)[timestep]
|
|
199
|
+
sqrt_beta = torch.sqrt(beta)
|
|
200
|
+
f = torch.sqrt(alpha)[:, None, None] * x - x
|
|
201
|
+
G = sqrt_beta
|
|
202
|
+
return f, G
|
|
203
|
+
|
|
204
|
+
def transition(self, x, t, dt):
|
|
205
|
+
# -------- negative timestep dt --------
|
|
206
|
+
log_mean_coeff = (
|
|
207
|
+
0.25 * dt * (2 * self.beta_0 + (2 * t + dt) * (self.beta_1 - self.beta_0))
|
|
208
|
+
)
|
|
209
|
+
mean = torch.exp(-log_mean_coeff[:, None, None]) * x
|
|
210
|
+
std = torch.sqrt(1.0 - torch.exp(2.0 * log_mean_coeff))
|
|
211
|
+
return mean, std
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class VESDE(SDE):
|
|
215
|
+
def __init__(self, sigma_min=0.01, sigma_max=50, N=1000):
|
|
216
|
+
"""Construct a Variance Exploding SDE.
|
|
217
|
+
Args:
|
|
218
|
+
sigma_min: smallest sigma.
|
|
219
|
+
sigma_max: largest sigma.
|
|
220
|
+
N: number of discretization steps
|
|
221
|
+
"""
|
|
222
|
+
super().__init__(N)
|
|
223
|
+
self.sigma_min = sigma_min
|
|
224
|
+
self.sigma_max = sigma_max
|
|
225
|
+
self.discrete_sigmas = torch.exp(
|
|
226
|
+
torch.linspace(np.log(self.sigma_min), np.log(self.sigma_max), N)
|
|
227
|
+
)
|
|
228
|
+
self.N = N
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def T(self):
|
|
232
|
+
return 1
|
|
233
|
+
|
|
234
|
+
def sde(self, x, t):
|
|
235
|
+
sigma = self.sigma_min * (self.sigma_max / self.sigma_min) ** t
|
|
236
|
+
drift = torch.zeros_like(x)
|
|
237
|
+
diffusion = sigma * torch.sqrt(
|
|
238
|
+
torch.tensor(
|
|
239
|
+
2 * (np.log(self.sigma_max) - np.log(self.sigma_min)), device=t.device
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
return drift, diffusion
|
|
243
|
+
|
|
244
|
+
def marginal_prob(self, x, t):
|
|
245
|
+
std = self.sigma_min * (self.sigma_max / self.sigma_min) ** t
|
|
246
|
+
mean = x
|
|
247
|
+
return mean, std
|
|
248
|
+
|
|
249
|
+
def prior_sampling(self, shape):
|
|
250
|
+
return torch.randn(*shape)
|
|
251
|
+
|
|
252
|
+
def prior_sampling_sym(self, shape):
|
|
253
|
+
x = torch.randn(*shape).triu(1)
|
|
254
|
+
x = x + x.transpose(-1, -2)
|
|
255
|
+
return x
|
|
256
|
+
|
|
257
|
+
def prior_logp(self, z):
|
|
258
|
+
shape = z.shape
|
|
259
|
+
N = np.prod(shape[1:])
|
|
260
|
+
return -N / 2.0 * np.log(2 * np.pi * self.sigma_max**2) - torch.sum(
|
|
261
|
+
z**2, dim=(1, 2, 3)
|
|
262
|
+
) / (2 * self.sigma_max**2)
|
|
263
|
+
|
|
264
|
+
def discretize(self, x, t):
|
|
265
|
+
"""SMLD(NCSN) discretization."""
|
|
266
|
+
timestep = (t * (self.N - 1) / self.T).long()
|
|
267
|
+
self.discrete_sigmas = self.discrete_sigmas.to(t.device)
|
|
268
|
+
sigma = self.discrete_sigmas.to(t.device)[timestep]
|
|
269
|
+
adjacent_sigma = torch.where(
|
|
270
|
+
timestep == 0,
|
|
271
|
+
torch.zeros_like(t),
|
|
272
|
+
self.discrete_sigmas[timestep - 1].to(t.device),
|
|
273
|
+
)
|
|
274
|
+
f = torch.zeros_like(x)
|
|
275
|
+
G = torch.sqrt(sigma**2 - adjacent_sigma**2)
|
|
276
|
+
return f, G
|
|
277
|
+
|
|
278
|
+
def transition(self, x, t, dt):
|
|
279
|
+
# -------- negative timestep dt --------
|
|
280
|
+
std = torch.square(
|
|
281
|
+
self.sigma_min * (self.sigma_max / self.sigma_min) ** t
|
|
282
|
+
) - torch.square(self.sigma_min * (self.sigma_max / self.sigma_min) ** (t + dt))
|
|
283
|
+
std = torch.sqrt(std)
|
|
284
|
+
mean = x
|
|
285
|
+
return mean, std
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class subVPSDE(SDE):
|
|
289
|
+
def __init__(self, beta_min=0.1, beta_max=20, N=1000):
|
|
290
|
+
"""Construct the sub-VP SDE that excels at likelihoods.
|
|
291
|
+
Args:
|
|
292
|
+
beta_min: value of beta(0)
|
|
293
|
+
beta_max: value of beta(1)
|
|
294
|
+
N: number of discretization steps
|
|
295
|
+
"""
|
|
296
|
+
super().__init__(N)
|
|
297
|
+
self.beta_0 = beta_min
|
|
298
|
+
self.beta_1 = beta_max
|
|
299
|
+
self.N = N
|
|
300
|
+
self.discrete_betas = torch.linspace(beta_min / N, beta_max / N, N)
|
|
301
|
+
self.alphas = 1.0 - self.discrete_betas
|
|
302
|
+
|
|
303
|
+
@property
|
|
304
|
+
def T(self):
|
|
305
|
+
return 1
|
|
306
|
+
|
|
307
|
+
def sde(self, x, t):
|
|
308
|
+
beta_t = self.beta_0 + t * (self.beta_1 - self.beta_0)
|
|
309
|
+
drift = -0.5 * beta_t[:, None, None] * x
|
|
310
|
+
discount = 1.0 - torch.exp(
|
|
311
|
+
-2 * self.beta_0 * t - (self.beta_1 - self.beta_0) * t**2
|
|
312
|
+
)
|
|
313
|
+
diffusion = torch.sqrt(beta_t * discount)
|
|
314
|
+
return drift, diffusion
|
|
315
|
+
|
|
316
|
+
def marginal_prob(self, x, t):
|
|
317
|
+
log_mean_coeff = (
|
|
318
|
+
-0.25 * t**2 * (self.beta_1 - self.beta_0) - 0.5 * t * self.beta_0
|
|
319
|
+
)
|
|
320
|
+
mean = torch.exp(log_mean_coeff)[:, None, None] * x
|
|
321
|
+
std = 1 - torch.exp(2.0 * log_mean_coeff)
|
|
322
|
+
return mean, std
|
|
323
|
+
|
|
324
|
+
def prior_sampling(self, shape):
|
|
325
|
+
return torch.randn(*shape)
|
|
326
|
+
|
|
327
|
+
def prior_sampling_sym(self, shape):
|
|
328
|
+
x = torch.randn(*shape).triu(1)
|
|
329
|
+
return x + x.transpose(-1, -2)
|
|
330
|
+
|
|
331
|
+
def prior_logp(self, z):
|
|
332
|
+
shape = z.shape
|
|
333
|
+
N = np.prod(shape[1:])
|
|
334
|
+
return -N / 2.0 * np.log(2 * np.pi) - torch.sum(z**2, dim=(1, 2, 3)) / 2.0
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
import numpy as np
|
|
3
|
+
import abc
|
|
4
|
+
|
|
5
|
+
from .utils import mask_adjs, mask_x, gen_noise
|
|
6
|
+
from .sde import VPSDE, subVPSDE, get_score_fn
|
|
7
|
+
|
|
8
|
+
### sampling
|
|
9
|
+
# -------- PC sampler --------
|
|
10
|
+
def get_pc_sampler(
|
|
11
|
+
sde_x,
|
|
12
|
+
sde_adj,
|
|
13
|
+
predictor="Euler",
|
|
14
|
+
corrector="None",
|
|
15
|
+
snr=0.1,
|
|
16
|
+
scale_eps=1.0,
|
|
17
|
+
n_steps=1,
|
|
18
|
+
probability_flow=False,
|
|
19
|
+
continuous=False,
|
|
20
|
+
denoise=True,
|
|
21
|
+
eps=1e-3,
|
|
22
|
+
device="cuda",
|
|
23
|
+
):
|
|
24
|
+
def pc_sampler(model_x, model_adj, shape_x, shape_adj, init_flags):
|
|
25
|
+
score_fn_x = get_score_fn(sde_x, model_x, train=False, continuous=continuous)
|
|
26
|
+
score_fn_adj = get_score_fn(
|
|
27
|
+
sde_adj, model_adj, train=False, continuous=continuous
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
predictor_fn = (
|
|
31
|
+
ReverseDiffusionPredictor
|
|
32
|
+
if predictor == "Reverse"
|
|
33
|
+
else EulerMaruyamaPredictor
|
|
34
|
+
)
|
|
35
|
+
corrector_fn = LangevinCorrector if corrector == "Langevin" else NoneCorrector
|
|
36
|
+
|
|
37
|
+
predictor_obj_x = predictor_fn("x", sde_x, score_fn_x, probability_flow)
|
|
38
|
+
corrector_obj_x = corrector_fn(
|
|
39
|
+
"x", sde_x, score_fn_x, snr, scale_eps, n_steps
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
predictor_obj_adj = predictor_fn(
|
|
43
|
+
"adj", sde_adj, score_fn_adj, probability_flow
|
|
44
|
+
)
|
|
45
|
+
corrector_obj_adj = corrector_fn(
|
|
46
|
+
"adj", sde_adj, score_fn_adj, snr, scale_eps, n_steps
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
with torch.no_grad():
|
|
50
|
+
# -------- Initial sample --------
|
|
51
|
+
x = sde_x.prior_sampling(shape_x).to(device)
|
|
52
|
+
adj = sde_adj.prior_sampling_sym(shape_adj).to(device)
|
|
53
|
+
flags = init_flags
|
|
54
|
+
x = mask_x(x, flags)
|
|
55
|
+
adj = mask_adjs(adj, flags)
|
|
56
|
+
diff_steps = sde_adj.N
|
|
57
|
+
timesteps = torch.linspace(sde_adj.T, eps, diff_steps, device=device)
|
|
58
|
+
|
|
59
|
+
# -------- Reverse diffusion process --------
|
|
60
|
+
# for i in trange(
|
|
61
|
+
# 0, (diff_steps), desc="[Sampling]", position=1, leave=False
|
|
62
|
+
# ):
|
|
63
|
+
for i in range(0, diff_steps):
|
|
64
|
+
t = timesteps[i]
|
|
65
|
+
vec_t = torch.ones(shape_adj[0], device=t.device) * t
|
|
66
|
+
|
|
67
|
+
_x = x
|
|
68
|
+
x, x_mean = corrector_obj_x.update_fn(x, adj, flags, vec_t)
|
|
69
|
+
adj, adj_mean = corrector_obj_adj.update_fn(_x, adj, flags, vec_t)
|
|
70
|
+
|
|
71
|
+
_x = x
|
|
72
|
+
x, x_mean = predictor_obj_x.update_fn(x, adj, flags, vec_t)
|
|
73
|
+
adj, adj_mean = predictor_obj_adj.update_fn(_x, adj, flags, vec_t)
|
|
74
|
+
# print(" ")
|
|
75
|
+
return (
|
|
76
|
+
(x_mean if denoise else x),
|
|
77
|
+
(adj_mean if denoise else adj),
|
|
78
|
+
diff_steps * (n_steps + 1),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return pc_sampler
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class Predictor(abc.ABC):
|
|
85
|
+
"""The abstract class for a predictor algorithm."""
|
|
86
|
+
|
|
87
|
+
def __init__(self, sde, score_fn, probability_flow=False):
|
|
88
|
+
super().__init__()
|
|
89
|
+
self.sde = sde
|
|
90
|
+
# Compute the reverse SDE/ODE
|
|
91
|
+
self.rsde = sde.reverse(score_fn, probability_flow)
|
|
92
|
+
self.score_fn = score_fn
|
|
93
|
+
|
|
94
|
+
@abc.abstractmethod
|
|
95
|
+
def update_fn(self, x, t, flags):
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Corrector(abc.ABC):
|
|
100
|
+
"""The abstract class for a corrector algorithm."""
|
|
101
|
+
|
|
102
|
+
def __init__(self, sde, score_fn, snr, scale_eps, n_steps):
|
|
103
|
+
super().__init__()
|
|
104
|
+
self.sde = sde
|
|
105
|
+
self.score_fn = score_fn
|
|
106
|
+
self.snr = snr
|
|
107
|
+
self.scale_eps = scale_eps
|
|
108
|
+
self.n_steps = n_steps
|
|
109
|
+
|
|
110
|
+
@abc.abstractmethod
|
|
111
|
+
def update_fn(self, x, t, flags):
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class EulerMaruyamaPredictor(Predictor):
|
|
116
|
+
def __init__(self, obj, sde, score_fn, probability_flow=False):
|
|
117
|
+
super().__init__(sde, score_fn, probability_flow)
|
|
118
|
+
self.obj = obj
|
|
119
|
+
|
|
120
|
+
def update_fn(self, x, adj, flags, t):
|
|
121
|
+
dt = -1.0 / self.rsde.N
|
|
122
|
+
|
|
123
|
+
if self.obj == "x":
|
|
124
|
+
z = gen_noise(x, flags, sym=False)
|
|
125
|
+
drift, diffusion = self.rsde.sde(x, adj, flags, t, is_adj=False)
|
|
126
|
+
x_mean = x + drift * dt
|
|
127
|
+
x = x_mean + diffusion[:, None, None] * np.sqrt(-dt) * z
|
|
128
|
+
return x, x_mean
|
|
129
|
+
|
|
130
|
+
elif self.obj == "adj":
|
|
131
|
+
z = gen_noise(adj, flags)
|
|
132
|
+
drift, diffusion = self.rsde.sde(x, adj, flags, t, is_adj=True)
|
|
133
|
+
adj_mean = adj + drift * dt
|
|
134
|
+
adj = adj_mean + diffusion[:, None, None] * np.sqrt(-dt) * z
|
|
135
|
+
|
|
136
|
+
return adj, adj_mean
|
|
137
|
+
|
|
138
|
+
else:
|
|
139
|
+
raise NotImplementedError(f"obj {self.obj} not yet supported.")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class ReverseDiffusionPredictor(Predictor):
|
|
143
|
+
def __init__(self, obj, sde, score_fn, probability_flow=False):
|
|
144
|
+
super().__init__(sde, score_fn, probability_flow)
|
|
145
|
+
self.obj = obj
|
|
146
|
+
|
|
147
|
+
def update_fn(self, x, adj, flags, t):
|
|
148
|
+
if self.obj == "x":
|
|
149
|
+
f, G = self.rsde.discretize(x, adj, flags, t, is_adj=False)
|
|
150
|
+
z = gen_noise(x, flags, sym=False)
|
|
151
|
+
x_mean = x - f
|
|
152
|
+
x = x_mean + G[:, None, None] * z
|
|
153
|
+
return x, x_mean
|
|
154
|
+
|
|
155
|
+
elif self.obj == "adj":
|
|
156
|
+
f, G = self.rsde.discretize(x, adj, flags, t, is_adj=True)
|
|
157
|
+
z = gen_noise(adj, flags)
|
|
158
|
+
adj_mean = adj - f
|
|
159
|
+
adj = adj_mean + G[:, None, None] * z
|
|
160
|
+
return adj, adj_mean
|
|
161
|
+
|
|
162
|
+
else:
|
|
163
|
+
raise NotImplementedError(f"obj {self.obj} not yet supported.")
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class NoneCorrector(Corrector):
|
|
167
|
+
"""An empty corrector that does nothing."""
|
|
168
|
+
|
|
169
|
+
def __init__(self, obj, sde, score_fn, snr, scale_eps, n_steps):
|
|
170
|
+
self.obj = obj
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
def update_fn(self, x, adj, flags, t):
|
|
174
|
+
if self.obj == "x":
|
|
175
|
+
return x, x
|
|
176
|
+
elif self.obj == "adj":
|
|
177
|
+
return adj, adj
|
|
178
|
+
else:
|
|
179
|
+
raise NotImplementedError(f"obj {self.obj} not yet supported.")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class LangevinCorrector(Corrector):
|
|
183
|
+
def __init__(self, obj, sde, score_fn, snr, scale_eps, n_steps):
|
|
184
|
+
super().__init__(sde, score_fn, snr, scale_eps, n_steps)
|
|
185
|
+
self.obj = obj
|
|
186
|
+
|
|
187
|
+
def update_fn(self, x, adj, flags, t):
|
|
188
|
+
sde = self.sde
|
|
189
|
+
score_fn = self.score_fn
|
|
190
|
+
n_steps = self.n_steps
|
|
191
|
+
target_snr = self.snr
|
|
192
|
+
seps = self.scale_eps
|
|
193
|
+
|
|
194
|
+
if isinstance(sde, VPSDE) or isinstance(sde, subVPSDE):
|
|
195
|
+
timestep = (t * (sde.N - 1) / sde.T).long()
|
|
196
|
+
alpha = sde.alphas.to(t.device)[timestep]
|
|
197
|
+
else:
|
|
198
|
+
alpha = torch.ones_like(t)
|
|
199
|
+
|
|
200
|
+
if self.obj == "x":
|
|
201
|
+
for i in range(n_steps):
|
|
202
|
+
grad = score_fn(x, adj, flags, t)
|
|
203
|
+
noise = gen_noise(x, flags, sym=False)
|
|
204
|
+
grad_norm = torch.norm(grad.reshape(grad.shape[0], -1), dim=-1).mean()
|
|
205
|
+
noise_norm = torch.norm(
|
|
206
|
+
noise.reshape(noise.shape[0], -1), dim=-1
|
|
207
|
+
).mean()
|
|
208
|
+
step_size = (target_snr * noise_norm / grad_norm) ** 2 * 2 * alpha
|
|
209
|
+
x_mean = x + step_size[:, None, None] * grad
|
|
210
|
+
x = x_mean + torch.sqrt(step_size * 2)[:, None, None] * noise * seps
|
|
211
|
+
return x, x_mean
|
|
212
|
+
|
|
213
|
+
elif self.obj == "adj":
|
|
214
|
+
for i in range(n_steps):
|
|
215
|
+
grad = score_fn(x, adj, flags, t)
|
|
216
|
+
noise = gen_noise(adj, flags)
|
|
217
|
+
grad_norm = torch.norm(grad.reshape(grad.shape[0], -1), dim=-1).mean()
|
|
218
|
+
noise_norm = torch.norm(
|
|
219
|
+
noise.reshape(noise.shape[0], -1), dim=-1
|
|
220
|
+
).mean()
|
|
221
|
+
step_size = (target_snr * noise_norm / grad_norm) ** 2 * 2 * alpha
|
|
222
|
+
adj_mean = adj + step_size[:, None, None] * grad
|
|
223
|
+
adj = adj_mean + torch.sqrt(step_size * 2)[:, None, None] * noise * seps
|
|
224
|
+
return adj, adj_mean
|
|
225
|
+
|
|
226
|
+
else:
|
|
227
|
+
raise NotImplementedError(f"obj {self.obj} not yet supported")
|