|
import math |
|
from dataclasses import dataclass |
|
|
|
import torch |
|
import torch.nn as nn |
|
from einops import rearrange, repeat |
|
from jaxtyping import Float |
|
from torch import Tensor |
|
|
|
from sf3d.models.utils import BaseModule |
|
|
|
|
|
class TriplaneLearnablePositionalEmbedding(BaseModule): |
|
@dataclass |
|
class Config(BaseModule.Config): |
|
plane_size: int = 96 |
|
num_channels: int = 1024 |
|
|
|
cfg: Config |
|
|
|
def configure(self) -> None: |
|
self.embeddings = nn.Parameter( |
|
torch.randn( |
|
(3, self.cfg.num_channels, self.cfg.plane_size, self.cfg.plane_size), |
|
dtype=torch.float32, |
|
) |
|
* 1 |
|
/ math.sqrt(self.cfg.num_channels) |
|
) |
|
|
|
def forward(self, batch_size: int) -> Float[Tensor, "B Ct Nt"]: |
|
return rearrange( |
|
repeat(self.embeddings, "Np Ct Hp Wp -> B Np Ct Hp Wp", B=batch_size), |
|
"B Np Ct Hp Wp -> B Ct (Np Hp Wp)", |
|
) |
|
|
|
def detokenize( |
|
self, tokens: Float[Tensor, "B Ct Nt"] |
|
) -> Float[Tensor, "B 3 Ct Hp Wp"]: |
|
batch_size, Ct, Nt = tokens.shape |
|
assert Nt == self.cfg.plane_size**2 * 3 |
|
assert Ct == self.cfg.num_channels |
|
return rearrange( |
|
tokens, |
|
"B Ct (Np Hp Wp) -> B Np Ct Hp Wp", |
|
Np=3, |
|
Hp=self.cfg.plane_size, |
|
Wp=self.cfg.plane_size, |
|
) |
|
|