系列文章:
相比于 Mip-NeRF 对 NeRF 性能上的提升,Instant-NGP 更多的是对 NeRF 在速度上做优化。
我们知道,在传统 NeRF 内,给定一个三维的方向向量 d \boldsymbol{d} d,会使用 γ \gamma γ 把它编成 24 24 24 维。
球谐函数
是传统图形学中的一种光照模型,在 Instant-NGP 中使用它将传统 NeRF 的视线方向编码做了替换-------使用球谐函数做方向编码,其将
d
\boldsymbol{d}
d 映射成了一个固定的
16
16
16 维向量。值得注意的是,在论文 3D Gaussian Splatting 中,也使用了这个概念。
在 Instant-NGP 中,球谐函数用于表达空间中某点的光照模型。
光照函数
C
(
θ
,
?
)
C(\theta, \phi)
C(θ,?) 可以表示为球谐函数的加权线性组合:
C
(
θ
,
?
)
=
∑
j
=
0
J
∑
m
=
?
j
j
c
j
m
Y
j
m
(
θ
,
?
)
(1)
\tag{1} {C(\theta, \phi)=\sum_{j=0}^{J} \sum_{m=-j}^{j} c_{j}^{m} Y_{j}^{m}(\theta, \phi)}
C(θ,?)=j=0∑J?m=?j∑j?cjm?Yjm?(θ,?)(1)其中,
球谐函数
;
Y
j
m
(
θ
,
?
)
Y_{j}^{m}(\theta, \phi)
Yjm?(θ,?) 又可以被称为基
,基个数的多少决定了模型能力-----基越多,颜色模型越多,但所需要的系数
c
j
m
c_{j}^{m}
cjm? 也越多。注意,这里使用的系数
c
j
m
c_{j}^{m}
cjm?,这个值是需要训练得到的。
上图表示了,当阶数
l
l
l 和次数
m
m
m 取不同值时,球谐函数基拟合的光场分布;随着球谐函数的阶数增加,球谐函数能够拟合光线在多个方向上的更复杂的分布。
当
J
=
0
J=0
J=0 时,从 Eq.1 和上图中都可以得到,当前阶有
m
=
0
m=0
m=0 的
1
1
1 个基;当
J
=
1
J=1
J=1 时,当前阶有
m
=
?
1
,
0
,
1
m=-1,0,1
m=?1,0,1 的
3
3
3 个基,总共有
4
4
4 个基; 当
J
=
2
J=2
J=2 时,当前阶有
m
=
?
2
,
?
1
,
0
,
1
,
2
m=-2,-1,0,1,2
m=?2,?1,0,1,2 的
5
5
5 个基,加上上面两阶的,总共有
9
9
9 个基。同理,可以得到:
只要确定了这几个基的系数,因为基都是已经知道的,这时就可以用光照函数算出这个点的颜色了。(注意这里说的是光照函数算颜色)
定义:球谐函数
是一组定义在球面上的正交函数基,球谐函数的形式可以通过下面的公式定义:
Y
j
m
(
θ
,
?
)
=
{
2
K
j
m
cos
?
(
m
?
)
P
j
m
(
cos
?
θ
)
(
m
>
0
)
2
K
j
m
sin
?
(
?
m
?
)
P
j
?
m
(
cos
?
θ
)
(
m
<
0
)
K
j
0
P
j
0
(
cos
?
θ
)
(
m
=
0
)
(2)
\tag{2} Y_{j}^{m}(\theta, \phi)=\left\{\begin{array}{cc} \sqrt{2} K_{j}^{m} \cos (m \phi) P_{j}^{m}(\cos \theta) & (m>0) \\ \sqrt{2} K_{j}^{m} \sin (-m \phi) P_{j}^{-m}(\cos \theta) & (m<0) \\ K_{j}^{0} P_{j}^{0}(\cos \theta) & (m=0) \end{array}\right.
Yjm?(θ,?)=?
?
??2?Kjm?cos(m?)Pjm?(cosθ)2?Kjm?sin(?m?)Pj?m?(cosθ)Kj0?Pj0?(cosθ)?(m>0)(m<0)(m=0)?(2)其中,
这个式子还是太复杂了,计算起来颇费算力。但是我们从该公式中可以指导,在 J J J 固定的时候,基的个数是相同的,要是我们能将公式内除了 θ \theta θ 和 ? \phi ? 的部分写出来,那计算起来就相当容易了。
下面会推导前面几个球谐函数:
P 0 ( x ) = 1 2 0 0 ! d 0 d x 0 [ ( x 2 ? 1 ) 0 ] = 1 P 0 0 ( x ) = ( ? 1 ) 0 ( 1 ? x 2 ) 0 / 2 d 0 d x 0 P 0 ( x ) = 1 K 0 0 = ( 2 ? 0 + 1 ) ( 0 ? 0 ) ! 4 π ( 0 + 0 ) ! = 1 4 π Y 0 0 ( θ , ? ) = 1 4 π \begin{aligned} &P_0(x)=\frac1{2^00!}\frac{d^0}{dx^0}[(x^2-1)^0]=1 \\ &P_0^0(x)=(-1)^0(1-x^2)^{0/2}\frac{d^0}{dx^0}P_0(x)=1 \\ &K_0^0=\sqrt{\frac{(2\cdot0+1)(0-0)!}{4\pi(0+0)!}}=\sqrt{\frac1{4\pi}} \\ &Y_0^0(\theta,\phi)=\sqrt{\frac{1}{4\pi}} \end{aligned} ?P0?(x)=200!1?dx0d0?[(x2?1)0]=1P00?(x)=(?1)0(1?x2)0/2dx0d0?P0?(x)=1K00?=4π(0+0)!(2?0+1)(0?0)!??=4π1??Y00?(θ,?)=4π1??? m = 0 m=0 m=0,带入的: Y j m ( θ , ? ) = K j 0 P j 0 ( cos ? θ ) Y_{j}^{m}(\theta, \phi)=K_{j}^{0} P_{j}^{0}(\cos \theta) Yjm?(θ,?)=Kj0?Pj0?(cosθ)。
K 1 0 = ( 2 ? 1 + 1 ) ( 1 ? 0 ) ! 4 π ( 1 + 0 ) ! = 3 4 π P 1 0 ( x ) = P 1 ( x ) = d d x [ ( x 2 ? 1 ) 2 ! ] = x Y 1 0 ( θ , ? ) = 3 4 π cos ? ( θ ) \begin{aligned} &K_1^0=\sqrt{\frac{(2\cdot1+1)(1-0)!}{4\pi(1+0)!}}=\sqrt{\frac3{4\pi}} \\ &P_1^0(x)=P_1(x)=\frac{d}{dx}\left[\frac{(x^2-1)}{2!}\right]=x \\ &Y_1^0(\theta,\phi)=\sqrt{\frac3{4\pi}}\cos(\theta) \end{aligned} ?K10?=4π(1+0)!(2?1+1)(1?0)!??=4π3??P10?(x)=P1?(x)=dxd?[2!(x2?1)?]=xY10?(θ,?)=4π3??cos(θ)? m = 0 m=0 m=0,带入的: Y j m ( θ , ? ) = K j 0 P j 0 ( cos ? θ ) Y_{j}^{m}(\theta, \phi)=K_{j}^{0} P_{j}^{0}(\cos \theta) Yjm?(θ,?)=Kj0?Pj0?(cosθ)。
K 1 1 = ( 2 ? 1 + 1 ) ( 1 ? 1 ) ! 4 π ( 1 + 1 ) ! = 3 8 π P 1 1 ( x ) = ( ? 1 ) 1 ( 1 ? x 2 ) 1 / 2 d d x P 1 ( x ) = ? ( 1 ? x 2 ) 1 / 2 Y 1 1 ( θ , ? ) = 2 × 3 8 π × cos ? ( ? ) × [ ? ( 1 ? cos ? 2 ( θ ) ) 1 / 2 ] Y 1 1 ( θ , ? ) = ? 3 4 π cos ? ( ? ) sin ? ( θ ) \begin{aligned} &K_1^1=\sqrt{\frac{(2\cdot1+1)(1-1)!}{4\pi(1+1)!}}=\sqrt{\frac3{8\pi}} \\ &P_1^1(x)=(-1)^1(1-x^2)^{1/2}\frac d{dx}P_1(x)=-(1-x^2)^{1/2} \\ &Y_1^1(\theta,\phi)=\sqrt{2}\times\sqrt{\frac3{8\pi}}\times\cos(\phi)\times[-(1-\cos^2(\theta))^{1/2}] \\ &Y_{1}^{1}(\theta,\phi)=-\sqrt{\frac{3}{4\pi}}\cos(\phi)\sin(\theta) \end{aligned} ?K11?=4π(1+1)!(2?1+1)(1?1)!??=8π3??P11?(x)=(?1)1(1?x2)1/2dxd?P1?(x)=?(1?x2)1/2Y11?(θ,?)=2?×8π3??×cos(?)×[?(1?cos2(θ))1/2]Y11?(θ,?)=?4π3??cos(?)sin(θ)? m = 1 m=1 m=1,带入的: 2 K j m cos ? ( m ? ) P j m ( cos ? θ ) \sqrt{2} K_{j}^{m} \cos (m \phi) P_{j}^{m}(\cos \theta) 2?Kjm?cos(m?)Pjm?(cosθ)。
K 1 ? 1 = K 1 1 = 3 8 π P 1 1 ( x ) = ( ? 1 ) 1 ( 1 ? x 2 ) 1 / 2 d d x P 1 ( x ) = ? ( 1 ? x 2 ) 1 / 2 Y 1 ? 1 ( θ , ? ) = 2 × 3 8 π × sin ? ( ? ) × ? ( 1 ? cos ? 2 ( θ ) ) 1 / 2 Y 1 ? 1 ( θ , ? ) = ? 3 4 π sin ? ( θ ) sin ? ( ? ) \begin{aligned} &K_{1}^{-1}=K_{1}^{1}=\sqrt{\frac{3}{8\pi}} \\ &P_1^1(x)=(-1)^1(1-x^2)^{1/2}\frac{d}{dx}P_1(x)=-(1-x^2)^{1/2} \\ &\begin{aligned}Y_1^{-1}(\theta,\phi)=\sqrt{2}\times\sqrt{\frac{3}{8\pi}}\times\sin(\phi)\times-(1-\cos^2(\theta))^{1/2}\end{aligned} \\ &Y_1^{-1}(\theta,\phi)=-\sqrt{\frac{3}{4\pi}}\sin(\theta)\sin(\phi) \end{aligned} ?K1?1?=K11?=8π3??P11?(x)=(?1)1(1?x2)1/2dxd?P1?(x)=?(1?x2)1/2Y1?1?(θ,?)=2?×8π3??×sin(?)×?(1?cos2(θ))1/2?Y1?1?(θ,?)=?4π3??sin(θ)sin(?)? m = ? 1 m=-1 m=?1,带入的: 2 K j m sin ? ( ? m ? ) P j ? m ( cos ? θ ) \sqrt{2} K_{j}^{m} \sin (-m \phi) P_{j}^{-m}(\cos \theta) 2?Kjm?sin(?m?)Pj?m?(cosθ)。
综上,当 J = 2 J=2 J=2 时,极坐标中的表达式如下:
j | m | 极坐标中的表达式 | j | m | 极坐标中的表达式 | j | m | 极坐标中的表达式 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 1 2 π \frac{1}{2\sqrt{\pi}} 2π?1? | 1 | 0 | 1 2 3 π cos ? θ \frac12\sqrt{\frac3\pi}\cos\theta 21?π3??cosθ | 1 | 1 | 1 2 3 π sin ? θ cos ? ? \frac12\sqrt{\frac3\pi}\sin\theta \cos\phi 21?π3??sinθcos? |
1 | -1 | 1 2 3 π sin ? θ sin ? ? \frac12\sqrt{\frac3\pi}\sin\theta \sin\phi 21?π3??sinθsin? | 2 | 0 | 1 4 5 π ( 3 c o s 2 θ ? 1 ) \frac14\sqrt{\frac5\pi}(3cos^2\theta-1) 41?π5??(3cos2θ?1) | 2 | 1 | 1 2 15 π sin ? θ cos ? θ cos ? ? \frac12\sqrt{\frac{15}\pi}\sin\theta \cos\theta \cos\phi 21?π15??sinθcosθcos? |
2 | -1 | 1 2 15 π sin ? θ cos ? θ sin ? ? \frac12\sqrt{\frac{15}\pi}\sin\theta \cos\theta \sin\phi 21?π15??sinθcosθsin? | 2 | 2 | 1 4 15 π sin ? 2 θ cos ? 2 ? \frac14\sqrt{\frac{15}\pi}\sin^2\theta \cos2\phi 41?π15??sin2θcos2? | 2 | -2 | 1 4 15 π sin ? 2 θ sin ? 2 ? \frac14\sqrt{\frac{15}\pi}\sin^2\theta \sin2\phi 41?π15??sin2θsin2? |
在前面文章 NeRF 其一 和 NeRF 其二:Mip-NeRF 内提到过,虽然在论文内使用的是 θ \theta θ 和 ? \phi ?,但是在实际的 d \boldsymbol{d} d 使用时,还是用的 ( x , y , z ) (x,y,z) (x,y,z),在 Instant-NGP 内也是如此。所以这里讲讲它俩间的转换关系:
在 Instant-NGP 内,使用
J
=
3
J=3
J=3,即
16
16
16 维球谐函数的基。在 Instant-NGP 内,球谐函数的用法是直接将原来 NeRF 内的位置编码
γ
\gamma
γ 给替换掉。
用新的
16
16
16 维球谐函数基和之前的
γ
\gamma
γ 有什么区别?
?
\longrightarrow
? 理论上加入这个视线是为了最后生成的 RGB 值,也就是说这个视线方向和 RGB 值是有关联的,但是在
γ
\gamma
γ 编码的过程中,生成的向量和 RGB 之间并没有直接关系;而如果使用球谐函数和颜色间即使不学习,它与 RGB 间也是有关系的。即在图形学中,就已经帮你建立了两件事间的关联。从这个角度讲,球谐函数编的
16
16
16 维码,对于颜色的帮助可能更大,在学习的时候会容易很多。
从 NeRF 其一 我们知道了,NeRF 的
这里需要位置编码,是为了保证网络拥有同时学习高、低频信号的能力。
但从图中可以看到,该编码的缺陷是:网络需要自适应选择位置编码中某几维数据来生成体密度与颜色值,导致网络规模过大,计算效率低。
Instant-NGP 认为,为了让网络达到自适应选择编码中哪几维的能力,使用了上图中红框框出来的很深的一部分网络。需要用这大量的层来确定现在的数据到底用哪一维坐标(NeRF内位置编码,差距小的用位置编码的前几维;差距大的用位置编码后几维),导致了这个网络过深、参数量过大,这样计算起来就慢。实验结果也表明了 NeRF 中大量工作都是在做从位置编码里选取哪几维重要的编码来代表当前点的坐标值。
于是在 Instant-NGP 内,选择的方式不再让网络自己做了,会使用其他算法得到后传入网络中。比如在差距小的时候,传入位置编码的前几维;差距大的时候,传入后几维,不再需要网络去猜测了。那么这样网络的层是不是就不需要很多了?
Instant-NGP 的流程与 NeRF 一模一样,只是觉得 NeRF 的 γ \gamma γ 编码效率太低,主要改动在于不再使用 γ \gamma γ,有了自己的一套编码方式(显著提速),以及使用球谐函数编码 d \boldsymbol{d} d(对加速没有太大贡献)。
想要先得到 Instant-NGP 内的位置编码,再送到网络内,需要先将这些位置编码存下来,那么有以下几种方案:
很显然,Instant-NGP 内使用了第三种方案,整体流程为:
将空间划分成多分辨率网格;
这里以二维图像为例,若使用
2
?
2
2*2
2?2 分辨率网格,图像会有
9
9
9 个顶点;若使用
3
?
3
3*3
3?3 分辨率网格,图像会有
16
16
16 个顶点,如下图所示。实际使用时,它不仅使用了
3
?
3
3*3
3?3 的网格来记录信息,还用了
5
?
5
5*5
5?5、
7
?
7
7*7
7?7 等更多分辨率网格,所以称为多分辨率网格。
为什么使用多分辨率?在粗的网格里,四个顶点是在描述关注的这一大块信息。如果这一大块里少量高频大部分低频,那么这四个顶点会倾向于学习低频信息。但假设一个点正好处于低频区域里的高频区域的话,编码就不够准确了。比如上图中的点,在蓝色 2 × 2 2\times2 2×2 分辨率内,该区域以低频主导,但在红色 3 × 3 3\times3 3×3 分辨率时,这块区域是以高频主导。
划分的网格越细,则表达的内容越准确,不会被周围的内容所平均。大网格倾向于这个整体区域怎么样,越小的网格越反应局部小区域里的信息,表达就会越细致。对于处于低频的点,尽量用大的表达就行,而高频区域的点用小的表达。拼在一起既能表现这个点的高频信息,又能表现这个点的低频信息。(感觉这里的高分辨率还对不同尺度的训练有帮助,和 Mip-NeRF 内抗混叠算法异曲同工,还起到了加速作用。)
给每个顶点赋予特征码(位置编码),该特征码通过训练得到;
即特征码都是神经网络学出来的。
给定任意一个点
x
\boldsymbol{x}
x,找到其落入的网格,通过网格顶点特征码线性插值获得特征码(位置编码);
该步骤如下图所示。要算一个顶点的位置编码,首先要将周围四个顶点的位置编码取出来。现在拿到的是坐标
x
\boldsymbol{x}
x,但想要的是特征码。这里需要使用哈希函数
,将每个坐标映射成了图中的
0
0
0,
1
1
1,
2
2
2 这样的数,然后从这些数里将特征编码取出来。哈希表
在这里的作用就是查找每个顶点的特征编码。
组合多个分辨率的特征码(位置编码),送入MLP预测体密度与颜色值。
在获得了多分辨率的特征编码后,需要将他们拼在一起获得一个新的位置编码。红框内框起来的是光线的视角编码。如果只输出体密度,就不需要这个光线的视角编码,只需要上面的位置编码即可;但要是输出 RGB 值,那就需要这里的视角编码了。
再来讲讲 Instant-NGP 内实现的几个细节部分:
知道使用多分辨率网格,但是每层的分辨率是需要确认的,具体使用的以下方式:
首先将场景空间划分为
L
(
l
=
0
,
1
,
.
.
.
,
L
?
1
)
L(l=0,1,...,L-1)
L(l=0,1,...,L?1) 种不同分辨率的网格,每种分辨率
N
l
N_l
Nl? 通过尺度因子是
b
b
b 的等比数列来计算:
N
l
:
=
?
N
min
?
?
b
l
?
,
b
:
=
exp
?
??
(
ln
?
N
max
?
?
ln
?
N
min
?
L
?
1
)
=
(
N
m
a
x
N
m
i
n
)
1
L
?
1
\begin{aligned}N_l&:=\left\lfloor N_{\min}\cdot b^l\right\rfloor,\\b&:=\exp\!\left(\frac{\ln N_{\max}-\ln N_{\min}}{L-1}\right)=(\frac{N_{max}}{N_{min}})^{\frac{1}{L-1}}\end{aligned}
Nl?b?:=?Nmin??bl?,:=exp(L?1lnNmax??lnNmin??)=(Nmin?Nmax??)L?11??其中,
从图中可以知道,Instant-NGP 使用的最小分辨率网格为 16 × 16 16\times16 16×16。最大分辨率为 512 ? 524288 512-524288 512?524288,一般为 512 512 512。
如果直接使用坐标的
(
x
,
y
,
z
)
(x,y,z)
(x,y,z) 作为哈希值,因为其不是一个整数,所以用作哈希并不容易。所以思路转换一下,索引方式变成了从每个方向看的第几个顶点。
获取网格顶点的算法如下,输入量为:采样点的坐标、采样点所在网格的边界、网格数量。
算法相对简单这里不做赘述,注意
?
?
\lfloor \rfloor
?? 代表向下取整即可。
图中 hashed_grid_indices
表示桶的ID值,也就是这里网格顶点的哈希值。网格顶点 grid_indices
到网格顶点的哈希值的计算公式为:
h
(
x
)
=
(
?
i
=
1
d
x
i
π
i
)
m
o
d
??
T
h(\mathbf{x})=\left(\bigoplus_{i=1}^dx_i\pi_i\right)\mod T
h(x)=(i=1?d?xi?πi?)modT其中,
该公式表示的含义也就是 grid_indices
的三维索引
(
i
n
d
x
,
i
n
d
y
,
i
n
d
z
)
→
h
a
s
h
(ind_x,ind_y,ind_z)\rightarrow hash
(indx?,indy?,indz?)→hash。
Instant-NGP:对每一个位置学习一个位置编码,学到的位置编码和这个点的位置有关系。点如果处在高频区域,学到的位置码等价于原来 γ \gamma γ 操作的最后几维。如果点处于低频区域,期望这个位置码学到的倾向于原来 γ \gamma γ 操作的前面几维。有了这个工作后,如果给的位置编码能反应频率,那么后面的网络不需要那么复杂,很简单的就可以了。
Instant-NGP 大体网络架构如下所示:
输入与传统 NeRF 一样,都是采样点位置 x \boldsymbol{x} x 和视线方向 d \boldsymbol{d} d;
虽然输入一样,但是视线方向没有使用原来的 γ \gamma γ 值编码,使用的是球谐函数的视线方向编码。因为使用的 J = 3 J=3 J=3,所以送进网络的是 16 16 16 维。 N N N 为同一批送进去的个数;
Instant-NGP 的核心部分。现在使用的是三维了,所以索引的是八个顶点,并使用这八个顶点的位置编码计算三线性插值得到传入网络中的位置编码。因为这里的 L = 16 L=16 L=16,即 16 16 16 层分辨率,每一层都计算它的位置编码。每一层用二维的位置编码就够用了, 16 16 16 层拼起来就是 32 32 32 维;
那么训练位置编码是怎样得到的?
?
\longrightarrow
?没有经过训练的时候,这些位置编码都是一些随机数,损失会非常大。损失首先传给了MLP,MLP自己会先进行一些参数更新,同时也会把一些损失传给输入进去的
8
8
8 个采样点。因为点是通过线性插值得到的,所以这里的正向过程是可微分的,那也可以将损失再传回去,对
8
8
8 个顶点进行更新。顶点和MLP同时得到了更新。
(4.5.6) 从图中可以看到,MLP网络比先前要小太多了。小网络直接预测体密度(⑤)。隐向量那里的 15 15 15 维和视线方向的 16 16 16 维合并成 31 31 31 维,再传入神经网络中,这说明 RGB 的预测模型比体密度大一些,说明颜色预测比体密度预测要难一些。