✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。
我是Srlua小谢,在这里我会分享我的知识和经验。🎥
希望在这里,我们能一起探索IT世界的奥妙,提升我们的技能。🔮
记得先点赞👍后阅读哦~ 👏👏
📘📚 所属专栏:传知代码论文复现
欢迎访问我的主页:Srlua小谢 获取更多信息和资源。✨✨🌙🌙
目录
图像、3D模型、场景快速参数化为神经网络MLP:Instant-NGP复现详解
本文所有资源均可在该地址处获取。
图像、3D模型、场景快速参数化为神经网络MLP:Instant-NGP复现详解
一、概述
NGP(Neural Graphics Primitives)是一种基于神经网络的图形基元,使用全连接的神经网络进行参数化,其训练和评估成本可能很高。
作者提出了一种多分辨率哈希编码方法,该编码具有自适应性和高效性的特点,可用于改善神经网络输入以提高近似质量和训练速度。多分辨率结构允许网络消除哈希冲突的歧义,从而形成一个简单的架构,可以在现代 GPU 上并行化。
作者将多分辨率哈希编码应用到全融合的CUDA内核,使得NGP得以利用其并行性,从而减小带宽和计算上的浪费。最终能够在几秒钟内训练得到高质量的NGP,并在数十毫秒内以1920x1080的分辨率进行渲染,故称Instant-NGP。
二、原理介绍
多分辨率哈希编码(Multiresolution Hash Encoding)具有自适应和高效的特点:
- 可以应用在多种场景表示,如 Gigapixel图像、sdf(符号距离场)、nerf(神经辐射场);
- 哈希查找的时间复杂度是O(1),无需控制流,在GPU上表现出色,避免了执行分歧和串行指针跟踪;
- 结合了多个不同分辨率的层次,以捕捉场景中的粗糙和精细特征。
具体实现原理如下:
- 对于给定的输入坐标x,在不同分辨率级别上找到包围它的体素,并通过对整数坐标进行哈希映射的方式,为这些体素的角(顶点)分配索引。
- 对于所有生成的角索引,从哈希表中查找相应的F维特征向量。
- 根据x在相应体素中的相对位置对这些特征向量进行线性插值。
- 将每个级别的特征向量以及辅助输入 ?∈ R? 连接起来,得到 MLP 的输入编码 ? ∈ R??+?。
- 最后,通过反向传播损失梯度(loss gradients)来训练编码,梯度将通过MLP网络(5)、连接(4)、线性插值(3)反向传播,然后累积到查找到的特征向量中(2)。
三、实现细节
作者在CUDA中实现该多分辨率哈希编码,将其与tiny-cuda-nn框架的快速完全融合的MLP相结合,下面是一些具体实现细节:
-
性能考虑:为了优化推理和反向传播性能,哈希表条目以半精度(每个条目2字节)存储。同时,维护一个全精度副本以稳定混合精度参数更新。
-
分级计算:作者按级别评估哈希表,在处理一批输入位置时,仅需小部分连续哈希表保留在缓存中,从而充分利用GPU的缓存和并行性。
-
模型结构:除了NeRF场景之外的任务,MLP的结构包括两个宽度为64个神经元的隐藏层(使用ReLU激活函数)和一个线性输出层。
-
最大分辨率(Nmax):使用较大的值可以支持在广阔场景中靠近物体时的高质量渲染。
- 对于NeRF和SDF,最大分辨率被设定为场景尺寸的2048倍;
- 对于gigapixel image(十亿像素图像),最大分辨率被设定为图像宽度的一半;
- 对于辐射缓存(Radiance Cache),最大分辨率被设定为219。
-
初始化:作者根据相关文献,对神经网络权重进行初始化,为神经网络各层的激活及其梯度提供合理的缩放;使用均匀分布 U(−10−4, 10−4) 对哈希表条目进行初始化,以提供一些随机性。
-
训练:作者使用Adam方法联合训练神经网络权重和哈希表条目,并在哈希表条目的梯度精确为零时跳过Adam步骤。这节省了约10%的性能,而且在梯度稀疏的情况下没有降低收敛速度。
通过这种实现和优化,多分辨率哈希编码在CUDA中获得了高效的性能和较低的开销。
四、构建Instant-NGP
如果读者使用的是Windows环境,可根据自己的显卡直接下载下面的发行版:
- RTX 3000 & 4000 series, RTX A4000–A6000, and other Ampere & Ada cards
- RTX 2000 series, Titan RTX, Quadro RTX 4000–8000, and other Turing cards
- GTX 1000 series, Titan Xp, Quadro P1000–P6000, and other Pascal cards
如果读者使用的是Linux环境,抑或是想通过Python bindings进行更多对照实验,则需要自己构建Instant-NGP,下面是构建的过程:
1. 安装环境
- 硬件要求:英伟达显卡(对于NeRF模型的渲染,尽量保证8GB以上的显存,最好能达到16GB)
- 支持C++14的编译器(以下是官方推荐的环境)
- Windows:Visual Studio 2019 或 2022
- Linux:GCC/G++ 8 及以上
- CMake工具(3.21及以上)
- CUDA
- Windows:CUDA11.5 及以上
- Linux:CUDA 10.2 及以上
读者首先要确保已配备英伟达显卡,并自行配置满足上述版本要求的C++14编译器和CMake工具,以及CUDA工具包(建议安装在/usr/local
下)。
安装依赖包
若使用基于 Debian 的 Linux 发行版(如Ubuntu),安装以下依赖包:
sudo apt-get install build-essential git python3-dev python3-pip libopenexr-dev libxi-dev libglfw3-dev libglew-dev libomp-dev libxinerama-dev libxcursor-dev
若使用 Arch 相关的Linux环境,安装以下依赖包:
sudo pacman -S cuda base-devel cmake openexr libxi glfw openmp libxinerama libxcursor
安装CUDA
官方建议将CUDA安装到/usr/local
目录下并配置环境变量。例如,如果已经在/usr/local
下安装了CUDA11.4,编辑~/.bashrc
文件,添加以下代码,重启终端或使用source ~/.bashrc
命令使之生效。
export PATH="/usr/local/cuda-11.4/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda-11.4/lib64:$LD_LIBRARY_PATH"
正确配置后,在命令行输入nvcc --version
应当正常输出cuda工具包的版本信息。
2. 编译源码
-
下载附件压缩包
- 解压附件压缩包并进入项目目录
- 根据
重要说明.txt
文档中的链接,下载dependencies
并解压到项目根目录
-
使用CMake构建项目
cmake . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo cmake --build build --config RelWithDebInfo -j
3. 启动
直接启动可执行文件
可直接启动可执行文件
./instant-ngp
通过python bindings调用接口启动
-
先使用conda创建并配置虚拟环境
# 创建虚拟环境(python版本>=3.7) conda create --name instant-ngp python=3.7 # 激活环境 conda activate instant-ngp # 安装最新版的pip工具 conda install pip pip install --upgrade pip # 使用pip安装依赖库 pip install -r requirements.txt
-
启动项目
python scripts/run.py
五、使用Instant-NGP
1. 基本操作介绍
- 键盘操作:
W
S
A
D
在场景中前后左右移动,space
(空格)和c
分别实现上升和下降 - 鼠标操作:左键拖拽旋转视角,中键拖拽平移视图,滚轮缩放视图
其他快捷键可查阅README.md
文档
2. 使用源码data目录下的模型
项目源码中已经有data
文件夹,其中包括了三种类型的文件:
-
exr格式的image文件
.exr格式的文件常用于制作贴图,用图片来实现动态的3D效果。
想要了解更多,可以阅读本文:EXR贴图究竟有多牛B?将要颠覆整个CG绘图行业! - 知乎 (zhihu.com)
我们只需要将
.exr
格式文件拖入窗口内,或者在启动时带上文件路径(如下)即可。./instant-ngp data/image/albert.exr
-
sdf文件
sdf(signed distance field)即符号距离场,通过记录每个点到模型边界的距离,在模型内侧的点数值为负,外侧的点数值为正,在边界上的点数值为0,所有距离为0的点构成了模型的表面,从而可以表示出一个2D或3D模型。
想要了解更多,可以阅读本文:SDF(signed distance field)基础理论和计算 - 知乎 (zhihu.com)
只需将
sdf
文件夹下的.obj
格式的文件拖入到窗口中,或者在启动时带上文件路径(如下)即可。./instant-ngp data/sdf/armadillo.obj
-
nerf模型
NeRF(Neural Radiance Fields)即神经辐射场,基于神经网络构建一个连续的5D函数来表示3D场景,并使用少量的输入视图来优化这个函数以生成复杂场景的新视角。
上一期我介绍了一种mip-NeRF模型,就是对NeRF的一种改进,有兴趣的可以阅读本文:【mip-NeRF】使用一组二维图像渲染3D场景视频(mip-NeRF论文复现)-CSDN博客
只需将
nerf
文件夹下的场景文件夹(如fox
场景)拖入窗口内,或在启动时带上场景目录路径(如下)即可。./instant-ngp data/nerf/fox
渲染效果图(在RTX 4090显卡上):
image(albert.exr) | SDF模型(armadillo.obj) | nerf模型(fox) |
---|---|---|
|
|
|
3. 使用任意NeRF数据集
如果读者有自己的NeRF数据集,也可以使用Instant-NGP进行快速渲染,例如我们可以使用谷歌最原始的NeRF数据集,对lego
,chair
,hotdog
这三个场景进行,下载数据集后,将场景文件夹拖入到窗口内即可。下面是渲染效果图:
lego场景 | chair场景 | hotdog场景 |
---|---|---|
|
|
|
4. 制作自己的NeRF数据集
NeRF数据集通常由一组图片和对应的相机位姿(通常存储在transforms.json
文件中)组成。想要制作一组NeRF数据集有很多方法,通常需要一些专业的相机设备。
但是,如果你是ios用户,那幸运的是,你可以从苹果app store下载一个叫NeRF Capture
的app(不清楚安卓是否有类似的app),它可以将图像及坐标(大概用到了ARKit)传输给Instant-NGP,并通过Instant-NGP提供的脚本快速制作NeRF数据集。
操作说明如下:
-
首先需要安装下面的依赖
pip install cyclonedds
-
用流(stream)传输
-
打开
NeRF Capture
app -
运行python脚本(启用stream模式)
python scripts/nerfcapture2nerf.py --stream
-
等待app与脚本连接,这会在app上显示
-
在app上点击
send
按钮,捕获到的场景将会发送到Instant-NGP -
开始训练
-
-
保存数据集
-
打开
NeRF Capture
app -
运行python脚本,
--save_path
指定保存路径,n_frames
指定保存数据集前要捕获多少帧python scripts/nerfcapture2nerf.py --save_path "dir1/dir2" --n_frames 20
-
等待app与脚本连接,这会在app上显示
-
在app上点击
send
按钮,捕获到的场景将会保存到指定的目录
-
六、总结
论文主要提出了一种多分辨率哈希编码,优化了NGP的输入特征编码,并将其融合CUDA内核进行实现,可以适应图像、模型、NeRF等多种场景的渲染。通过复现实验,Instant-NGP的收敛速度之快、渲染质量之高不禁令人称奇!但是Hash编码是一种以空间换时间的数据结构,因此这种方法对显存的要求也比较高。
七、参考资料
论文地址:[2201.05989] Instant Neural Graphics Primitives with a Multiresolution Hash Encoding (arxiv.org)
希望对你有帮助!加油!
若您认为本文内容有益,请不吝赐予赞同并订阅,以便持续接收有价值的信息。衷心感谢您的关注和支持!