NeRF 位置编码代码分析
以下是对 get_embedder()
函数的具体分析:
def get_embedder(multires, i=0):
if i == -1:
return nn.Identity(), 3
embed_kwargs = {
'include_input' : True, # 如果为真,最终的编码结果包含原始坐标
'input_dims' : 3, # 输入给编码器的数据的维度
'max_freq_log2' : multires-1,
'num_freqs' : multires, # 即论文中 5.1 节位置编码公式中的 L
'log_sampling' : True,
'periodic_fns' : [torch.sin, torch.cos],
}
embedder_obj = Embedder(**embed_kwargs)
embed = lambda x, eo=embedder_obj : eo.embed(x) # embed 现在相当于一个编码器,具体的编码公式与论文中的一致。
return embed, embedder_obj.out_dim
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, steps=N_freqs) # 得到 [2^0, 2^1, ... ,2^(L-1)] 参考论文 5.1 中的公式
else:
freq_bands = torch.linspace(2.**0., 2.**max_freq, steps=N_freqs) # 得到 [2^0, 2^(L-1)] 的等差数列,列表中有 L 个元素
for freq in freq_bands:
for p_fn in self.kwargs['periodic_fns']:
embed_fns.append(lambda x, p_fn=p_fn, freq=freq : p_fn(x * freq)) # sin(x * 2^n) 参考位置编码公式
out_dim += d # 每使用子编码公式一次就要把输出维度加 3,因为每个待编码的位置维度是 3
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)