Spaces:
Running on Zero
Running on Zero
Download diffusionGS/models/denoiser/denoiser.py from CaiYuanhao/DiffusionGS-Object: direct link, hf CLI and curl.
- Browser
- Download file 16 kB
-
https://huggingface.co/spaces/CaiYuanhao/DiffusionGS-Object/resolve/main/diffusionGS/models/denoiser/denoiser.py
- Command line
-
hf download hf://spaces/CaiYuanhao/DiffusionGS-Object/diffusionGS/models/denoiser/denoiser.py
-
curl -L -o denoiser.py https://huggingface.co/spaces/CaiYuanhao/DiffusionGS-Object/resolve/main/diffusionGS/models/denoiser/denoiser.py
16 kB
| from dataclasses import dataclass | |
| import math | |
| import copy | |
| import torch | |
| import torch.nn as nn | |
| from einops import repeat, rearrange | |
| from einops.layers.torch import Rearrange | |
| from easydict import EasyDict as edict | |
| import diffusionGS | |
| from diffusionGS.models.transformers.utils_transformer import DiTBlock,_init_weights | |
| from diffusionGS.models.gsrenderer.renderer import Renderer | |
| from diffusionGS.utils.checkpoint import checkpoint, load_denoiser_checkpoint | |
| from diffusionGS.utils.base import BaseModule | |
| from diffusionGS.utils.typing import * | |
| from diffusionGS.utils.ops import generate_dense_grid_points | |
| from tqdm import tqdm | |
| from torchvision.utils import save_image | |
| import numpy as np | |
| def modulate(x, shift, scale): | |
| return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1) | |
| ################################################################################# | |
| # Embedding Layers for Timesteps and Class Labels # | |
| ################################################################################# | |
| class TimestepEmbedder(nn.Module): | |
| """ | |
| Embeds scalar timesteps into vector representations. | |
| """ | |
| def __init__(self, hidden_size, frequency_embedding_size=256): | |
| super().__init__() | |
| self.mlp = nn.Sequential( | |
| nn.Linear(frequency_embedding_size, hidden_size, bias=True), | |
| nn.SiLU(), | |
| nn.Linear(hidden_size, hidden_size, bias=True), | |
| ) | |
| self.frequency_embedding_size = frequency_embedding_size | |
| ''' | |
| staticmethod 装饰器可以声明静态方法 | |
| 无需实例化 TimestepEmbedder 类, 就可以直接调用 timestep_embedding 方法 | |
| ''' | |
| def timestep_embedding(t, dim, max_period=10000): | |
| """ | |
| Create sinusoidal timestep embeddings. | |
| :param t: a 1-D Tensor of N indices, one per batch element. | |
| These may be fractional. | |
| :param dim: the dimension of the output. | |
| :param max_period: controls the minimum frequency of the embeddings. | |
| :return: an (N, D) Tensor of positional embeddings. | |
| """ | |
| # https://github.com/openai/glide-text2im/blob/main/glide_text2im/nn.py | |
| 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 | |
| def forward(self, t): | |
| t_freq = self.timestep_embedding(t, self.frequency_embedding_size) | |
| t_emb = self.mlp(t_freq) | |
| return t_emb | |
| class GaussiansUpsampler(nn.Module): | |
| def __init__(self, config): | |
| super().__init__() | |
| self.config = config | |
| """ | |
| xyz : torch.tensor of shape (n_gaussians, 3) | |
| features : torch.tensor of shape (n_gaussians, (sh_degree + 1) ** 2, 3) | |
| scaling : torch.tensor of shape (n_gaussians, 3) | |
| rotation : torch.tensor of shape (n_gaussians, 4) | |
| opacity : torch.tensor of shape (n_gaussians, 1) | |
| """ | |
| self.layernorm = nn.LayerNorm(config.width, bias=False) # d - dimension - channel | |
| u = 1 #config.model.gaussians.upsampler.upsample_factor | |
| if u > 1: | |
| raise NotImplementedError("GaussiansUpsampler only supports u=1") | |
| else: | |
| self.linear = nn.Linear( | |
| config.width, | |
| 3 + (config.gaussians_sh_degree + 1) ** 2 * 3 + 3 + 4 + 1, # 直接转成 per-pixel Gaussian map | |
| bias=False, | |
| ) | |
| self.adaLN_modulation = nn.Sequential( | |
| nn.SiLU(), nn.Linear(config.width, 2 * config.width, bias=True) | |
| ) | |
| def to_gs(self, gaussians): # 把 dimenssion 分掉,分出对应的维度 | |
| """ | |
| gaussians: [b, n_gaussians, d] | |
| n_gaussians - 高斯的数量 | |
| d - 每个高斯的 attribute 的数量 | |
| """ | |
| xyz, features, scaling, rotation, opacity = gaussians.split( | |
| [3, (self.config.gaussians_sh_degree + 1) ** 2 * 3, 3, 4, 1], dim=2 | |
| ) | |
| features = features.reshape( | |
| features.size(0), | |
| features.size(1), | |
| (self.config.gaussians_sh_degree + 1) ** 2, | |
| 3, | |
| ) | |
| scaling = (scaling - 2.3).clamp(max=-1.20) | |
| opacity = opacity - 2.0 | |
| return xyz, features, scaling, rotation, opacity | |
| def forward(self, gaussians, t_embedding): | |
| """ | |
| gaussians: [b, n_gaussians, d] | |
| t_embedding: [b, d] | |
| output: [b, n_gaussians, dd] | |
| """ | |
| u = 1 #self.config.model.gaussians.upsampler.upsample_factor | |
| if u > 1: | |
| raise NotImplementedError("GaussiansUpsampler only supports u=1") | |
| shift, scale = self.adaLN_modulation(t_embedding).chunk(2, dim=1) | |
| gaussians = modulate(self.layernorm(gaussians), shift, scale) | |
| gaussians = self.linear(gaussians) | |
| return gaussians | |
| class ImageTokenDecoder(nn.Module): | |
| def __init__(self, config): | |
| super().__init__() | |
| self.config = config | |
| self.layernorm = nn.LayerNorm(config.width, bias=False) | |
| self.linear = nn.Linear( | |
| config.width, | |
| (config.patch_size**2) | |
| * (3 + (config.gaussians_sh_degree + 1) ** 2 * 3 + 3 + 4 + 1), | |
| bias=False, | |
| ) | |
| self.adaLN_modulation = nn.Sequential( | |
| nn.SiLU(), nn.Linear(config.width, 2 * config.width, bias=True) | |
| ) | |
| def forward(self, img_tokens, t_embedding): | |
| """ | |
| img_tokens: [b, n_patches, d] | |
| t_embedding: [b, d] | |
| output: [b, n_patches, dd] | |
| """ | |
| shift, scale = self.adaLN_modulation(t_embedding).chunk(2, dim=1) | |
| img_tokens = modulate(self.layernorm(img_tokens), shift, scale) | |
| img_tokens = self.linear(img_tokens) | |
| return img_tokens | |
| ###################### AutoEncoder | |
| class DGSDenoiser(BaseModule): | |
| r""" | |
| An image to gaussian diffusion models. | |
| """ | |
| class Config(BaseModule.Config): | |
| pretrained_model_name_or_path: str = "" | |
| use_downsample: bool = False | |
| num_latents: int = 256 | |
| width: int = 1024 | |
| in_channels: int = 3 | |
| patch_size: int = 16 | |
| n_gaussians: int = 2 | |
| dim_heads: int = 64 | |
| num_layers: int = 24 | |
| ray_pe_type: str = "relative_plk" | |
| hard_pixelalign: bool = True | |
| clip_xyz: bool = True | |
| ##gaussian relative | |
| gaussians_sh_degree: int = 0 | |
| use_gssplat: bool = False | |
| ##diffusion relative | |
| prior_distribution: str = "gaussian" | |
| #### | |
| use_flash: bool = False | |
| use_checkpoint: bool = True | |
| grad_checkpoint_every: int = 1 | |
| cfg: Config | |
| def configure(self) -> None: | |
| super().configure() | |
| ## | |
| ##time embedder | |
| self.t_embedder = TimestepEmbedder(self.cfg.width) | |
| # Initialize timestep embedding MLP: | |
| nn.init.normal_(self.t_embedder.mlp[0].weight, std=0.02) | |
| nn.init.normal_(self.t_embedder.mlp[2].weight, std=0.02) | |
| ##image tokenlizer | |
| # 这是 patchify and linear layer | |
| self.image_tokenizer = nn.Sequential( | |
| Rearrange( | |
| "b v c (hh ph) (ww pw) -> (b v) (hh ww) (ph pw c)", | |
| ph=self.cfg.patch_size, | |
| pw=self.cfg.patch_size, | |
| ), | |
| nn.Linear( | |
| self.cfg.in_channels | |
| * (self.cfg.patch_size**2), | |
| self.cfg.width, | |
| bias=False, | |
| ), | |
| ) | |
| self.image_tokenizer.apply(_init_weights) | |
| ##gaussian pos embedding | |
| self.gaussians_pos_embedding = nn.Parameter( | |
| torch.randn( | |
| self.cfg.n_gaussians, # 3d gaussian 的个数?n_gaussians = 2? | |
| self.cfg.width, # d = 1024 | |
| ) | |
| ) | |
| nn.init.trunc_normal_(self.gaussians_pos_embedding, std=0.02) | |
| self.transformer_input_layernorm = nn.LayerNorm( | |
| self.cfg.width, bias=False | |
| ) | |
| self.transformer = nn.ModuleList( | |
| [ | |
| DiTBlock( | |
| self.cfg.width, self.cfg.width // self.cfg.dim_heads | |
| ) | |
| for _ in range(self.cfg.num_layers) | |
| ] | |
| ) | |
| self.transformer.apply(_init_weights) | |
| self.upsampler = GaussiansUpsampler(self.cfg) | |
| self.upsampler.apply(_init_weights) | |
| self.image_token_decoder = ImageTokenDecoder(self.cfg) | |
| self.image_token_decoder.apply(_init_weights) | |
| # encoder | |
| self.gs_renderer = Renderer(self.cfg) | |
| # renderer | |
| if self.cfg.pretrained_model_name_or_path != "": | |
| print(f"Loading pretrained shape model from {self.cfg.pretrained_model_name_or_path}") | |
| self.load_state_dict( | |
| load_denoiser_checkpoint(self.cfg.pretrained_model_name_or_path), strict=True, | |
| ) | |
| def forward(self, input_batch, timesteps): | |
| guassians_parameters,_ = self.image_to_gaussians(input_batch['image'], input_batch['ray_o'], input_batch['ray_d'], timesteps) | |
| rendered_images = self.render_gaussians(guassians_parameters, input_batch['c2w'], input_batch['fxfycxcy'], input_batch['image'].shape[3], input_batch['image'].shape[4]) | |
| return rendered_images, self.prepare_to_save(guassians_parameters) | |
| def prepare_to_save(self,gaussians_parameters): | |
| gaussians = [] | |
| for b in range(gaussians_parameters.xyz.size(0)): | |
| self.gs_renderer.gaussians_model.empty() | |
| gaussians_model = copy.deepcopy(self.gs_renderer.gaussians_model) | |
| gaussians.append( | |
| gaussians_model.set_data( | |
| gaussians_parameters.xyz[b].detach().float(), | |
| gaussians_parameters.features[b].detach().float(), | |
| gaussians_parameters.scaling[b].detach().float(), | |
| gaussians_parameters.rotation[b].detach().float(), | |
| gaussians_parameters.opacity[b].detach().float(), | |
| ) | |
| ) | |
| return gaussians | |
| def image_to_gaussians(self, | |
| images:torch.FloatTensor, | |
| ray_o:torch.FloatTensor, | |
| ray_d:torch.FloatTensor, | |
| t:torch.LongTensor, | |
| training: bool = False): | |
| if self.cfg.ray_pe_type == "relative_plk": | |
| o_dot_d = torch.sum(-ray_o * ray_d, dim=2, keepdim=True) | |
| nearest_pts = ray_o + o_dot_d * ray_d | |
| posed_images = torch.cat( | |
| [ | |
| images[:, :, :3, :, :] * 2.0 - 1.0, | |
| ray_d, | |
| nearest_pts, | |
| ], | |
| dim=2, | |
| ) | |
| else: | |
| o_cross_d = torch.cross(ray_o, ray_d, dim=2) | |
| posed_images = torch.cat( | |
| [ | |
| images[:, :, :3, :, :] * 2.0 - 1.0, | |
| o_cross_d, | |
| ray_d, | |
| ], | |
| dim=2, | |
| ) | |
| b, v, c, h, w = posed_images.size() | |
| img_tokens = self.image_tokenizer(posed_images) | |
| t = self.t_embedder(t) # [b, d] | |
| _, n_patches, d = img_tokens.size() # [b*v, n_patches, d] | |
| img_tokens = img_tokens.reshape(b, v * n_patches, d) # [b, v*n_patches, d] | |
| # [b, n_gaussians, d] | |
| gaussians_tokens = self.gaussians_pos_embedding.expand(b, -1, -1) # 复制 b 份 | |
| checkpoint_every = self.cfg.grad_checkpoint_every | |
| concat_nerf_img_tokens = torch.cat((gaussians_tokens, img_tokens), dim=1) | |
| concat_nerf_img_tokens = self.transformer_input_layernorm( | |
| concat_nerf_img_tokens | |
| ) | |
| for i in range(0, len(self.transformer), checkpoint_every): | |
| concat_nerf_img_tokens = torch.utils.checkpoint.checkpoint( | |
| self.run_layers(i, i + checkpoint_every), | |
| concat_nerf_img_tokens, | |
| t, | |
| use_reentrant=False, | |
| ) | |
| gaussians_tokens, img_tokens = concat_nerf_img_tokens.split( | |
| [self.cfg.n_gaussians, v * n_patches], dim=1 | |
| ) | |
| gaussians = self.upsampler(gaussians_tokens, t) | |
| # [b, v*n_patches, p*p*gs] | |
| img_aligned_gaussians = self.image_token_decoder(img_tokens, t) | |
| img_aligned_gaussians = img_aligned_gaussians.reshape( | |
| b, | |
| -1, | |
| (3 + (self.cfg.gaussians_sh_degree + 1) ** 2 * 3 + 3 + 4 + 1), | |
| ) # [b, v*pixels, gs] | |
| n_img_aligned_gaussians = img_aligned_gaussians.size(1) | |
| all_gaussians = torch.cat((gaussians, img_aligned_gaussians), dim=1) | |
| xyz, features, scaling, rotation, opacity = self.upsampler.to_gs(all_gaussians) | |
| img_aligned_xyz = xyz[:, -n_img_aligned_gaussians:, :] # 把 image 对应的 Gaussians 模型 xyz 取出来 | |
| img_aligned_xyz = rearrange( | |
| img_aligned_xyz, | |
| "b (v h w ph pw) c -> b v c (h ph) (w pw)", | |
| v=v, | |
| h=h // self.cfg.patch_size, | |
| w=w // self.cfg.patch_size, | |
| ph=self.cfg.patch_size, | |
| pw=self.cfg.patch_size, | |
| ) | |
| # 对 image_aligned_xyz 进行矫正 | |
| if self.cfg.hard_pixelalign: #这是 true, 要执行的 | |
| depth_preact_bias = 0. | |
| img_aligned_xyz = torch.sigmoid( | |
| img_aligned_xyz.mean(dim=2, keepdim=True) + depth_preact_bias | |
| ) | |
| # stx() | |
| #breakpoint() | |
| if self.cfg.ray_pe_type == 'relative_plk': | |
| img_aligned_xyz = (2.0 * img_aligned_xyz - 1.0) * 1.8 + o_dot_d | |
| # print(f"Using augmented plucker coordinates to compute xyz") | |
| img_aligned_xyz = ray_o + img_aligned_xyz * ray_d | |
| # breakpoint() | |
| # 将坐标限制在 -1 到 1 之间 | |
| if self.cfg.clip_xyz and training: | |
| img_aligned_xyz = img_aligned_xyz.clamp(-1.0, 1.0) | |
| img_aligned_xyz_reshape = rearrange( | |
| img_aligned_xyz, | |
| "b v c (h ph) (w pw) -> b (v h w ph pw) c", | |
| ph=self.cfg.patch_size, | |
| pw=self.cfg.patch_size, | |
| ) | |
| xyz = torch.cat( | |
| (xyz[:, :-n_img_aligned_gaussians, :], img_aligned_xyz_reshape), dim=1 | |
| ) | |
| result_softpa = edict( | |
| xyz=xyz, | |
| features=features, | |
| scaling=scaling, | |
| rotation=rotation, | |
| opacity=opacity, | |
| ) | |
| return result_softpa, img_aligned_xyz | |
| def render_gaussians(self, gaussian_params, c2w, fxfycxcy, height, width): | |
| # breakpoint() | |
| render_input = self.gs_renderer( | |
| gaussian_params.xyz, | |
| gaussian_params.features, | |
| gaussian_params.scaling, | |
| gaussian_params.rotation, | |
| gaussian_params.opacity, | |
| height, | |
| width, | |
| C2W=c2w, # | |
| fxfycxcy=fxfycxcy, # | |
| ) | |
| #self.gs_renderer() | |
| return render_input | |
| def dtype(self): | |
| # 返回模型参数的数据类型 | |
| return next(self.parameters()).dtype | |
| def run_layers(self, start, end): | |
| def custom_forward(concat_nerf_img_tokens, t): | |
| for i in range(start, min(end, len(self.transformer))): | |
| concat_nerf_img_tokens = self.transformer[i](concat_nerf_img_tokens, t) | |
| return concat_nerf_img_tokens | |
| return custom_forward |