NeRF & NeRF Studio 使用经历 (个人记录)

关于NeRF

1. 特性

NeRF技术会为每个场景单独优化一个神经网络

对于合成数据:NeRF使用真实的相机姿态、内参和边界

对于真实数据:使用COLMAP从运动软件包估计这些参数

NeRF技术在不需要显式地重建场景几何的情况下,可以从输入的 RGB 图像数据集中学习场景的连续体积表示

2. 原理

image.png

2.1 利用MLP模拟5D函数以表示连续空间场景

方法:用一个5D向量值函数表示连续场景,其输入为3D坐标 x = (x, y, z) 和2D视角方向 (θ, φ)(实践中用单位向量 d表示),输出为该坐标发射的颜色 c = (r, g, b) 和体积密度 σ。用一个MLP网络 FΘ : (x, d) → (c, σ) 来近似这个连续的5D场景表示,并优化权重 Θ 以将每个输入的5D坐标映射到其对应的体积密度和方向发射颜色。

为了保证多视角一致性,我们限制网络仅将体积密度σ作为位置x的函数进行预测,同时允许将RGB颜色c作为位置和观察方向的函数进行预测。为了实现这一点,MLP FΘ首先用8个全连接层(使用ReLU激活函数和每层256个通道)处理输入的3D坐标x,并输出σ和一个256维的特征向量。然后,将这个特征向量与摄像机光线的观察方向连接,并传递到另一个全连接层(使用ReLU激活函数和128个通道),输出视角相关的RGB颜色。

2.2 利用体渲染技术得到特定的摄像机光线颜色

沿一条摄像机光线在场景中生成一组采样的3D点,将这些点及其相应的观察方向作为神经网络的输入,产生一组颜色和密度的输出,使用经典体渲染技术将这些颜色和密度累积成一个2D图像

2.3. 通过梯度下降优化2.1构建的MLP网络

上文提到的过程可微分,可通过梯度下降来优化这个模型,使每个现实图像与渲染出的视图之间的误差最小化。

3. 改进

原理部分谈到原始NeRF的最初想法与实现过程,但实际使用时发现(a)在对高频场景进行复现时,经过大量迭代依然无法收敛到高分辨率表示,(b)2.2提到的分层“采样一组点”效率低,因为对光线颜色无影响的部分也会被采样(例如被遮挡)。因此论文分别提出两项改进

3.1. 加入位置编码

Rahaman 等人研究表明深度网络更倾向于学习低频函数,以及在将输入传递给网络之前,使用高频函数将输入映射到更高维空间可以更好地拟合包含高频变化的数据。

本文利用这些发现,将F_θ改写为两个函数F_θ=F_θ^′∘γ的组合,其中γ 是一个从R映射到更高维空间R^2L的映射,而F_θ^′是一个普通的 MLP。

image.png

 

将此函数分别应用于 x 中的三个坐标值(x, y, z)与单位向量d的三个分量。在本实验中,L = 10 用于 γ(x),L = 4 用于 γ(d)。

3.2. 层次化采样

原始策略:在每个相机光线上对神经辐射场网络进行密集评估,共计 N 个查询点,但不会对最终渲染图像产生贡献的自由空间和被遮挡区域仍然会被重复采样,导致效率较低

层次化表示:对整个体积空间进行层次划分,然后基于每个层级的预期贡献来分配采样点。

方法:同时优化两个神经网络,先用分层采样取Nc个点,评估出“粗糙”神经网络。把从“粗糙”网络获得的颜色作为权重因子,将更多的采样点Nf分配到对最终渲染结果影响较大的体积部分。以此提高效率且降低渲染的计算成本。

4. 实际训练过程

使用4096条光线优化神经网络

对于“粗糙”网络,Nc = 64 个坐标

对于“精细”网络,额外采样Nf = 128个坐标

使用NVIDIA V100训练,100k-300k次迭代后收敛(约1-2天)

5. 结果与对比

image.png

 

image.png

 

其中第一列为现实图片,第二列为NeRF生成效果,三至四/五列为其他模型生成效果(Ship & Lego 分别为LLFF, SRN, NV; T-Rex 分别为LLFF, SRN)

关于NeRF Studio

1. 简介

NeRF Studio提供了一个调用各种NeRF模型的接口。

它包含的模型有Nerfacto, Instant-NGP, NeRF, Mip-NeRF, TensoRF等,同时还有一些第三方模型,例如Instruct-NeRF2NeRF和K-Planes。

其中Nerfacto是nerfstudio提出的,通过整合多篇论文对nerf模型的优化,设计了一个比较全面的神经辐射场解决方案。它是nerfstudio的默认模型,也是最推荐使用的模型。从效率和准确度来讲,个人通过一次简单的对比发现它可以在与instant-NGP,一个以快速为核心特性的模型,训练速度差不多的情况下,渲染效果比instant-NGP更好。

而第三个NeRF就是最熟悉的初代NeRF。根据个人对论文的理解,NeRF训练的时间应该比nerfacto慢的多,可能需要1-2天才能完成一个场景的训练。原始的NeRF是不需要cuda加速的,可能这也解释了它和nerfacto这种模型的速度差异。而因为nerfstudio提供了配有cuda加速的模型,因此在安装nerfstudio前需要先安装好cuda toolkit。

2. 使用方法

NeRF一共有三个调用方法,分别是在本地从头配置环境、下载docker镜像与使用Google Colab在线使用。配置环境需要的时间按顺序递减,但便利性理论来讲也是递减的。nerfstudio提供了一个网页https://github.com/nerfstudio-project/nerfstudio/blob/main/docs/quickstart/installation.md#dependencies专门讲解各种配置与使用流程。

  1. 按照GitHub教程配置环境。这样的好处是可以完全本地化而不需要联网,因为无论是nerfstudio还是用来查看训练进度的viewer都是可以本地安装与使用的。但缺点是nerfstudio对于环境的依赖比较多,像这样从头配置环境可能会遇到相比后两种多的多的问题。
  2. 下载Docker镜像。上文的连接有很详细的使用教程。
  3. 使用Google Colab上提供的现成demo直接训练范例数据或直接上传自己的数据训练。这样的好处是完全不需要环境,可以直接运行,但训练成果只能以视频的形式导出。

3. 配置环境

Note:

  1. NeRF Studio需要在有Nvidia显卡且装了CUDA Toolkit的机器上运行,因为其默认使用的Nerfacto模型需要使用CUDA加速,尽管原始NeRF模型并不需要CUDA
  2. 尽管Windows与Linux系统都可以安装NeRF Studio,但Windows系统下环境配置过程更加复杂,因此更加建议在Linux下配置环境,下文的环境配置步骤也是在Linux下
  3. “使用方法”中附上的链接有较为详细的介绍从头搭建的环境步骤,但是个人经历是它所提供的步骤出现问题的概率极高。因此更建议按照它每一步骤的要求分别利用其他的攻略完成对应依赖的安装。

3.1. 安装Nvidia显卡驱动

终端输入nvidia-smi查询当前系统显卡驱动版本,若报错则意味着需要先安装显卡驱动。Linux系统自带Nouveau开源显卡驱动,这与Nvidia驱动是互斥的,需要先屏蔽Nouveau才能安装Nvidia driver。目前网上有大量在Linux下安装Nvidia显卡驱动的教程,且均会谈及到禁用自带驱动的过程,因此这里就不再附上详细步骤。

Note:

  1. 安装Nvidia驱动时需要禁用GUI,进入命令行模式,这时需要输入电脑用户名和密码,因此在进入命令行模式前要记住电脑本用户的用户名称及密码
  2. 下载的驱动文件应放在Downloads目录下并以管理员身份运行,建议Downloads目录下只留这一个安装文件避免在命令行安装时无法定位到下载的驱动

3.2. 安装CUDA 11.8

目前NeRF Studio官方测试成功的CUDA版本有11.7和11.8,个人使用11.8完成了全套环境的配置。理论上更老的版本也可以成功配置环境,但可能会出现兼容性问题。因此,如果本身没有安装过CUDA,或现有的CUDA已经在配置过程中报错,需重新安装CUDA 11.8。可在Nvidia官网下载CUDA 11.8 Local Run File安装文件,选择Local以避免安装失败后需要重新下载。

Note:

  1. 下载的文件应放在Downloads目录下,不可放于子目录中
  2. 以管理员身份运行该安装文件
  3. 因为3.1步骤已经安装了最新的显卡驱动,在运行CUDA安装文件时务必取消勾选安装Nvidia显卡驱动的选项

3.3. 安装conda与Python

官方教程中给出了安装miniconda的教程,这里miniconda和anaconda都是可以的,不过如果后续要使用自己的数据,利用Colmap得到相机姿态则需要安装anaconda。Python有对应的版本要求,只要版本正确就可以。

3.4. 安装Pytorch

一直到这一步目前互联网上都有非常成熟的一整套流程,可以直接按照详细的第三方流程安装,只是一定要在安装Pytorch前"conda activate nerfstudio"(官方教程中有详细指令)。否则还需要在nerfstudio环境中再次安装PyTorch。

3.5. 安装Tiny-cuda-nn

主流教程中给出的安装指令都是“pip install ninja git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch”,但如果没有换源/设置代理则无法连接到该服务器,会出现连接错误。CSDN上有一篇“在服务器配置nerfstudio”的文章有提到对应的解决方案,即"git clone --recursive"再cmake。

Note:

  1. 在手动安装的时候ninja与tiny cuda nn可以分开装,并且ninja可能不是必须的依赖(未验证)
  2. tiny cuda nn的在线软件包里存在导向另外两个git的超链接(fmt和cutlass),必须在git clone时加上“--recursive”才能将它们一并下载下来,缺少“--recursive”指令或直接从github上下载zip文件都会因缺少这两个dependencies导致cmake出现错误
  3. 总的来说,这一步无论是nerf studio还是tiny cuda nn给出的安装方案在本地安装时都会出现问题,建议在csdn上找到本地安装的攻略照其方式安装

3.6. 安装NeRF Studio

到这一步安装NS所需要的所有依赖都已经装好了。官方给了两种方法安装Nerfstudio,第一种是:

pip install nerfstudio

它更简单,但据说后续会疯狂报错,所以更建议使用第二种:

git clone https://github.com/nerfstudio-project/nerfstudio.git

cd nerfstudio

pip install --upgrade

pip setuptools pip install -e .

Note:

  1. 按照第二种方法也依然会用到pip install,且如果不换源会因为安装速度慢导致进程被终结

3.7. 下载范例数据

Note:

  1. 这一步terminal要设置代理才能下载,不然也会出现连接问题

3.8. 训练数据

NeRF Studio默认使用的是nerfacto模型,这个模型并没有在论文中提到,它是nerf studio的研发人员结合了多篇论文提到的技术而整合成的综合模型,对于现实场景的重现,nerfacto应当是综合表现最好的。同时,nerf studio也提供了多种论文中提到的模型,包括原始的nerf和nvidia于2022年提出的instant-ngp,并且很多模型都已经内置,可以通过更换指令参数非常简单的指定训练使用的模型。

NeRF Studio 使用经历

1. 使用样例数据

如果是在本地完成训练的话,使用ns-download-data nerfstudio --capture-name=poster命令下载一组样例数据,然后使用ns-train nerfacto --data data/nerfstudio/poster开始训练。如果使用Nerfacto模型的话训练过程中就可以点击Terminal给的链接进入Viewer实时观察训练进度。Using the viewer - nerfstudio这里有Viewer的详细使用教程。要注意的是下载样例数据前Terminal得先设置代理,不然会出现连接错误。

如果是在Google Colab上训练就简单了很多,直接在对应板块的下拉菜单选择想要训练的样例数据就可以了,甚至也可以直接在下拉菜单选择使用自己的数据而不需要任何额外的操作。

2. 使用Polycam

Polycam是一个IOS系统上的扫描软件,可以非常简单的扫描需要重建的场景。同时因为Polycam可以直接生成相机的位姿、深度图这些参数,我们不需要调用Comap来后期反推位姿,效率和准确度上都有很大的优势。但缺点是Polycam要求手机有LiDAR,也就是说只有iPhone的Pro系列可以使用这个软件,同时在扫描的时候也要用LiDAR选项。

扫描完成后点击导出,选择Raw格式,将文件最终存储到电脑的某个路径下,使用ns-process-data polycam --data {OUTPUT_FILE.zip} --output-dir {output directory}这个指令就可以把数据处理成nerfstudio需要的格式了。处理数据的速度非常快。Using custom data - nerfstudio官网的这个链接中有详细介绍Polycam以及其他很多数据来源的使用教程。

3. 使用自己的数据

3.1. 数据要求

Nerfstudio可以训练的最低要求是一个图片文件夹+一个transforms.json文件。图片文件夹里存了全部用来训练的图片,在实际训练的时候会选择90%作为训练集,而将剩下的10%用作测试集。json文档里包含了相机的内外参数。

相机的内参有两种表达方式,如果所有照片的相机内参都是一样的,可以选择像下面这样把内参写在“frames”这个dictionary之前,从而避免在每张照片里都重复表述完全一致的相机内参。

{
  "camera_model": "OPENCV_FISHEYE", // camera model type [OPENCV, OPENCV_FISHEYE]
  "fl_x": 1072.0, // focal length x
  "fl_y": 1068.0, // focal length y
  "cx": 1504.0, // principal point x
  "cy": 1000.0, // principal point y
  "w": 3008, // image width
  "h": 2000, // image height
  "k1": 0.0312, // first radial distorial parameter, used by [OPENCV, OPENCV_FISHEYE]
  "k2": 0.0051, // second radial distorial parameter, used by [OPENCV, OPENCV_FISHEYE]
  "k3": 0.0006, // third radial distorial parameter, used by [OPENCV_FISHEYE]
  "k4": 0.0001, // fourth radial distorial parameter, used by [OPENCV_FISHEYE]
  "p1": -6.47e-5, // first tangential distortion parameter, used by [OPENCV]
  "p2": -1.37e-7, // second tangential distortion parameter, used by [OPENCV]
  "frames": // ... per-frame intrinsics and extrinsics parameters
}

nerfstudio支持使用鱼眼睛头,只要对应的畸变参数是正确的就可以。上面的例子个人感觉是内参的全集,实际上就算缺少一些例如畸变参数也应该是可以完成训练的,只是可能会影响实际重建效果。因为Polycam生成的数据就是没有畸变参数的,使用ns-process-data指令得到的transforms.json里也是没有k1-k4, p1-p2的信息,但也依然可以完成训练。

如果一组数据里相机的内参不完全相同,就需要对每一幅照片单独设定相机的内参,比如下面这样。

{
    "camera_model": "OPENCV",
    "orientation_override": "none",
    "frames": [
        {
            "fl_x": 719.270159210472,
            "fl_y": 719.270159210472,
            "cx": 499.42877197265625,
            "cy": 370.6988525390625,
            "w": 994,
            "h": 738,
            "file_path": "./images/frame_00001.jpg",
            "transform_matrix": [
                [
                    0.3537980020046234,
                    -0.18390803039073944,
                    0.9170631170272827,
                    0.48517340421676636
                ],
                [
                    0.05734516307711601,
                    0.9828992486000061,
                    0.17498736083507538,
                    -0.2881288230419159
                ],
                [
                    -0.9335622787475586,
                    -0.009321045130491257,
                    0.3582940399646759,
                    0.08796890079975128
                ],
                [
                    0.0,
                    0.0,
                    0.0,
                    1.0
                ]
            ]
        }
    ]
}

相机的外参nerfstudio的数据里是用一个变换矩阵表示的,上面的例子也有展示到。关于坐标系的定义在下面这个链接中有详细的介绍:

Data conventions - nerfstudio

同时这个链接中也介绍了深度图和遮罩的使用方法。本人在实际训练中也使用了遮罩,但是遮罩会显著的增加内存占用以及降低效率。

3.2. 训练方法

当我们准备好可以用来训练的图片文件夹和transform.json后,可以通过ns-train nerfacto --data {PROCESSED_DATA_DIR}这个指令来开始训练。这里的{PROCESSED_DATA_DIR}就是导向存有照片&json的文件夹路径。注意在此之前需要先通过conda activate nerfstudio进入到nerfstudio环境中。而nerfacto是我们目前使用的模型。Methods - nerfstudio点进这个链接,左侧导航栏Methods下拉菜单中有所有可供使用的训练模型。并且非常贴心的附上了每个模型的基本原理以及使用方法,使用起来还是非常容易的。

3.3. 训练结果可视化

nerfstudio提供了一个默认互联网程序来实时可视化训练成果(但只适用于nerfacto, instant-ngp这种训练速度非常快的模型,原始的nerf并不支持),开始训练后会提供一个链接,只需要打开它就可以实时看到训练结果。这个viewer可以在本地部署,Local Server - nerfstudio这个链接包含了相关的介绍。

ns-viewer --load-config {outputs/.../config.yml}这个链接可以重新打开任何已经训练成功的项目。

  • 12
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值