Spaces:
Running on Zero
Running on Zero
| from collections.abc import Sequence | |
| import torch | |
| from torch import nn | |
| import torch.nn.functional as F | |
| class ImplicitMLP(nn.Module): | |
| def __init__( | |
| self, | |
| in_dim: int, | |
| out_dim: int, | |
| hidden_list: Sequence[int], | |
| ) -> None: | |
| super().__init__() | |
| layers = [] | |
| last_dim = in_dim | |
| for hidden_dim in hidden_list: | |
| layers.extend((nn.Linear(last_dim, hidden_dim), nn.ReLU())) | |
| last_dim = hidden_dim | |
| layers.append(nn.Linear(last_dim, out_dim)) | |
| self.layers = nn.Sequential(*layers) | |
| def forward(self, inputs: torch.Tensor) -> torch.Tensor: | |
| return self.layers(inputs) | |
| class ImplicitGSHead(nn.Module): | |
| """Decode Gaussian parameters from DINOv3 and BasicEncoder features.""" | |
| def __init__( | |
| self, | |
| hidden_dim: int, | |
| basic_dim: int, | |
| hidden_list: Sequence[int], | |
| ) -> None: | |
| super().__init__() | |
| self.gate_proj = nn.Linear(basic_dim, hidden_dim) | |
| self.gate = nn.Sequential( | |
| nn.Linear(hidden_dim * 2, hidden_dim), | |
| nn.Sigmoid(), | |
| ) | |
| self.out_layer = ImplicitMLP( | |
| in_dim=hidden_dim, | |
| out_dim=14, | |
| hidden_list=hidden_list, | |
| ) | |
| def encode_feat(self, features, patch_h: int, patch_w: int) -> torch.Tensor: | |
| """Reshape the last DINOv3 layer into a spatial feature map.""" | |
| tokens = features[-1][0] | |
| return tokens.permute(0, 2, 1).reshape( | |
| tokens.shape[0], | |
| tokens.shape[-1], | |
| patch_h, | |
| patch_w, | |
| ) | |
| def decode_dpt( | |
| self, | |
| feat: torch.Tensor, | |
| basic_feat: torch.Tensor, | |
| coord: torch.Tensor, | |
| ) -> torch.Tensor: | |
| coord = coord.clone() | |
| coord.clamp_(-1 + 1e-6, 1 - 1e-6) | |
| query_dino = F.grid_sample( | |
| feat, | |
| coord.flip(-1).unsqueeze(1), | |
| mode="bilinear", | |
| align_corners=False, | |
| )[:, :, 0, :].permute(0, 2, 1) | |
| query_basic = F.grid_sample( | |
| basic_feat, | |
| coord.flip(-1).unsqueeze(1), | |
| mode="bilinear", | |
| align_corners=False, | |
| )[:, :, 0, :].permute(0, 2, 1) | |
| query_basic = self.gate_proj(query_basic) | |
| gate_weights = self.gate(torch.cat((query_dino, query_basic), dim=-1)) | |
| fused_features = gate_weights * query_dino + (1 - gate_weights) * query_basic | |
| return self.out_layer(fused_features) | |