NeRF位置编码分析

 引用:

NeRF中的位置编码_nerf位置编码-CSDN博客

NeRF位置编码代码解读_get_embedder-CSDN博客 

NeRF位置编码

朴素NeRF中直接采用频率变换来做位置编码,为的是避免空间相邻采样点在MLP表示中的过平滑问题。比如位置(237, 332, 198)和位置(237,332,199)这两个点作为MLP的输入,MLP可能对个位不够敏感,导致输出过平滑的问题。例如:

由于缺乏位置编码,导致纹理相近区域的细节会丢失。
我们来看一下原文中关于Position Encoding的公式:

频率编码,其实是一种广义的傅里叶变换,代码如下:

import torch

class FreqEmbedder:
    def __init__(self, multi_freq, include_input=True, input_dims=3, log_sampling=True):
        self.multi_freq = multi_freq
        self.input_dims = input_dims
        self.include_input = include_input
        self.log_sampling = log_sampling
        self.periodic_fns = [torch.sin, torch.cos]

        self.embed_fns = None
        self.out_dim = None
        self.create_embedding_fn()

    def create_embedding_fn(self):
        embed_fns = []
        d = self.input_dims
        out_dim = 0
        if self.include_input:
            embed_fns.append(lambda x: x)
            out_dim += d

        max_freq = self.multi_freq - 1
        N_freqs = self.multi_freq

        if self.log_sampling:
            freq_bands = 2. ** torch.linspace(0., max_freq, steps=N_freqs)
        else:
            freq_bands = torch.linspace(2. ** 0., 2. ** max_freq, steps=N_freqs)

        for freq in freq_bands:
            for p_fn in self.periodic_fns:
                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)

其中torch.sin和torch.cos实现的就是数学意义的功能,举个例子:

import torch
pi = 3.1415926
degree_30 = pi / 6 # 30 degree

a = torch.Tensor([degree_30])
r = torch.sin(a)
print(r) # tensor([0.5000])

上图就是NeRF中MLP的输入顺序,图中并没有加原始位置,所以位置编码的维度为60,而方向编码的维度为24。

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)

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值