Spaces:
Running
on
Zero
Running
on
Zero
import torch | |
from torch import nn | |
from torch.nn import functional as F | |
from einops import rearrange | |
from vector_quantize_pytorch import ResidualVQ, FSQ | |
from .nn.quantize import ResidualVectorQuantize as DACResidualVQ | |
class Bottleneck(nn.Module): | |
def __init__(self, is_discrete: bool = False): | |
super().__init__() | |
self.is_discrete = is_discrete | |
def encode(self, x, return_info=False, **kwargs): | |
raise NotImplementedError | |
def decode(self, x): | |
raise NotImplementedError | |
class DiscreteBottleneck(Bottleneck): | |
def __init__(self, num_quantizers, codebook_size, tokens_id): | |
super().__init__(is_discrete=True) | |
self.num_quantizers = num_quantizers | |
self.codebook_size = codebook_size | |
self.tokens_id = tokens_id | |
def decode_tokens(self, codes, **kwargs): | |
raise NotImplementedError | |
class TanhBottleneck(Bottleneck): | |
def __init__(self): | |
super().__init__(is_discrete=False) | |
self.tanh = nn.Tanh() | |
def encode(self, x, return_info=False): | |
info = {} | |
x = torch.tanh(x) | |
if return_info: | |
return x, info | |
else: | |
return x | |
def decode(self, x): | |
return x | |
def vae_sample_kl(mean, scale): | |
stdev = nn.functional.softplus(scale) + 1e-4 | |
var = stdev * stdev | |
logvar = torch.log(var) | |
latents = torch.randn_like(mean) * stdev + mean | |
kl = (mean * mean + var - logvar - 1).sum(1).mean() | |
return latents, kl | |
def vae_sample(mean, scale): | |
stdev = nn.functional.softplus(scale) + 1e-4 | |
latents = torch.randn_like(mean) * stdev + mean | |
return latents | |
class VAEBottleneck(Bottleneck): | |
def __init__(self): | |
super().__init__(is_discrete=False) | |
def encode(self, x, return_info=False, **kwargs): | |
mean, scale = x.chunk(2, dim=1) | |
if return_info: | |
info = {} | |
x, kl = vae_sample_kl(mean, scale) | |
info["kl"] = kl | |
return x, info | |
else: | |
x = vae_sample(mean, scale) | |
return x | |
def decode(self, x): | |
return x | |
def compute_mean_kernel(x, y): | |
kernel_input = (x[:, None] - y[None]).pow(2).mean(2) / x.shape[-1] | |
return torch.exp(-kernel_input).mean() | |
def compute_mmd(latents): | |
latents_reshaped = latents.permute(0, 2, 1).reshape(-1, latents.shape[1]) | |
noise = torch.randn_like(latents_reshaped) | |
latents_kernel = compute_mean_kernel(latents_reshaped, latents_reshaped) | |
noise_kernel = compute_mean_kernel(noise, noise) | |
latents_noise_kernel = compute_mean_kernel(latents_reshaped, noise) | |
mmd = latents_kernel + noise_kernel - 2 * latents_noise_kernel | |
return mmd.mean() | |
class WassersteinBottleneck(Bottleneck): | |
def __init__(self, noise_augment_dim: int = 0): | |
super().__init__(is_discrete=False) | |
self.noise_augment_dim = noise_augment_dim | |
def encode(self, x, return_info=False): | |
info = {} | |
if self.training and return_info: | |
mmd = compute_mmd(x) | |
info["mmd"] = mmd | |
if return_info: | |
return x, info | |
return x | |
def decode(self, x): | |
if self.noise_augment_dim > 0: | |
noise = torch.randn(x.shape[0], self.noise_augment_dim, | |
x.shape[-1]).type_as(x) | |
x = torch.cat([x, noise], dim=1) | |
return x | |
class L2Bottleneck(Bottleneck): | |
def __init__(self): | |
super().__init__(is_discrete=False) | |
def encode(self, x, return_info=False): | |
info = {} | |
x = F.normalize(x, dim=1) | |
if return_info: | |
return x, info | |
else: | |
return x | |
def decode(self, x): | |
return F.normalize(x, dim=1) | |
class RVQBottleneck(DiscreteBottleneck): | |
def __init__(self, **quantizer_kwargs): | |
super().__init__(num_quantizers = quantizer_kwargs["num_quantizers"], codebook_size = quantizer_kwargs["codebook_size"], tokens_id = "quantizer_indices") | |
self.quantizer = ResidualVQ(**quantizer_kwargs) | |
self.num_quantizers = quantizer_kwargs["num_quantizers"] | |
def encode(self, x, return_info=False, **kwargs): | |
info = {} | |
x = rearrange(x, "b c n -> b n c") | |
x, indices, loss = self.quantizer(x) | |
x = rearrange(x, "b n c -> b c n") | |
info["quantizer_indices"] = indices | |
info["quantizer_loss"] = loss.mean() | |
if return_info: | |
return x, info | |
else: | |
return x | |
def decode(self, x): | |
return x | |
def decode_tokens(self, codes, **kwargs): | |
latents = self.quantizer.get_outputs_from_indices(codes) | |
return self.decode(latents, **kwargs) | |
class RVQVAEBottleneck(DiscreteBottleneck): | |
def __init__(self, **quantizer_kwargs): | |
super().__init__(num_quantizers = quantizer_kwargs["num_quantizers"], codebook_size = quantizer_kwargs["codebook_size"], tokens_id = "quantizer_indices") | |
self.quantizer = ResidualVQ(**quantizer_kwargs) | |
self.num_quantizers = quantizer_kwargs["num_quantizers"] | |
def encode(self, x, return_info=False): | |
info = {} | |
x, kl = vae_sample(*x.chunk(2, dim=1)) | |
info["kl"] = kl | |
x = rearrange(x, "b c n -> b n c") | |
x, indices, loss = self.quantizer(x) | |
x = rearrange(x, "b n c -> b c n") | |
info["quantizer_indices"] = indices | |
info["quantizer_loss"] = loss.mean() | |
if return_info: | |
return x, info | |
else: | |
return x | |
def decode(self, x): | |
return x | |
def decode_tokens(self, codes, **kwargs): | |
latents = self.quantizer.get_outputs_from_indices(codes) | |
return self.decode(latents, **kwargs) | |
class DACRVQBottleneck(DiscreteBottleneck): | |
def __init__(self, quantize_on_decode=False, **quantizer_kwargs): | |
super().__init__(num_quantizers = quantizer_kwargs["n_codebooks"], codebook_size = quantizer_kwargs["codebook_size"], tokens_id = "codes") | |
self.quantizer = DACResidualVQ(**quantizer_kwargs) | |
self.num_quantizers = quantizer_kwargs["n_codebooks"] | |
self.quantize_on_decode = quantize_on_decode | |
def encode(self, x, return_info=False, **kwargs): | |
info = {} | |
info["pre_quantizer"] = x | |
if self.quantize_on_decode: | |
return x, info if return_info else x | |
z, codes, latents, commitment_loss, codebook_loss = self.quantizer(x, **kwargs) | |
output = { | |
"z": z, | |
"codes": codes, | |
"latents": latents, | |
"vq/commitment_loss": commitment_loss, | |
"vq/codebook_loss": codebook_loss, | |
} | |
output["vq/commitment_loss"] /= self.num_quantizers | |
output["vq/codebook_loss"] /= self.num_quantizers | |
info.update(output) | |
if return_info: | |
return output["z"], info | |
return output["z"] | |
def decode(self, x): | |
if self.quantize_on_decode: | |
x = self.quantizer(x)[0] | |
return x | |
def decode_tokens(self, codes, **kwargs): | |
latents, _, _ = self.quantizer.from_codes(codes) | |
return self.decode(latents, **kwargs) | |
class DACRVQVAEBottleneck(DiscreteBottleneck): | |
def __init__(self, quantize_on_decode=False, **quantizer_kwargs): | |
super().__init__(num_quantizers = quantizer_kwargs["n_codebooks"], codebook_size = quantizer_kwargs["codebook_size"], tokens_id = "codes") | |
self.quantizer = DACResidualVQ(**quantizer_kwargs) | |
self.num_quantizers = quantizer_kwargs["n_codebooks"] | |
self.quantize_on_decode = quantize_on_decode | |
def encode(self, x, return_info=False, n_quantizers: int = None): | |
info = {} | |
mean, scale = x.chunk(2, dim=1) | |
x, kl = vae_sample(mean, scale) | |
info["pre_quantizer"] = x | |
info["kl"] = kl | |
if self.quantize_on_decode: | |
return x, info if return_info else x | |
z, codes, latents, commitment_loss, codebook_loss = self.quantizer(x, n_quantizers=n_quantizers) | |
output = { | |
"z": z, | |
"codes": codes, | |
"latents": latents, | |
"vq/commitment_loss": commitment_loss, | |
"vq/codebook_loss": codebook_loss, | |
} | |
output["vq/commitment_loss"] /= self.num_quantizers | |
output["vq/codebook_loss"] /= self.num_quantizers | |
info.update(output) | |
if return_info: | |
return output["z"], info | |
return output["z"] | |
def decode(self, x): | |
if self.quantize_on_decode: | |
x = self.quantizer(x)[0] | |
return x | |
def decode_tokens(self, codes, **kwargs): | |
latents, _, _ = self.quantizer.from_codes(codes) | |
return self.decode(latents, **kwargs) | |
class FSQBottleneck(DiscreteBottleneck): | |
def __init__(self, dim, levels): | |
super().__init__(num_quantizers = 1, codebook_size = levels ** dim, tokens_id = "quantizer_indices") | |
self.quantizer = FSQ(levels=[levels] * dim) | |
def encode(self, x, return_info=False): | |
info = {} | |
x = rearrange(x, "b c n -> b n c") | |
x, indices = self.quantizer(x) | |
x = rearrange(x, "b n c -> b c n") | |
info["quantizer_indices"] = indices | |
if return_info: | |
return x, info | |
else: | |
return x | |
def decode(self, x): | |
return x | |
def decode_tokens(self, tokens, **kwargs): | |
latents = self.quantizer.indices_to_codes(tokens) | |
return self.decode(latents, **kwargs) |