Spaces:
Running on Zero
Running on Zero
Download src/model/encoder/common/gs_decoder.py from hugging-apps/codecsplat: direct link, hf CLI and curl.
- Browser
- Download file 3.67 kB
-
https://huggingface.co/spaces/hugging-apps/codecsplat/resolve/main/src/model/encoder/common/gs_decoder.py
- Command line
-
hf download hf://spaces/hugging-apps/codecsplat/src/model/encoder/common/gs_decoder.py
-
curl -L -o gs_decoder.py https://huggingface.co/spaces/hugging-apps/codecsplat/resolve/main/src/model/encoder/common/gs_decoder.py
3.67 kB
| import torch | |
| from torch import nn | |
| class GaussianLatentDecoder(nn.Module): | |
| def __init__( | |
| self, | |
| latent_channels: int, | |
| hidden_channels: int, | |
| num_gaussian_parameters: int, | |
| init_sh_input_img: bool = True, | |
| ) -> None: | |
| super().__init__() | |
| in_channels = latent_channels + 1 # out_hat + depth | |
| self.decoder = nn.Sequential( | |
| nn.Conv2d(in_channels, hidden_channels, 3, 1, 1, padding_mode="replicate"), | |
| nn.GELU(), | |
| nn.Conv2d( | |
| hidden_channels, | |
| num_gaussian_parameters, | |
| 3, | |
| 1, | |
| 1, | |
| padding_mode="replicate", | |
| ), | |
| nn.GELU(), | |
| nn.Conv2d( | |
| num_gaussian_parameters, | |
| num_gaussian_parameters, | |
| 3, | |
| 1, | |
| 1, | |
| padding_mode="replicate", | |
| ), | |
| ) | |
| self._init_output_layer(init_sh_input_img) | |
| def _init_output_layer(self, init_sh_input_img: bool) -> None: | |
| # Keep the Gaussian head initially close to identity-like residuals. | |
| # Channel order: opacity, offset_xy, scales, quaternion, SH residuals. | |
| output_layer = self.decoder[-1] | |
| if init_sh_input_img: | |
| nn.init.zeros_(output_layer.weight[10:]) | |
| nn.init.zeros_(output_layer.bias[10:]) | |
| nn.init.zeros_(output_layer.weight[3:6]) | |
| nn.init.zeros_(output_layer.bias[3:6]) | |
| def forward( | |
| self, | |
| latent: torch.Tensor, | |
| depth: torch.Tensor, | |
| ) -> torch.Tensor: | |
| x = torch.cat((latent, depth), dim=1) | |
| return self.decoder(x) | |
| class GaussianLatentDepthDecoder(nn.Module): | |
| def __init__( | |
| self, | |
| latent_channels: int, | |
| hidden_channels: int, | |
| ) -> None: | |
| super().__init__() | |
| self.inv_depth_logits = nn.Sequential( | |
| nn.Conv2d(latent_channels, hidden_channels, 3, 1, 1, padding_mode="replicate"), | |
| nn.GELU(), | |
| nn.Conv2d(hidden_channels, hidden_channels, 3, 1, 1, padding_mode="replicate"), | |
| nn.GELU(), | |
| nn.Conv2d(hidden_channels, 1, 3, 1, 1, padding_mode="replicate"), | |
| ) | |
| # Predict the midpoint of the valid inverse-depth interval at initialization. | |
| nn.init.zeros_(self.inv_depth_logits[-1].weight) | |
| nn.init.zeros_(self.inv_depth_logits[-1].bias) | |
| def forward( | |
| self, | |
| latent: torch.Tensor, | |
| near: torch.Tensor, | |
| far: torch.Tensor, | |
| return_inverse: bool = False, | |
| return_normalized_inverse: bool = False, | |
| ) -> torch.Tensor | tuple[torch.Tensor, ...]: | |
| with torch.autocast(device_type=latent.device.type, enabled=False): | |
| inv_depth_logits = self.inv_depth_logits(latent.float()) | |
| near = near.float().clamp_min(torch.finfo(torch.float32).eps) | |
| far = far.float().clamp_min(torch.finfo(torch.float32).eps) | |
| inv_min = far.reciprocal() | |
| inv_max = near.reciprocal() | |
| inv_range = (inv_max - inv_min).clamp_min(torch.finfo(torch.float32).eps) | |
| normalized_inv_depth = torch.sigmoid(inv_depth_logits.float()) | |
| inv_depth = inv_min + normalized_inv_depth * inv_range | |
| depth = inv_depth.clamp_min(torch.finfo(torch.float32).eps).reciprocal() | |
| outputs: list[torch.Tensor] = [depth] | |
| if return_inverse: | |
| outputs.append(inv_depth) | |
| if return_normalized_inverse: | |
| outputs.append(normalized_inv_depth) | |
| if len(outputs) == 1: | |
| return outputs[0] | |
| return tuple(outputs) | |