Spaces:
Running on Zero
Running on Zero
| import math | |
| import copy | |
| import os | |
| import json | |
| from dataclasses import dataclass, field, asdict, fields | |
| from pathlib import Path | |
| from typing import Any, Dict, List, Optional, Tuple, Union | |
| import torch | |
| import torch.nn.init as init | |
| from PIL import Image | |
| from einops import rearrange | |
| from torch import Tensor, nn | |
| from diffusers.configuration_utils import ConfigMixin, register_to_config | |
| from diffusers.image_processor import VaeImageProcessor | |
| from diffusers.pipelines.pipeline_utils import DiffusionPipeline | |
| from diffusers.schedulers.scheduling_utils import SchedulerMixin | |
| from diffusers.configuration_utils import FrozenDict | |
| from diffusers.utils import BaseOutput | |
| from diffusers.utils.torch_utils import randn_tensor | |
| from rosetta.utils import PRECISION_TO_TYPE | |
| def normal_weight_reset_parameters(std=0.02, bias_type="default"): | |
| def _wrap_fn(_self): | |
| init.normal_(_self.weight, std=std) | |
| if hasattr(_self, "bias") and _self.bias is not None: | |
| if bias_type == "default": | |
| fan_in, _ = init._calculate_fan_in_and_fan_out(_self.weight) | |
| bound = 1 / math.sqrt(fan_in) if fan_in > 0 else 0 | |
| init.uniform_(_self.bias, -bound, bound) | |
| elif bias_type == "zeros": | |
| init.zeros_(_self.bias) | |
| else: | |
| raise ValueError(f"Unsupported bias_init_type: {bias_type}") | |
| return _wrap_fn | |
| def timestep_embedding(t, dim, max_period=10000): | |
| half = dim // 2 | |
| freqs = torch.exp( | |
| -math.log(max_period) | |
| * torch.arange(start=0, end=half, dtype=torch.float32) | |
| / half | |
| ).to(device=t.device) | |
| args = t[:, None].float() * freqs[None] | |
| embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1) | |
| if dim % 2: | |
| embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1) | |
| return embedding | |
| class TimestepEmbedder(nn.Module): | |
| def __init__( | |
| self, | |
| hidden_size, | |
| act_layer=nn.GELU, | |
| frequency_embedding_size=256, | |
| max_period=10000, | |
| out_size=None, | |
| dtype=None, | |
| device=None, | |
| config=None, | |
| ): | |
| factory_kwargs = {'dtype': dtype, 'device': device} | |
| super().__init__() | |
| self.frequency_embedding_size = frequency_embedding_size | |
| self.max_period = max_period | |
| self.init_std = config.init_std if config is not None and hasattr(config, 'init_std') else 0.02 | |
| out_size = hidden_size if out_size is None else out_size | |
| self.mlp = nn.Sequential( | |
| nn.Linear(frequency_embedding_size, hidden_size, bias=True, **factory_kwargs), | |
| act_layer(), | |
| nn.Linear(hidden_size, out_size, bias=True, **factory_kwargs), | |
| ) | |
| nn.init.normal_(self.mlp[0].weight, std=self.init_std) | |
| nn.init.normal_(self.mlp[2].weight, std=self.init_std) | |
| def prepare_reset_parameters(self): | |
| self.mlp[0].reset_parameters = normal_weight_reset_parameters(std=self.init_std).__get__(self.mlp[0]) | |
| self.mlp[2].reset_parameters = normal_weight_reset_parameters(std=self.init_std).__get__(self.mlp[2]) | |
| def forward(self, t): | |
| t_freq = timestep_embedding(t, self.frequency_embedding_size, self.max_period).type(self.mlp[0].weight.dtype) | |
| return self.mlp(t_freq) | |
| def zero_reset_parameters(_self): | |
| init.zeros_(_self.weight) | |
| if hasattr(_self, 'bias') and _self.bias is not None: | |
| init.zeros_(_self.bias) | |
| def conv_nd(dims, *args, **kwargs): | |
| if dims != 2: | |
| raise ValueError(f"unsupported dimensions: {dims}") | |
| return nn.Conv2d(*args, **kwargs) | |
| def linear(*args, **kwargs): | |
| return nn.Linear(*args, **kwargs) | |
| def zero_module(module): | |
| for p in module.parameters(): | |
| p.detach().zero_() | |
| return module | |
| def normalization(channels, **kwargs): | |
| return nn.GroupNorm(32, channels, **kwargs) | |
| class ResBlock(nn.Module): | |
| def __init__( | |
| self, | |
| in_channels, | |
| emb_channels, | |
| out_channels=None, | |
| dropout=0.0, | |
| dims=2, | |
| device=None, | |
| dtype=None, | |
| kernel_size=3, | |
| padding=1, | |
| ): | |
| factory_kwargs = {'dtype': dtype, 'device': device} | |
| super().__init__() | |
| self.in_channels = in_channels | |
| self.dropout = dropout | |
| self.out_channels = out_channels or self.in_channels | |
| if dims != 2: | |
| raise ValueError("Only 2D image projector blocks are supported.") | |
| self.in_layers = nn.Sequential( | |
| normalization(self.in_channels, **factory_kwargs), | |
| nn.SiLU(), | |
| conv_nd(dims, self.in_channels, self.out_channels, kernel_size, padding=padding, **factory_kwargs), | |
| ) | |
| self.emb_layers = nn.Sequential( | |
| nn.SiLU(), | |
| linear(emb_channels, 2 * self.out_channels, **factory_kwargs), | |
| ) | |
| self.out_layers = nn.Sequential( | |
| normalization(self.out_channels, **factory_kwargs), | |
| nn.SiLU(), | |
| nn.Dropout(p=dropout), | |
| zero_module(conv_nd(dims, self.out_channels, self.out_channels, kernel_size, padding=padding, **factory_kwargs)), | |
| ) | |
| self.skip_connection = ( | |
| nn.Identity() | |
| if self.out_channels == self.in_channels | |
| else conv_nd(dims, self.in_channels, self.out_channels, 1, **factory_kwargs) | |
| ) | |
| def reset_parameters(self): | |
| self.out_layers[3].reset_parameters = zero_reset_parameters.__get__(self.out_layers[3]) | |
| def forward(self, x, emb): | |
| h = self.in_layers(x) | |
| emb_out = self.emb_layers(emb) | |
| while len(emb_out.shape) < len(h.shape): | |
| emb_out = emb_out[..., None] | |
| out_norm, out_rest = self.out_layers[0], self.out_layers[1:] | |
| scale, shift = torch.chunk(emb_out, 2, dim=1) | |
| h = out_norm(h) * (1. + scale) + shift | |
| h = out_rest(h) | |
| return self.skip_connection(x) + h | |
| class UNetDown(nn.Module): | |
| def __init__( | |
| self, in_channels, emb_channels, hidden_channels, out_channels, dropout=0.0, | |
| device=None, dtype=None, kernel_size=3, padding=1, | |
| ): | |
| factory_kwargs = {'dtype': dtype, 'device': device} | |
| super().__init__() | |
| self.model = nn.ModuleList([ | |
| conv_nd(2, in_channels=in_channels, out_channels=hidden_channels, kernel_size=kernel_size, padding=padding, **factory_kwargs), | |
| ResBlock( | |
| in_channels=hidden_channels, emb_channels=emb_channels, out_channels=out_channels, | |
| dropout=dropout, dims=2, kernel_size=kernel_size, padding=padding, **factory_kwargs, | |
| ), | |
| ]) | |
| def forward(self, x, t): | |
| assert x.ndim == 4, f"image latents should be 4D [B, C, H, W], got {list(x.shape)}" | |
| for module in self.model: | |
| x = module(x, t) if isinstance(module, ResBlock) else module(x) | |
| _, _, *token_sizes = x.shape | |
| x = rearrange(x, 'b c h w -> b (h w) c') | |
| return x, *token_sizes | |
| class UNetUp(nn.Module): | |
| def __init__( | |
| self, in_channels, emb_channels, hidden_channels, out_channels, dropout=0.0, | |
| device=None, dtype=None, out_norm=False, kernel_size=3, padding=1, | |
| ): | |
| factory_kwargs = {'dtype': dtype, 'device': device} | |
| super().__init__() | |
| self.model = nn.ModuleList([ | |
| ResBlock( | |
| in_channels=in_channels, emb_channels=emb_channels, out_channels=hidden_channels, | |
| dropout=dropout, dims=2, kernel_size=kernel_size, padding=padding, **factory_kwargs, | |
| ) | |
| ]) | |
| if out_norm: | |
| self.model.append(nn.Sequential( | |
| normalization(hidden_channels, **factory_kwargs), | |
| nn.SiLU(), | |
| conv_nd(2, in_channels=hidden_channels, out_channels=out_channels, kernel_size=kernel_size, padding=padding, **factory_kwargs), | |
| )) | |
| else: | |
| self.model.append(conv_nd( | |
| 2, in_channels=hidden_channels, out_channels=out_channels, | |
| kernel_size=kernel_size, padding=padding, **factory_kwargs, | |
| )) | |
| def forward(self, x, t, *token_sizes): | |
| token_h, token_w = token_sizes | |
| x = rearrange(x, 'b (h w) c -> b c h w', h=token_h, w=token_w) | |
| for module in self.model: | |
| x = module(x, t) if isinstance(module, ResBlock) else module(x) | |
| return x | |
| def project_in_layer(config, **kwargs): | |
| return UNetDown( | |
| emb_channels=config.hidden_size, | |
| in_channels=config.vae_latent_dim, | |
| hidden_channels=config.patch_embed_hidden_dim, | |
| out_channels=config.hidden_size, | |
| **kwargs, | |
| ) | |
| def project_out_layer(config, **kwargs): | |
| return UNetUp( | |
| emb_channels=config.hidden_size, | |
| in_channels=config.hidden_size, | |
| hidden_channels=config.patch_embed_hidden_dim, | |
| out_channels=config.vae_latent_dim, | |
| out_norm=True, | |
| **kwargs, | |
| ) | |
| class FlowMatchDiscreteScheduler(SchedulerMixin, ConfigMixin): | |
| order = 1 | |
| def __init__( | |
| self, | |
| num_train_timesteps: int = 1000, | |
| shift: float = 1.0, | |
| reverse: bool = True, | |
| start_sigma: float = 1.0, | |
| end_sigma: float = 0.0, | |
| ): | |
| sigmas = torch.linspace(start_sigma, end_sigma, num_train_timesteps + 1) | |
| if not reverse: | |
| sigmas = sigmas.flip(0) | |
| self.sigmas = sigmas | |
| self.timesteps = (sigmas[:-1] * num_train_timesteps).to(dtype=torch.float32) | |
| self._step_index = None | |
| def set_timesteps(self, num_inference_steps: int, device: Union[str, torch.device] = None): | |
| self.num_inference_steps = num_inference_steps | |
| sigmas = torch.linspace(self.config.start_sigma, self.config.end_sigma, num_inference_steps + 1) | |
| if self.config.shift != 1.: | |
| sigmas = (self.config.shift * sigmas) / (1 + (self.config.shift - 1) * sigmas) | |
| if not self.config.reverse: | |
| sigmas = 1 - sigmas | |
| self.sigmas = sigmas | |
| self.timesteps = (sigmas[:-1] * self.config.num_train_timesteps).to(dtype=torch.float32, device=device) | |
| self._step_index = None | |
| def _init_step_index(self, timestep): | |
| if isinstance(timestep, torch.Tensor): | |
| timestep = timestep.to(self.timesteps.device) | |
| indices = (self.timesteps == timestep).nonzero() | |
| self._step_index = indices[1 if len(indices) > 1 else 0].item() | |
| def step( | |
| self, | |
| model_output: torch.FloatTensor, | |
| timestep: Union[float, torch.FloatTensor], | |
| sample: torch.FloatTensor, | |
| ) -> Tuple[torch.Tensor]: | |
| if isinstance(timestep, (int, torch.IntTensor, torch.LongTensor)): | |
| raise ValueError("Pass a scheduler timestep value, not an integer step index.") | |
| if self._step_index is None: | |
| self._init_step_index(timestep) | |
| sample = sample.to(torch.float32) | |
| model_output = model_output.to(torch.float32) | |
| sigma = self.sigmas[self._step_index] | |
| sigma_next = self.sigmas[self._step_index + 1] | |
| self._step_index += 1 | |
| return (sample + model_output * (sigma_next - sigma),) | |
| class ClassifierFreeGuidance: | |
| def __call__(self, pred_cond: torch.Tensor, pred_uncond: torch.Tensor, guidance_scale: float, step: int): | |
| return pred_uncond + guidance_scale * (pred_cond - pred_uncond) | |
| class MultimodalPipeline(DiffusionPipeline): | |
| def __init__( | |
| self, | |
| model, | |
| scheduler: SchedulerMixin, | |
| vae, | |
| vae_autocast_dtype: Optional[torch.dtype] = None, | |
| progress_bar_config: Dict[str, Any] = None, | |
| ): | |
| super().__init__() | |
| self._progress_bar_config = getattr(self, "_progress_bar_config", {}) | |
| self._progress_bar_config.update(progress_bar_config or {}) | |
| self.vae_autocast_dtype = vae_autocast_dtype | |
| self.register_modules(model=model, scheduler=scheduler, vae=vae) | |
| self.latent_scale_factor = self.model.config.vae_downsample_factor | |
| self.image_processor = VaeImageProcessor(vae_scale_factor=self.latent_scale_factor) | |
| self.cfg_operator = ClassifierFreeGuidance() | |
| def prepare_latents(self, batch_size, latent_channel, image_size, dtype, device, generator, latents=None): | |
| if isinstance(image_size, list): | |
| assert len(image_size) == batch_size | |
| return self._prepare_latents_variable_res( | |
| batch_size, latent_channel, image_size, dtype, device, generator, latents, | |
| ) | |
| if self.latent_scale_factor is None: | |
| latent_scale_factor = (1,) * len(image_size) | |
| elif isinstance(self.latent_scale_factor, int): | |
| latent_scale_factor = (self.latent_scale_factor,) * len(image_size) | |
| elif isinstance(self.latent_scale_factor, (tuple, list)): | |
| latent_scale_factor = self.latent_scale_factor | |
| else: | |
| raise ValueError(f"Unsupported latent_scale_factor: {self.latent_scale_factor}") | |
| latents_shape = ( | |
| batch_size, latent_channel, | |
| *[int(s) // f for s, f in zip(image_size, latent_scale_factor)], | |
| ) | |
| if isinstance(generator, list) and len(generator) != batch_size: | |
| raise ValueError("Generator list length must match batch size.") | |
| latents = randn_tensor(latents_shape, generator=generator, device=device, dtype=dtype) if latents is None else latents.to(device) | |
| if hasattr(self.scheduler, "init_noise_sigma"): | |
| latents = latents * self.scheduler.init_noise_sigma | |
| return latents | |
| def _prepare_latents_variable_res( | |
| self, batch_size, latent_channel, image_sizes, dtype, device, generator, latents=None, | |
| ): | |
| ndim = len(image_sizes[0]) | |
| if self.latent_scale_factor is None: | |
| scale_factors = (1,) * ndim | |
| elif isinstance(self.latent_scale_factor, int): | |
| scale_factors = (self.latent_scale_factor,) * ndim | |
| else: | |
| scale_factors = tuple(self.latent_scale_factor) | |
| latents_list = [] | |
| for i, img_size in enumerate(image_sizes): | |
| shape = (1, latent_channel, *tuple(int(s) // f for s, f in zip(img_size, scale_factors))) | |
| gen = generator[i] if isinstance(generator, list) else generator | |
| lat = randn_tensor(shape, generator=gen, device=device, dtype=dtype) if latents is None else latents[i:i + 1].to(device) | |
| if hasattr(self.per_sample_schedulers[i], "init_noise_sigma"): | |
| lat = lat * self.per_sample_schedulers[i].init_noise_sigma | |
| latents_list.append(lat) | |
| return latents_list | |
| def guidance_scale(self): | |
| return self._guidance_scale | |
| def do_classifier_free_guidance(self): | |
| return self._guidance_scale > 1.0 and self._cfg_factor > 1 | |
| def __call__( | |
| self, | |
| batch_size: int, | |
| image_size: tuple[int, int] | list[tuple[int, int]], | |
| num_inference_steps: int = 50, | |
| guidance_scale: float = 7.5, | |
| generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None, | |
| latents: Optional[torch.Tensor] = None, | |
| output_type: Optional[str] = "pil", | |
| model_kwargs: Dict[str, Any] = None, | |
| **kwargs, | |
| ) -> list[Image.Image]: | |
| self._guidance_scale = guidance_scale | |
| cfg_factor = kwargs.pop('cfg_factor', None) | |
| self._cfg_factor = cfg_factor if cfg_factor is not None else (2 if guidance_scale > 1.0 else 1) | |
| device = self.model.device | |
| is_variable_res = isinstance(image_size, list) | |
| if is_variable_res: | |
| self.per_sample_schedulers = [copy.deepcopy(self.scheduler) for _ in range(batch_size)] | |
| latents = self.prepare_latents( | |
| batch_size=batch_size, | |
| latent_channel=self.model.config.vae_latent_dim, | |
| image_size=image_size, | |
| dtype=torch.float32, | |
| device=device, | |
| generator=generator, | |
| latents=latents, | |
| ) | |
| if is_variable_res: | |
| per_sample_timesteps = [] | |
| for b_idx in range(batch_size): | |
| self.per_sample_schedulers[b_idx].set_timesteps(num_inference_steps, device=device) | |
| per_sample_timesteps.append(self.per_sample_schedulers[b_idx].timesteps) | |
| timesteps = per_sample_timesteps[0] | |
| scheduler_order = self.per_sample_schedulers[0].order | |
| else: | |
| self.scheduler.set_timesteps(num_inference_steps, device=device) | |
| timesteps = self.scheduler.timesteps | |
| scheduler_order = self.scheduler.order | |
| input_ids = model_kwargs.pop("input_ids") | |
| attention_mask = self.model._prepare_attention_mask_for_generation( | |
| input_ids, self.model.generation_config, model_kwargs=model_kwargs, | |
| ) | |
| model_kwargs["attention_mask"] = attention_mask.to(device) | |
| num_warmup_steps = len(timesteps) - num_inference_steps * scheduler_order | |
| with self.progress_bar(total=num_inference_steps) as progress_bar: | |
| for i, t in enumerate(timesteps): | |
| if is_variable_res: | |
| latent_model_input = [lat.clone() for lat in latents] * self._cfg_factor | |
| per_t = [per_sample_timesteps[j][i] for j in range(batch_size)] | |
| t_expand = torch.stack(per_t * self._cfg_factor) | |
| else: | |
| latent_model_input = torch.cat([latents] * self._cfg_factor) | |
| t_expand = t.repeat(latent_model_input.shape[0]) | |
| model_inputs = self.model.prepare_inputs_for_generation( | |
| input_ids, images=latent_model_input, timesteps=t_expand, **model_kwargs, | |
| ) | |
| with torch.autocast(device_type="cuda", dtype=torch.bfloat16, enabled=True): | |
| model_output = self.model(**model_inputs, first_step=(i == 0)) | |
| pred = model_output["diffusion_prediction"] | |
| if is_variable_res: | |
| pred = [p.to(dtype=torch.float32) for p in pred] | |
| if self.do_classifier_free_guidance: | |
| half = len(pred) // 2 | |
| pred = [ | |
| self.cfg_operator(pc, pu, self.guidance_scale, step=i) | |
| for pc, pu in zip(pred[:half], pred[half:]) | |
| ] | |
| for j in range(batch_size): | |
| latents[j] = self.per_sample_schedulers[j].step( | |
| pred[j], per_sample_timesteps[j][i], latents[j], | |
| )[0] | |
| else: | |
| pred = pred.to(dtype=torch.float32) | |
| if pred.ndim == 5 and pred.size(2) == 1 and latents.ndim == 4: | |
| pred = pred.squeeze(2) | |
| if self.do_classifier_free_guidance: | |
| pred_cond, pred_uncond = pred.chunk(2) | |
| pred = self.cfg_operator(pred_cond, pred_uncond, self.guidance_scale, step=i) | |
| latents = self.scheduler.step(pred, t, latents)[0] | |
| if i != len(timesteps) - 1: | |
| model_kwargs = self.model._update_model_kwargs_for_generation(model_output, model_kwargs) | |
| input_ids = None | |
| if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % scheduler_order == 0): | |
| progress_bar.update() | |
| return self.decode_latents(latents, is_variable_res, output_type, generator) | |
| def decode_latents(self, latents, is_variable_res, output_type, generator): | |
| if is_variable_res: | |
| images = [] | |
| for lat in latents: | |
| images.extend(self.decode_latents(lat, False, output_type, generator)) | |
| return images | |
| if hasattr(self.vae.config, 'scaling_factor') and self.vae.config.scaling_factor: | |
| latents = latents / self.vae.config.scaling_factor | |
| if hasattr(self.vae.config, 'shift_factor') and self.vae.config.shift_factor: | |
| latents = latents + self.vae.config.shift_factor | |
| with torch.autocast( | |
| device_type="cuda", dtype=self.vae_autocast_dtype, | |
| enabled=self.vae_autocast_dtype is not None and self.vae_autocast_dtype != torch.float32, | |
| ): | |
| image = self.vae.decode(latents, return_dict=False, generator=generator)[0] | |
| return self.image_processor.postprocess( | |
| image, output_type=output_type, do_denormalize=[True] * image.shape[0], | |
| ) | |
| class AutoEncoderParams: | |
| resolution: int = 256 | |
| in_channels: int = 3 | |
| ch: int = 128 | |
| out_ch: int = 3 | |
| ch_mult: list[int] = field(default_factory=lambda: [1, 2, 4, 4]) | |
| num_res_blocks: int = 2 | |
| z_channels: int = 32 | |
| def from_json(cls, json_path: str | Path) -> "AutoEncoderParams": | |
| with open(json_path, 'r') as f: | |
| config_dict = json.load(f) | |
| valid_fields = {f.name for f in fields(cls)} | |
| filtered_dict = {k: v for k, v in config_dict.items() if k in valid_fields} | |
| return cls(**filtered_dict) | |
| def to_dict(self) -> dict[str, Any]: | |
| return asdict(self) | |
| class DecoderOutput(BaseOutput): | |
| sample: torch.FloatTensor | |
| def swish(x: Tensor) -> Tensor: | |
| return x * torch.sigmoid(x) | |
| class AttnBlock(nn.Module): | |
| def __init__(self, in_channels: int): | |
| super().__init__() | |
| self.in_channels = in_channels | |
| self.norm = nn.GroupNorm(num_groups=32, num_channels=in_channels, eps=1e-6, affine=True) | |
| self.q = nn.Conv2d(in_channels, in_channels, kernel_size=1) | |
| self.k = nn.Conv2d(in_channels, in_channels, kernel_size=1) | |
| self.v = nn.Conv2d(in_channels, in_channels, kernel_size=1) | |
| self.proj_out = nn.Conv2d(in_channels, in_channels, kernel_size=1) | |
| def attention(self, h_: Tensor) -> Tensor: | |
| h_ = self.norm(h_) | |
| q = self.q(h_) | |
| k = self.k(h_) | |
| v = self.v(h_) | |
| b, c, h, w = q.shape | |
| q = rearrange(q, "b c h w -> b 1 (h w) c").contiguous() | |
| k = rearrange(k, "b c h w -> b 1 (h w) c").contiguous() | |
| v = rearrange(v, "b c h w -> b 1 (h w) c").contiguous() | |
| h_ = nn.functional.scaled_dot_product_attention(q, k, v) | |
| return rearrange(h_, "b 1 (h w) c -> b c h w", h=h, w=w, c=c, b=b) | |
| def forward(self, x: Tensor) -> Tensor: | |
| return x + self.proj_out(self.attention(x)) | |
| class ResnetBlock(nn.Module): | |
| def __init__(self, in_channels: int, out_channels: int): | |
| 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.norm1 = nn.GroupNorm(num_groups=32, num_channels=in_channels, eps=1e-6, affine=True) | |
| self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) | |
| self.norm2 = nn.GroupNorm(num_groups=32, num_channels=out_channels, eps=1e-6, affine=True) | |
| self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1) | |
| if self.in_channels != self.out_channels: | |
| 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 = swish(h) | |
| h = self.conv1(h) | |
| h = self.norm2(h) | |
| h = swish(h) | |
| h = self.conv2(h) | |
| if self.in_channels != self.out_channels: | |
| x = self.nin_shortcut(x) | |
| return x + h | |
| class Downsample(nn.Module): | |
| def __init__(self, in_channels: int): | |
| super().__init__() | |
| self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=2, padding=0) | |
| def forward(self, x: Tensor): | |
| pad = (0, 1, 0, 1) | |
| x = nn.functional.pad(x, pad, mode="constant", value=0) | |
| x = self.conv(x) | |
| return x | |
| class Upsample(nn.Module): | |
| def __init__(self, in_channels: int): | |
| super().__init__() | |
| self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1) | |
| def forward(self, x: Tensor): | |
| x = nn.functional.interpolate(x, scale_factor=2.0, mode="nearest") | |
| x = self.conv(x) | |
| return x | |
| class Encoder(nn.Module): | |
| def __init__( | |
| self, | |
| resolution: int, | |
| in_channels: int, | |
| ch: int, | |
| ch_mult: list[int], | |
| num_res_blocks: int, | |
| z_channels: int, | |
| ): | |
| super().__init__() | |
| self.quant_conv = torch.nn.Conv2d(2 * z_channels, 2 * z_channels, 1) | |
| self.ch = ch | |
| self.num_resolutions = len(ch_mult) | |
| self.num_res_blocks = num_res_blocks | |
| self.resolution = resolution | |
| self.in_channels = in_channels | |
| self.conv_in = nn.Conv2d(in_channels, self.ch, kernel_size=3, stride=1, padding=1) | |
| curr_res = resolution | |
| in_ch_mult = (1,) + tuple(ch_mult) | |
| self.in_ch_mult = in_ch_mult | |
| self.down = nn.ModuleList() | |
| block_in = self.ch | |
| for i_level in range(self.num_resolutions): | |
| block = nn.ModuleList() | |
| attn = nn.ModuleList() | |
| block_in = ch * in_ch_mult[i_level] | |
| block_out = ch * ch_mult[i_level] | |
| for _ in range(self.num_res_blocks): | |
| block.append(ResnetBlock(in_channels=block_in, out_channels=block_out)) | |
| block_in = block_out | |
| down = nn.Module() | |
| down.block = block | |
| down.attn = attn | |
| if i_level != self.num_resolutions - 1: | |
| down.downsample = Downsample(block_in) | |
| curr_res = curr_res // 2 | |
| self.down.append(down) | |
| self.mid = nn.Module() | |
| self.mid.block_1 = ResnetBlock(in_channels=block_in, out_channels=block_in) | |
| self.mid.attn_1 = AttnBlock(block_in) | |
| self.mid.block_2 = ResnetBlock(in_channels=block_in, out_channels=block_in) | |
| self.norm_out = nn.GroupNorm(num_groups=32, num_channels=block_in, eps=1e-6, affine=True) | |
| self.conv_out = nn.Conv2d(block_in, 2 * z_channels, kernel_size=3, stride=1, padding=1) | |
| def forward(self, x: Tensor) -> Tensor: | |
| hs = [self.conv_in(x)] | |
| for i_level in range(self.num_resolutions): | |
| for i_block in range(self.num_res_blocks): | |
| h = self.down[i_level].block[i_block](hs[-1]) | |
| if len(self.down[i_level].attn) > 0: | |
| h = self.down[i_level].attn[i_block](h) | |
| hs.append(h) | |
| if i_level != self.num_resolutions - 1: | |
| hs.append(self.down[i_level].downsample(hs[-1])) | |
| h = hs[-1] | |
| h = self.mid.block_1(h) | |
| h = self.mid.attn_1(h) | |
| h = self.mid.block_2(h) | |
| h = self.norm_out(h) | |
| h = swish(h) | |
| h = self.conv_out(h) | |
| h = self.quant_conv(h) | |
| return h | |
| class Decoder(nn.Module): | |
| def __init__( | |
| self, | |
| ch: int, | |
| out_ch: int, | |
| ch_mult: list[int], | |
| num_res_blocks: int, | |
| in_channels: int, | |
| resolution: int, | |
| z_channels: int, | |
| ): | |
| super().__init__() | |
| self.post_quant_conv = torch.nn.Conv2d(z_channels, z_channels, 1) | |
| self.ch = ch | |
| self.num_resolutions = len(ch_mult) | |
| self.num_res_blocks = num_res_blocks | |
| self.resolution = resolution | |
| self.in_channels = in_channels | |
| self.ffactor = 2 ** (self.num_resolutions - 1) | |
| block_in = ch * ch_mult[self.num_resolutions - 1] | |
| curr_res = resolution // 2 ** (self.num_resolutions - 1) | |
| self.z_shape = (1, z_channels, curr_res, curr_res) | |
| self.conv_in = nn.Conv2d(z_channels, block_in, kernel_size=3, stride=1, padding=1) | |
| self.mid = nn.Module() | |
| self.mid.block_1 = ResnetBlock(in_channels=block_in, out_channels=block_in) | |
| self.mid.attn_1 = AttnBlock(block_in) | |
| self.mid.block_2 = ResnetBlock(in_channels=block_in, out_channels=block_in) | |
| self.up = nn.ModuleList() | |
| for i_level in reversed(range(self.num_resolutions)): | |
| block = nn.ModuleList() | |
| attn = nn.ModuleList() | |
| block_out = ch * ch_mult[i_level] | |
| for _ in range(self.num_res_blocks + 1): | |
| block.append(ResnetBlock(in_channels=block_in, out_channels=block_out)) | |
| block_in = block_out | |
| up = nn.Module() | |
| up.block = block | |
| up.attn = attn | |
| if i_level != 0: | |
| up.upsample = Upsample(block_in) | |
| curr_res = curr_res * 2 | |
| self.up.insert(0, up) # prepend to get consistent order | |
| self.norm_out = nn.GroupNorm(num_groups=32, num_channels=block_in, eps=1e-6, affine=True) | |
| self.conv_out = nn.Conv2d(block_in, out_ch, kernel_size=3, stride=1, padding=1) | |
| def forward(self, z: Tensor) -> Tensor: | |
| z = self.post_quant_conv(z) | |
| upscale_dtype = next(self.up.parameters()).dtype | |
| h = self.conv_in(z) | |
| h = self.mid.block_1(h) | |
| h = self.mid.attn_1(h) | |
| h = self.mid.block_2(h) | |
| h = h.to(upscale_dtype) | |
| for i_level in reversed(range(self.num_resolutions)): | |
| for i_block in range(self.num_res_blocks + 1): | |
| h = self.up[i_level].block[i_block](h) | |
| if len(self.up[i_level].attn) > 0: | |
| h = self.up[i_level].attn[i_block](h) | |
| if i_level != 0: | |
| h = self.up[i_level].upsample(h) | |
| h = self.norm_out(h) | |
| h = swish(h) | |
| h = self.conv_out(h) | |
| return h | |
| class AutoEncoder(nn.Module): | |
| def __init__(self, params: AutoEncoderParams): | |
| super().__init__() | |
| self.params = params | |
| self.encoder = Encoder( | |
| resolution=params.resolution, | |
| in_channels=params.in_channels, | |
| ch=params.ch, | |
| ch_mult=params.ch_mult, | |
| num_res_blocks=params.num_res_blocks, | |
| z_channels=params.z_channels, | |
| ) | |
| self.decoder = Decoder( | |
| resolution=params.resolution, | |
| in_channels=params.in_channels, | |
| ch=params.ch, | |
| out_ch=params.out_ch, | |
| ch_mult=params.ch_mult, | |
| num_res_blocks=params.num_res_blocks, | |
| z_channels=params.z_channels, | |
| ) | |
| self.bn_eps = 1e-4 | |
| self.bn_momentum = 0.1 | |
| self.ps = [2, 2] | |
| self.bn = torch.nn.BatchNorm2d( | |
| math.prod(self.ps) * params.z_channels, | |
| eps=self.bn_eps, | |
| momentum=self.bn_momentum, | |
| affine=False, | |
| track_running_stats=True, | |
| ) | |
| def normalize(self, z): | |
| self.bn.eval() | |
| return self.bn(z) | |
| def inv_normalize(self, z): | |
| self.bn.eval() | |
| s = torch.sqrt(self.bn.running_var.view(1, -1, 1, 1) + self.bn_eps) | |
| m = self.bn.running_mean.view(1, -1, 1, 1) | |
| return z * s + m | |
| def encode(self, x: Tensor) -> Tensor: | |
| moments = self.encoder(x) | |
| mean = torch.chunk(moments, 2, dim=1)[0] | |
| z = rearrange( | |
| mean, | |
| "... c (i pi) (j pj) -> ... (c pi pj) i j", | |
| pi=self.ps[0], | |
| pj=self.ps[1], | |
| ) | |
| z = self.normalize(z) | |
| return z | |
| def decode(self, z: Tensor, return_dict: bool = True, generator=None) -> Tensor: | |
| z = self.inv_normalize(z) | |
| z = rearrange( | |
| z, | |
| "... (c pi pj) i j -> ... c (i pi) (j pj)", | |
| pi=self.ps[0], | |
| pj=self.ps[1], | |
| ) | |
| dec = self.decoder(z) | |
| if not return_dict: | |
| return (dec,) | |
| return DecoderOutput(sample=dec) | |
| def from_pretrained(cls, path: str): | |
| path = Path(path) | |
| config_path = path / "config.json" | |
| if config_path.exists(): | |
| with open(config_path, 'r') as f: | |
| config_dict = json.load(f) | |
| params = AutoEncoderParams.from_json(config_path) | |
| config = FrozenDict(config_dict) | |
| else: | |
| print(f"Warning: config.json not found at {config_path}, using default params") | |
| params = AutoEncoderParams() | |
| config = FrozenDict(params.to_dict()) | |
| model = cls(params=params) | |
| model.config = config | |
| model.load_state_dict(torch.load(path / "model.pt", map_location="cpu", weights_only=True), strict=True) | |
| return model | |
| ASSETS_BASE = os.getenv("ASSETS_BASE", "./public_assets").rstrip("/") | |
| VAE_BASE = os.getenv("VAE_BASE", f"{ASSETS_BASE}/image_encoder").rstrip("/") | |
| VAE_META_INFO = { | |
| "16x16-128c-flux2": { | |
| "path": f"{VAE_BASE}/flux2-vae", | |
| "downsample_factor": [16, 16], | |
| "trans_type": "-11", | |
| }, | |
| } | |
| def load_vae( | |
| vae_type, | |
| vae_precision=None, | |
| device=None, | |
| logger=None, | |
| args=None, | |
| ): | |
| if logger is None: | |
| from loguru import logger | |
| vae_meta_info = VAE_META_INFO[vae_type] | |
| vae_path = Path(vae_meta_info["path"]) | |
| config_file = vae_path / "config.json" | |
| with open(config_file, "r") as f: | |
| config = json.load(f) | |
| if "_class_name" in config: | |
| classname = config.pop("_class_name") | |
| else: | |
| raise ValueError(f"Cannot find the _class_name in {config_file}") | |
| logger.info(f"Load VAE with class {classname} from {config_file}") | |
| logger.info(f"Load vae_type: {vae_type} from path: {vae_path}") | |
| if classname != "AutoencoderKLFlux2" and "flux" not in vae_type: | |
| raise NotImplementedError(f"VAE class {classname} is not supported.") | |
| vae = AutoEncoder.from_pretrained(vae_path) | |
| vae._downsample_factor = vae_meta_info["downsample_factor"] | |
| if not hasattr(vae, 'downsample_factor'): | |
| vae.downsample_factor = vae_meta_info["downsample_factor"][0] | |
| vae._trans_type = vae_meta_info["trans_type"] | |
| if args is not None: | |
| vae.autocast_dtype = PRECISION_TO_TYPE[args.vae_autocast_dtype] | |
| if vae_precision is not None: | |
| logger.warning(f"You are transforming VAE to {vae_precision} precision! Please make sure this is what you want.") | |
| vae = vae.to(dtype=PRECISION_TO_TYPE[vae_precision]) | |
| if device is not None: | |
| vae = vae.to(device=device) | |
| vae.requires_grad_(False) | |
| vae.eval() | |
| return vae | |