├── .gitignore
├── README.md
├── configs
└── hydrogen.py
├── core
├── hmodel.py
├── losses.py
└── samplers.py
├── launch.py
├── models
├── ema.py
└── mlp.py
├── notebooks
├── annealed_Langevin.ipynb
├── gifs
│ ├── am_celeba_diffusion.gif
│ ├── am_celeba_inpaint.gif
│ ├── am_celeba_superres.gif
│ ├── am_celeba_torus.gif
│ ├── am_cifar_color.gif
│ ├── am_cifar_diffusion.gif
│ ├── am_cifar_superres.gif
│ ├── am_cifar_torus.gif
│ ├── am_results.gif
│ ├── dynamics_densities.gif
│ ├── sm_results.gif
│ └── ssm_results.gif
├── loss_plots.ipynb
├── losses_se.png
├── mmd_se.png
└── visualize.ipynb
└── utils
├── eval_utils.py
├── plot_utils.py
└── train_utils.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Action Matching for Schrödinger Equation Simulation
2 |
3 | We demonstrate that Action Matching can learn a wide range of stochastic dynamics by applying it to the dynamics of a quantum system evolving according to the Schrödinger equation. The Schrödinger equation describes the evolution of many quantum systems, and in particular, it describes the physics of molecular systems. Here, for the ground truth dynamics, we take the dynamics of an excited state of the hydrogen atom, which is described by the following equation
4 |
5 | $i\frac{\partial}{\partial t}\psi(x,t) = -\frac{1}{|x|}\psi(x,t) -\frac{1}{2}\nabla^2\psi(x,t).$
6 |
7 | The function $\psi(x,t): \mathbb{R}^3\times \mathbb{R} \to \mathbb{C}$ is called a wavefunction and it completely describes the state of the quantum system.
8 | In particular, it defines the distribution of the coordinates $x$ by defining its density as $q_t(x) := |\psi(x,t)|^2$, which dynamics is defined by the dynamics of $\psi(x,t)$.
9 | Below we demonstrate the ground truth dynamics where we project the density $q_t(x)$ on three different planes.
10 |
11 |
12 |
13 | In what follows we illustrate the histograms for the learned dynamics. Since the original distribution is in $\mathbb{R}^3$ we project the samples onto three different planes and draw 2d-histograms.
14 | The top row for every model corresponds to the ground truth dynamics (the training data), and the bottom rows corresspond to the learned models.
15 |
16 | #### Action Matching (AM) results visualization
17 |
18 |
19 | #### Score Matching (SM) results visualization
20 |
21 |
22 | #### Sliced Score Matching (SSM) results visualization
23 |
24 |
--------------------------------------------------------------------------------
/configs/hydrogen.py:
--------------------------------------------------------------------------------
1 | from ml_collections import config_dict
2 | import torch
3 | import numpy as np
4 |
5 | def get_config():
6 | config = config_dict.ConfigDict()
7 |
8 | config.data = config_dict.ConfigDict()
9 | config.data.T = 14_000
10 | config.data.n_steps = 1_000
11 | config.data.batch_size = 5_000
12 | config.data.n = torch.tensor([3,2])
13 | config.data.l = torch.tensor([2,1])
14 | config.data.m = torch.tensor([-1,0])
15 | config.data.c = torch.tensor([1.0+0.0j, 1.0+0.0j])
16 | config.data.name = 'hydrogen'
17 |
18 | config.model = config_dict.ConfigDict()
19 | config.model.method = 'am'
20 | config.model.n_hid = 256
21 | config.model.savepath = config.model.method + '_' + config.data.name
22 | config.model.checkpoints = []
23 |
24 | config.train = config_dict.ConfigDict()
25 | config.train.batch_size = 1_000
26 | config.train.lr = 1e-4
27 | config.train.warmup = 5_000
28 | config.train.grad_clip = 1.0
29 | config.train.betas = (0.9, 0.999)
30 | config.train.wd = 0.0
31 | config.train.n_iter = 100_000
32 | config.train.regen_every = 5_000
33 | config.train.save_every = 10_000
34 | config.train.eval_every = 5_000
35 | config.train.current_step = 0
36 |
37 | config.eval = config_dict.ConfigDict()
38 | config.eval.ema = 0.9999
39 |
40 | return config
41 |
--------------------------------------------------------------------------------
/core/hmodel.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import numpy as np
3 |
4 | from scipy.special import genlaguerre
5 | from scipy.special import lpmv
6 | from scipy.special import factorial2
7 |
8 |
9 | hbar = 1.0 # reduced Planck constant
10 | m_e = 1.0 # electron mass
11 | eps0 = 1.0
12 | e = 1.0
13 | a0 = 4*np.pi*eps0*hbar**2/m_e/e**2 # Bohr radius
14 | EPS = 1e-2
15 |
16 | def asslaguerre_torch(n, alpha, x):
17 | if n == 0:
18 | return torch.ones_like(x)
19 | elif n == 1:
20 | return 1.0 + alpha - x
21 | else:
22 | output = (2*n-1.0+alpha-x)*asslaguerre_torch(n-1,alpha,x)
23 | output = output-(n-1+alpha)*asslaguerre_torch(n-2,alpha,x)
24 | output = output/n
25 | return output
26 |
27 | def asslegendre_torch(m, l, x):
28 | if m < 0:
29 | m = np.abs(m)
30 | return (-1)**m*np.math.factorial(l-m)/np.math.factorial(l+m)*asslegendre_torch(m, l, x)
31 | if m == l:
32 | return (-1)**l*factorial2(2*l-1)*torch.pow(1.0-x**2, torch.tensor([l]).to(x.device)/2.0)
33 | elif m > l:
34 | return torch.zeros_like(x)
35 | else:
36 | output = (2*l-1)*x*asslegendre_torch(m, l-1, x)
37 | output = output - (l+m-1)*asslegendre_torch(m, l-2, x)
38 | output = output/(l-m)
39 | return output
40 |
41 | class EigenState:
42 | def __init__(self, n, l, m):
43 | self.n, self.l, self.m = n, l, m
44 | self.E = -hbar**2/(2.0*m_e*a0**2)/self.n**2
45 | self.L2 = hbar**2*self.l*(self.l+1)
46 | self.Lz = hbar**2*self.m
47 |
48 | def radial(self, r):
49 | n, l, m = self.n, self.l, self.m
50 | # output = torch.exp(-r/n/a0)*(2*r/(n*a0))**l
51 | output = torch.exp(-r/n/a0 + l*torch.log(2*r) - l*np.log(n*a0))
52 | output = output*np.sqrt((2.0/n/a0)**3*np.math.factorial(n-l-1)/np.math.factorial(n+l)/2.0/n)
53 | output = output*asslaguerre_torch(n-l-1, 2*l+1, 2.0*r/(n*a0))
54 | return output
55 |
56 | def angular(self, theta, phi):
57 | n, l, m = self.n, self.l, self.m
58 | output = asslegendre_torch(m, l, torch.cos(theta))
59 | output = output*(-1)**m*np.sqrt((2.0*l+1.0)*np.math.factorial(l-m)/np.math.factorial(l+m)/4.0/np.pi)
60 | output = output*torch.exp(1.0j*m*phi)
61 | return output
62 |
63 | def _radial(self, r):
64 | n, l, m = self.n, self.l, self.m
65 | output = np.sqrt((2.0/n/a0)**3*np.math.factorial(n-l-1)/np.math.factorial(n+l)/2.0/n)
66 | output = output*asslaguerre_torch(n-l-1, 2*l+1, 2.0*r/(n*a0))
67 | return output
68 |
69 | def _radial_log(self, r):
70 | n, l, m = self.n, self.l, self.m
71 | return -r/n/a0 + l*torch.log(2*r) - l*np.log(n*a0)
72 |
73 | class WaveFunction:
74 | def __init__(self, n, l, m, c0, device):
75 | assert (n < 0).sum() == 0
76 | assert (l < 0).sum() == (l >= n).sum() == 0
77 | assert (m > l).sum() == (m < -l).sum() == 0
78 | self.n, self.l, self.m, self.c0 = n, l, m, c0
79 | self.c0 = self.c0.to(device)
80 | self.c0 = self.c0/torch.sqrt(torch.sum(self.c0.abs()**2))
81 | self.states = list(EigenState(qnum[0], qnum[1], qnum[2]) for qnum in zip(n,l,m))
82 | self.dim = 3
83 | self.device = device
84 |
85 | def evolve_to(self, t):
86 | E = torch.tensor(list(psi.E for psi in self.states)).to(self.device)
87 | return WaveFunction(self.n, self.l, self.m, torch.exp(-1j*E*t/hbar)*self.c0, self.device)
88 |
89 | def avgH(self):
90 | E = torch.tensor(list(psi.E for psi in self.states))
91 | return torch.sum(self.c0.abs()**2*E)
92 |
93 | def avgL2(self):
94 | L2 = torch.tensor(list(psi.L2 for psi in self.states))
95 | return torch.sum(self.c0.abs()**2*L2)
96 |
97 | def avgLz(self):
98 | Lz = torch.tensor(list(psi.Lz for psi in self.states))
99 | return torch.sum(self.c0.abs()**2*Lz)
100 |
101 | def at(self, x):
102 | r = torch.sqrt(x[:,0]**2 + x[:,1]**2 + x[:,2]**2+EPS).flatten()
103 | theta = torch.atan2(torch.sqrt(x[:,0]**2 + x[:,1]**2+EPS),x[:,2]).flatten()
104 | x_coord = torch.sign(x[:,0])*(torch.abs(x[:,0])+EPS)
105 | phi = torch.atan2(x[:,1],x_coord).flatten()
106 | return self.at_polar(r, theta, phi)
107 |
108 | def at_polar(self, r, theta, phi):
109 | assert r.shape == theta.shape == phi.shape
110 | output = 1j*torch.zeros_like(r)
111 | for i in range(len(self.states)):
112 | psi_i = self.states[i]
113 | output += self.c0[i]*psi_i.radial(r)*psi_i.angular(theta, phi)
114 | return output
115 |
116 | def log_prob(self, x):
117 | # x.shape = [num_points, 3]
118 | r = torch.sqrt(x[:,0]**2 + x[:,1]**2 + x[:,2]**2+EPS).flatten()
119 | z = torch.sign(x[:,2])*(torch.abs(x[:,2])+EPS)
120 | theta = torch.atan2(torch.sqrt(x[:,0]**2 + x[:,1]**2+EPS),z).flatten()
121 | x_coord = torch.sign(x[:,0])*(torch.abs(x[:,0])+EPS)
122 | phi = torch.atan2(x[:,1],x_coord).flatten()
123 |
124 | radial_log = torch.stack([psi._radial_log(r) for psi in self.states])
125 | angular = torch.stack([psi._radial(r)*psi.angular(theta, phi) for psi in self.states])
126 | coords = self.c0.view([-1,1])
127 | max_log, _ = torch.max(radial_log, dim=0)
128 | psi = (torch.exp(radial_log-max_log)*angular*coords).sum(0)
129 | output = 2*torch.log(psi.abs()) + 2*max_log
130 | return output
131 |
132 |
133 | class BohmianDynamics:
134 | def __init__(self, wave_function, samples):
135 | self.psi = wave_function
136 | self.samples = samples
137 |
138 | def propagate(self, dt):
139 | samples = self.samples
140 | samples.requires_grad = True
141 | v = torch.autograd.grad(self.psi.at(samples).angle().sum(), samples)[0]
142 | samples.data += dt*v
143 | samples.requires_grad = False
144 | self.samples = samples
145 | self.psi = self.psi.evolve_to(dt)
146 |
--------------------------------------------------------------------------------
/core/losses.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import numpy as np
3 | import math
4 |
5 |
6 | class AMLoss:
7 | def __init__(self, s, q_t, config, device):
8 | self.u0 = 0.5
9 | self.batch_size = config.train.batch_size
10 | self.s = s
11 | self.q_t = q_t
12 | self.device = device
13 |
14 | def sample_t(self, n):
15 | u = (self.u0 + np.sqrt(2)*np.arange(n)) % 1
16 | return torch.tensor(u).view(-1,1).to(self.device)
17 |
18 | def eval_loss(self):
19 | q_t, s = self.q_t, self.s
20 | bs = self.batch_size
21 |
22 | t = self.sample_t(bs)
23 | x_t, t = q_t(t)
24 | x_t.requires_grad, t.requires_grad = True, True
25 | s_t = s(t, x_t)
26 | assert (2 == s_t.dim())
27 | dsdt, dsdx = torch.autograd.grad(s_t.sum(), [t, x_t], create_graph=True, retain_graph=True)
28 | x_t.requires_grad, t.requires_grad = False, False
29 |
30 | loss = 0.5*(dsdx**2).sum(1, keepdim=True) + dsdt.sum(1, keepdim=True)
31 | loss = loss.squeeze()
32 |
33 | t_0 = torch.zeros([bs, 1], device=self.device)
34 | x_0, _ = q_t(t_0)
35 | loss = loss + s(t_0,x_0).squeeze()
36 | t_1 = torch.ones([bs, 1], device=self.device)
37 | x_1, _ = q_t(t_1)
38 | loss = loss - s(t_1,x_1).squeeze()
39 | return loss.mean()
40 |
41 |
42 | class SMLoss:
43 | def __init__(self, s, q_t, config, device, sliced=True):
44 | self.u0 = 0.5
45 | self.batch_size = config.train.batch_size
46 | self.s = s
47 | self.q_t = q_t
48 | self.device = device
49 | self.div = div
50 | if sliced:
51 | self.div = divH
52 |
53 | def sample_t(self, n):
54 | u = (self.u0 + np.sqrt(2)*np.arange(n)) % 1
55 | return torch.tensor(u).view(-1,1).to(self.device)
56 |
57 | def eval_loss(self):
58 | q_t, s = self.q_t, self.s
59 | bs = self.batch_size
60 |
61 | t = self.sample_t(bs)
62 | x_t, t = q_t(t)
63 | dsdx = self.div(s, t, x_t, create_graph=True)
64 |
65 | loss = 0.5*(s(t, x_t)**2).sum(1, keepdim=True) + dsdx
66 | loss = loss.squeeze()
67 | return loss.mean()
68 |
69 | def div(v, t, x, create_graph=False):
70 | f = lambda x: v(t, x).sum(0)
71 | J = torch.autograd.functional.jacobian(f, x, create_graph=create_graph).swapaxes(0,1)
72 | return J.diagonal(dim1=1,dim2=2).sum(1, keepdim=True)
73 |
74 | def divH(v, t, x, create_graph=False):
75 | eps = torch.randint_like(x, low=0, high=2).float() * 2 - 1.
76 | x.requires_grad = True
77 | dxdt = v(t, x)
78 | div = (eps*torch.autograd.grad(dxdt, x, grad_outputs=eps, create_graph=create_graph)[0]).sum(1)
79 | x.requires_grad = False
80 | return div
81 |
--------------------------------------------------------------------------------
/core/samplers.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import torch
3 |
4 |
5 | class RWMH:
6 | def __init__(self, target, sigma=5.0):
7 | self.device = target.device
8 | self.target = target
9 | self.sigma = sigma
10 |
11 | @torch.no_grad()
12 | def log_prob(self, x):
13 | return self.target.log_prob(x).view([-1,1])
14 |
15 | def sample_n(self, x_0, n):
16 | # x_0.shape = [batch_size, dim]
17 | x = x_0.clone()
18 | log_p = self.log_prob(x)
19 | ar = torch.zeros_like(log_p)
20 | for i in range(n):
21 | _x = x + self.sigma*torch.empty_like(x).normal_()
22 | _log_p = self.log_prob(_x)
23 | accept_mask = (_log_p - log_p > torch.log(torch.zeros_like(log_p).uniform_())).float()
24 | x = accept_mask*_x + (1-accept_mask)*x
25 | log_p = accept_mask*_log_p + (1-accept_mask)*log_p
26 | ar += accept_mask
27 | ar = ar/n
28 | return x, ar
29 |
--------------------------------------------------------------------------------
/launch.py:
--------------------------------------------------------------------------------
1 | import os
2 | import copy
3 | import argparse
4 | import json
5 |
6 | import torch
7 | import numpy as np
8 | import wandb
9 |
10 | from torch import nn
11 | from tqdm.auto import tqdm, trange
12 |
13 | from models.mlp import *
14 | from models import ema
15 | from utils.train_utils import *
16 |
17 | from core.hmodel import *
18 | from core.losses import *
19 |
20 |
21 | def main(args):
22 | device = torch.device('cuda')
23 |
24 | model, data_gen, loss, config = prepare_hydrogen(device)
25 | config.model.savepath = os.path.join(args.checkpoint_dir, config.model.savepath)
26 | config.train.wandbid = wandb.util.generate_id()
27 |
28 | wandb.login()
29 | wandb.init(id=config.train.wandbid,
30 | project=config.data.name,
31 | resume="allow",
32 | config=json.loads(config.to_json_best_effort()))
33 | os.environ["WANDB_RESUME"] = "allow"
34 | os.environ["WANDB_RUN_ID"] = config.train.wandbid
35 |
36 | optim = torch.optim.Adam(model.parameters(), lr=config.train.lr, betas=config.train.betas,
37 | eps=1e-8, weight_decay=config.train.wd)
38 | ema_ = ema.ExponentialMovingAverage(model.parameters(), decay=config.eval.ema)
39 | train(model, ema_, loss, data_gen, optim, config, device)
40 |
41 | if __name__ == "__main__":
42 | parser = argparse.ArgumentParser(
43 | description=''
44 | )
45 |
46 | parser.add_argument(
47 | '--checkpoint_dir',
48 | type=str,
49 | help='path to save and look for the checkpoint file',
50 | default=os.getcwd()
51 | )
52 |
53 | main(parser.parse_args())
54 |
--------------------------------------------------------------------------------
/models/ema.py:
--------------------------------------------------------------------------------
1 | # Modified from https://raw.githubusercontent.com/fadel/pytorch_ema/master/torch_ema/ema.py
2 |
3 | from __future__ import division
4 | from __future__ import unicode_literals
5 |
6 | import torch
7 |
8 |
9 | # Partially based on: https://github.com/tensorflow/tensorflow/blob/r1.13/tensorflow/python/training/moving_averages.py
10 | class ExponentialMovingAverage:
11 | """
12 | Maintains (exponential) moving average of a set of parameters.
13 | """
14 |
15 | def __init__(self, parameters, decay, use_num_updates=True):
16 | """
17 | Args:
18 | parameters: Iterable of `torch.nn.Parameter`; usually the result of
19 | `model.parameters()`.
20 | decay: The exponential decay.
21 | use_num_updates: Whether to use number of updates when computing
22 | averages.
23 | """
24 | if decay < 0.0 or decay > 1.0:
25 | raise ValueError('Decay must be between 0 and 1')
26 | self.decay = decay
27 | self.num_updates = 0 if use_num_updates else None
28 | self.shadow_params = [p.clone().detach()
29 | for p in parameters if p.requires_grad]
30 | self.collected_params = []
31 |
32 | def update(self, parameters):
33 | """
34 | Update currently maintained parameters.
35 |
36 | Call this every time the parameters are updated, such as the result of
37 | the `optimizer.step()` call.
38 |
39 | Args:
40 | parameters: Iterable of `torch.nn.Parameter`; usually the same set of
41 | parameters used to initialize this object.
42 | """
43 | decay = self.decay
44 | if self.num_updates is not None:
45 | self.num_updates += 1
46 | decay = min(decay, (1 + self.num_updates) / (10 + self.num_updates))
47 | one_minus_decay = 1.0 - decay
48 | with torch.no_grad():
49 | parameters = [p for p in parameters if p.requires_grad]
50 | for s_param, param in zip(self.shadow_params, parameters):
51 | s_param.sub_(one_minus_decay * (s_param - param))
52 |
53 | def copy_to(self, parameters):
54 | """
55 | Copy current parameters into given collection of parameters.
56 |
57 | Args:
58 | parameters: Iterable of `torch.nn.Parameter`; the parameters to be
59 | updated with the stored moving averages.
60 | """
61 | parameters = [p for p in parameters if p.requires_grad]
62 | for s_param, param in zip(self.shadow_params, parameters):
63 | if param.requires_grad:
64 | param.data.copy_(s_param.data)
65 |
66 | def store(self, parameters):
67 | """
68 | Save the current parameters for restoring later.
69 |
70 | Args:
71 | parameters: Iterable of `torch.nn.Parameter`; the parameters to be
72 | temporarily stored.
73 | """
74 | self.collected_params = [param.clone() for param in parameters]
75 |
76 | def restore(self, parameters):
77 | """
78 | Restore the parameters stored with the `store` method.
79 | Useful to validate the model with EMA parameters without affecting the
80 | original optimization process. Store the parameters before the
81 | `copy_to` method. After validation (or model saving), use this to
82 | restore the former parameters.
83 |
84 | Args:
85 | parameters: Iterable of `torch.nn.Parameter`; the parameters to be
86 | updated with the stored parameters.
87 | """
88 | for c_param, param in zip(self.collected_params, parameters):
89 | param.data.copy_(c_param.data)
90 |
91 | def state_dict(self):
92 | return dict(decay=self.decay, num_updates=self.num_updates,
93 | shadow_params=self.shadow_params)
94 |
95 | def load_state_dict(self, state_dict):
96 | self.decay = state_dict['decay']
97 | self.num_updates = state_dict['num_updates']
98 | self.shadow_params = state_dict['shadow_params']
99 |
--------------------------------------------------------------------------------
/models/mlp.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torch.nn as nn
3 | import math
4 |
5 | class ActionNet(nn.Module):
6 | def __init__(self, net):
7 | super(ActionNet, self).__init__()
8 | self.net = net
9 |
10 | def forward(self, t, x):
11 | h = self.net(t, x)
12 | out = 0.5*((x-h)**2).sum(dim=1, keepdim=True)
13 | return out
14 |
15 | def propagate(self, t, x, dt):
16 | x.requires_grad = True
17 | v = torch.autograd.grad(self(t,x).sum(), x)[0]
18 | x.data += dt*v
19 | x.requires_grad = False
20 | return x
21 |
22 |
23 | class ScoreNet(nn.Module):
24 | def __init__(self, net):
25 | super(ScoreNet, self).__init__()
26 | self.net = net
27 |
28 | def forward(self, t, x):
29 | return 1e-2*self.net(t, x)
30 |
31 | def propagate(self, t, x, dt, eps=15.0, n_steps=5):
32 | for _ in range(n_steps):
33 | x.data += 0.5*eps*self(t+dt, x) + math.sqrt(eps)*torch.randn_like(x)
34 | return x
35 |
36 |
37 | class MLP(nn.Module):
38 | def __init__(self, n_dims=4, n_out=3, n_hid=512, layer=nn.Linear, relu=False):
39 | super(MLP, self).__init__()
40 | self._built = False
41 | self.net = nn.Sequential(
42 | layer(n_dims, n_hid),
43 | nn.LeakyReLU(.2) if relu else nn.SiLU(n_hid),
44 | layer(n_hid, n_hid),
45 | nn.LeakyReLU(.2) if relu else nn.SiLU(n_hid),
46 | layer(n_hid, n_hid),
47 | nn.LeakyReLU(.2) if relu else nn.SiLU(n_hid),
48 | layer(n_hid, n_hid),
49 | nn.LeakyReLU(.2) if relu else nn.SiLU(n_hid),
50 | layer(n_hid, n_out)
51 | )
52 |
53 | def forward(self, t, x):
54 | x = x.view(x.size(0), -1)
55 | t = t.view(t.size(0), 1)
56 | h = torch.hstack([t,x])
57 | h = self.net(h)
58 | return h
59 |
--------------------------------------------------------------------------------
/notebooks/annealed_Langevin.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "id": "de3d2fa2",
7 | "metadata": {},
8 | "outputs": [],
9 | "source": [
10 | "%matplotlib inline"
11 | ]
12 | },
13 | {
14 | "cell_type": "code",
15 | "execution_count": 2,
16 | "id": "aefa42d3",
17 | "metadata": {},
18 | "outputs": [],
19 | "source": [
20 | "import torch\n",
21 | "import numpy as np\n",
22 | "\n",
23 | "import sys\n",
24 | "sys.path.append('../')\n",
25 | "from core.hmodel import *\n",
26 | "from core.losses import *\n",
27 | "from models.mlp import MLP\n",
28 | "from models import ema\n",
29 | "from utils.train_utils import *\n",
30 | "from utils.plot_utils import *\n",
31 | "from utils.eval_utils import *\n",
32 | "\n",
33 | "from ml_collections import config_dict\n",
34 | "from tqdm.auto import tqdm, trange"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": 3,
40 | "id": "ca4cf6cd",
41 | "metadata": {},
42 | "outputs": [],
43 | "source": [
44 | "def propagate(t,x,dt,eps=10.0,n_steps=5):\n",
45 | " x_t, gen_t = data_gen.q_t(t + dt, replace=False)\n",
46 | " gen_t = gen_t*data_gen.T\n",
47 | " psi_t = data_gen.psi.evolve_to(gen_t[0].to(device))\n",
48 | " for _ in range(n_steps):\n",
49 | " x.requires_grad = True\n",
50 | " nabla_logp = torch.autograd.grad(psi_t.log_prob(x.to(device)).sum(), x)[0]\n",
51 | " x.requires_grad = False\n",
52 | " x.data += 0.5*eps*nabla_logp + math.sqrt(eps)*torch.randn_like(x)\n",
53 | " return x\n",
54 | "\n",
55 | "def evaluate(data_gen, eps, n_steps, device, config):\n",
56 | " N = config.data.n_steps//4\n",
57 | " x = data_gen.samples[0].to(device)\n",
58 | " dt = 1./config.data.n_steps\n",
59 | " t = torch.zeros([x.shape[0],1], device=device)\n",
60 | " n_evals = 5\n",
61 | " eval_every = N//n_evals\n",
62 | " avg_mmd = 0.0\n",
63 | " mmd = MMDStatistic(config.data.batch_size, config.data.batch_size)\n",
64 | " for i in range(N):\n",
65 | " x = propagate(t, x, dt, eps, n_steps)\n",
66 | " t.data += dt\n",
67 | " if ((i+1) % eval_every) == 0:\n",
68 | " x_t, gen_t = data_gen.q_t(t, replace=False)\n",
69 | " gen_t = gen_t*data_gen.T\n",
70 | " cur_mmd = mmd(x, x_t, 1e-4*torch.ones(x.shape[1], device=device))\n",
71 | " avg_mmd += cur_mmd.abs().cpu().numpy()/n_evals\n",
72 | " return avg_mmd\n",
73 | "\n",
74 | "def plot_frame(x, x_gt, kde=False):\n",
75 | " fig, ax = plt.subplots(2,3, figsize=(16,10))\n",
76 | " if kde:\n",
77 | " plot_samples_kde(x_gt, axes=ax[0])\n",
78 | " plot_samples_kde(x, axes=ax[1])\n",
79 | " else:\n",
80 | " plot_samples(x_gt, bins=40, axes=ax[0])\n",
81 | " plot_samples(x, bins=40, axes=ax[1])\n",
82 | " for j in range(3):\n",
83 | " ax[0,j].set_title('training data', fontsize=15)\n",
84 | " ax[1,j].set_title(f'samples from model', fontsize=15)\n",
85 | " plt.draw()\n",
86 | " fig.tight_layout()\n",
87 | " return fig"
88 | ]
89 | },
90 | {
91 | "cell_type": "code",
92 | "execution_count": 4,
93 | "id": "06063f4c",
94 | "metadata": {},
95 | "outputs": [],
96 | "source": [
97 | "device = torch.device('cuda')\n",
98 | "model, data_gen, loss, config = prepare_hydrogen(device)"
99 | ]
100 | },
101 | {
102 | "cell_type": "code",
103 | "execution_count": 5,
104 | "id": "4da7ce14",
105 | "metadata": {},
106 | "outputs": [
107 | {
108 | "data": {
109 | "application/vnd.jupyter.widget-view+json": {
110 | "model_id": "48e9394110c64be0b06f735ce320ac69",
111 | "version_major": 2,
112 | "version_minor": 0
113 | },
114 | "text/plain": [
115 | " 0%| | 0/30 [00:00, ?it/s]"
116 | ]
117 | },
118 | "metadata": {},
119 | "output_type": "display_data"
120 | }
121 | ],
122 | "source": [
123 | "n = 30\n",
124 | "eps_space = np.linspace(10.0,40.0,n)\n",
125 | "mmd_plot = np.zeros(n)\n",
126 | "for i in trange(n):\n",
127 | " mmd_plot[i] = evaluate(data_gen, eps_space[i], 5, device, config)"
128 | ]
129 | },
130 | {
131 | "cell_type": "code",
132 | "execution_count": 6,
133 | "id": "f892e6bb",
134 | "metadata": {},
135 | "outputs": [
136 | {
137 | "data": {
138 | "image/png": "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\n",
139 | "text/plain": [
140 | ""
141 | ]
142 | },
143 | "metadata": {},
144 | "output_type": "display_data"
145 | }
146 | ],
147 | "source": [
148 | "plt.plot(eps_space, mmd_plot)\n",
149 | "plt.grid()"
150 | ]
151 | },
152 | {
153 | "cell_type": "code",
154 | "execution_count": 7,
155 | "id": "d9a8f717",
156 | "metadata": {},
157 | "outputs": [
158 | {
159 | "data": {
160 | "application/vnd.jupyter.widget-view+json": {
161 | "model_id": "285c745f5e8548c69cda83d59df6354a",
162 | "version_major": 2,
163 | "version_minor": 0
164 | },
165 | "text/plain": [
166 | " 0%| | 0/10 [00:00, ?it/s]"
167 | ]
168 | },
169 | "metadata": {},
170 | "output_type": "display_data"
171 | }
172 | ],
173 | "source": [
174 | "n = 10\n",
175 | "eps_space = 15.0*np.ones(n)\n",
176 | "mmd_plot = np.zeros(n)\n",
177 | "for i in trange(n):\n",
178 | " mmd_plot[i] = evaluate(data_gen, eps_space[i], 5, device, config)"
179 | ]
180 | },
181 | {
182 | "cell_type": "code",
183 | "execution_count": 11,
184 | "id": "fa51b847",
185 | "metadata": {},
186 | "outputs": [
187 | {
188 | "data": {
189 | "text/plain": [
190 | "(0.0036192345619201665, 0.0004063455492671459)"
191 | ]
192 | },
193 | "execution_count": 11,
194 | "metadata": {},
195 | "output_type": "execute_result"
196 | }
197 | ],
198 | "source": [
199 | "mmd_plot.mean(), mmd_plot.std()"
200 | ]
201 | },
202 | {
203 | "cell_type": "code",
204 | "execution_count": null,
205 | "id": "daa35a1f",
206 | "metadata": {},
207 | "outputs": [],
208 | "source": []
209 | }
210 | ],
211 | "metadata": {
212 | "kernelspec": {
213 | "display_name": "Python 3 (ipykernel)",
214 | "language": "python",
215 | "name": "python3"
216 | },
217 | "language_info": {
218 | "codemirror_mode": {
219 | "name": "ipython",
220 | "version": 3
221 | },
222 | "file_extension": ".py",
223 | "mimetype": "text/x-python",
224 | "name": "python",
225 | "nbconvert_exporter": "python",
226 | "pygments_lexer": "ipython3",
227 | "version": "3.9.13"
228 | }
229 | },
230 | "nbformat": 4,
231 | "nbformat_minor": 5
232 | }
233 |
--------------------------------------------------------------------------------
/notebooks/gifs/am_celeba_diffusion.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/am_celeba_diffusion.gif
--------------------------------------------------------------------------------
/notebooks/gifs/am_celeba_inpaint.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/am_celeba_inpaint.gif
--------------------------------------------------------------------------------
/notebooks/gifs/am_celeba_superres.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/am_celeba_superres.gif
--------------------------------------------------------------------------------
/notebooks/gifs/am_celeba_torus.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/am_celeba_torus.gif
--------------------------------------------------------------------------------
/notebooks/gifs/am_cifar_color.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/am_cifar_color.gif
--------------------------------------------------------------------------------
/notebooks/gifs/am_cifar_diffusion.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/am_cifar_diffusion.gif
--------------------------------------------------------------------------------
/notebooks/gifs/am_cifar_superres.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/am_cifar_superres.gif
--------------------------------------------------------------------------------
/notebooks/gifs/am_cifar_torus.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/am_cifar_torus.gif
--------------------------------------------------------------------------------
/notebooks/gifs/am_results.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/am_results.gif
--------------------------------------------------------------------------------
/notebooks/gifs/dynamics_densities.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/dynamics_densities.gif
--------------------------------------------------------------------------------
/notebooks/gifs/sm_results.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/sm_results.gif
--------------------------------------------------------------------------------
/notebooks/gifs/ssm_results.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/gifs/ssm_results.gif
--------------------------------------------------------------------------------
/notebooks/losses_se.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/losses_se.png
--------------------------------------------------------------------------------
/notebooks/mmd_se.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/necludov/action-matching/29f2fd1d29e879e86e5a8fe34e4da2bc242b6c3b/notebooks/mmd_se.png
--------------------------------------------------------------------------------
/notebooks/visualize.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "id": "51950b96",
7 | "metadata": {},
8 | "outputs": [],
9 | "source": [
10 | "%matplotlib inline"
11 | ]
12 | },
13 | {
14 | "cell_type": "code",
15 | "execution_count": 2,
16 | "id": "04f7e8ad",
17 | "metadata": {},
18 | "outputs": [],
19 | "source": [
20 | "import torch\n",
21 | "import numpy as np\n",
22 | "\n",
23 | "import sys\n",
24 | "sys.path.append('../')\n",
25 | "from core.hmodel import *\n",
26 | "from core.losses import *\n",
27 | "from models.mlp import MLP\n",
28 | "from models import ema\n",
29 | "from utils.train_utils import *\n",
30 | "from utils.plot_utils import *\n",
31 | "from utils.eval_utils import *\n",
32 | "\n",
33 | "from ml_collections import config_dict\n",
34 | "from tqdm.auto import tqdm, trange"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": 4,
40 | "id": "f7cfdf85",
41 | "metadata": {},
42 | "outputs": [],
43 | "source": [
44 | "config_path_am = '../checkpoint/8724567/am_hydrogen.config'\n",
45 | "config_path_sm = '../checkpoint/8724481/sm_hydrogen.config'\n",
46 | "config_path_ssm = '../checkpoint/8724464/ssm_hydrogen.config'\n",
47 | "config = torch.load(config_path_ssm)"
48 | ]
49 | },
50 | {
51 | "cell_type": "code",
52 | "execution_count": 6,
53 | "id": "f6fdd724",
54 | "metadata": {},
55 | "outputs": [
56 | {
57 | "data": {
58 | "text/plain": [
59 | "ScoreNet(\n",
60 | " (net): MLP(\n",
61 | " (net): Sequential(\n",
62 | " (0): Linear(in_features=4, out_features=256, bias=True)\n",
63 | " (1): SiLU(inplace=True)\n",
64 | " (2): Linear(in_features=256, out_features=256, bias=True)\n",
65 | " (3): SiLU(inplace=True)\n",
66 | " (4): Linear(in_features=256, out_features=256, bias=True)\n",
67 | " (5): SiLU(inplace=True)\n",
68 | " (6): Linear(in_features=256, out_features=256, bias=True)\n",
69 | " (7): SiLU(inplace=True)\n",
70 | " (8): Linear(in_features=256, out_features=3, bias=True)\n",
71 | " )\n",
72 | " )\n",
73 | ")"
74 | ]
75 | },
76 | "execution_count": 6,
77 | "metadata": {},
78 | "output_type": "execute_result"
79 | }
80 | ],
81 | "source": [
82 | "device = torch.device('cuda')\n",
83 | "config.data.batch_size = int(1e4)\n",
84 | "model, data_gen, loss, _ = prepare_hydrogen(device, config)\n",
85 | "use_ema = True\n",
86 | "\n",
87 | "state = torch.load(config.model.checkpoints[2])\n",
88 | "model.load_state_dict(state['model'], strict=True)\n",
89 | "if use_ema:\n",
90 | " ema_ = ema.ExponentialMovingAverage(model.parameters(), decay=config.eval.ema)\n",
91 | " ema_.load_state_dict(state['ema'])\n",
92 | " ema_.copy_to(model.parameters())\n",
93 | "\n",
94 | "model.eval()"
95 | ]
96 | },
97 | {
98 | "cell_type": "code",
99 | "execution_count": 7,
100 | "id": "53e8b074",
101 | "metadata": {},
102 | "outputs": [
103 | {
104 | "data": {
105 | "text/plain": [
106 | "{'avg_mmd': 0.03509710431098938,\n",
107 | " 'score_loss': tensor(0.0006, device='cuda:0', grad_fn=)}"
108 | ]
109 | },
110 | "execution_count": 7,
111 | "metadata": {},
112 | "output_type": "execute_result"
113 | }
114 | ],
115 | "source": [
116 | "evaluate(model, ema_, data_gen, device, config)"
117 | ]
118 | },
119 | {
120 | "cell_type": "code",
121 | "execution_count": 8,
122 | "id": "b7b7b1de",
123 | "metadata": {},
124 | "outputs": [],
125 | "source": [
126 | "def plot_frame(x, x_gt, kde=False):\n",
127 | " fig, ax = plt.subplots(2,3, figsize=(16,10))\n",
128 | " if kde:\n",
129 | " plot_samples_kde(x_gt, axes=ax[0])\n",
130 | " plot_samples_kde(x, axes=ax[1])\n",
131 | " else:\n",
132 | " plot_samples(x_gt, bins=40, axes=ax[0])\n",
133 | " plot_samples(x, bins=40, axes=ax[1])\n",
134 | " for j in range(3):\n",
135 | " ax[0,j].set_title('training data', fontsize=15)\n",
136 | " ax[1,j].set_title(f'samples from {config.model.method}', fontsize=15)\n",
137 | " plt.draw()\n",
138 | " fig.tight_layout()\n",
139 | " return fig"
140 | ]
141 | },
142 | {
143 | "cell_type": "code",
144 | "execution_count": 9,
145 | "id": "e0aebc6d",
146 | "metadata": {
147 | "scrolled": false
148 | },
149 | "outputs": [
150 | {
151 | "data": {
152 | "application/vnd.jupyter.widget-view+json": {
153 | "model_id": "289a3829da92490e823a28a3fa536cce",
154 | "version_major": 2,
155 | "version_minor": 0
156 | },
157 | "text/plain": [
158 | " 0%| | 0/1000 [00:00, ?it/s]"
159 | ]
160 | },
161 | "metadata": {},
162 | "output_type": "display_data"
163 | },
164 | {
165 | "data": {
166 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABjYAAAPeCAYAAACvDyPsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAD4EklEQVR4nOzdeXhV5bn+8XszhYAJUyAhQQYF6gBogcqogAJKFasWFTlHwaNWq2AVrIraMrQKDlXPsVV/rRTUtoJHi7NVRFAQFUSoqFhAmSFExgQNCcP6/eFh10iA54lZ2Xttvp/r4ro0ufOs911r7bWfvd/srFgQBIEAAAAAAAAAAAAioFqiBwAAAAAAAAAAAGDFwgYAAAAAAAAAAIgMFjYAAAAAAAAAAEBksLABAAAAAAAAAAAig4UNAAAAAAAAAAAQGSxsAAAAAAAAAACAyGBhAwAAAAAAAAAARAYLGwAAAAAAAAAAIDJY2AAAAAAAAAAAAJHBwgaAMsaOHatYLKYpU6YkVa2qNGXKFMViMY0dOzbRQwEAIBLoH+gfAADwon+gfwC+DxY2gCS1atUqxWIx9e7dO9FDwfcQi8XUsmXLRA8DAHCEoH9IDfQPAICqRP+QGugfcKSpkegBAEguw4cP1+DBg9W0adOkqgUAAJIX/QMAAPCifwDwfbCwAaCMrKwsZWVlJV0tAACQvOgfAACAF/0DgO+DP0UFJKGxY8eqVatWkqS33npLsVgs/m/YsGHx3P6PGZaWlmr8+PE67rjjlJaWpvPOO0+StGvXLk2aNEk/+clPdMwxxyg9PV3169fXaaedpqlTpx502+X9XcrevXsrFotp1apVeu6559S1a1fVrVtXDRs21CWXXKJ169aFWkuSCgoKdNVVVyk7O1t16tRRx44d9be//a3CH5v96KOPdM4556hevXqqV6+e+vXrp3ffffeg+RUrVmjs2LHq1q2bcnJyVKtWLTVr1kyXXXaZli1bVia7/+9kStLq1avLHMNvj3Px4sW6+eab1alTJzVu3FhpaWk65phjdO2112rDhg2u+QAAjmz0D/QP9A8AAC/6B/oH+gdEFZ/YAJLQySefrJ/+9Kd69tlnlZ2drbPOOiv+vZ49e5bJ7tu3T+edd57efvtt9erVSx06dFCjRo0kffN3Mq+88kplZ2fruOOO0ymnnKL8/HzNmzdPc+bM0Weffea+QdXDDz+s3/3ud+rcubPOOussLViwQFOnTtXChQv1z3/+U+np6aHU2rx5s7p3767PP/9cRx99tPr06aNNmzbp0ksv1fDhw11zkKT3339fp59+ur7++mudfPLJOu644/Txxx+rV69eZZq3b3vsscd0991364QTTlDnzp1Vu3Ztffrpp3ryySf1/PPPa86cOerQoYMkqXXr1ho6dKgef/xx1a1bV4MGDYrXOe644+L/PXHiRD3zzDNq166devTooVgspsWLF+uRRx7Rc889pw8++EC5ubnu+QEAjjz0D/QP9A8AAC/6B/oH+gdEVgAgKa1cuTKQFPTq1eugGUmBpKB169bBunXrDvj+5s2bg9deey3Yu3dvma9/8cUXQcuWLYNq1aoFK1euLPO9MWPGBJKCyZMnl/l6r169AklB3bp1g5kzZ8a//tVXXwXdu3cPJAWTJk0KrdYVV1wRSArOP//8YNeuXfGvv/HGG0GtWrUOu6++be/evcFxxx0XSAomTJhQ5nt33HFHfL+OGTOmzPfefffdYMWKFQfU+/Of/xxICvr06XPA9yQFLVq0OOhYZs6cGWzYsOGA8Y0bNy6QFFx++eWmOQEAEAT0D/QP9A8AAD/6B/oH+gdEEX+KCkgBEyZMUF5e3gFfb9Sokfr3769q1co+1Fu1aqXbb79d+/bt04svvuja1o033qjTTz89/v916tTRqFGjJElvv/12KLV27typv/71r6pRo4b++7//W2lpafHvnXHGGRo8eLBru7Nnz9Znn32mtm3b6pZbbinzvTFjxqh58+bl/lzXrl117LHHHvD1yy+/XD169NDs2bO1Y8cO11hOP/30A25uVq1aNf36179WXl6enn/+eVc9AACs6B/oHwAA8KJ/oH8AkgV/igqIuFgspoEDBx4yM3fuXM2ePVvr16/Xrl27FASBNm7cKElavny5a3v9+/c/4Gtt27aVpHjNyq714YcfateuXerZs6eOPvroA37mwgsv1BNPPGHe7ty5c+M/t//vUO5Xo0YNDRo0SPfff3+5P7tz5069+OKLWrx4sbZu3ardu3fHxxsEgT7//HN17NjRPBZJ2rJli1544QV9/PHH2r59u/bu3StJ2r17t7Zu3aqtW7eqYcOGrpoAABwK/QP9AwAAXvQP9A9AMmFhA4i4Jk2alPkNgm/bsWOHLrjgAr355psH/fmioiLX9po1a3bA14466ihJUklJSSi19t/EqrymQtJBf8PhYPbXO9jPHezrb775pgYPHqwvv/zyoLW9+/Opp57Sz372M+3cufOQNWksAACVif6B/gEAAC/6B/oHIJnwp6iAiKtdu/ZBv3fLLbfozTff1GmnnabZs2dr8+bN2rNnj4Ig0GuvvSZJCoLAtb3v/obB9+GtdbC8dw77857t79y5UxdddJG+/PJL/epXv9Knn36qr776Svv27VMQBLrkkkvcY1m9erWGDRumkpISPfjgg1q+fLm+/vprBUGgIAjUrVs3d00AACzoH+gfAADwon+gfwCSCZ/YAFLY9OnTVb16db3wwguqV69eme998cUXCRqV3/6/AblmzZpyv7927VpXvdzcXEnfPLGXp7ztzJkzR1u2bNFPf/pTjR8//oDvV2R/vvLKKyotLdWoUaP0i1/8olJqAgDwfdE/lI/+AQCAg6N/KB/9AxAePrEBJKlatWpJkvbs2VPhGtu2bVNGRsYBTYUkPf300xWuW9U6duyotLQ0vffee1q3bt0B33/mmWdc9Xr27ClJevbZZw/4bYQ9e/bo2WefPeBntm3bJqn8j6OuWLFCH374Ybnbqlmz5kGP4aFqvv3229q0adMhZgEAwIHoH/6N/gEAABv6h3+jfwCig4UNIEllZWWpZs2a+vzzz+M3c/Jq27attm/frmnTppX5+gMPPKBZs2ZVxjCrREZGhoYMGaI9e/boxhtvVGlpafx7s2fP1lNPPeWq16dPH7Vt21afffaZ7rvvvjLf++1vf1vub1Lsv6nY3//+9zJ/43L79u264oor4jfx+q7c3Fxt2rRJ27dvP2jNv/zlL/rqq6/iX1+/fr2uueYa15wAAJDoH76N/gEAABv6h3+jfwCig4UNIEnVqlVLZ511lvLz83XSSSfpsssu05VXXqnJkyeba4wePVqSNHjwYJ122mkaMmSITjzxRN1000268cYbwxp6KCZOnKhWrVrpmWeeUZs2bXTJJZfojDPO0BlnnKGf/exnkv79WyaHU61aNU2ZMkXp6em6+eab1bFjRw0ZMkQdOnTQXXfdpSuvvPKAn+ncubP69eunNWvWqG3btjr//PN1/vnnq1WrVtqwYYN+8pOflLutc889V3v27FHHjh31n//5n7ryyit17733xr934okn6oMPPlDr1q01aNAgnXPOOWrbtq0aNGig7t27V3BvAQCOVPQPZdE/AABwePQPZdE/ANHAwgaQxB577DFdeuml2rJli/72t79p0qRJeuutt8w//x//8R96+eWX1bVrVy1evFivvvqqcnNz9eabb+rcc88NceSVr0mTJnr33Xf1X//1XyouLtZzzz2nLVu2aPLkyRo8eLAkqVGjRuZ63bp107x58zRgwACtWLFCL730kho3bqxZs2apR48e5f7M888/r9tvv12NGzfWq6++qoULF2rw4MF67733VL9+/XJ/ZsKECRo+fLj27NmjadOmadKkSXr55ZclfdMIzZkzRz//+c9Vu3ZtvfTSS1q6dKlGjBihGTNmqGbNmr6dBACA6B++jf4BAAAb+od/o38AoiEWcLt7ABF3991369Zbb9XEiRN1yy23JHo4AAAgAugfAACAF/0DkDxY2AAQGR9++KE6duxY5mtvv/22Bg4cqK+//lrLli1Tq1atEjQ6AACQjOgfAACAF/0DkPxqJHoAAGDVvXt35ebm6vjjj1fdunW1YsUKLVq0SNK//wYmAADAt9E/AAAAL/oHIPnxiQ0AkTFu3Di9/PLL+uKLL7Rjxw5lZmaqc+fOGj58uAYOHJjo4QEAgCRE/wAAALzoH4DkF/mbh0+YMEE/+tGPlJGRoSZNmui8887Tv/71rzKZIAg0duxY5ebmKj09Xb1799Ynn3xSJlNSUqIRI0YoKytLdevW1bnnnqt169ZV5VQAHMaYMWM0f/58bd68Wbt379aWLVv02muv0VQAqBB6CODIQP8AoDLRPwBHBvoHIPlFfmHjrbfe0nXXXaf33ntPM2bM0J49e9S/f3999dVX8cw999yj+++/X7///e+1YMEC5eTkqF+/fioqKopnbrjhBk2fPl1Tp07V3LlztXPnTp1zzjnau3dvIqYFAABCRg8BAAC86B8AAEgOKfenqL788ks1adJEb731lk477TQFQaDc3FzdcMMNuuWWWyR985sR2dnZuvvuu3X11Vdrx44daty4sZ588kldfPHFkqQNGzbo6KOP1iuvvKIzzzwzkVMCAABVgB4CAAB40T8AAJAYKXfz8B07dkiSGjZsKElauXKl8vPz1b9//3gmLS1NvXr10rx583T11Vdr4cKF2r17d5lMbm6u2rVrp3nz5h20qSgpKVFJSUn8//ft26etW7eqUaNGisVi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/QMAAGVF/hMbh5Ofn6/s7OwyX2vQoIFq1aql/Pz8eKZly5ZlMvt/Jj8/X61atSq39oQJE+K/rZE8io25hiHU9GQ9NdMdWaswtv9hCDU92TccNXs4sk8bc30dNTs6skuNua2Omp7z37r/Pdv3nH95xtx6R00P675a4agZxjXFc0w9x8p6/D1zCoN1+7tCHUUqSe7+ociYy3DUzKzIQA7D84aL9RrmmZMnazU/hJqS1MEWW/GOveR6x3N9b2PuVXtJZTmycz4yBlvaa37mOKeLrROzPidLmuN5XmpmzHkOgGOsnv1qZr1OSfZez3Odet+RDeOa6pl/GNc/JFJYPcTB+4d0SbUNIyswZMLk6ZetY/XMqYkx53ldFcLj8tVVjrBjnxYbn2t7G3sSSfrJKntW2YePSFKO472SBxzbT29py22zl/T1urONOc97JZ7H1DpjzvOY8pz/rY25TY6aYfD0Gp6s5/0Sq+WObKLfrwhPUn5iY+zYsYrFYof898EHH5jrlfcxziAIynz9u5n9N+061EdAR48erR07dsT/rV271jwmAABQuegfAABARUShh6B/AACgrKT8xMbw4cM1ePDgQ2a++9sNB5OTk6P33y/7Gzvbtm3T7t27478RkZOTE//Nif0KCr5Zpfzub1p8W1paWpmPjgIAgMShfwAAABURhR6C/gEAgLKScmEjKytLWVmez68fXLdu3XTnnXdq48aNatq0qaRvbuaVlpamTp06xTO33XabSktLVatWrXgmNzfX3LwAAIDEon8AAAAVQQ8BAED0JOWfovJYs2aNFi9erDVr1mjv3r1avHixFi9erJ07d0qS+vfvrxNOOEGXXnqpFi1apJkzZ+qmm27SVVddpczMb/4e2pAhQ5SWlqZhw4bp448/1vTp03XXXXdp5MiRh/xTEgAAIJroHwAAQEXQQwAAkByS8hMbHr/+9a/1+OOPx///hz/8oSRp1qxZ6t27t6pXr66XX35Z1157rXr06KH09HQNGTJE9913X/xn6tWrpxkzZui6665T586d1aBBA40cOVIjR46s8vkAAIDw0T8AAICKoIcAACA5RH5hY8qUKZoyZcohM82bN9dLL710yEz79u319ttvV+LIAABAsqJ/AAAAFUEPAQBAcoj8n6ICAAAAAAAAAABHDhY2AAAAAAAAAABAZLCwAQAAAAAAAAAAIiPy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ecsttwSSgp/97Gdlvl5eY/HAAw8EkoLRo0eXO6cbbrjhgKYrPT09OOmkk8rfCQ6WxqJdu3blrvKfdtppgaRg0qRJB3zvo48+CmKxWJCRkVGmIdrfWJTXIPzP//xPICmoV6/eAefB9u3bg1gsFrRo0cI0r2nTph3QRB7M3XffHUiK/6bI4exvLMprEDp27HjQ+f33f/93IOmA38AAAFQc/QP9A/0DAMCL/oH+gf4BODzusQEYderUSZLif1OwvL9T+V2LFy/WPffco+uuu06XX365hg0bpkceeUSStHz58nJ/pl+/fgd8bf+Nq1q2bKnWrVuX+V716tXVsmVL7d69W5s3bz7gZ3/4wx/qBz/4wQFfv+SSSyRJc+fOPew8ZsyYIUk677zzyv1+z549JUkLFiyIf61Tp0765z//qVtvvVWff/75YbfxfQwcOFCxWKzM13bv3q333ntPsVhMQ4YMOeBn2rdvrw4dOqioqEj//Oc/D/j+oY5D586dVb9+/TLfq1evnho1alTmb50eysknn6xq1arp3nvv1dSpU1VUVHTQ7P5z77bbbtNLL71U7t/m/K5atWqpV69eB51DefM79thjJck8BwDA4dE/0D/QPwAAvOgf6B/oH4DDq5HoAQBR8ctf/lJz587Viy++qBdffFH16tVTly5ddM4552jYsGHKyMiIZ0tLSzVs2DA99dRTB613sCeSvLy8A75Wt27dg37v298vKSk54HstWrQo92datmwpSdqwYcNBx7jfqlWrJEldunQ5ZO7bjc0f/vAHnXfeebr77rt19913Kzc3V6eeeqoGDRqkCy64QNWqVd66avPmzQ/42pYtW1RaWqqcnBzVrl273J9r2bKl/vnPf5a7Dyp6HMpr7srTtm1b3Xvvvbr11lt1ySWXqHr16mrXrp369u2ryy+/XCeeeGI8e8YZZ+jGG2/Ugw8+qIEDB6pWrVo6+eST1b9/f11xxRXxY/ltOTk55e7jQ83hUOcRAKBi6B/oH+gfAABe9A/0D/QPwOGxsAEYZWZm6s0339Q777yjF198UbNnz9bMmTP1+uuva8KECZozZ058xfn+++/XU089pXbt2unee+9Vx44d1aBBA9WsWVPLli3TD37wAwVBUO52vrvyb/1emPbu3StJuvDCC1WnTp2D5r7deHTo0EGffvqp/vGPf+iVV17RW2+9pWnT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pER5eXk1cq1bt1bTpk1VUlJSnencuXONzN5/U1JSoi5duoQdeC385Cc/0ZlnnqmsrCy9+uqrGjdunD766CPdcccdkpI5p3R4rX74wx+qR48eat26tRYuXKjx48dr1apVevzxx6vHeKg5ppKPPvpIu3fv3mfMeXl5KTne/endu7d+9atf6dhjj9XmzZt15513ql+/fnr33Xer57C/+a1ZsyaO4daKZR4lJSVq2rSpWrduvU8mVV/LIUOG6JJLLlGnTp20atUq/eu//qvOOOMMLV68WJmZmSk/pyiKNHbsWJ122mkqKiqSlL6vVdI1pP5BSr8eIl1eK3qI1JPuPUS63pPoH1JzXumqIfUQ9A+fS7U50T+kHvqH5N6TktxDpEL/wCc2/tf+HrTz5T9vvfVWjX+zceNGnXPOObrkkkt0zTXX1PhaRkbGPtuIoqjG3385E/3vw6D292/ra04Hc8cdd6hv3746+eSTNW7cOE2ePFn33XdfjUzoOUl1P69UeK2+zDPHG2+8Uf3799eJJ56oa665Ro8++qimTZumLVu2HHD8e+cQavx1YX/7PJXH+0VDhgzRRRddpO7du2vQoEF64YUXJElPPvlkdSbJ8/ui2swjled62WWX6dxzz1VRUZGGDh2ql156ScuXL69+DQ8kVeY0atQovf322/rtb3+7z9fS7bVKFenYP0jp2UM0hP5BooeQkn2PbSg9RLrdk+gf5M4gPXsI+odDS4XXaX/oH5J9f6V/OLBUn2eSe4hU6B/4xMb/GjVqlC6//PKDZr64ar5x40YNHDhQffv21WOPPVYjl5+frzfffLPG323btk27du2qXrHKz8/fZxVq70eNvryqVVveOXn16dNH5eXl2rx5s/Ly8uplTlLdzitVXqsvO5w59unTR5K0cuVKtWnTxjTHVJKbm6tGjRrtd5+n4ngtWrRooe7du2vFihX6zne+I+nzFer27dtXZ5I2v/z8fEkHn0d+fr6qqqq0bdu2GivxpaWl6tevX/0OuJbat2+vTp06acWKFZJSe06jR4/WH//4R7322mvq0KFD9d83lNcqLunYP0jp2UM0hP5Booegh0htDeWeRP8Q/7ySIB17CPqHg0uV12l/6B/oH1JZQ7onJaWHSJn+wfVEDkRRFEXr16+PunXrFl1++eX7fVr73gclbdy4sfrvZsyYsc8DoY466qiosrKyOnP33XfH/kCogz2468seeuihqFmzZtUPtUrVOUXRoR/elcTX6kCef/75SFK0Zs2aKIpsc0w1p5xySvT973+/xt8df/zxiXlw15ft3LkzKiwsjCZNmlT9IKV77rmn+uuVlZUp/eCuKDrww7sONo+9D4R65plnqjMbN25MmYdcfXlO+/PRRx9FmZmZ0ZNPPhlFUWrOac+ePdENN9wQFRQURMuXL9/v15P+WqWLdO4foig9e4iG1D9EET1EKkp6D0H/QP+AupHOPQT9QzJep4Ohf0g99A+fS7V7Ujr0EKnWP7Cw4bRhw4aoa9eu0RlnnBGtX78+2rRpU/WfvT777LOoqKgoOvPMM6MlS5ZEr7zyStShQ4do1KhR1ZmPP/44ysvLi6644oqouLg4+v3vfx9lZ2dH999/fxzTitasWRMtXbo0mjRpUnTkkUdGS5cujZYuXRpt3749iqIo+uMf/xg99thjUXFxcbRy5crol7/8ZZSdnR394Ac/SNk5RdGh55XE1+qLFixYED3wwAPR0qVLow8//DB65plnooKCguj888+vzljmmGpmzJgRNWnSJJo2bVr03nvvRWPGjIlatGgRrV69Ou6hmYwbNy6aO3du9OGHH0ZvvPFGdN5550UtW7asHv/dd98dtWrVKvr9738fFRcXR1dccUXUvn37qLy8POaR17R9+/bqc0ZS9bG2t2G1zOP666+POnToEL3yyivRkiVLojPOOCM66aST9vsNWdxz2r59ezRu3LhowYIF0apVq6I5c+ZEffv2jQoLC1N6Tt///vejVq1aRXPnzq1xT/r000+rM0l8rdJNuvYPUZSePUS69w9RRA+RqtKhh6B/oH+gf6hb6dpD0D8k43X6MvqH1ET/8LlUvCelWw+Rav0DCxtOTzzxRCRpv3++aM2aNdG5554bZWVlRTk5OdGoUaOqf6pgr7fffjv65je/GWVmZkb5+fnRxIkTY1uBHz58+H7nNGfOnCiKouill16KTj755OjII4+MmjdvHhUVFUUPPvhgtGvXrhp1UmlOUXToeUVR8l6rL1q8eHHUu3fvqFWrVlGzZs2ir371q9GECROiTz75pEbOMsdU8+///u9Rp06doqZNm0Y9evSI5s2bF/eQzC677LKoffv2UZMmTaKCgoLowgsvjN59993qr+/ZsyeaMGFClJ+fH2VmZkann356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\n",
167 | "text/plain": [
168 | ""
169 | ]
170 | },
171 | "metadata": {},
172 | "output_type": "display_data"
173 | }
174 | ],
175 | "source": [
176 | "x = data_gen.samples[0].to(device)\n",
177 | "t = torch.zeros([len(x),1]).to(device)\n",
178 | "dt = 1.0/config.data.n_steps\n",
179 | "for i in trange(config.data.n_steps):\n",
180 | " x = model.propagate(t, x, dt)\n",
181 | " t += dt\n",
182 | "\n",
183 | "plot_frame(x, data_gen.samples[-1]).show()"
184 | ]
185 | },
186 | {
187 | "cell_type": "code",
188 | "execution_count": 10,
189 | "id": "356b669e",
190 | "metadata": {},
191 | "outputs": [],
192 | "source": [
193 | "!mkdir gifs/ssm_results"
194 | ]
195 | },
196 | {
197 | "cell_type": "code",
198 | "execution_count": 11,
199 | "id": "d54fa282",
200 | "metadata": {},
201 | "outputs": [
202 | {
203 | "data": {
204 | "application/vnd.jupyter.widget-view+json": {
205 | "model_id": "e892eb913d934395a54f1d0224881d67",
206 | "version_major": 2,
207 | "version_minor": 0
208 | },
209 | "text/plain": [
210 | " 0%| | 0/1000 [00:00, ?it/s]"
211 | ]
212 | },
213 | "metadata": {},
214 | "output_type": "display_data"
215 | }
216 | ],
217 | "source": [
218 | "use_kde = False\n",
219 | "suffix = '_kde' if use_kde else ''\n",
220 | "x = data_gen.samples[0].to(device)\n",
221 | "t = torch.zeros([len(x),1]).to(device)\n",
222 | "dt = 1.0/config.data.n_steps\n",
223 | "\n",
224 | "frame_id = 0\n",
225 | "for i in trange(config.data.n_steps):\n",
226 | " if (i % 10) == 0:\n",
227 | " fig = plot_frame(x, data_gen.samples[i], kde=use_kde)\n",
228 | " fig.savefig(f\"./gifs/{config.model.method}_results{suffix}/frame_{frame_id}.png\", \n",
229 | " bbox_inches='tight', dpi=60)\n",
230 | " plt.close(fig)\n",
231 | " frame_id += 1\n",
232 | " x = model.propagate(t, x, dt)\n",
233 | " t += dt\n",
234 | "fig = plot_frame(x, data_gen.samples[i], kde=use_kde)\n",
235 | "fig.savefig(f\"./gifs/{config.model.method}_results{suffix}/frame_{frame_id}.png\", \n",
236 | " bbox_inches='tight', dpi=60)\n",
237 | "plt.close(fig)"
238 | ]
239 | },
240 | {
241 | "cell_type": "code",
242 | "execution_count": 12,
243 | "id": "61cedb9a",
244 | "metadata": {},
245 | "outputs": [],
246 | "source": [
247 | "!convert -delay 5 -loop 0 ./gifs/ssm_results/frame_{0..99}.png ./gifs/ssm_results.gif"
248 | ]
249 | },
250 | {
251 | "cell_type": "code",
252 | "execution_count": null,
253 | "id": "6b320848",
254 | "metadata": {},
255 | "outputs": [],
256 | "source": []
257 | }
258 | ],
259 | "metadata": {
260 | "kernelspec": {
261 | "display_name": "Python 3 (ipykernel)",
262 | "language": "python",
263 | "name": "python3"
264 | },
265 | "language_info": {
266 | "codemirror_mode": {
267 | "name": "ipython",
268 | "version": 3
269 | },
270 | "file_extension": ".py",
271 | "mimetype": "text/x-python",
272 | "name": "python",
273 | "nbconvert_exporter": "python",
274 | "pygments_lexer": "ipython3",
275 | "version": "3.9.13"
276 | }
277 | },
278 | "nbformat": 4,
279 | "nbformat_minor": 5
280 | }
281 |
--------------------------------------------------------------------------------
/utils/eval_utils.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import math
3 | import numpy as np
4 |
5 | from scipy import integrate
6 |
7 |
8 | def euler_scheme(ode_func, t0, t1, x, dt):
9 | solution = dotdict()
10 | timesteps = np.arange(t0, t1, dt)
11 | solution.y = np.zeros([len(x), len(timesteps)+1])
12 | solution.y[:,0] = x
13 | solution.nfev = 0
14 | for i, t in enumerate(timesteps):
15 | dx = ode_func(t, solution.y[:,i])
16 | solution.y[:,i+1] = solution.y[:,i] + dt*dx
17 | solution.nfev += 1
18 | return solution
19 |
20 | @torch.no_grad()
21 | def solve_ode(device, dxdt, x, t0=1.0, t1=0.0, atol=1e-5, rtol=1e-5, method='RK45', dt=-1e-2):
22 | shape = x.shape
23 | def ode_func(t, x_):
24 | x_ = torch.from_numpy(x_).reshape(shape).to(device).type(torch.float32)
25 | t_vec = torch.ones(x_.shape[0], device=x_.device) * t
26 | with torch.enable_grad():
27 | x_.requires_grad = True
28 | dx = dxdt(t_vec,x_).detach()
29 | x_.requires_grad = False
30 | dx = dx.cpu().numpy().flatten()
31 | return dx
32 |
33 | x = x.detach().cpu().numpy().flatten()
34 | if 'euler' != method:
35 | solution = integrate.solve_ivp(ode_func, (t0, t1), x, rtol=rtol, atol=atol, method=method)
36 | else:
37 | solution = euler_scheme(ode_func, t0, t1, x, dt)
38 | return torch.from_numpy(solution.y[:,-1].reshape(shape)), solution.nfev
39 |
40 | @torch.no_grad()
41 | def get_likelihood(device, dxdt, x, t0=0.0, t1=1.0, atol=1e-5, rtol=1e-5, method='RK45', dt=1e-2):
42 | assert (2 == x.dim())
43 | shape = x.shape
44 | eps = torch.randint_like(x, low=0, high=2).float() * 2 - 1.
45 | x = x.detach().cpu().numpy().flatten()
46 |
47 | def ode_func(t, x_):
48 | x_ = torch.from_numpy(x_[:-shape[0]]).reshape(shape).to(device).type(torch.float32)
49 | t_vec = torch.ones(x_.shape[0], device=x_.device) * t
50 | with torch.enable_grad():
51 | x_.requires_grad = True
52 | dx = dxdt(t_vec,x_)
53 | div = (eps*torch.autograd.grad(dx, x_, grad_outputs=eps)[0]).sum(1)
54 | x_.requires_grad = False
55 | dx = dx.detach().cpu().numpy().flatten()
56 | div = div.detach().cpu().numpy().flatten()
57 | return np.concatenate([dx, div], axis=0)
58 |
59 | init = np.concatenate([x, np.zeros((shape[0],))], axis=0)
60 | if 'euler' != method:
61 | solution = integrate.solve_ivp(ode_func, (t0, t1), init, rtol=rtol, atol=atol, method=method)
62 | else:
63 | solution = euler_scheme(ode_func, t0, t1, init, dt)
64 |
65 | z = torch.from_numpy(solution.y[:-shape[0],-1]).reshape(shape).to(device).type(torch.float32)
66 | delta_logp = torch.from_numpy(solution.y[-shape[0]:,-1]).to(device).type(torch.float32)
67 | return delta_logp, z, solution.nfev
68 |
69 | ######################################################
70 | # Code from https://github.com/josipd/torch-two-sample
71 | ######################################################
72 |
73 | def pdist(sample_1, sample_2, norm=2, eps=1e-5):
74 | r"""Compute the matrix of all squared pairwise distances.
75 | Arguments
76 | ---------
77 | sample_1 : torch.Tensor or Variable
78 | The first sample, should be of shape ``(n_1, d)``.
79 | sample_2 : torch.Tensor or Variable
80 | The second sample, should be of shape ``(n_2, d)``.
81 | norm : float
82 | The l_p norm to be used.
83 | Returns
84 | -------
85 | torch.Tensor or Variable
86 | Matrix of shape (n_1, n_2). The [i, j]-th entry is equal to
87 | ``|| sample_1[i, :] - sample_2[j, :] ||_p``."""
88 | n_1, n_2 = sample_1.size(0), sample_2.size(0)
89 | norm = float(norm)
90 | if norm == 2.:
91 | norms_1 = torch.sum(sample_1**2, dim=1, keepdim=True)
92 | norms_2 = torch.sum(sample_2**2, dim=1, keepdim=True)
93 | norms = (norms_1.expand(n_1, n_2) +
94 | norms_2.transpose(0, 1).expand(n_1, n_2))
95 | distances_squared = norms - 2 * sample_1.mm(sample_2.t())
96 | return torch.sqrt(eps + torch.abs(distances_squared))
97 | else:
98 | dim = sample_1.size(1)
99 | expanded_1 = sample_1.unsqueeze(1).expand(n_1, n_2, dim)
100 | expanded_2 = sample_2.unsqueeze(0).expand(n_1, n_2, dim)
101 | differences = torch.abs(expanded_1 - expanded_2) ** norm
102 | inner = torch.sum(differences, dim=2, keepdim=False)
103 | return (eps + inner) ** (1. / norm)
104 |
105 |
106 | class MMDStatistic:
107 | r"""The *unbiased* MMD test of :cite:`gretton2012kernel`.
108 | The kernel used is equal to:
109 | .. math ::
110 | k(x, x') = \sum_{j=1}^k e^{-\alpha_j\|x - x'\|^2},
111 | for the :math:`\alpha_j` proved in :py:meth:`~.MMDStatistic.__call__`.
112 | Arguments
113 | ---------
114 | n_1: int
115 | The number of points in the first sample.
116 | n_2: int
117 | The number of points in the second sample."""
118 |
119 | def __init__(self, n_1, n_2):
120 | self.n_1 = n_1
121 | self.n_2 = n_2
122 |
123 | # The three constants used in the test.
124 | self.a00 = 1. / (n_1 * (n_1 - 1))
125 | self.a11 = 1. / (n_2 * (n_2 - 1))
126 | self.a01 = - 1. / (n_1 * n_2)
127 |
128 | def __call__(self, sample_1, sample_2, alphas, ret_matrix=False):
129 | r"""Evaluate the statistic.
130 | The kernel used is
131 | .. math::
132 | k(x, x') = \sum_{j=1}^k e^{-\alpha_j \|x - x'\|^2},
133 | for the provided ``alphas``.
134 | Arguments
135 | ---------
136 | sample_1: :class:`torch:torch.autograd.Variable`
137 | The first sample, of size ``(n_1, d)``.
138 | sample_2: variable of shape (n_2, d)
139 | The second sample, of size ``(n_2, d)``.
140 | alphas : list of :class:`float`
141 | The kernel parameters.
142 | ret_matrix: bool
143 | If set, the call with also return a second variable.
144 | This variable can be then used to compute a p-value using
145 | :py:meth:`~.MMDStatistic.pval`.
146 | Returns
147 | -------
148 | :class:`float`
149 | The test statistic.
150 | :class:`torch:torch.autograd.Variable`
151 | Returned only if ``ret_matrix`` was set to true."""
152 | sample_12 = torch.cat((sample_1, sample_2), 0)
153 | distances = pdist(sample_12, sample_12, norm=2)
154 |
155 | kernels = None
156 | for alpha in alphas:
157 | kernels_a = torch.exp(- alpha * distances ** 2)
158 | if kernels is None:
159 | kernels = kernels_a
160 | else:
161 | kernels = kernels + kernels_a
162 |
163 | k_1 = kernels[:self.n_1, :self.n_1]
164 | k_2 = kernels[self.n_1:, self.n_1:]
165 | k_12 = kernels[:self.n_1, self.n_1:]
166 |
167 | mmd = (2 * self.a01 * k_12.sum() +
168 | self.a00 * (k_1.sum() - torch.trace(k_1)) +
169 | self.a11 * (k_2.sum() - torch.trace(k_2)))
170 | if ret_matrix:
171 | return mmd, kernels
172 | else:
173 | return mmd
174 |
175 | def pval(self, distances, n_permutations=1000):
176 | r"""Compute a p-value using a permutation test.
177 | Arguments
178 | ---------
179 | matrix: :class:`torch:torch.autograd.Variable`
180 | The matrix computed using :py:meth:`~.MMDStatistic.__call__`.
181 | n_permutations: int
182 | The number of random draws from the permutation null.
183 | Returns
184 | -------
185 | float
186 | The estimated p-value."""
187 | if isinstance(distances, Variable):
188 | distances = distances.data
189 | return permutation_test_mat(distances.cpu().numpy(),
190 | self.n_1, self.n_2,
191 | n_permutations,
192 | a00=self.a00, a11=self.a11, a01=self.a01)
193 |
194 |
--------------------------------------------------------------------------------
/utils/plot_utils.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import numpy as np
3 |
4 | from mpl_toolkits.mplot3d import Axes3D
5 | from matplotlib.colors import ListedColormap
6 | import matplotlib.pyplot as plt
7 | from matplotlib import cm
8 |
9 | import seaborn as sns
10 |
11 | def plot_scatter(samples, R=200, bins=75, axes=None):
12 | data = samples.detach().cpu().numpy()
13 |
14 | fig = None
15 | fs = 15
16 | if axes is None:
17 | fig, axes = plt.subplots(1,3)
18 | order = [[0,1], [1,2], [0,2]]
19 | labels = ['x', 'y', 'z']
20 | for i in range(len(axes)):
21 | a = axes[i]
22 | current_a = order[i]
23 | a.set_xlabel(labels[current_a[0]], fontsize=fs)
24 | a.set_ylabel(labels[current_a[1]], fontsize=fs)
25 | a.set_xlim(-R,R)
26 | a.set_ylim(-R,R)
27 | a.scatter(data[:,current_a[0]], data[:,current_a[1]], cmap = cm.jet, linewidth=0, marker=".")
28 | return fig
29 |
30 | def plot_samples_kde(samples, R=200, ppa=300, axes=None):
31 | data = samples.detach().cpu().numpy()
32 |
33 | fig = None
34 | fs = 15
35 | if axes is None:
36 | fig, axes = plt.subplots(1,3)
37 | order = [[0,1], [1,2], [0,2]]
38 | labels = ['x', 'y', 'z']
39 | for i in range(len(axes)):
40 | a = axes[i]
41 | current_a = order[i]
42 | a.set_xlabel(labels[current_a[0]], fontsize=fs)
43 | a.set_ylabel(labels[current_a[1]], fontsize=fs)
44 | a.set_xlim(-R,R)
45 | a.set_ylim(-R,R)
46 | sns.kdeplot(x=data[:,current_a[0]], y=data[:,current_a[1]],
47 | fill=True, thresh=0, levels=40, cmap=cm.jet, ax=axes[0], bw_adjust=6e-1)
48 | return fig
49 |
50 | def plot_samples(samples, R=200, bins=50, axes=None):
51 | data = samples.detach().cpu().numpy()
52 |
53 | fig = None
54 | fs = 15
55 | if axes is None:
56 | fig, axes = plt.subplots(1,3)
57 | order = [[0,1], [1,2], [0,2]]
58 | labels = ['x', 'y', 'z']
59 | for i in range(len(axes)):
60 | a = axes[i]
61 | current_a = order[i]
62 | a.set_xlabel(labels[current_a[0]], fontsize=fs)
63 | a.set_ylabel(labels[current_a[1]], fontsize=fs)
64 | a.set_xlim(-R,R)
65 | a.set_ylim(-R,R)
66 | a.hist2d(data[:,current_a[0]], data[:,current_a[1]], cmap = cm.jet,
67 | bins=bins, range=[[-R,R],[-R,R]])
68 | return fig
69 |
70 | def plot_projections(prob, R=200, ppa=300, device=torch.device('cpu'), axes=None):
71 | x, y, z = torch.linspace(-R, R, ppa), torch.linspace(-R, R, ppa), torch.linspace(-R, R, ppa)
72 | x, y, z = torch.meshgrid(x, y, z, indexing='xy')
73 | x, y, z = x.to(device), y.to(device), z.to(device)
74 |
75 | points = torch.stack([x.flatten(), y.flatten(), z.flatten()], dim=1)
76 | probs = prob(points).reshape([ppa,ppa,ppa]).detach().cpu().numpy().transpose([1,0,2])
77 |
78 | fig = None
79 | fs = 15
80 | if axes is None:
81 | fig, axes = plt.subplots(1,3)
82 | order = [[0,1], [1,2], [0,2]]
83 | third_a = [2, 0, 1]
84 | labels = ['x', 'y', 'z']
85 | for i in range(len(axes)):
86 | a = axes[i]
87 | current_a = order[i]
88 | a.set_xlabel(labels[current_a[0]], fontsize=fs)
89 | a.set_ylabel(labels[current_a[1]], fontsize=fs)
90 | a.set_xlim(-R,R)
91 | a.set_ylim(-R,R)
92 | a.imshow(probs.sum(third_a[i]).T, cmap = cm.jet, origin='lower', extent = [-R,R,-R,R])
93 | return fig
94 |
95 | def plot_slices(prob, R=300, ppa=300, device=torch.device('cpu')):
96 | x, y = torch.linspace(-R, R, ppa), torch.linspace(-R, R, ppa)
97 | x, y = torch.meshgrid(x, y, indexing='xy')
98 | x = x.to(device)
99 | y = y.to(device)
100 |
101 | fs = 15
102 | plt.subplot(131)
103 | prob_vals = prob(torch.stack([x.flatten(), y.flatten(), torch.zeros_like(x.flatten())], 1)).detach().cpu().numpy()
104 | plt.imshow(prob_vals.reshape(x.shape), cmap = cm.jet, origin='lower', extent = [-R,R,-R,R])
105 | plt.xlabel('x', fontsize=fs)
106 | plt.ylabel('y', fontsize=fs)
107 | plt.subplot(132)
108 | prob_vals = prob(torch.stack([torch.zeros_like(x.flatten()), x.flatten(), y.flatten()], 1)).detach().cpu().numpy()
109 | plt.imshow(prob_vals.reshape(x.shape), cmap = cm.jet, origin='lower', extent = [-R,R,-R,R])
110 | plt.xlabel('y', fontsize=fs)
111 | plt.ylabel('z', fontsize=fs)
112 | plt.subplot(133)
113 | prob_vals = prob(torch.stack([x.flatten(), torch.zeros_like(x.flatten()), y.flatten()], 1)).detach().cpu().numpy()
114 | plt.imshow(prob_vals.reshape(x.shape), cmap = cm.jet, origin='lower', extent = [-R,R,-R,R])
115 | plt.xlabel('x', fontsize=fs)
116 | plt.ylabel('z', fontsize=fs)
117 |
118 | def plot_sphere(prob, ppa=300):
119 | phi = torch.linspace(0.0, 2*np.pi, ppa)
120 | theta = torch.linspace(0.0, 2*np.pi, ppa)
121 | phi, theta = torch.meshgrid(phi, theta, indexing='xy')
122 | phi, theta, r = phi.flatten(), theta.flatten(), torch.ones_like(theta.flatten())
123 | x = torch.stack([r*torch.cos(phi)*torch.sin(theta), r*torch.sin(phi)*torch.sin(theta), r*torch.cos(theta)], 1)
124 | rho = prob(x).reshape([ppa, ppa])
125 | rho, xs, ys, zs = rho.numpy(), x[:,0].numpy(), x[:,1].numpy(), x[:,2].numpy()
126 | xs, ys, zs = xs.reshape([ppa, ppa]), ys.reshape([ppa, ppa]), zs.reshape([ppa, ppa])
127 | color_map = ListedColormap(sns.color_palette("coolwarm", 50))
128 | scalarMap = cm.ScalarMappable(norm = plt.Normalize(vmin=np.min(rho), vmax =np.max(rho)),
129 | cmap = cm.jet)
130 | C = scalarMap.to_rgba(rho)
131 | fig = plt.figure(figsize=(16,6))
132 | ax1 = fig.add_subplot(121, projection ='3d')
133 | ax1.plot_surface(xs, ys, zs, rcount = 100, ccount = 100, color = 'b', facecolors = C)
134 | plt.xlabel('x')
135 | plt.ylabel('y')
136 |
137 | ax2 = fig.add_subplot(122, projection ='3d')
138 | ax2.plot_surface(rho*xs, rho*ys, rho*zs, rstride = 1, cstride = 1, color = 'b', facecolors = C)
139 | plt.xlabel('x')
140 | plt.ylabel('y')
141 |
--------------------------------------------------------------------------------
/utils/train_utils.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import numpy as np
3 |
4 | from core.samplers import RWMH
5 | from core.hmodel import *
6 | from core.losses import *
7 | from models.mlp import *
8 | from utils.eval_utils import *
9 | from tqdm.auto import tqdm, trange
10 |
11 | import wandb
12 |
13 |
14 | class DataGenerator:
15 | def __init__(self, psi, config):
16 | self.sampler = RWMH(psi, sigma=10.0)
17 | self.bs = config.data.batch_size
18 | self.samples, self.times = None, None
19 | self.n_steps = config.data.n_steps # in time
20 | self.T = config.data.T
21 | self.psi = psi
22 | self.device = self.psi.device
23 | self.gen_data()
24 |
25 | def gen_data(self):
26 | batch_size, T, n_steps = self.bs, self.T, self.n_steps
27 | psi = self.psi
28 | x_0 = 50*torch.zeros([batch_size, psi.dim], device=psi.device).normal_()
29 | x, ar = self.sampler.sample_n(x_0, 5000)
30 | dynamics = BohmianDynamics(psi, x)
31 | dt = T/n_steps
32 | samples = torch.zeros([n_steps+1, batch_size, psi.dim], device=torch.device('cpu'))
33 | samples[0] = dynamics.samples.cpu()
34 | times = torch.zeros(n_steps + 1, device=torch.device('cpu'))
35 | for i in range(n_steps):
36 | dynamics.propagate(dt)
37 | samples[i+1] = dynamics.samples.cpu()
38 | times[i+1] = times[i] + dt
39 | self.samples, self.times = samples, times
40 |
41 | def q_t(self, t, replace=False):
42 | device = t.device
43 | t_ids = torch.round(t*(len(self.samples)-1)).long().squeeze().cpu()
44 | sample_ids = torch.from_numpy(np.random.choice(self.bs, t.shape[0], replace=replace)).squeeze()
45 | subsamples = self.samples[t_ids, sample_ids, :].to(device)
46 | times = self.times[t_ids].reshape(-1,1).to(device)
47 | return subsamples, times/self.T
48 |
49 |
50 | def prepare_hydrogen(device, config=None):
51 | if config is None:
52 | from configs.hydrogen import get_config
53 | config = get_config()
54 | n, l, m, c = config.data.n, config.data.l, config.data.m, config.data.c
55 | psi = WaveFunction(n,l,m,c,device)
56 | data_gen = DataGenerator(psi, config)
57 |
58 | net = MLP(n_hid=config.model.n_hid)
59 | if 'sm' == config.model.method:
60 | model = ScoreNet(net)
61 | loss = SMLoss(model, data_gen.q_t, config, device, sliced=False)
62 | elif 'ssm' == config.model.method:
63 | model = ScoreNet(net)
64 | loss = SMLoss(model, data_gen.q_t, config, device, sliced=True)
65 | elif 'am' == config.model.method:
66 | model = ActionNet(net)
67 | loss = AMLoss(model, data_gen.q_t, config, device)
68 | else:
69 | raise NameError(f'undefined method: {config.model.method}')
70 | model.to(device)
71 | return model, data_gen, loss, config
72 |
73 | def train(model, ema, loss, data_gen, optim, config, device):
74 | for current_step in range(config.train.n_iter):
75 | config.train.current_step = current_step
76 | model.train()
77 | loss_total = loss.eval_loss()
78 | optim.zero_grad(set_to_none=True)
79 | loss_total.backward()
80 |
81 | if config.train.warmup > 0:
82 | for g in optim.param_groups:
83 | g['lr'] = config.train.lr * np.minimum(current_step / config.train.warmup, 1.0)
84 | if config.train.grad_clip >= 0:
85 | torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=config.train.grad_clip)
86 | optim.step()
87 | ema.update(model.parameters())
88 |
89 | if (current_step % 50) == 0:
90 | logging_dict = {
91 | 'loss_' + config.model.method: loss_total.detach().cpu()
92 | }
93 | wandb.log(logging_dict, step=current_step)
94 |
95 | if ((current_step % config.train.regen_every) == 0) and current_step > 0:
96 | data_gen.gen_data()
97 | if ((current_step % config.train.eval_every) == 0):
98 | metric_dict = evaluate(model, ema, data_gen, device, config)
99 | wandb.log(metric_dict, step=current_step)
100 | if ((current_step % config.train.save_every) == 0):
101 | save(model, ema, optim, loss, config)
102 | config.train.current_step = current_step
103 | save(model, ema, optim, loss, config)
104 | metric_dict = evaluate(model, ema, data_gen, device, config)
105 | wandb.log(metric_dict, step=current_step)
106 |
107 | def save(model, ema, optim, loss, config):
108 | checkpoint_name = config.model.savepath + '_%d.cpt' % config.train.current_step
109 | config.model.checkpoints.append(checkpoint_name)
110 | torch.save({'model': model.state_dict(),
111 | 'ema': ema.state_dict(),
112 | 'optim': optim.state_dict()}, checkpoint_name)
113 | torch.save(config, config.model.savepath + '.config')
114 |
115 | def evaluate(model, ema, data_gen, device, config):
116 | ema.store(model.parameters())
117 | ema.copy_to(model.parameters())
118 | model.eval()
119 | ######## evaluation ########
120 | metric_dict = {}
121 | x = data_gen.samples[0].to(device)
122 | dt = 1./config.data.n_steps
123 | t = torch.zeros([x.shape[0],1], device=device)
124 | n_evals = 10
125 | eval_every = config.data.n_steps//n_evals
126 | metric_dict['avg_mmd'] = 0.0
127 | metric_dict['score_loss'] = 0.0
128 | mmd = MMDStatistic(config.data.batch_size, config.data.batch_size)
129 | for i in range(config.data.n_steps):
130 | x = model.propagate(t, x, dt)
131 | t.data += dt
132 | if ((i+1) % eval_every) == 0:
133 | x_t, gen_t = data_gen.q_t(t, replace=False)
134 | gen_t = gen_t*data_gen.T
135 | cur_mmd = mmd(x, x_t, 1e-4*torch.ones(x.shape[1], device=device))
136 | metric_dict['avg_mmd'] += cur_mmd.abs().cpu().numpy()/n_evals
137 | if config.model.method in {'sm', 'ssm'}:
138 | psi_t = data_gen.psi.evolve_to(gen_t[0].to(device))
139 | x_t.requires_grad = True
140 | nabla_logp = torch.autograd.grad(psi_t.log_prob(x_t.to(device)).sum(), x_t)[0]
141 | x_t.requires_grad = False
142 | loss = 0.5*((nabla_logp - model(t, x_t))**2).sum(1)
143 | metric_dict['score_loss'] += loss.mean()/n_evals
144 | ############################
145 | ema.restore(model.parameters())
146 | return metric_dict
147 |
--------------------------------------------------------------------------------