CoolFace
Modelpublic

TensorForger/FlowUpscaler

sourceHugging Faceunlicenseupdated 3mo agoView on Hugging Face
19likes42downloads
upscaler_unet.py398 linesDownload Raw Back to root
1import torch2import torch.nn as nn3import torch.nn.functional as F4 5 6def make_group_norm(7    channels: int, max_groups: int = 32, eps: float = 1e-68) -> nn.GroupNorm:9    groups = min(max_groups, channels)10    while channels % groups != 0 and groups > 1:11        groups -= 112    return nn.GroupNorm(groups, channels, eps=eps)13 14 15class SinusoidalTimeEmbedding(nn.Module):16    def __init__(self, dim: int = 128, max_period: int = 10000):17        super().__init__()18        self.dim = dim19        self.max_period = max_period20 21    def forward(self, timesteps: torch.Tensor) -> torch.Tensor:22        half = self.dim // 223 24        freqs = torch.exp(25            -torch.log(torch.tensor(float(self.max_period), device=timesteps.device))26            * torch.arange(half, device=timesteps.device, dtype=timesteps.dtype)27            / half28        )29        args = timesteps[:, None] * freqs[None]30        emb = torch.cat([torch.sin(args), torch.cos(args)], dim=-1)31 32        if self.dim % 2 == 1:33            emb = F.pad(emb, (0, 1))34 35        return emb36 37 38class ConditioningEncoder(nn.Module):39    def __init__(self, time_dim: int = 128, cond_dim: int = 256):40        super().__init__()41        self.time_embed = SinusoidalTimeEmbedding(time_dim)42 43        self.time_proj = nn.Sequential(44            nn.Linear(time_dim, cond_dim),45            nn.SiLU(),46            nn.Linear(cond_dim, cond_dim),47        )48 49    def forward(self, timestep: torch.Tensor) -> torch.Tensor:50        time_vec = self.time_proj(self.time_embed(timestep))51        return time_vec52 53 54class ConditionedResidualBlock(nn.Module):55    """56    SDXL-style residual block:57      GN -> SiLU -> Conv58      + condition (scale/shift)59      GN -> SiLU -> Dropout -> Conv60      + skip connection61    """62 63    def __init__(64        self,65        input_channels: int,66        output_channels: int,67        cond_dim: int = 256,68        dropout: float = 0.0,69    ):70        super().__init__()71 72        self.norm1 = make_group_norm(input_channels)73        self.conv1 = nn.Conv2d(74            input_channels, output_channels, kernel_size=3, padding=175        )76 77        self.cond_proj = nn.Sequential(78            nn.SiLU(),79            nn.Linear(cond_dim, 2 * output_channels),80        )81 82        self.norm2 = make_group_norm(output_channels)83        self.dropout = nn.Dropout(dropout)84        self.conv2 = nn.Conv2d(85            output_channels, output_channels, kernel_size=3, padding=186        )87 88        if input_channels != output_channels:89            self.skip = nn.Conv2d(90                input_channels, output_channels, kernel_size=1, bias=False91            )92        else:93            self.skip = nn.Identity()94 95    def forward(self, x: torch.Tensor, cond: torch.Tensor) -> torch.Tensor:96        residual = self.skip(x)97 98        h = self.norm1(x)99        h = F.silu(h)100        h = self.conv1(h)101 102        scale_shift = self.cond_proj(cond)103        scale, shift = scale_shift.chunk(2, dim=1)104 105        h = self.norm2(h)106        h = h * (1 + scale[:, :, None, None]) + shift[:, :, None, None]107        h = F.silu(h)108        h = self.dropout(h)109        h = self.conv2(h)110 111        return h + residual112 113 114class DownStage(nn.Module):115    def __init__(116        self,117        input_channels: int,118        output_channels: int,119        cond_dim: int = 256,120        dropout: float = 0.0,121        num_blocks: int = 1,122        downsample_first: bool = False,123    ):124        super().__init__()125        self.downsample_first = downsample_first126 127        self.blocks = nn.ModuleList()128        for i in range(num_blocks):129            in_ch = input_channels if i == 0 else output_channels130            self.blocks.append(131                ConditionedResidualBlock(132                    input_channels=in_ch,133                    output_channels=output_channels,134                    cond_dim=cond_dim,135                    dropout=dropout,136                )137            )138 139        self.downsample = nn.Conv2d(140            output_channels, output_channels, kernel_size=3, stride=2, padding=1141        )142 143    def forward(self, x: torch.Tensor, cond: torch.Tensor):144 145        if self.downsample_first:146            x = self.downsample(x)147 148        for block in self.blocks:149            x = block(x, cond)150        skip = x151 152        if not self.downsample_first:153            x = self.downsample(x)154 155        return x, skip156 157 158class UpStage(nn.Module):159    def __init__(160        self,161        input_channels: int,162        skip_channels: int,163        output_channels: int,164        cond_dim: int = 256,165        dropout: float = 0.0,166        num_blocks: int = 1,167    ):168        super().__init__()169 170        self.upsample = nn.Upsample(171            scale_factor=2, mode="bilinear", align_corners=False172        )173 174        self.blocks = nn.ModuleList()175        for i in range(num_blocks):176            in_ch = (input_channels + skip_channels) if i == 0 else output_channels177            self.blocks.append(178                ConditionedResidualBlock(179                    input_channels=in_ch,180                    output_channels=output_channels,181                    cond_dim=cond_dim,182                    dropout=dropout,183                )184            )185 186    def forward(187        self, x: torch.Tensor, skip: torch.Tensor, cond: torch.Tensor188    ) -> torch.Tensor:189        x = self.upsample(x)190 191        if x.shape[-2:] != skip.shape[-2:]:192            x = F.interpolate(193                x, size=skip.shape[-2:], mode="bilinear", align_corners=False194            )195 196        x = torch.cat([x, skip], dim=1)197 198        for block in self.blocks:199            x = block(x, cond)200 201        return x202 203 204class LowResEncoder(nn.Module):205    def __init__(206        self,207        sample_channels: int = 32,208        base_channels: int = 128,209        cond_dim: int = 1024,210        dropout: float = 0.0,211    ):212        super().__init__()213 214        self.in_conv = nn.Conv2d(215            sample_channels, base_channels, kernel_size=1, padding=0216        )217 218        self.block_1 = ConditionedResidualBlock(219            input_channels=base_channels,220            output_channels=base_channels,221            cond_dim=cond_dim,222            dropout=dropout,223        )224 225        self.block_2 = DownStage(226            input_channels=base_channels,227            output_channels=base_channels,228            cond_dim=cond_dim,229            dropout=dropout,230            num_blocks=1,231            downsample_first=True,232        )233 234        self.block_3 = DownStage(235            input_channels=base_channels,236            output_channels=base_channels,237            cond_dim=cond_dim,238            dropout=dropout,239            num_blocks=1,240            downsample_first=True,241        )242 243    def forward(self, latents_small, cond):244        x = self.in_conv(latents_small)245        block_1_out = self.block_1(x, cond)246        block_2_out, _ = self.block_2(block_1_out, cond)247        block_3_out, _ = self.block_3(block_2_out, cond)248 249        return block_1_out, block_2_out, block_3_out250 251 252class FilmCond2D(nn.Module):253    def __init__(self, base_channels: int = 256, cond_channels: int = 256):254        super().__init__()255 256        self.cond_proj = nn.Sequential(257            nn.SiLU(),258            nn.Conv2d(cond_channels, base_channels * 2, kernel_size=1),259        )260 261    def forward(self, x, cond):262        scale_shift = self.cond_proj(cond)263        scale, shift = scale_shift.chunk(2, dim=1)264 265        x = x * (1 + scale) + shift266 267        return x268 269 270class UpscalerUNet(nn.Module):271    def __init__(272        self,273        sample_channels: int = 32,274        base_channels: int = 384,275        time_dim: int = 512,276        cond_dim: int = 1024,277        dropout: float = 0.01,278    ):279        super().__init__()280 281        self.conditioning = ConditioningEncoder(282            time_dim=time_dim,283            cond_dim=cond_dim,284        )285 286        self.in_conv = nn.Conv2d(287            sample_channels, base_channels, kernel_size=1, padding=0288        )289 290        self.low_res_encoder = LowResEncoder(base_channels=base_channels)291 292        self.film_cond_1 = FilmCond2D(293            base_channels=base_channels, cond_channels=base_channels294        )295        self.film_cond_2 = FilmCond2D(296            base_channels=base_channels, cond_channels=base_channels297        )298        self.film_cond_3 = FilmCond2D(299            base_channels=base_channels, cond_channels=base_channels300        )301 302        self.down_stages = nn.ModuleList(303            [304                DownStage(305                    input_channels=base_channels,306                    output_channels=base_channels,307                    cond_dim=cond_dim,308                    dropout=dropout,309                    num_blocks=3,310                ),311                DownStage(312                    input_channels=base_channels,313                    output_channels=base_channels,314                    cond_dim=cond_dim,315                    dropout=dropout,316                    num_blocks=2,317                ),318            ]319        )320 321        self.mid_stages = nn.ModuleList(322            [323                ConditionedResidualBlock(324                    input_channels=base_channels,325                    output_channels=base_channels,326                    cond_dim=cond_dim,327                    dropout=dropout,328                )329                for i in range(1)330            ]331        )332 333        self.up_stages = nn.ModuleList(334            [335                UpStage(336                    input_channels=base_channels,337                    skip_channels=base_channels,338                    output_channels=base_channels,339                    cond_dim=cond_dim,340                    dropout=dropout,341                    num_blocks=2,342                ),343                UpStage(344                    input_channels=base_channels,345                    skip_channels=base_channels,346                    output_channels=base_channels,347                    cond_dim=cond_dim,348                    dropout=dropout,349                    num_blocks=3,350                ),351            ]352        )353 354        self.out_conv = nn.Conv2d(355            base_channels, sample_channels, kernel_size=1, padding=0356        )357 358    def forward(359        self, sample: torch.Tensor, timestep: torch.Tensor, latents_small: torch.Tensor360    ) -> torch.Tensor:361        cond = self.conditioning(timestep)362 363        B, C, H, W = sample.shape364 365        lr_cond_1, lr_cond_2, lr_cond_3 = self.low_res_encoder(latents_small, cond)366 367        lr_cond_1 = torch.nn.functional.interpolate(lr_cond_1, (H, W), mode="bilinear")368        lr_cond_2 = torch.nn.functional.interpolate(369            lr_cond_2, (H // 2, W // 2), mode="bilinear"370        )371        lr_cond_3 = torch.nn.functional.interpolate(372            lr_cond_3, (H // 4, W // 4), mode="bilinear"373        )374 375        x = self.in_conv(sample)376        x = self.film_cond_1(x, lr_cond_1)377 378        skips = []379 380        x, skip = self.down_stages[0](x, cond)381        skips.append(skip)382 383        x = self.film_cond_2(x, lr_cond_2)384 385        x, skip = self.down_stages[1](x, cond)386        skips.append(skip)387 388        x = self.film_cond_3(x, lr_cond_3)389 390        for mid in self.mid_stages:391            x = mid(x, cond)392 393        for up in self.up_stages:394            x = up(x, skips.pop(), cond)395 396        x = self.out_conv(x)397        return x398