add mnist_vae/ (checkpoint + code)
Browse files- mnist_vae/load.py +17 -0
- mnist_vae/mnist_vae.pkl +3 -0
- mnist_vae/vae.py +142 -0
mnist_vae/load.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pickle
|
| 2 |
+
|
| 3 |
+
from vae import VAE
|
| 4 |
+
|
| 5 |
+
with open("mnist_vae.pkl", "rb") as f:
|
| 6 |
+
bundle = pickle.load(f)
|
| 7 |
+
meta = bundle["meta"]
|
| 8 |
+
params = bundle["params"]
|
| 9 |
+
|
| 10 |
+
model = VAE(
|
| 11 |
+
latent_dim=meta["latent_dim"],
|
| 12 |
+
in_channels=meta["in_channels"],
|
| 13 |
+
base_channels=meta["base_channels"],
|
| 14 |
+
channel_mults=tuple(meta["channel_mults"]),
|
| 15 |
+
image_size=meta["image_size"],
|
| 16 |
+
obs_sigma=meta["obs_sigma"],
|
| 17 |
+
)
|
mnist_vae/mnist_vae.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:64a52c2eff25217b17fc727b168538fd87feb2a1a753fd8cd6fb608a0a038e05
|
| 3 |
+
size 867032
|
mnist_vae/vae.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any
|
| 2 |
+
|
| 3 |
+
import jax
|
| 4 |
+
import jax.numpy as jnp
|
| 5 |
+
from flax import linen as nn
|
| 6 |
+
|
| 7 |
+
Array = jax.Array
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class ResBlock(nn.Module):
|
| 11 |
+
features: int
|
| 12 |
+
groups: int = 8
|
| 13 |
+
|
| 14 |
+
@nn.compact
|
| 15 |
+
def __call__(self, x: Array) -> Array:
|
| 16 |
+
residual = x
|
| 17 |
+
if x.shape[-1] != self.features:
|
| 18 |
+
residual = nn.Conv(self.features, kernel_size=(1, 1))(residual)
|
| 19 |
+
h = nn.GroupNorm(num_groups=min(self.groups, self.features))(x)
|
| 20 |
+
h = nn.swish(h)
|
| 21 |
+
h = nn.Conv(self.features, kernel_size=(3, 3))(h)
|
| 22 |
+
h = nn.GroupNorm(num_groups=min(self.groups, self.features))(h)
|
| 23 |
+
h = nn.swish(h)
|
| 24 |
+
h = nn.Conv(self.features, kernel_size=(3, 3))(h)
|
| 25 |
+
return h + residual
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class Downsample(nn.Module):
|
| 29 |
+
features: int
|
| 30 |
+
|
| 31 |
+
@nn.compact
|
| 32 |
+
def __call__(self, x: Array) -> Array:
|
| 33 |
+
return nn.Conv(self.features, kernel_size=(3, 3), strides=(2, 2))(x)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
class Upsample(nn.Module):
|
| 37 |
+
features: int
|
| 38 |
+
|
| 39 |
+
@nn.compact
|
| 40 |
+
def __call__(self, x: Array) -> Array:
|
| 41 |
+
b, h, w, _ = x.shape
|
| 42 |
+
x = jax.image.resize(x, (b, h * 2, w * 2, x.shape[-1]), method="nearest")
|
| 43 |
+
return nn.Conv(self.features, kernel_size=(3, 3))(x)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class Encoder(nn.Module):
|
| 47 |
+
latent_dim: int
|
| 48 |
+
base_channels: int = 64
|
| 49 |
+
channel_mults: tuple[int, ...] = (1, 2, 4)
|
| 50 |
+
|
| 51 |
+
@nn.compact
|
| 52 |
+
def __call__(self, x: Array) -> tuple[Array, Array]:
|
| 53 |
+
h = nn.Conv(self.base_channels, kernel_size=(3, 3))(x)
|
| 54 |
+
for i, mult in enumerate(self.channel_mults):
|
| 55 |
+
features = self.base_channels * mult
|
| 56 |
+
h = ResBlock(features)(h)
|
| 57 |
+
h = ResBlock(features)(h)
|
| 58 |
+
if i < len(self.channel_mults) - 1:
|
| 59 |
+
h = Downsample(features)(h)
|
| 60 |
+
h = Downsample(self.base_channels * self.channel_mults[-1])(h)
|
| 61 |
+
h = nn.GroupNorm(num_groups=8)(h)
|
| 62 |
+
h = nn.swish(h)
|
| 63 |
+
h = h.reshape(h.shape[0], -1)
|
| 64 |
+
mu = nn.Dense(self.latent_dim)(h)
|
| 65 |
+
log_var = nn.Dense(self.latent_dim)(h)
|
| 66 |
+
log_var = jnp.clip(log_var, -10.0, 10.0)
|
| 67 |
+
return mu, log_var
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
class Decoder(nn.Module):
|
| 71 |
+
out_channels: int
|
| 72 |
+
base_channels: int = 64
|
| 73 |
+
channel_mults: tuple[int, ...] = (1, 2, 4)
|
| 74 |
+
image_size: int = 32
|
| 75 |
+
|
| 76 |
+
@nn.compact
|
| 77 |
+
def __call__(self, z: Array) -> Array:
|
| 78 |
+
n_down = len(self.channel_mults)
|
| 79 |
+
start = self.image_size // (2**n_down)
|
| 80 |
+
features_top = self.base_channels * self.channel_mults[-1]
|
| 81 |
+
h = nn.Dense(start * start * features_top)(z)
|
| 82 |
+
h = h.reshape(z.shape[0], start, start, features_top)
|
| 83 |
+
h = Upsample(features_top)(h)
|
| 84 |
+
for i, mult in enumerate(reversed(self.channel_mults)):
|
| 85 |
+
features = self.base_channels * mult
|
| 86 |
+
h = ResBlock(features)(h)
|
| 87 |
+
h = ResBlock(features)(h)
|
| 88 |
+
if i < len(self.channel_mults) - 1:
|
| 89 |
+
next_features = self.base_channels * list(reversed(self.channel_mults))[i + 1]
|
| 90 |
+
h = Upsample(next_features)(h)
|
| 91 |
+
h = nn.GroupNorm(num_groups=8)(h)
|
| 92 |
+
h = nn.swish(h)
|
| 93 |
+
h = nn.Conv(self.out_channels, kernel_size=(3, 3))(h)
|
| 94 |
+
return nn.sigmoid(h)
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
class VAE(nn.Module):
|
| 98 |
+
latent_dim: int = 128
|
| 99 |
+
in_channels: int = 3
|
| 100 |
+
base_channels: int = 64
|
| 101 |
+
channel_mults: tuple[int, ...] = (1, 2, 4)
|
| 102 |
+
image_size: int = 32
|
| 103 |
+
obs_sigma: float = 0.1
|
| 104 |
+
|
| 105 |
+
def setup(self):
|
| 106 |
+
self.encoder = Encoder(
|
| 107 |
+
latent_dim=self.latent_dim,
|
| 108 |
+
base_channels=self.base_channels,
|
| 109 |
+
channel_mults=self.channel_mults,
|
| 110 |
+
)
|
| 111 |
+
self.decoder = Decoder(
|
| 112 |
+
out_channels=self.in_channels,
|
| 113 |
+
base_channels=self.base_channels,
|
| 114 |
+
channel_mults=self.channel_mults,
|
| 115 |
+
image_size=self.image_size,
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
def encode(self, x: Array) -> tuple[Array, Array]:
|
| 119 |
+
return self.encoder(x)
|
| 120 |
+
|
| 121 |
+
def decode(self, z: Array) -> Array:
|
| 122 |
+
return self.decoder(z)
|
| 123 |
+
|
| 124 |
+
def reparameterize(self, rng: Array, mu: Array, log_var: Array) -> Array:
|
| 125 |
+
eps = jax.random.normal(rng, mu.shape)
|
| 126 |
+
return mu + jnp.exp(0.5 * log_var) * eps
|
| 127 |
+
|
| 128 |
+
def __call__(self, x: Array, rng: Array) -> dict[str, Array]:
|
| 129 |
+
mu, log_var = self.encode(x)
|
| 130 |
+
z = self.reparameterize(rng, mu, log_var)
|
| 131 |
+
x_hat = self.decode(z)
|
| 132 |
+
return {"x_hat": x_hat, "mu": mu, "log_var": log_var, "z": z}
|
| 133 |
+
|
| 134 |
+
def sample_prior(self, rng: Array, n: int) -> Array:
|
| 135 |
+
z = jax.random.normal(rng, (n, self.latent_dim))
|
| 136 |
+
return self.decode(z)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def latent_log_prior(z: Array) -> Array:
|
| 140 |
+
"""Standard normal prior log density, summed over latent dimensions."""
|
| 141 |
+
d = z.shape[-1]
|
| 142 |
+
return -0.5 * (jnp.sum(z * z, axis=-1) + d * jnp.log(2 * jnp.pi))
|