Files
2026-07-13 13:24:13 +08:00

139 lines
4.7 KiB
Python

import torch
from torch import nn
from torch.nn import functional as F
from timm.models.registry import register_model
from .modeling_common import EncoderDecoderArchForImageReconstrction, get_basic_config
class DecodeHeadBLC(nn.Module):
def __init__(self, decoder_output_dim, patch_size, output_channels, patches_shape):
super().__init__()
num_pixels_per_patch = patch_size * patch_size * output_channels
self.patch_size = patch_size
self.output_channels = output_channels
self.fc1 = nn.Linear(decoder_output_dim, decoder_output_dim)
self.act = nn.Tanh()
self.fc2 = nn.Linear(decoder_output_dim, num_pixels_per_patch)
self.patches_shape = patches_shape
def forward(self, x):
x = self.fc1(x)
x = self.act(x)
x = self.fc2(x)
bsz = x.size(0)
x = x.view(
bsz, self.patches_shape[0], self.patches_shape[1],
self.output_channels, self.patch_size, self.patch_size)
x = x.permute(0, 3, 1, 4, 2, 5)
x = x.reshape(
bsz, self.output_channels,
self.patches_shape[0] * self.patch_size,
self.patches_shape[1] * self.patch_size,
)
return x
class GaussianDistribution(object):
def __init__(self, parameters, std):
self.parameters = parameters
self.mean = parameters
self.std = std
def sample(self, sampling_std=None):
if sampling_std is not None:
x = self.mean + sampling_std * torch.randn(self.mean.shape).to(device=self.parameters.device)
else:
batch_size = self.mean.size(0)
value = self.std / 0.8
std = torch.randn(batch_size).to(device=self.parameters.device) * value
while std.dim() < self.mean.dim():
std = std.unsqueeze(-1)
x = self.mean + std * torch.randn(self.mean.shape).to(device=self.parameters.device)
return x
def kl(self):
target = torch.zeros_like(self.mean)
return F.mse_loss(self.mean, target, reduction='mean')
def mode(self):
return self.mean
class EncodeHeadBLC(nn.Module):
def __init__(self, output_dim, latent_size, patches_shape, std):
super().__init__()
self.dense = nn.Linear(output_dim, latent_size)
self.patches_shape = patches_shape
self.latent_size = latent_size
self.std = std
def forward(self, x):
bsz = x.size(0)
x = self.dense(x)
x = x.reshape(bsz, self.patches_shape[0], self.patches_shape[1], self.latent_size)
x = x.permute(0, 3, 1, 2)
x = GaussianDistribution(x, self.std)
return x
class SigmaVAE(EncoderDecoderArchForImageReconstrction):
# SigmaVAE
def __init__(
self,
encoder_config: dict,
decoder_config: dict,
patch_size: int,
latent_size: int = 16,
kl_weight: float = 1e-2,
std: float = 0.75,
):
img_size = encoder_config['img_size']
patches_shape = (img_size // patch_size, img_size // patch_size, latent_size)
num_patches = (encoder_config['img_size'] // patch_size) ** 2
self.num_patches = num_patches
encoder_post_processor = EncodeHeadBLC(
encoder_config['embed_dim'], latent_size,
patches_shape, std=std
)
decoder_pre_processor = nn.Identity()
decoder_post_processor = DecodeHeadBLC(
decoder_config['embed_dim'], patch_size, encoder_config['in_chans'], patches_shape)
super().__init__(
encoder_config=encoder_config,
encoder_post_processor=encoder_post_processor,
decoder_pre_processor=decoder_pre_processor,
decoder_config=decoder_config,
decoder_post_processor=decoder_post_processor,
)
self.kl_weight = kl_weight
self.init_weights()
@register_model
def sigma_vae(latent_size, std, **kwargs):
basic_config, unused_kwargs = get_basic_config(**kwargs)
decoder_config = basic_config.pop('decoder_config')
decoder_config['patch_size'] = 1
# if decoder is vit arch, adjust the image size to be the size of the latent space
# without modification for the vit implementation
decoder_config['img_size'] = kwargs['img_size'] // kwargs['patch_size']
decoder_config['in_chans'] = latent_size
print("Unused args = %s" % str(unused_kwargs))
model = SigmaVAE(
latent_size=latent_size, std=std,
decoder_config=decoder_config, **basic_config)
return model