Neural Radiance Field

Neural Radiance Field

这里假设大家都看过 NeRF 的原始论文了。

Novel View Synthesis & Reconstructions

真实感渲染是图形学研究了几十年的一大方向。以前我们都是用 rasterization 或者 ray tracing 来渲染已经指定好属性的场景。一个比较取巧的方法就是基于图像的渲染。大致的想法就是先拍摄一组标定好的图像,然后从图像中恢复场景,再重恢复的场景中得到合理的新视角图片。因此新视角合成的一大重点研究方向就是如何重建好场景。

重建也是一个古老的问题了。有基于几何限制的对极几何;有基于激光雷达扫描的点云重建,一般用在 SLAM 上;还有基于傅里叶切片定理的 CT 重建。如今新出现的 NeRF 也是一种新的重建方法,而且我们实验室已经开始着手在各个传统重建领域中使用 NeRF 的方法进行重建了,比如 CT,和 CT 同样原理的冷冻电镜成像。

Scene Representations

传统算法将具体定义的几何表达和材料属性作为输入,这些输入共同定义了实际场景和渲染的内容,并被称为场景表达(其中场景由一个或多个对象组成)。场景表达按照属性的存储方式可以分为面表达和体表达,也可以按照表达本身的属性分为离散表达和连续表达,而面表达按照查询点的方式分为显示表达和隐式表达。

首先介绍面表达和体表达的分别。表面表达存储与物体的表面有关的属性,例如物体表面的颜色,法向量,BRDF 等属性。而体积表达存储体积属性例如密度、不透明度或占用率,和表面表达一样也可以存储向量表示的信息。通常,体积表达可以表达表面,但反之则不行。

对于表面和体积表达,都有连续的和离散的对应物。一般来说,我们对于各种表达做出如下划分:

 DiscretizedContinuous
SurfacePointclouds, meshesParametric Surfaces, SDFs
VolumetricVoxels, 3D texturesNeural Networks

显式表达和隐式表达一般来说是对面表达来说的。以二元函数为例,在数学上,我们现在经常接触到的函数大多是满足 $y=f(x)$ 形式的函数,通常称这种函数为显函数。而隐函数的定义是:如果方程 $F(x,y)=0$ 在 $(x,y)\in{D}\subset\mathbb{R}^2$ 上能确定变量 $x$ 和 $y$ 之间的函数关系 $y=y(x)$ 或 $x=x(y)$,那么称这样的函数是由方程确定的隐函数。比如对于 $x^2+y^2-1=0$来说,可以局部地解出上半圆的函数 $y=\sqrt{1-x^2}$, $x\in(-1,1)$,以及局部地解出表示下半圆的函数 $y=-\sqrt{1-x^2}$, $x\in(-1,1)$。在图形学中,如果一个几何体上的点(以及所在点的性质)可以通过显函数的方法得到,比如显式的单位球的表达,那么我们把这种表达称为显示表达。反之,用隐函数的方法得到就是隐式表达。

Explicit Continuous Volumetric Representations

因此,我们可以得出一个结论,NeRF 是显式连续体表达。那么为什么是这样的表达?或者说这些表达的好处分别是什么?

显式相对于隐式的好处是:

  1. 显式方法获得空间点的属性更为容易,而隐式方法需要用数值方法,比如牛顿法,Marching Cube 来解方程。

连续相对于离散的好处是:

  1. 连续的表达理论上分辨率是无限的。
  2. 连续表达,特别是利用率 MLP 的连续表达,模型大小和内存占用非常紧凑。而离散的表达随着分辨率的增长对于存储的需求会越来越大。

体表达相对于面表达的好处是:

  1. 体表达能更好的表示空间中的物体的性质。体积表达可以表达表面,但反之则不行。

不过我们经常可以听到一种说法: NeRF 之类的表达形式是隐式。这是因为我们是使用体密度来提取表面,比如提取 $\sigma(x,y,z)=2.5$ 的点作为表面。这个时候表面就用隐函数的方法得到。关于这一点,我的研究不是很深入,但是我提一个想法。这里要介绍流形学习中嵌入(embedding)的概念。通俗来说:我们所能观察到的数据实际上是由一个低维流形嵌入到高维空间上的。由于数据内部特征的限制,一些高维中的数据会产生维度上的冗余,实际上只需要比较低的维度就能唯一地表示。比如三维空间中一个球面,用 3 个分量 $x,y,z$ 表达时候很多点并不在球面上,只需要 $\theta,\phi$ 两个参数就可以表达。从一个体表达中提取表面,也是同样的道理。不过我们甚至不能知道嵌入维度的大小,只能用 $\sigma(x,y,z)=2.5$ 来限制这个嵌入的流型,因此它只能是隐函数表示。这其实和神经网络完全没有一点关系,只是高维到低维的一种映射。(不过很多人好像把直接能看到模型的叫显式,不能直接看到的叫隐式。。。)

Neural Scene Representations

在神经渲染中,使用神经网络来拟合表面或体积表达函数的场景表达称为神经场景表达。DeepSDF 这篇 2019 年 CVPR 的论文是早期利用神经场景表达 SDF ,获取表面的论文。后续的 NeRF 也是沿用完全一致的思路,只不过 DeepSDF 是 $(x,y,z)\mapsto d$,而 NeRF 是 $(x,y,z,\theta,\Phi)\mapsto (r,g,b,\sigma)$。

这里我觉得只要用到了基于反向传播的深度学习方法,就都可以算神经场景表达,比如 Plenoxels,没有利用神经网络,但是用了可学习的参数组成的 3 维网格作为场景。

Light Field / Radiance Field

光场是从 1990s 发展起来的概念。光场描述了任意时刻空间中从任意一个方向经过任意一点的光强。空间中所有可能的光线由七维全光函数给出,每条光线的强度用辐射度描述。但是 7 维全光函数过于复杂、数据量大,难以记录以及存储。需要对其进行简化处理。在实际应用中,颜色和时间维度的信息通常是被 RGB 通道和不同帧表示,所以就光场而言,只关注光线的方向和位置就可以了,这样就从 7 维降到了 5 维。这样光场也就是辐射场。

Differentiable Rendering

什么是可微渲染?首先要知道什么是渲染。这张图片展示了渲染过程:把场景的建模信息编码为 $\mathbf{x}$,输入到渲染过程 $f$,随后输出了图像 $\mathbf{y}$。假如说这个渲染过程 $f$ 是可逆的,也就是通过一张图像 $\mathbf{y}$,那么我们就可以得到场景的建模 $\mathbf{x}$。我们把从模型到图像的过程叫做前向渲染(forward rendering),把图像到模型的过程叫做逆渲染(inverse rendering)。但是通常来说,$f$ 是高度复杂的非线性函数,获得其逆映射一般来说不太可能。

因此,出现了可微渲染。可微渲染并不是尝试去获得渲染过程逆映射 $f^{-1}$,而是通过迭代的方式,连续的去优化输入模型。具体来说,可微渲染的步骤是

  1. 假设我们已经有了一个初始场景模型 $\mathbf{x}$,经过渲染过程 $f$ 得到一张图像 $\mathbf{y}$,即前向渲染一次。
  2. 把图像 $\mathbf{y}$ 经过一个质量评估函数 $g$,我们就能得到这张图像的不相似度 $z$。
  3. 根据不相似度 $z$ 我们可以用梯度下降的方法利用 $\partial{z}/\partial\mathbf{x}$ 连续优化场景模型 $\mathbf{x}$。
  4. 不断迭代直到不相似度 $z$ 收敛。

这里,根据链式法则,我们有: \(\frac{\partial{z}}{\partial\mathbf{x}}=\frac{\partial{z}}{\partial\mathbf{y}}\frac{\partial\mathbf{y}}{\partial\mathbf{x}}=g'(\mathbf{y})f'(\mathbf{x})\) 只要 $f$ 是可微的,那么整个过程就可以持续迭代连续优化。此外,可微渲染的另一个好处是,它与端到端训练的概率推理和机器学习流水线是兼容的。因此利用 2D 的图片,来进行监督学习 3D 的场景参数。

Volume Rendering

上周我们已经介绍过 Volume Rendering 了,这里我们把连续和离散的公式再摆出来:

连续: \(C(\mathbf r)=\int^{t_f}_{t_n}T(t)\sigma(\mathbf r(t))\mathbf c(\mathbf r(t),\mathbf d)\mathrm dt\\ T(t)=\exp\left(-\int^{t}_{t_n}{\sigma(\mathbf r(s))}\mathrm ds\right)\) 离散: \(\hat C(\mathbf r)=\sum_{i=1}^NT_i(1-\exp(-\sigma_i\delta_i))\mathbf c_i=\sum_{i=1}^NT_i\alpha_i\mathbf c_i\\ T_i=\prod_{i=1}^N\exp(-\sigma_i\delta_i)=\prod_{i=1}^N(1-\alpha_i)\) 值得注意的是: \(\int_0^{\infty}T(t)\sigma(\mathbf{r}(t))=1\) 可以看成概率密度函数。而且趋近于 dirac-delta,需要注意的是 $\delta(t-1)$ 只是示意图。

Positional Encoding

其实有了前面的操作,我们已经能够开始训练一个模型了。但是很遗憾,不 work。NeRF 团队敏锐地把 Positional Encoding 加到了网络的输入和第一层网络之间。Positional encoding 最早出自 Transformer,应用在 NLP 领域,但是和我们没什么大的关系。Positional encoding 做的是把低维的输入向量映射到高维的编码空间。有一篇论文 Fourier Features Mapping 从理论上研究了 positional encoding 为什么可以作用的原因。简单来说,MLP 倾向于学习低频的信息,或者说非常缓慢地收敛到目标函数的高频分量,以至于 MLP 实际上无法学习这些分量。之前的机器学习任务都是从高维映射到低维的任务,而 NeRF 是低维向高维映射的任务。引入 Fourier Features Mapping 可以加速高频分量的收敛速度。其实从 Mip-NeRF 的论文配图中我们就可以很明显的看出,positional encoding 将原本很相近的位置输入在高维空间里面有效的打散了。从回归任务的角度来说,神经网络非常适合将区别鲜明的高维特征分离开。

介绍 Hash encoding。

Sampling Strategies

这部分和图形学相关更大,且比较容易理解,就简单介绍。图形学中对于积分的求值基本是用 Monte Carlo 积分。但是一维函数的积分也有更多的方法。对于 Monte Carlo 积分,合理的采样能大大提高收敛速度。这两个采样方法也是图形学中常用的方法。