Download native/vq_model.py from gatilin/tokenflow_clipb_32k_visual_codec: direct link, hf CLI and curl.
- Browser
- Download file 39.3 kB
-
https://huggingface.co/gatilin/tokenflow_clipb_32k_visual_codec/resolve/main/native/vq_model.py
- Command line
-
hf download hf://gatilin/tokenflow_clipb_32k_visual_codec/native/vq_model.py
-
curl -L -o vq_model.py https://huggingface.co/gatilin/tokenflow_clipb_32k_visual_codec/resolve/main/native/vq_model.py
39.3 kB
| # Modified from: | |
| # taming-transformers: https://github.com/CompVis/taming-transformers | |
| # maskgit: https://github.com/google-research/maskgit | |
| # LlamaGen: https://github.com/FoundationVision/LlamaGen/ | |
| # VAR: https://github.com/FoundationVision/VAR | |
| import os | |
| import sys | |
| cur_dir = os.path.dirname(os.path.abspath(__file__)) | |
| sys.path.append(cur_dir) | |
| from dataclasses import dataclass, field | |
| from typing import List | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| from .vqkd_model import VisionTransformer | |
| import math | |
| from einops import rearrange | |
| from .clip import clip | |
| import numpy as np | |
| from .compat import get_parameter_device, get_parameter_dtype | |
| from .norm_ema_quantizer import EmbeddingEMA, l2norm, norm_ema_inplace, kmeans | |
| import torch.distributed as dist | |
| import random | |
| from timm.models.layers import trunc_normal_ | |
| from timm import create_model | |
| from transformers import SiglipImageProcessor, SiglipVisionConfig | |
| from transformers.models.siglip.modeling_siglip import SiglipVisionModel | |
| def copy_new_embedding(old_embedding, requires_grad=True): | |
| new_embedding = nn.Embedding(old_embedding.weight.size(0), old_embedding.weight.size(1)) | |
| new_embedding.weight = nn.Parameter(old_embedding.weight.clone()) | |
| new_embedding.weight.requires_grad = requires_grad | |
| return new_embedding | |
| def drop_scale(original_scales, num_to_drop=1): | |
| """ | |
| Randomly remove scales from scale list. | |
| Args: | |
| original_scales: list of scales | |
| num_to_drop: Number of scales to randomly remove (default 1) | |
| Returns: | |
| New scale list | |
| """ | |
| if num_to_drop >= len(original_scales) - 1: | |
| raise ValueError("Cannot drop that many items") | |
| drop_candidates = list(range(1, len(original_scales))) | |
| indices_to_drop = set(random.sample(drop_candidates, num_to_drop)) | |
| return [item for i, item in enumerate(original_scales) if i not in indices_to_drop] | |
| class ModelArgs: | |
| codebook_size: int = 16384 | |
| codebook_embed_dim: int = 8 | |
| semantic_code_dim: int = 32 | |
| codebook_l2_norm: bool = True | |
| codebook_show_usage: bool = True | |
| commit_loss_beta: float = 1.0 | |
| entropy_loss_ratio: float = 0.0 | |
| encoder_ch_mult: List[int] = field(default_factory=lambda: [1, 1, 2, 2, 4]) | |
| decoder_ch_mult: List[int] = field(default_factory=lambda: [1, 1, 2, 2, 4]) | |
| z_channels: int = 256 | |
| dropout_p: float = 0.0 | |
| kmeans: bool = False | |
| teacher: str = None # option: ["clipb_224", "vitamin_xlarge_256", "siglip_384"] | |
| enhanced_decoder: bool = False | |
| infer_interpolate: bool = False | |
| def get_model_default_params(): | |
| return dict(img_size=256, patch_size=16, in_chans=3, num_classes=1000, embed_dim=1152, depth=12, num_heads=12, | |
| mlp_ratio=4., qkv_bias=True, qk_scale=None, drop_rate=0., attn_drop_rate=0., drop_path_rate=0., | |
| norm_layer='LayerNorm', init_values=0., use_abs_pos_emb=True, | |
| use_rel_pos_bias=False, use_shared_rel_pos_bias=False, use_mean_pooling=True, init_scale=0.001) | |
| class TokenFlow(nn.Module): | |
| def __init__(self, config: ModelArgs): | |
| super().__init__() | |
| self.config = config | |
| ### VQGAN encoder decoder definitions ### | |
| self.encoder = Encoder(ch_mult=config.encoder_ch_mult, z_channels=config.z_channels, dropout=config.dropout_p) | |
| if not config.enhanced_decoder: | |
| print("Using normal pixel decoder") | |
| self.decoder = Decoder(ch_mult=config.decoder_ch_mult, z_channels=config.z_channels, dropout=config.dropout_p) | |
| else: | |
| print("Using 2 times enhanced pixel decoder") | |
| self.decoder = Decoder( | |
| ch_mult=config.decoder_ch_mult, | |
| z_channels=config.z_channels, | |
| dropout=config.dropout_p, | |
| ch=256, | |
| num_res_blocks=4, | |
| ) | |
| ### VQGAN encoder decoder definitions ### | |
| self.quant_conv = nn.Conv2d(config.z_channels, config.codebook_embed_dim, 1) | |
| self.post_quant_conv = nn.Conv2d(config.codebook_embed_dim, config.z_channels, 1) | |
| ### VQKD semantic teacher choice ### | |
| ### option: ["clipb_224", "vitamin_xlarge_256", "siglip_384"] | |
| self.teacher = config.teacher | |
| ### multi-scale quantizer ### | |
| self.enable_var = True | |
| if self.enable_var: | |
| if self.teacher == 'clipb_224': | |
| if not config.infer_interpolate: | |
| self.scale_rq_layers = [1,2,4,6,8,10,12,14] | |
| else: # directly interpolate the positional encoding of clip for higher resolution inference | |
| print("using interpolated scales") | |
| self.scale_rq_layers = [1,2,4,6,8,10,12,14,16] | |
| elif self.teacher == 'vitamin_xlarge_256': | |
| self.scale_rq_layers = [1,2,4,6,8,10,12,14,16] | |
| elif self.teacher == 'siglip_384': | |
| self.scale_rq_layers = [1,2,3,4,5,6,7,8,9,10,12,14,17,22,27] | |
| else: | |
| raise NotImplementedError | |
| self.rq_depth = len(self.scale_rq_layers) | |
| ### multi-scale quantizer ### | |
| encoder_config, decoder_config = get_model_default_params(), get_model_default_params() | |
| if self.teacher == 'clipb_224': | |
| encoder_config["embed_dim"] = decoder_config["embed_dim"] = 768 | |
| img_size = 224 | |
| self.decoder_out_dim = 512 | |
| elif self.teacher == 'vitamin_xlarge_256': | |
| img_size = 256 | |
| self.decoder_out_dim = 1152 | |
| elif self.teacher == 'siglip_384': | |
| img_size = 27 * 2**4 # 384 | |
| self.decoder_out_dim = 1152 | |
| else: | |
| raise NotImplementedError | |
| semantic_code_dim = config.semantic_code_dim # 32 by default | |
| encoder_config['img_size'] = img_size | |
| encoder_config['num_classes'] = 0 | |
| # decoder settings | |
| decoder_config['img_size'] = img_size // decoder_config['patch_size'] | |
| decoder_config['patch_size'] = 1 | |
| decoder_config['in_chans'] = semantic_code_dim | |
| decoder_config['num_classes'] = 0 | |
| decoder_config['depth'] = 3 | |
| print('Final encoder config', encoder_config) | |
| ### VQKD encoder decoder definition ### | |
| ### define semantic encoder, initialize it with pretrained clip ### | |
| if self.teacher == 'clipb_224': | |
| self.encoder_vqkd = clip.load_clip_vision("ViT-B/16", download_root='./clip_model') | |
| elif self.teacher == 'vitamin_xlarge_256': | |
| print('Current teacher is vitamin_xlarge_256') | |
| self.encoder_vqkd = create_model(self.teacher, pretrained=True) | |
| del self.encoder_vqkd.head | |
| del self.encoder_vqkd.fc_norm | |
| elif self.teacher == 'siglip_384': | |
| print('Current teacher is google/siglip-so400m-patch14-384') | |
| self.encoder_vqkd = SiglipVisionModel.from_pretrained("google/siglip-so400m-patch14-384") | |
| # Freeze the head's parameters and 26th layer's parameters | |
| for name, param in self.encoder_vqkd.named_parameters(): | |
| if 'head' in name: | |
| param.requires_grad = False | |
| if 'encoder.layers.26' in name: | |
| param.requires_grad = False | |
| if 'post_layernorm' in name: | |
| param.requires_grad = False | |
| else: | |
| raise ValueError(f'teacher {self.teacher} not supported') | |
| print('Final decoder config', decoder_config) | |
| self.decoder_vqkd = VisionTransformer(**decoder_config) | |
| ### VQKD encoder decoder definition ### | |
| ### task layer ### | |
| self.encode_task_layer = nn.Sequential( | |
| nn.Linear(encoder_config['embed_dim'], encoder_config['embed_dim']), | |
| nn.Tanh(), | |
| nn.Linear(encoder_config['embed_dim'], semantic_code_dim) # for quantize | |
| ) | |
| self.decode_task_layer = nn.Sequential( | |
| nn.Linear(decoder_config['embed_dim'], decoder_config['embed_dim']), | |
| nn.Tanh(), | |
| nn.Linear(decoder_config['embed_dim'], self.decoder_out_dim), | |
| ) | |
| self.encode_task_layer.apply(self._init_weights) | |
| self.decode_task_layer.apply(self._init_weights) | |
| ### task layer ### | |
| # scaling layers | |
| if self.teacher == 'clipb_224': | |
| self.scaling_layer = None # can be changed to ScalingLayerForClip() | |
| elif self.teacher == 'vitamin_xlarge_256': | |
| self.scaling_layer = ScalingLayerForClip() | |
| elif self.teacher == 'siglip_384': | |
| self.scaling_layer = ScalingLayerForSigLip() | |
| else: | |
| raise ValueError(f'teacher {self.teacher} not supported') | |
| ### parameters required by llava ### | |
| self.semantic_code_dim = semantic_code_dim | |
| self.vqgan_code_dim = config.codebook_embed_dim | |
| self.code_dim = self.semantic_code_dim + self.vqgan_code_dim | |
| self.embed_dim = self.code_dim | |
| self.n_embed = config.codebook_size | |
| self.compression = 2**(len(config.encoder_ch_mult) - 1) | |
| ### parameters required by llava ### | |
| # quantizer | |
| self.use_kmeans = config.kmeans | |
| self.quantize = VectorQuantizer(config.codebook_size, self.code_dim, | |
| config.commit_loss_beta, config.entropy_loss_ratio, | |
| config.codebook_l2_norm, config.codebook_show_usage, split=[self.semantic_code_dim, self.vqgan_code_dim], kmeans=config.kmeans) | |
| ### whether using shared conv in VAR ### | |
| self.using_shared_conv = False # default not use. | |
| if self.using_shared_conv: | |
| quant_resi = 0.5 | |
| share_quant_resi = 4 | |
| self.vqkd_quant_resi = PhiPartiallyShared(nn.ModuleList([(Phi(self.vqkd_code_dim, quant_resi) if abs(quant_resi) > 1e-6 else nn.Identity()) for _ in range(share_quant_resi)])) | |
| self.vqgan_quant_resi = PhiPartiallyShared(nn.ModuleList([(Phi(self.vqgan_code_dim, quant_resi) if abs(quant_resi) > 1e-6 else nn.Identity()) for _ in range(share_quant_resi)])) | |
| print("quant conv initialized") | |
| ### whether using random scale drop when training ### | |
| self.random_scale_drop = True | |
| self.random_scale_drop_ratio = 0.1 # default 10% | |
| self.num_of_random_drop = 1 | |
| print(f'Current model is: TokenFlow with teacher {self.teacher}, initialization finished.') | |
| def clone_vq_codebook(self, requires_grad): | |
| cloned_vqkd_embedding = copy_new_embedding(self.quantize.embedding_vqkd, requires_grad) | |
| cloned_vqgan_embedding = copy_new_embedding(self.quantize.embedding_vqgan, requires_grad) | |
| return (cloned_vqkd_embedding, cloned_vqgan_embedding) | |
| def _init_weights(self, m): | |
| if isinstance(m, nn.Linear): | |
| trunc_normal_(m.weight, std=.02) | |
| if isinstance(m, nn.Linear) and m.bias is not None: | |
| nn.init.constant_(m.bias, 0) | |
| elif isinstance(m, nn.LayerNorm): | |
| nn.init.constant_(m.bias, 0) | |
| nn.init.constant_(m.weight, 1.0) | |
| def device(self): | |
| return get_parameter_device(self) | |
| def dtype(self): | |
| return get_parameter_dtype(self) | |
| def encode(self, x): | |
| if self.teacher == "clipb_224": | |
| vqkd_feature = self.encoder_vqkd(x, return_patch_tokens=True) | |
| vqkd_feature = self.encode_task_layer(vqkd_feature.type_as(self.encode_task_layer[-1].weight)) | |
| N = vqkd_feature.shape[1] | |
| B = vqkd_feature.shape[0] | |
| h, w = int(math.sqrt(N)), int(math.sqrt(N)) | |
| vqkd_feature = rearrange(vqkd_feature, 'b (h w) c -> b c h w', h=h, w=w) # reshape for quantizer | |
| elif self.teacher == 'vitamin_xlarge_256': | |
| vqkd_x = self.scaling_layer(x) | |
| # vqkd | |
| vqkd_feature = self.encoder_vqkd.forward_features(vqkd_x) | |
| vqkd_feature = self.encode_task_layer(vqkd_feature.type_as(self.encode_task_layer[-1].weight)) | |
| N = vqkd_feature.shape[1] | |
| h, w = int(math.sqrt(N)), int(math.sqrt(N)) | |
| vqkd_feature = rearrange(vqkd_feature, 'b (h w) c -> b c h w', h=h, w=w) # reshape for quantizer | |
| elif self.teacher == 'siglip_384': | |
| vqkd_x = self.scaling_layer(x) | |
| vqkd_feature = self.encoder_vqkd(vqkd_x, output_hidden_states=True).hidden_states[-2] | |
| vqkd_feature = self.encode_task_layer(vqkd_feature.type_as(self.encode_task_layer[-1].weight)) | |
| N = vqkd_feature.shape[1] | |
| h, w = int(math.sqrt(N)), int(math.sqrt(N)) | |
| vqkd_feature = rearrange(vqkd_feature, 'b (h w) c -> b c h w', h=h, w=w) # reshape for quantizer | |
| else: | |
| raise ValueError(f'teacher {self.teacher} not supported') | |
| # vqgan | |
| if self.teacher in ['clipb_224', 'vitamin_xlarge_256']: | |
| vqgan_features = self.encoder(x) | |
| vqgan_features = self.quant_conv(vqgan_features) | |
| elif self.teacher == 'siglip_384': | |
| upscale_reso = 2**4 * vqkd_feature.shape[-1] | |
| vqgan_x = F.interpolate(x, size=(upscale_reso, upscale_reso), mode='bicubic') | |
| vqgan_features = self.encoder(vqgan_x) | |
| vqgan_features = self.quant_conv(vqgan_features) | |
| else: | |
| raise ValueError(f'teacher {self.teacher} not supported') | |
| h = torch.cat([vqkd_feature, vqgan_features], dim=1) | |
| if self.enable_var: | |
| # VAR | |
| residual = h | |
| final_quantize = 0. | |
| all_loss = [] | |
| all_inds = [] | |
| new_layers = self.scale_rq_layers | |
| if self.training and self.random_scale_drop: | |
| if random.random() < self.random_scale_drop_ratio: | |
| new_layers = drop_scale(self.scale_rq_layers, self.num_of_random_drop) | |
| for i, scale_size in enumerate(new_layers): # random drop scale | |
| residual_si = F.interpolate(residual, size=(scale_size, scale_size), mode='area') | |
| quantize, emb_loss, info = self.quantize(residual_si) | |
| quantize = F.interpolate(quantize, size=(self.scale_rq_layers[-1], self.scale_rq_layers[-1]), mode='bicubic') | |
| if self.using_shared_conv: # default not use | |
| quantize_vqkd, quantize_vqgan = torch.split(quantize, split_size_or_sections=[self.semantic_code_dim, self.vqgan_code_dim], dim=1) | |
| quantize_vqkd = self.vqkd_quant_resi[i/(self.rq_depth-1)](quantize_vqkd) | |
| quantize_vqgan = self.vqgan_quant_resi[i/(self.rq_depth-1)](quantize_vqgan) | |
| quantize = torch.cat([quantize_vqkd, quantize_vqgan], dim=1) | |
| final_quantize += quantize | |
| residual = residual - quantize.detach() | |
| all_loss.append(emb_loss) | |
| inds = info[-1].reshape([-1, scale_size ** 2]) | |
| all_inds.append(inds) | |
| all_loss = zip(*all_loss) | |
| all_loss = [sum(group) / len(group) if group[0] is not None else None for group in all_loss] | |
| all_inds = torch.cat(all_inds, dim=1) | |
| return final_quantize, all_loss, all_inds | |
| else: | |
| quant, emb_loss, info = self.quantize(h) | |
| return quant, emb_loss, info | |
| def decode(self, quant): | |
| vqkd_quant, vqgan_quant = torch.split(quant, [self.semantic_code_dim, self.vqgan_code_dim], dim=1) | |
| vqkd_recon = self.decoder_vqkd(vqkd_quant, return_patch_tokens=True) | |
| vqkd_recon = self.decode_task_layer(vqkd_recon) | |
| vqgan_recon = self.post_quant_conv(vqgan_quant) | |
| vqgan_recon = self.decoder(vqgan_recon) | |
| if self.teacher == 'siglip_384': | |
| vqgan_recon = F.interpolate(vqgan_recon, size=(384, 384), mode='bicubic') | |
| dec = (vqkd_recon, vqgan_recon) | |
| return dec | |
| def decode_code(self, code_b): | |
| batch_size = code_b.size(0) | |
| total_tokens = code_b.size(1) | |
| current_total = 0 | |
| used_scales = [] | |
| for scale_size in self.scale_rq_layers: | |
| scale_tokens = scale_size ** 2 | |
| if current_total + scale_tokens > total_tokens: | |
| break | |
| used_scales.append(scale_size) | |
| current_total += scale_tokens | |
| if current_total == total_tokens: | |
| break | |
| if current_total != total_tokens: | |
| raise ValueError( | |
| f"Invalid code_b size {total_tokens}, " | |
| f"expected sum of scale tokens {current_total} " | |
| f"(scales: {used_scales})" | |
| ) | |
| quant_b = 0.0 | |
| current_pos = 0 | |
| for scale_size in used_scales: | |
| num_tokens = scale_size ** 2 | |
| indices = code_b[:, current_pos:current_pos+num_tokens] | |
| current_pos += num_tokens | |
| quant_this_scale = self.quantize.get_codebook_entry(indices) | |
| quant_this_scale = rearrange(quant_this_scale, 'b (h w) c -> b c h w', h=scale_size, w=scale_size) | |
| quant_this_scale = F.interpolate( | |
| quant_this_scale, | |
| size=(self.scale_rq_layers[-1], self.scale_rq_layers[-1]), | |
| mode='bicubic' | |
| ) | |
| quant_b += quant_this_scale | |
| dec = self.decode(quant_b) | |
| return dec | |
| def forward(self, input): | |
| quant, diff, _ = self.encode(input) | |
| dec = self.decode(quant) | |
| if not self.enable_var and self.use_kmeans: | |
| self.enable_var = True # kmeans use last scale features instead of 1*1, and change to multiscale setting after kmeans init. modify this for different teacher | |
| self.scale_rq_layers = [1,2,4,6,8,10,12,14,16] | |
| self.rq_depth = len(self.scale_rq_layers) | |
| return dec, diff | |
| class ScalingLayerForClip(nn.Module): | |
| def __init__(self): | |
| super(ScalingLayerForClip, self).__init__() | |
| self.register_buffer('shift', torch.Tensor([0.48145466, 0.4578275, 0.40821073])[None, :, None, None]) | |
| self.register_buffer('scale', torch.Tensor([0.26862954, 0.26130258, 0.27577711])[None, :, None, None]) | |
| def forward(self, inp): | |
| inp = ((inp + 1.) * 127.5).clamp(0, 255.) / 255. # rescale to [0, 1.] | |
| return (inp - self.shift) / self.scale | |
| class ScalingLayerForSigLip(nn.Module): | |
| def __init__(self): | |
| super(ScalingLayerForSigLip, self).__init__() | |
| self.register_buffer('shift', torch.Tensor([0.5, 0.5, 0.5])[None, :, None, None]) | |
| self.register_buffer('scale', torch.Tensor([0.5, 0.5, 0.5])[None, :, None, None]) | |
| def forward(self, inp): | |
| inp = ((inp + 1.) * 127.5).clamp(0, 255.) / 255. # rescale to [0, 1.] | |
| return (inp - self.shift) / self.scale | |
| class Encoder(nn.Module): | |
| def __init__(self, in_channels=3, ch=128, ch_mult=(1,1,2,2,4), num_res_blocks=2, | |
| norm_type='group', dropout=0.0, resamp_with_conv=True, z_channels=256): | |
| super().__init__() | |
| self.num_resolutions = len(ch_mult) | |
| self.num_res_blocks = num_res_blocks | |
| self.conv_in = nn.Conv2d(in_channels, ch, kernel_size=3, stride=1, padding=1) | |
| # downsampling | |
| in_ch_mult = (1,) + tuple(ch_mult) | |
| self.conv_blocks = nn.ModuleList() | |
| for i_level in range(self.num_resolutions): | |
| conv_block = nn.Module() | |
| # res & attn | |
| res_block = nn.ModuleList() | |
| attn_block = nn.ModuleList() | |
| block_in = ch*in_ch_mult[i_level] | |
| block_out = ch*ch_mult[i_level] | |
| for _ in range(self.num_res_blocks): | |
| res_block.append(ResnetBlock(block_in, block_out, dropout=dropout, norm_type=norm_type)) | |
| block_in = block_out | |
| if i_level == self.num_resolutions - 1: | |
| attn_block.append(AttnBlock(block_in, norm_type)) | |
| conv_block.res = res_block | |
| conv_block.attn = attn_block | |
| # downsample | |
| if i_level != self.num_resolutions-1: | |
| conv_block.downsample = Downsample(block_in, resamp_with_conv) | |
| self.conv_blocks.append(conv_block) | |
| # middle | |
| self.mid = nn.ModuleList() | |
| self.mid.append(ResnetBlock(block_in, block_in, dropout=dropout, norm_type=norm_type)) | |
| self.mid.append(AttnBlock(block_in, norm_type=norm_type)) | |
| self.mid.append(ResnetBlock(block_in, block_in, dropout=dropout, norm_type=norm_type)) | |
| # end | |
| self.norm_out = Normalize(block_in, norm_type) | |
| self.conv_out = nn.Conv2d(block_in, z_channels, kernel_size=3, stride=1, padding=1) | |
| def forward(self, x): | |
| h = self.conv_in(x) | |
| # downsampling | |
| for i_level, block in enumerate(self.conv_blocks): | |
| for i_block in range(self.num_res_blocks): | |
| h = block.res[i_block](h) | |
| if len(block.attn) > 0: | |
| h = block.attn[i_block](h) | |
| if i_level != self.num_resolutions - 1: | |
| h = block.downsample(h) | |
| # middle | |
| for mid_block in self.mid: | |
| h = mid_block(h) | |
| # end | |
| h = self.norm_out(h) | |
| h = nonlinearity(h) | |
| h = self.conv_out(h) | |
| return h | |
| class Decoder(nn.Module): | |
| def __init__(self, z_channels=256, ch=128, ch_mult=(1,1,2,2,4), num_res_blocks=2, norm_type="group", | |
| dropout=0.0, resamp_with_conv=True, out_channels=3): | |
| super().__init__() | |
| self.num_resolutions = len(ch_mult) | |
| self.num_res_blocks = num_res_blocks | |
| block_in = ch*ch_mult[self.num_resolutions-1] | |
| # z to block_in | |
| self.conv_in = nn.Conv2d(z_channels, block_in, kernel_size=3, stride=1, padding=1) | |
| # middle | |
| self.mid = nn.ModuleList() | |
| self.mid.append(ResnetBlock(block_in, block_in, dropout=dropout, norm_type=norm_type)) | |
| self.mid.append(AttnBlock(block_in, norm_type=norm_type)) | |
| self.mid.append(ResnetBlock(block_in, block_in, dropout=dropout, norm_type=norm_type)) | |
| # upsampling | |
| self.conv_blocks = nn.ModuleList() | |
| for i_level in reversed(range(self.num_resolutions)): | |
| conv_block = nn.Module() | |
| # res & attn | |
| res_block = nn.ModuleList() | |
| attn_block = nn.ModuleList() | |
| block_out = ch*ch_mult[i_level] | |
| for _ in range(self.num_res_blocks + 1): | |
| res_block.append(ResnetBlock(block_in, block_out, dropout=dropout, norm_type=norm_type)) | |
| block_in = block_out | |
| if i_level == self.num_resolutions - 1: | |
| attn_block.append(AttnBlock(block_in, norm_type)) | |
| conv_block.res = res_block | |
| conv_block.attn = attn_block | |
| # downsample | |
| if i_level != 0: | |
| conv_block.upsample = Upsample(block_in, resamp_with_conv) | |
| self.conv_blocks.append(conv_block) | |
| # end | |
| self.norm_out = Normalize(block_in, norm_type) | |
| self.conv_out = nn.Conv2d(block_in, out_channels, kernel_size=3, stride=1, padding=1) | |
| def last_layer(self): | |
| return self.conv_out.weight | |
| def forward(self, z): | |
| # z to block_in | |
| h = self.conv_in(z) | |
| # middle | |
| for mid_block in self.mid: | |
| h = mid_block(h) | |
| # upsampling | |
| for i_level, block in enumerate(self.conv_blocks): | |
| for i_block in range(self.num_res_blocks + 1): | |
| h = block.res[i_block](h) | |
| if len(block.attn) > 0: | |
| h = block.attn[i_block](h) | |
| if i_level != self.num_resolutions - 1: | |
| h = block.upsample(h) | |
| # end | |
| h = self.norm_out(h) | |
| h = nonlinearity(h) | |
| h = self.conv_out(h) | |
| return h | |
| ### shared quantizer | |
| class VectorQuantizer(nn.Module): | |
| def __init__(self, n_e, e_dim, beta, entropy_loss_ratio, l2_norm, show_usage, split, kmeans=False): | |
| super().__init__() | |
| self.n_e = n_e | |
| self.e_dim = e_dim | |
| self.beta = beta | |
| self.entropy_loss_ratio = entropy_loss_ratio | |
| self.l2_norm = l2_norm | |
| self.show_usage = show_usage | |
| self.split = split | |
| self.kmeans_init = kmeans | |
| self.initted = False | |
| if self.kmeans_init: # default not use | |
| print("using kmeans init") | |
| self.embedding_vqkd = EmbeddingEMA(self.n_e, self.split[0]) | |
| self.embedding_vqkd.weight.requires_grad = False | |
| self.embedding_vqgan = EmbeddingEMA(self.n_e, self.split[1]) | |
| self.embedding_vqgan.weight.requires_grad = False | |
| else: | |
| print("no kmeans init") | |
| self.embedding_vqkd = nn.Embedding(self.n_e, self.split[0]) | |
| self.embedding_vqkd.weight.data.uniform_(-1.0 / self.n_e, 1.0 / self.n_e) | |
| if self.l2_norm: | |
| self.embedding_vqkd.weight.data = F.normalize(self.embedding_vqkd.weight.data, p=2, dim=-1) | |
| self.embedding_vqgan = nn.Embedding(self.n_e, self.split[1]) | |
| self.embedding_vqgan.weight.data.uniform_(-1.0 / self.n_e, 1.0 / self.n_e) | |
| if self.l2_norm: | |
| self.embedding_vqgan.weight.data = F.normalize(self.embedding_vqgan.weight.data, p=2, dim=-1) | |
| if self.show_usage: | |
| self.register_buffer("codebook_used", nn.Parameter(torch.zeros(131072))) | |
| def forward(self, z): | |
| z = torch.einsum('b c h w -> b h w c', z).contiguous() | |
| z_flattened = z.view(-1, self.e_dim) | |
| z_vqkd, z_vqgan = torch.split(z, split_size_or_sections=self.split, dim=-1) | |
| z_flattened_vqkd, z_flattened_vqgan = torch.split(z_flattened, split_size_or_sections=self.split, dim=-1) | |
| if self.l2_norm: | |
| z_flattened_vqkd = F.normalize(z_flattened_vqkd, p=2, dim=-1) | |
| z_flattened_vqgan = F.normalize(z_flattened_vqgan, p=2, dim=-1) | |
| z_flattened = torch.cat([z_flattened_vqkd, z_flattened_vqgan], dim=-1) | |
| if self.kmeans_init and not self.initted: # default not use kmeans | |
| with torch.no_grad(): | |
| # Gather outputs from all GPUs | |
| z_flattened_vqkds = [torch.zeros_like(z_flattened_vqkd) for _ in range(torch.distributed.get_world_size())] | |
| dist.all_gather(z_flattened_vqkds, z_flattened_vqkd) | |
| combined_z_flatteneds = torch.cat(z_flattened_vqkds, dim=0) | |
| print("combined_z_flatteneds.shape", combined_z_flatteneds.shape) | |
| self.embedding_vqkd.init_embed_(combined_z_flatteneds) | |
| self.initted = True # kmeans from the first batch | |
| if self.l2_norm: | |
| z_vqkd = F.normalize(z_vqkd, p=2, dim=-1) | |
| embedding_vqkd = F.normalize(self.embedding_vqkd.weight, p=2, dim=-1) | |
| z_vqgan = F.normalize(z_vqgan, p=2, dim=-1) | |
| embedding_vqgan = F.normalize(self.embedding_vqgan.weight, p=2, dim=-1) | |
| z = torch.cat([z_vqkd, z_vqgan], dim=-1) | |
| else: | |
| embedding_vqkd = self.embedding.weight[:, :self.split[0]] | |
| embedding_vqgan = self.embedding.weight[:, self.split[0]:] | |
| d_vqkd = torch.sum(z_flattened_vqkd ** 2, dim=1, keepdim=True) + \ | |
| torch.sum(embedding_vqkd**2, dim=1) - 2 * \ | |
| torch.einsum('bd,dn->bn', z_flattened_vqkd, torch.einsum('n d -> d n', embedding_vqkd)) | |
| d_vqgan = torch.sum(z_flattened_vqgan ** 2, dim=1, keepdim=True) + \ | |
| torch.sum(embedding_vqgan**2, dim=1) - 2 * \ | |
| torch.einsum('bd,dn->bn', z_flattened_vqgan, torch.einsum('n d -> d n', embedding_vqgan)) | |
| vqkd_d_norm = torch.mean(torch.sum(d_vqkd**2, dim=-1)) | |
| vqgan_d_norm = torch.mean(torch.sum(d_vqgan**2, dim=-1)) | |
| ### shared mapping ### | |
| d = d_vqkd + 1.0 * d_vqgan | |
| min_encoding_indices = torch.argmin(d, dim=1) | |
| ### shared mapping ### | |
| aggregate_usage = False | |
| if aggregate_usage: | |
| with torch.no_grad(): | |
| min_encoding_indices_all = [torch.zeros_like(min_encoding_indices) for _ in range(torch.distributed.get_world_size())] | |
| dist.all_gather(min_encoding_indices_all, min_encoding_indices) | |
| min_encoding_indices_all = torch.cat(min_encoding_indices_all, dim=0) | |
| all_embedding = torch.cat([embedding_vqkd, embedding_vqgan], dim=-1) | |
| z_q = all_embedding[min_encoding_indices].view(z.shape) | |
| z_q_vqkd = embedding_vqkd[min_encoding_indices].view(z_vqkd.shape) | |
| z_q_vqgan = embedding_vqgan[min_encoding_indices].view(z_vqgan.shape) | |
| perplexity = None | |
| min_encodings = None | |
| vq_loss = None | |
| commit_loss = None | |
| entropy_loss = None | |
| codebook_usage = 0 | |
| if self.show_usage and self.training: | |
| if aggregate_usage: | |
| cur_len = min_encoding_indices_all.shape[0] | |
| self.codebook_used[:-cur_len] = self.codebook_used[cur_len:].clone() | |
| self.codebook_used[-cur_len:] = min_encoding_indices_all | |
| codebook_usage = len(torch.unique(self.codebook_used)) / self.n_e | |
| else: | |
| cur_len = min_encoding_indices.shape[0] | |
| self.codebook_used[:-cur_len] = self.codebook_used[cur_len:].clone() | |
| self.codebook_used[-cur_len:] = min_encoding_indices | |
| codebook_usage = len(torch.unique(self.codebook_used)) / self.n_e | |
| encodings = F.one_hot(min_encoding_indices, self.n_e).type(z.dtype) | |
| if self.kmeans_init and self.training: # default not use, if using kmeans, remember to remove the vq loss and commit loss | |
| bins = encodings.sum(0) | |
| dist.all_reduce(bins) | |
| zero_mask = (bins == 0) | |
| bins = bins.masked_fill(zero_mask, 1.) | |
| embed_sum = z_flattened_vqkd.t() @ encodings | |
| dist.all_reduce(embed_sum) | |
| embed_normalized = (embed_sum / bins.unsqueeze(0)).t() | |
| embed_normalized = l2norm(embed_normalized) | |
| embed_normalized = torch.where(zero_mask[..., None], self.embedding_vqkd.weight, | |
| embed_normalized) | |
| norm_ema_inplace(self.embedding_vqkd.weight, embed_normalized, 0.99) | |
| # compute loss for embedding | |
| if self.training: | |
| if self.kmeans_init: | |
| vq_loss = torch.mean((z_q_vqgan - z_vqgan.detach()) ** 2) | |
| commit_loss = self.beta * torch.mean((z_q_vqkd.detach() - z_vqkd) ** 2) + self.beta * torch.mean((z_q_vqgan.detach() - z_vqgan) ** 2) | |
| entropy_loss = self.entropy_loss_ratio * compute_entropy_loss(-d) | |
| else: | |
| vq_loss = torch.mean((z_q - z.detach()) ** 2) | |
| commit_loss = self.beta * torch.mean((z_q.detach() - z) ** 2) | |
| entropy_loss = self.entropy_loss_ratio * compute_entropy_loss(-d) | |
| # preserve gradients | |
| z_q = z + (z_q - z).detach() | |
| # reshape back to match original input shape | |
| z_q = torch.einsum('b h w c -> b c h w', z_q) | |
| return z_q, (vq_loss, commit_loss, entropy_loss, codebook_usage, vqkd_d_norm, vqgan_d_norm), (perplexity, min_encodings, min_encoding_indices) | |
| def get_codebook_entry(self, indices, shape=None, channel_first=True): | |
| # shape = (batch, channel, height, width) if channel_first else (batch, height, width, channel) | |
| if self.l2_norm: | |
| embedding_vqkd = F.normalize(self.embedding_vqkd.weight, p=2, dim=-1) | |
| embedding_vqgan = F.normalize(self.embedding_vqgan.weight, p=2, dim=-1) | |
| embedding = torch.cat([embedding_vqkd, embedding_vqgan], dim=-1) | |
| else: | |
| embedding = self.embedding.weight | |
| z_q = embedding[indices] # (b*h*w, c) | |
| if shape is not None: | |
| if channel_first: | |
| z_q = z_q.reshape(shape[0], shape[2], shape[3], shape[1]) | |
| # reshape back to match original input shape | |
| z_q = z_q.permute(0, 3, 1, 2).contiguous() | |
| else: | |
| z_q = z_q.view(shape) | |
| return z_q | |
| def get_codebook_entry_outside(self, indices, outside_embedding, shape=None, channel_first=True): | |
| # shape = (batch, channel, height, width) if channel_first else (batch, height, width, channel) | |
| if self.l2_norm: | |
| embedding_vqkd = F.normalize(outside_embedding[0].weight, p=2, dim=-1) | |
| embedding_vqgan = F.normalize(outside_embedding[1].weight, p=2, dim=-1) | |
| embedding = torch.cat([embedding_vqkd, embedding_vqgan], dim=-1) | |
| else: | |
| embedding = self.embedding.weight | |
| z_q = embedding[indices] # (b*h*w, c) | |
| if shape is not None: | |
| if channel_first: | |
| z_q = z_q.reshape(shape[0], shape[2], shape[3], shape[1]) | |
| z_q = z_q.permute(0, 3, 1, 2).contiguous() | |
| else: | |
| z_q = z_q.view(shape) | |
| return z_q | |
| class ResnetBlock(nn.Module): | |
| def __init__(self, in_channels, out_channels=None, conv_shortcut=False, dropout=0.0, norm_type='group'): | |
| super().__init__() | |
| self.in_channels = in_channels | |
| out_channels = in_channels if out_channels is None else out_channels | |
| self.out_channels = out_channels | |
| self.use_conv_shortcut = conv_shortcut | |
| self.norm1 = Normalize(in_channels, norm_type) | |
| self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) | |
| self.norm2 = Normalize(out_channels, norm_type) | |
| self.dropout = nn.Dropout(dropout) | |
| self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1) | |
| if self.in_channels != self.out_channels: | |
| if self.use_conv_shortcut: | |
| self.conv_shortcut = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) | |
| else: | |
| self.nin_shortcut = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0) | |
| def forward(self, x): | |
| h = x | |
| h = self.norm1(h) | |
| h = nonlinearity(h) | |
| h = self.conv1(h) | |
| h = self.norm2(h) | |
| h = nonlinearity(h) | |
| h = self.dropout(h) | |
| h = self.conv2(h) | |
| if self.in_channels != self.out_channels: | |
| if self.use_conv_shortcut: | |
| x = self.conv_shortcut(x) | |
| else: | |
| x = self.nin_shortcut(x) | |
| return x+h | |
| class AttnBlock(nn.Module): | |
| def __init__(self, in_channels, norm_type='group'): | |
| super().__init__() | |
| self.norm = Normalize(in_channels, norm_type) | |
| self.q = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0) | |
| self.k = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0) | |
| self.v = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0) | |
| self.proj_out = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=1, padding=0) | |
| def forward(self, x): | |
| h_ = x | |
| h_ = self.norm(h_) | |
| q = self.q(h_) | |
| k = self.k(h_) | |
| v = self.v(h_) | |
| # compute attention | |
| b,c,h,w = q.shape | |
| q = q.reshape(b,c,h*w) | |
| q = q.permute(0,2,1) # b,hw,c | |
| k = k.reshape(b,c,h*w) # b,c,hw | |
| w_ = torch.bmm(q,k) # b,hw,hw w[b,i,j]=sum_c q[b,i,c]k[b,c,j] | |
| w_ = w_ * (int(c)**(-0.5)) | |
| w_ = F.softmax(w_, dim=2) | |
| # attend to values | |
| v = v.reshape(b,c,h*w) | |
| w_ = w_.permute(0,2,1) # b,hw,hw (first hw of k, second of q) | |
| h_ = torch.bmm(v,w_) # b, c,hw (hw of q) h_[b,c,j] = sum_i v[b,c,i] w_[b,i,j] | |
| h_ = h_.reshape(b,c,h,w) | |
| h_ = self.proj_out(h_) | |
| return x+h_ | |
| class Phi(nn.Conv2d): | |
| def __init__(self, embed_dim, quant_resi): | |
| ks = 3 | |
| super().__init__(in_channels=embed_dim, out_channels=embed_dim, kernel_size=ks, stride=1, padding=ks//2) | |
| self.resi_ratio = abs(quant_resi) | |
| def forward(self, h_BChw): | |
| return h_BChw.mul(1-self.resi_ratio) + super().forward(h_BChw).mul_(self.resi_ratio) | |
| class PhiPartiallyShared(nn.Module): | |
| def __init__(self, qresi_ls: nn.ModuleList): | |
| super().__init__() | |
| self.qresi_ls = qresi_ls | |
| K = len(qresi_ls) | |
| self.ticks = np.linspace(1/3/K, 1-1/3/K, K) if K == 4 else np.linspace(1/2/K, 1-1/2/K, K) | |
| def __getitem__(self, at_from_0_to_1: float) -> Phi: | |
| return self.qresi_ls[np.argmin(np.abs(self.ticks - at_from_0_to_1)).item()] | |
| def extra_repr(self) -> str: | |
| return f'ticks={self.ticks}' | |
| def nonlinearity(x): | |
| # swish | |
| return x*torch.sigmoid(x) | |
| def Normalize(in_channels, norm_type='group'): | |
| assert norm_type in ['group', 'batch'] | |
| if norm_type == 'group': | |
| return nn.GroupNorm(num_groups=32, num_channels=in_channels, eps=1e-6, affine=True) | |
| elif norm_type == 'batch': | |
| return nn.SyncBatchNorm(in_channels) | |
| class Upsample(nn.Module): | |
| def __init__(self, in_channels, with_conv): | |
| super().__init__() | |
| self.with_conv = with_conv | |
| if self.with_conv: | |
| self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1) | |
| def forward(self, x): | |
| x = F.interpolate(x, scale_factor=2.0, mode="nearest") | |
| if self.with_conv: | |
| x = self.conv(x) | |
| return x | |
| class Downsample(nn.Module): | |
| def __init__(self, in_channels, with_conv): | |
| super().__init__() | |
| self.with_conv = with_conv | |
| if self.with_conv: | |
| # no asymmetric padding in torch conv, must do it ourselves | |
| self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=2, padding=0) | |
| def forward(self, x): | |
| if self.with_conv: | |
| pad = (0,1,0,1) | |
| x = F.pad(x, pad, mode="constant", value=0) | |
| x = self.conv(x) | |
| else: | |
| x = F.avg_pool2d(x, kernel_size=2, stride=2) | |
| return x | |
| def compute_entropy_loss(affinity, loss_type="softmax", temperature=0.01): | |
| flat_affinity = affinity.reshape(-1, affinity.shape[-1]) | |
| flat_affinity /= temperature | |
| probs = F.softmax(flat_affinity, dim=-1) | |
| log_probs = F.log_softmax(flat_affinity + 1e-5, dim=-1) | |
| if loss_type == "softmax": | |
| target_probs = probs | |
| else: | |
| raise ValueError("Entropy loss {} not supported".format(loss_type)) | |
| avg_probs = torch.mean(target_probs, dim=0) | |
| avg_entropy = - torch.sum(avg_probs * torch.log(avg_probs + 1e-5)) | |
| sample_entropy = - torch.mean(torch.sum(target_probs * log_probs, dim=-1)) | |
| loss = sample_entropy - avg_entropy | |
| return loss | |
| ################################################################################# | |
| # VQ Model Configs # | |
| ################################################################################# | |
| def TokenFlowFunc(**kwargs): | |
| return TokenFlow(ModelArgs(encoder_ch_mult=[1, 1, 2, 2, 4], decoder_ch_mult=[1, 1, 2, 2, 4], **kwargs)) | |
| VQ_models = {'TokenFlow': TokenFlowFunc} | |