Nerfstudio 中的经典 NeRF:从体积渲染原理到 `vanilla-nerf` 实战解析
Nerfstudio 中的经典 NeRF从体积渲染原理到vanilla-nerf实战解析【免费下载链接】nerfstudioA collaboration friendly studio for NeRFs项目地址: https://gitcode.com/GitHub_Trending/ne/nerfstudio本文以 nerfstudio 仓库的 NeRF 技术文档 为核心骨架系统梳理 2020 年原版 NeRF 论文《NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis》在 nerfstudio 中的工程化实现从神经辐射场Neural Radiance Field的体素式体积表示、位置编码Positional Encoding到分层采样Hierarchical Sampling与体积渲染Volumetric Rendering的完整链路。读完本文你将理解ns-train vanilla-nerf背后粗-细双场 均匀/PDF 两级采样的完整数据流掌握NeRFField、NeRFEncoding、UniformSampler/PDFSampler、RGBRenderer等核心组件的实例化方式与参数含义并能结合 Ray Samplers 可视化指南 与 Encoders 可视化指南 进一步做交互式探索。一、为什么还要讲原版 NeRFnerfstudio 提供了nerfacto、instant-ngp、splatfacto等大量更先进、更适合日常任务的模型注册列表可见 method_configs.py其中vanilla-nerf被注释为Original NeRF model. (slow)。但对于绝大多数任务直接使用原版 NeRF 并不是一个好选择——它的训练与推理速度明显落后于后提出的方法。然而理解 NeRF 的工作原理仍然极具价值原因有三绝大多数后续方法都沿用同一套骨架从mipnerf、tensorf到nerfacto无不包含神经场 射线采样 体积渲染这三要素只是替换了场表示、编码方式或采样策略vanilla-nerf不依赖 CUDA 扩展这意味着即使在没有 GPU 的机器上也可以用调试器单步跟进整个训练/前向过程是理解 nerfstudio 框架内部数据流的最佳入门案例它是 nerfstudio 中结构最教科书式的实现粗场coarse field与细场fine field双网络、位置/方向双编码、均匀采样 PDF 重要性采样全部以最直白的方式呈现。NeRF 的目标是从一组图像及其对应的相机位姿出发优化得到一个场景的体积表示从而能够从任意新颖视角novel viewpoint渲染出新图像。它既不是 3D 网格mesh也不是体素栅格voxel而是把整个场景烘焙进一个多层感知机MLP的权重之中。1.1 适用前提Assumptions原版 NeRF 的成功依赖以下假设任一假设被破坏都可能导致重建完全失败或出现多余几何excess geometry之类的伪影假设含义被破坏时的典型后果相机位姿已知每张输入图像都有准确的外参/内参几何错位、模糊重影场景静态场景中物体不移动动态物体被涂抹成半透明残影外观恒定曝光、光照等不随时间变化颜色伪影、闪烁输入采集密集场景中每个点应被多张图像覆盖空洞、漂浮几何这四条假设直接决定了数据采集方式手持相机环绕目标物体缓慢移动、保证重叠度、固定曝光是最稳妥的拍摄策略。1.2 快速上手训练一个 vanilla-nerfnerfstudio 将方法封装为统一的 CLI一行命令即可启动训练ns-train vanilla-nerf该命令对应的配置在 method_configs.py 中注册。从配置可以看出其默认结构数据端使用BlenderDataParserConfig即 Blender Synthetic 数据集如乐高、椅子等经典场景模型端使用VanillaModelConfig(_targetNeRFModel)优化器使用 RAdamRAdamOptimizerConfig(lr5e-4, eps1e-08)分为fields与temporal_distortion两个参数组。基于这一配置可以直观地重写训练命令例如调整采样数量ns-train vanilla-nerf --pipeline.model.num_coarse_samples 64 --pipeline.model.num_importance_samples 128num_coarse_samples默认 64与num_importance_samples默认 128正是分层采样中粗/细两个阶段每根射线的采样点数其定义见 vanilla_nerf.py。二、NeRF 管线总览nerfstudio 文档给出的 NeRF 管线分为四大组件下面逐一展开Field 表示NeRFField用 MLP 把空间坐标映射为密度 与视角相关的颜色位置/方向编码NeRFEncoding把低维输入坐标升维到高频特征空间射线采样UniformSamplerPDFSampler分层采样策略先在整条射线上均匀采样再按权重重要性重采样体积渲染RGBRenderer等把沿射线的采样点合成最终像素颜色。整个前向过程在 NeRFModel.get_outputs 中串联可概括为ray_bundle └─ UniformSampler ── ray_samples_uniform └─ field_coarse ── 密度/颜色 ── weights_coarse ── RGB_coarse粗渲染 └─ PDFSampler(weights_coarse) ── ray_samples_pdf └─ field_fine ── 密度/颜色 ── weights_fine ── RGB_fine细渲染三、Field 表示神经辐射场NeRF 的核心思想是空间中每个点都表示为一个与视角相关的辐射量。具体地每个点携带两个量密度density描述该点在空间中是不透明还是透明决定了体积渲染中的不透明度/alpha与视角相关的颜色view dependent color颜色会随观察角度 $(\theta, \phi)$ 变化这正是 NeRF 能重现高光、镜面反射等随视角变化外观的关键——输入不仅有点坐标 $(x, y, z)$还拼接了观察方向。在 nerfstudio 中场field的实现位于 vanilla_nerf_field.py类名为NeRFField。其网络结构是经典的双 MLP设计base MLP输入位置编码后的坐标8 层、每层 256 维在第 4 层处有跳跃连接skip_connections(4,)输出经过DensityFieldHead得到密度head MLP输入base MLP 输出 方向编码2 层、每层 128 维再交给RGBFieldHead等 field head 输出颜色。get_density与get_outputs分别对应这两段计算见 vanilla_nerf_field.py。默认参数一览参数默认值说明base_mlp_num_layers8base MLP 层数base_mlp_layer_width256base MLP 每层宽度head_mlp_num_layers2head MLP 层数head_mlp_layer_width128head MLP 每层宽度skip_connections(4,)base MLP 中跳跃连接的层位置use_integrated_encodingFalse是否使用集成位置编码mip-NeRF 风格注意原版 NeRF 使用两个完全独立的场coarse/fine来处理两阶段采样这一点在 nerfstudio 中通过实例化两个NeRFField实现from nerfstudio.fields.vanilla_nerf_field import NeRFField field_coarse NeRFField(position_encodingpos_enc, direction_encodingdir_enc) field_fine NeRFField(position_encodingpos_enc, direction_encodingdir_enc)在 NeRFModel.populate_modules 中两个场共享同一组位置/方向编码器但拥有各自独立的网络权重并统一归入fields参数组参与优化见 get_param_groups。3.1 位置编码Positional Encoding深度网络天然偏向学习低频函数直接输入原始坐标 $(x,y,z,\theta,\phi)$ 会导致网络难以表达高频几何与纹理细节。原版 NeRF 的解决思路是在输入网络前先把坐标编码到更高维空间即多尺度正弦编码。from nerfstudio.field_components.encodings import NeRFEncoding pos_enc NeRFEncoding( in_dim3, num_frequencies10, min_freq_exp0.0, max_freq_exp8.0, include_inputTrue ) dir_enc NeRFEncoding( in_dim3, num_frequencies4, min_freq_exp0.0, max_freq_exp4.0, include_inputTrue )参数语义如下实现见 encodings.pyin_dim输入维度位置为 3、方向为 3num_frequencies每个轴上的频率个数min_freq_exp/max_freq_exp频率范围的下/上指数实际频率为 $2^{\text{min_freq_exp}} \sim 2^{\text{max_freq_exp}}$ 的等差数列include_input是否把原始坐标拼接进编码结果原版 NeRF 默认开启。输出维度为in_dim * num_frequencies * 2 (in_dim if include_input else 0)。因此位置编码输出 $3 \times 10 \times 2 3 63$ 维方向编码输出 $3 \times 4 \times 2 3 27$ 维与论文中的 60 维位置编码 24 维方向编码一一对应。代码实现上编码通过对2 * pi * x施加正弦/余弦即 $\sin$ 与 $\sin(\cdot \pi/2)$实现。值得注意的是NeRFEncoding还支持covs协方差输入以启用 mip-NeRF 风格的集成位置编码integrated positional encoding并可在implementationtcnn时切换到 tiny-cnn 加速实现。更直观的编码可视化可参考 Encoders 可视化 Notebook。四、渲染体积渲染公式与输出类型有了空间表示下一步是从目标像素出发投射一条射线沿射线评估采样点再用经典体积渲染volumetric renderingKajiya, 1984把各点合成为预测颜色。这一合成过程与 Photoshop 中把多个不同不透明度的图层叠加十分相似唯一的区别是 NeRF 会显式考虑采样点之间的间距spacing差异。在 rays.py 的RaySamples.get_weights中权重由密度按如下公式计算计算每个采样段的透射衰减delta_density deltas * densitiesalphas 1 - exp(-delta_density)累计得到透射率transmittancetransmittance exp(-cumsum(delta_density))权重为weights alphas * transmittance。最终像素颜色即采样点颜色按权重的加权和这一alpha compositing逻辑实现在 renderers.py 的RGBRenderer.combine_rgb中comp_rgb torch.sum(weights * rgb, dim-2) # 加权求和 comp_rgb comp_rgb background_color * (1.0 - accumulated_weight) # 背景混合RGBRenderer的background_color支持random、last_sample、black、white等选项由VanillaModelConfig.background_color控制默认white。其底层还有BACKGROUND_COLOR_OVERRIDE机制用于在训练/渲染时统一覆盖背景色。nerfstudio 中对应的渲染调用如下from nerfstudio.model_components.renderers import RGBRenderer renderer_rgb RGBRenderer(background_colorcolors.WHITE) # Ray samples discussed in the next section field_outputs field_coarse.forward(ray_samples) weights ray_samples.get_weights(field_outputs[FieldHeadNames.DENSITY]) rgb renderer_rgb( rgbfield_outputs[FieldHeadNames.RGB], weightsweights, )RGB 渲染并不是唯一支持的输出。体积渲染框架天然可以推广到其他每点标量/向量属性上。nerfstudio 提供了多种渲染器renderers.py渲染器输出说明RGBRendererRGB 颜色颜色合成 背景混合AccumulationRenderer累积不透明度每个像素的权重和可视为前景掩码DepthRenderer深度图按权重对采样距离加权平均在 NeRFModel.get_outputs 中粗、细两阶段都会同时产出rgb、accumulation、depth三种输出并分别保存在outputs字典中如rgb_coarse、rgb_fine、depth_fine等供损失计算、可视化和评估使用。其他渲染器的完整清单可查阅 renderers API 文档。五、射线采样分层采样Hierarchical Sampling如何沿射线选取采样点是 NeRF 的重要设计决策。均匀撒点会浪费大量样本在空旷空间只在表面附近密集采样又不知道表面在哪。原版 NeRF 采用分层coarse-to-fine采样先均匀采样做一次粗评估再根据粗评估的权重做重要性重采样把细阶段的样本集中在物体表面附近。对应的 nerfstudio 代码from nerfstudio.model_components.ray_samplers import PDFSampler, UniformSampler sampler_uniform UniformSampler(num_samplesnum_coarse_samples) ray_samples_uniform sampler_uniform(ray_bundle) sampler_pdf PDFSampler(num_samplesnum_importance_samples) field_outputs_coarse field_coarse.forward(ray_samples_uniform) weights_coarse ray_samples_uniform.get_weights(field_outputs_coarse[FieldHeadNames.DENSITY]) ray_samples_pdf sampler_pdf(ray_bundle, ray_samples_uniform, weights_coarse)5.1 均匀采样器UniformSamplerUniformSamplerray_samplers.py在相机与预定义距离范围之间等间距分布样本用于计算场景的初始渲染。它属于SpacedSampler家族使用恒等spacing_fnlambda x: x即样本在欧氏距离上均匀分布。粗评估渲染得到的权重weights会传递给细阶段其含义是每个样本对最终渲染的贡献程度。get_weights的实现rays.py表明权重既取决于密度通过 alpha也取决于前面所有样本的累计透射率——因此高权重天然集中在从相机看过去第一次遇到的表面附近。5.2 PDF 采样器PDFSamplerPDFSamplerray_samplers.py利用粗阶段的权重构建一个概率密度函数PDF从中抽取一组新样本使样本偏向高权重区域。在实践上这些区域正是物体表面附近从而用同样数量的样本换来更精确的表面定位与细节重建。nerfstudio 提供的采样器远不止这两种同文件还实现了LinearDisparitySampler视差线性采样、SqrtSampler、LogSampler、UniformLinDispPiecewiseSampler等它们的区别仅在于spacing_fn不同。各采样器行为的交互式对比可参考 Ray Samplers 可视化 Notebook。5.3 分层采样的边界条件与注意事项::: warning 以上描述仅适用于已知边界bounded的场景例如 Blender Synthetic 数据集。对于无边界unbounded场景原版 NeRF 论文使用归一化设备坐标Normalized Device Coordinates, NDC对空间做扭曲并搭配视差线性采样器linear in disparity sampler。nerfstudio 不实现 NDC对无边界场景请改用 Spatial Distortions 可视化指南 中介绍的空间扭曲方案如SceneContraction其实现位于 spatial_distortions.py。 :::::: tip 在优化训练阶段所有采样都使用分层随机stratified样本——即在每个采样区间内随机偏移以消除量化伪影而在推理inference阶段使用未修改的确定性样本。这一行为由采样器的train_stratified参数控制UniformSampler与PDFSampler默认均为True详见 Ray Samplers 指南。 :::六、完整模型组装VanillaModelConfig 与 NeRFModel把上述组件串起来的模型类是NeRFModelvanilla_nerf.py其配置类为VanillaModelConfig核心参数如下参数默认值说明num_coarse_samples64粗场评估的采样点数num_importance_samples128细场评估的采样点数enable_temporal_distortionFalse是否启用基于时间的射线扭曲D-NeRF 风格动态场景temporal_distortion_params{kind: DNERF}时间扭曲的实例化参数use_gradient_scalingFalse是否对靠近相机的点降低梯度梯度缩放background_colorwhite背景色策略random/last_sample/black/whitepopulate_modulesvanilla_nerf.py按以下顺序完成组装构造位置编码10 频、63 维输出与方向编码4 频、27 维输出用同一组编码实例化field_coarse与field_fine两个NeRFField构造UniformSampler64 样本与PDFSampler128 样本构造RGBRenderer、AccumulationRenderer、DepthRenderer注册 PSNR / SSIM / LPIPS 评估指标若启用enable_temporal_distortion额外构造时间扭曲模块这一配置正是dnerf方法的基础见 method_configs.py 中的dnerf注册。前向过程get_outputs严格遵循均匀采样 → 粗场 → 权重 → PDF 采样 → 细场 → 权重的顺序粗、细两阶段各计算一次 RGB、累积不透明度与深度。6.1 损失与评估get_loss_dictvanilla_nerf.py对粗、细两个预测分别计算MSE 颜色损失loss_dict {rgb_loss_coarse: rgb_loss_coarse, rgb_loss_fine: rgb_loss_fine} loss_dict misc.scale_dict(loss_dict, self.config.loss_coefficients)粗、细损失可通过loss_coefficients配置权重如 mipnerf 配置中{rgb_loss_coarse: 0.1, rgb_loss_fine: 1.0}见 method_configs.py。训练时背景先经blend_background_for_loss_computation与真实图混合使模型在合成背景上也能正确优化。评估阶段get_image_metrics_and_imagesvanilla_nerf.py会同时计算细场的 PSNR、SSIM、LPIPS以及粗场的 PSNR并拼接连通图GT / coarse / fine 并排、累积不透明度图与深度图应用了深度配色映射。七、基准测试Blender Synthetic 数据集文档给出了原版 NeRF 在Blender Synthetic数据集上的对比结果PSNR 指标8 个经典场景实现MicFicusChairHotdogMaterialsDrumsShipLegoAveragenerfstudio33.7631.9834.3536.5731.0025.1129.8734.4632.14TF NeRF原版32.9130.1333.0036.1829.6225.0128.6532.5431.04JaxNeRF34.5330.4334.0836.9229.9125.0329.3633.2831.69从表中可以看出nerfstudio 的vanilla-nerf实现平均 PSNR 为32.14在 Ficus、Chair、Materials、Drums、Lego 五个场景上超过原版 TF 实现与 JaxNeRF平均分亦为三者最高。这印证了 nerfstudio 的工程实现包括分层采样、训练细节与数值稳定性处理在保持原版算法结构不变的前提下依然能达到甚至超过原论文实现的精度。需要说明的是此表数据来自仓库文档原样呈现具体复现结果会受随机种子、硬件与训练时长影响。八、进一步探索vanilla-nerf是理解 nerfstudio 框架的绝佳入口沿着本文的脉络可以继续深入交互式理解采样器Ray Samplers 可视化 Notebook 展示了均匀采样、分层采样、视差采样等策略的差异交互式理解编码器Encoders 可视化 Notebook 直观呈现位置编码对高频细节表达的影响无边界场景处理Spatial Distortions 可视化 Notebook 解释了 nerfstudio 如何替代原论文的 NDC 方案进阶方法理解了 NeRF 之后可以继续阅读 mipnerf集成位置编码、tensorf张量分解、nerfactonerfstudio 默认推荐方法等技术文档观察它们如何在场 采样 渲染骨架上做改进。九、总结原版 NeRF 用一句线性的前向过程——坐标 → 编码 → 双 MLP 场 → 分层采样 → 体积渲染 → 颜色——奠定了神经辐射场领域的基本范式。在 nerfstudio 中这一范式被拆解为高度模块化的组件NeRFField、NeRFEncoding、UniformSampler/PDFSampler、RGBRenderer并通过ns-train vanilla-nerf一键可跑。虽然它在速度上不是最优选择但作为不依赖 CUDA、结构最接近论文原意的实现它既是调试学习框架内部机制的最佳样本也是阅读后续一切 NeRF 变体的知识地基。核心参考文件索引本文主体文档docs/nerfology/methods/nerf.md场实现nerfstudio/fields/vanilla_nerf_field.py模型与配置nerfstudio/models/vanilla_nerf.py方法注册nerfstudio/configs/method_configs.py编码实现nerfstudio/field_components/encodings.py采样器实现nerfstudio/model_components/ray_samplers.py渲染器实现nerfstudio/model_components/renderers.py权重计算nerfstudio/cameras/rays.py【免费下载链接】nerfstudioA collaboration friendly studio for NeRFs项目地址: https://gitcode.com/GitHub_Trending/ne/nerfstudio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →