|
import torch |
|
import torch.nn as nn |
|
|
|
""" Positional encoding embedding. Code was taken from https://github.com/bmild/nerf. """ |
|
|
|
|
|
class Embedder: |
|
def __init__(self, **kwargs): |
|
self.kwargs = kwargs |
|
self.create_embedding_fn() |
|
|
|
def create_embedding_fn(self): |
|
embed_fns = [] |
|
d = self.kwargs['input_dims'] |
|
out_dim = 0 |
|
if self.kwargs['include_input']: |
|
embed_fns.append(lambda x: x) |
|
out_dim += d |
|
|
|
max_freq = self.kwargs['max_freq_log2'] |
|
N_freqs = self.kwargs['num_freqs'] |
|
|
|
if self.kwargs['log_sampling']: |
|
freq_bands = 2. ** torch.linspace(0., max_freq, N_freqs) |
|
else: |
|
freq_bands = torch.linspace(2. ** 0., 2. ** max_freq, N_freqs) |
|
|
|
for freq in freq_bands: |
|
for p_fn in self.kwargs['periodic_fns']: |
|
if self.kwargs['normalize']: |
|
embed_fns.append(lambda x, p_fn=p_fn, |
|
freq=freq: p_fn(x * freq) / freq) |
|
else: |
|
embed_fns.append(lambda x, p_fn=p_fn, |
|
freq=freq: p_fn(x * freq)) |
|
out_dim += d |
|
|
|
self.embed_fns = embed_fns |
|
self.out_dim = out_dim |
|
|
|
def embed(self, inputs): |
|
return torch.cat([fn(inputs) for fn in self.embed_fns], -1) |
|
|
|
|
|
def get_embedder(multires, normalize=False, input_dims=3): |
|
embed_kwargs = { |
|
'include_input': True, |
|
'input_dims': input_dims, |
|
'max_freq_log2': multires - 1, |
|
'num_freqs': multires, |
|
'normalize': normalize, |
|
'log_sampling': True, |
|
'periodic_fns': [torch.sin, torch.cos], |
|
} |
|
|
|
embedder_obj = Embedder(**embed_kwargs) |
|
|
|
def embed(x, eo=embedder_obj): return eo.embed(x) |
|
|
|
return embed, embedder_obj.out_dim |
|
|
|
|
|
class Embedding(nn.Module): |
|
def __init__(self, in_channels, N_freqs, logscale=True, normalize=False): |
|
""" |
|
Defines a function that embeds x to (x, sin(2^k x), cos(2^k x), ...) |
|
in_channels: number of input channels (3 for both xyz and direction) |
|
""" |
|
super(Embedding, self).__init__() |
|
self.N_freqs = N_freqs |
|
self.in_channels = in_channels |
|
self.funcs = [torch.sin, torch.cos] |
|
self.out_channels = in_channels * (len(self.funcs) * N_freqs + 1) |
|
self.normalize = normalize |
|
|
|
if logscale: |
|
self.freq_bands = 2 ** torch.linspace(0, N_freqs - 1, N_freqs) |
|
else: |
|
self.freq_bands = torch.linspace(1, 2 ** (N_freqs - 1), N_freqs) |
|
|
|
def forward(self, x): |
|
""" |
|
Embeds x to (x, sin(2^k x), cos(2^k x), ...) |
|
Different from the paper, "x" is also in the output |
|
See https://github.com/bmild/nerf/issues/12 |
|
|
|
Inputs: |
|
x: (B, self.in_channels) |
|
|
|
Outputs: |
|
out: (B, self.out_channels) |
|
""" |
|
out = [x] |
|
for freq in self.freq_bands: |
|
for func in self.funcs: |
|
if self.normalize: |
|
out += [func(freq * x) / freq] |
|
else: |
|
out += [func(freq * x)] |
|
|
|
return torch.cat(out, -1) |
|
|