| from typing import Optional |
|
|
| import torch |
| import torch.nn as nn |
|
|
| from models.stylegan2 import FullyConnectedLayer, normalize_2nd_moment |
| from models.rtm_core import RTMMappingNetwork |
|
|
|
|
| class RTMMappingNetworkStyleGAN2(nn.Module): |
| def __init__( |
| self, |
| z_dim: int, |
| c_dim: int, |
| w_dim: int, |
| num_ws: Optional[int], |
| num_layers: int = 8, |
| embed_features: Optional[int] = None, |
| layer_features: Optional[int] = None, |
| activation: str = "lrelu", |
| lr_multiplier: float = 0.01, |
| w_avg_beta: float = 0.998, |
| rtm_num_tokens: int = 4, |
| rtm_H_cycles: int = 4, |
| rtm_L_cycles: int = 1, |
| rtm_H_layers: int = 2, |
| rtm_L_layers: int = 2, |
| rtm_hidden_size: int = 128, |
| rtm_expansion: float = 4.0, |
| rtm_refinement_steps: int = 4, |
| rtm_with_grad: bool = False, |
| rtm_cycle_noise_std: float = 0.0, |
| use_rtm_equalized: bool = True, |
| rtm_lr_multiplier: float = 0.01, |
| ): |
| super().__init__() |
| del layer_features |
| self.z_dim = z_dim |
| self.c_dim = c_dim |
| self.w_dim = w_dim |
| self.num_ws = num_ws |
| self.num_layers = num_layers |
| self.w_avg_beta = w_avg_beta |
|
|
| if embed_features is None: |
| embed_features = w_dim |
| if c_dim == 0: |
| embed_features = 0 |
|
|
| if c_dim > 0: |
| self.embed = FullyConnectedLayer(c_dim, embed_features) |
| else: |
| self.embed = None |
|
|
| self.fuse = FullyConnectedLayer( |
| z_dim + embed_features, w_dim, |
| activation=activation, lr_multiplier=lr_multiplier, |
| ) |
|
|
| self.rtm = RTMMappingNetwork( |
| code_dim=w_dim, |
| num_tokens=rtm_num_tokens, |
| H_cycles=rtm_H_cycles, |
| L_cycles=rtm_L_cycles, |
| H_layers=rtm_H_layers, |
| L_layers=rtm_L_layers, |
| hidden_size=rtm_hidden_size, |
| expansion=rtm_expansion, |
| refinement_steps=rtm_refinement_steps, |
| with_grad=rtm_with_grad, |
| cycle_noise_std=rtm_cycle_noise_std, |
| use_equalized=use_rtm_equalized, |
| lr_multiplier=rtm_lr_multiplier, |
| ) |
|
|
| if num_ws is not None and w_avg_beta is not None: |
| self.register_buffer("w_avg", torch.zeros([w_dim])) |
|
|
| def forward( |
| self, |
| z: torch.Tensor, |
| c: Optional[torch.Tensor], |
| truncation_psi: float = 1.0, |
| truncation_cutoff: Optional[int] = None, |
| update_emas: bool = False, |
| ) -> torch.Tensor: |
| x = None |
| if self.z_dim > 0: |
| x = normalize_2nd_moment(z.to(torch.float32)) |
| if self.c_dim > 0: |
| assert c is not None and self.embed is not None |
| y = normalize_2nd_moment(self.embed(c.to(torch.float32))) |
| x = torch.cat([x, y], dim=1) if x is not None else y |
|
|
| x = self.fuse(x) |
| x = self.rtm(x) |
| if isinstance(x, (list, tuple)): |
| x = x[-1] |
|
|
| if update_emas and self.w_avg_beta is not None and hasattr(self, "w_avg"): |
| self.w_avg.copy_( |
| x.detach().mean(dim=0).lerp(self.w_avg, self.w_avg_beta) |
| ) |
|
|
| if self.num_ws is not None: |
| x = x.unsqueeze(1).repeat([1, self.num_ws, 1]) |
|
|
| if truncation_psi != 1: |
| assert self.w_avg_beta is not None |
| if self.num_ws is None or truncation_cutoff is None: |
| x = self.w_avg.lerp(x, truncation_psi) |
| else: |
| x[:, :truncation_cutoff] = self.w_avg.lerp( |
| x[:, :truncation_cutoff], truncation_psi |
| ) |
| return x |
|
|
| def forward_ws_trajectory( |
| self, |
| z: torch.Tensor, |
| c: Optional[torch.Tensor], |
| truncation_psi: float = 1.0, |
| truncation_cutoff: Optional[int] = None, |
| ): |
| x = None |
| if self.z_dim > 0: |
| x = normalize_2nd_moment(z.to(torch.float32)) |
| if self.c_dim > 0: |
| assert c is not None and self.embed is not None |
| y = normalize_2nd_moment(self.embed(c.to(torch.float32))) |
| x = torch.cat([x, y], dim=1) if x is not None else y |
|
|
| x = self.fuse(x) |
| flat_list = self.rtm.forward_w_trajectory(x) |
|
|
| ws_out = [] |
| for xf in flat_list: |
| if isinstance(xf, (list, tuple)): |
| xf = xf[-1] |
| xcur = xf |
| if self.num_ws is not None: |
| xcur = xcur.unsqueeze(1).repeat([1, self.num_ws, 1]) |
| if truncation_psi != 1: |
| assert self.w_avg_beta is not None |
| if self.num_ws is None or truncation_cutoff is None: |
| xcur = self.w_avg.lerp(xcur, truncation_psi) |
| else: |
| xcur[:, :truncation_cutoff] = self.w_avg.lerp( |
| xcur[:, :truncation_cutoff], truncation_psi |
| ) |
| ws_out.append(xcur) |
| return ws_out |
|
|