nerfstudio 中的 TensoRF:张量辐射场的 CP/VM 分解原理与实战配置指南
【免费下载链接】nerfstudioA collaboration friendly studio for NeRFs项目地址: https://gitcode.com/GitHub_Trending/ne/nerfstudio
本文是 nerfstudio 开源仓库中 TensoRF 方法文档 的深度展开,围绕 TensoRF(Tensorial Radiance Fields,张量辐射场)在 nerfstudio 中的完整实现展开:先讲清其用 4D 张量 + 低秩分解(CP / Vector-Matrix)表达辐射场的核心思想,再结合仓库源码逐一剖析模型配置参数、三种张量编码、多分辨率上采样流程、损失与正则化设计,最后给出可直接运行的训练命令与调参建议。读完你将既能理解 TensoRF 为何能以远小于 NeRF 的模型体积获得更快重建,也能在 nerfstudio 中熟练配置和运行ns-train tensorf。
TensoRF 是什么:用张量分解压缩辐射场
传统 NeRF 用坐标 MLP 隐式建模辐射场,而 TensoRF(Tensorial Radiance Fields)走的是另一条路线:它把场景的辐射场建模为一个4D 张量——这个张量本质上是一个带逐体素多通道特征的3D 体素网格(三维空间坐标 + 特征通道)。直接为每个体素存特征(如 Plenoxels、PlenOctrees 的做法)内存开销极大,TensoRF 的核心创新在于对这张 4D 场景张量做紧凑的低秩分解,用少量参数逼近完整张量,从而大幅压缩模型体积。
原文档明确指出,TensoRF 支持两种分解模式:
- CP 分解(CANDECOMP/PARAFAC):把张量分解为多个秩一分量的组合,每个分量由紧凑的向量构成;
- VM 分解(Vector-Matrix,向量-矩阵分解):把张量分解为紧凑的向量因子与矩阵因子的组合。
两种分解都显著降低了内存占用。原文档给出的实验结论是:CP 分解相比 NeRF 能实现更快重建、更好渲染质量和更小的模型体积;VM 分解则在此基础之上进一步提升了渲染质量,同时缩短重建时间并保持模型紧凑。在 nerfstudio 中,这两种分解(以及第三种 triplane 变体)都被实现为可插拔的编码器,由tensorf_encoding配置项一键切换。
快速上手:一条命令启动 TensoRF 训练
原文档给出了最核心的运行命令。在 nerfstudio 中,TensoRF 与 NeRF、Instant-NGP 等一样被注册为内置方法(见 method_configs.py 中的method_configs["tensorf"]),因此直接运行:
ns-train tensorf默认配置会使用 Blender 格式数据集(BlenderDataParserConfig),每批 4096 条光线。配合自己的数据时,通过--data别名指定数据集路径即可(train.py 会把--data映射到--data.pipeline.datamanager.data):
ns-train tensorf --data /path/to/your/dataset训练过程中默认开启vis="viewer",可通过浏览器实时观察渲染结果;评估指标(PSNR / SSIM / LPIPS)会在训练和评估阶段自动计算。
核心概念:4D 场景张量与低秩分解
TensoRF 的思想可以拆成两层:
- 显式体素特征场:辐射场被表示为一个 3D 体素网格,每个体素存放多通道特征(密度通道 + 颜色/外观通道),这比纯 MLP 的隐式表达更易优化、收敛更快;
- 低秩张量分解:直接存逐体素特征需要 $R^3 \times C$ 量级的参数量($R$ 为分辨率、$C$ 为特征数),而 CP 或 VM 分解把这张张量拆成少量向量/矩阵/平面因子的外积组合,参数量降为 $O(R^2)$ 量级,换来数量级的体积压缩。
以 VM 分解为例:一个 4D 张量 $\mathcal{A}$(形状约等于 $R\times R\times R\times C$)被近似为三组平面因子(plane)与三组向量因子(line)的逐元素乘积之和。每个位置的特征值由其在三个正交平面上的投影采样值乘以对应轴向量采样值得到。
在 nerfstudio 中,这一思想由三个编码器类实现(全部位于 encodings.py):
| 编码器类 | 对应分解 | 参数张量 | 输出维度 | 行号 |
|---|---|---|---|---|
TensorCPEncoding | CP 分解 | line_coef:(3, num_components, R, 1) | num_components | encodings.py |
TensorVMEncoding | VM 分解 | plane_coef:(3, num_components, R, R)+line_coef:(3, num_components, R, 1) | num_components * 3 | encodings.py |
TriplaneEncoding | Triplane 变体 | plane_coef:(3, num_components, R, R) | num_components | encodings.py |
TensorVMEncoding的前向过程(encodings.py)很好地说明了原理:输入坐标被分别投影到三组平面坐标(xy、xz、yz)与三组线坐标,通过F.grid_sample在平面/线系数上采样,然后做plane_features * line_features的逐元素乘积,拼接成3 * num_components维特征。TensorCPEncoding则只保留线系数,用torch.prod对三轴采样结果做乘积(encodings.py),即秩一分量的外积组合。TriplaneEncoding是对称性更好、分量相互独立的变体,默认使用reduce="sum"的求和归约。
从源码结构可以推断:CP 编码只有线系数(秩一向量外积),VM 编码额外引入平面系数(矩阵因子),因此 VM 的表达能力更强,这也是原文档中 VM 渲染质量优于 CP 的实现基础。
模型与字段结构:TensoRF 在 nerfstudio 中的组织方式
TensoRF 在 nerfstudio 中的实现分为两个主要文件:
- nerfstudio/models/tensorf.py:
TensoRFModel与TensoRFModelConfig,负责模型装配、采样、渲染、损失与训练回调; - nerfstudio/fields/tensorf_field.py:
TensoRFField,负责密度与颜色的前向推理。
TensoRFField的密度路径(tensorf_field.py)会把采样点坐标归一化到 $[-1,1]$,送入density_encoding(即上节的张量编码),对所有分量求和后过 ReLU 得到密度。颜色路径(tensorf_field.py)则先由color_encoding提取颜色特征,经线性层B映射到外观维度,再与方向编码、特征编码拼接后由两层 128 宽度的mlp_head解码,最终经 Sigmoid 输出 RGB。字段内部还预留了use_sh开关(默认关闭),开启时改用球谐函数直接解码颜色。
模型装配逻辑在 tensorf.py 的populate_modules中:
- 依据
tensorf_encoding选择TensorVMEncoding/TensorCPEncoding/TriplaneEncoding,分别实例化密度编码与颜色编码; - 外观特征与方向均使用
NeRFEncoding(2 个频率、指数 0~2); - 使用
UniformSampler(200 个均匀样本)+PDFSampler(50 个重要性采样样本)构成粗-细两阶段采样,这与 NeRF 的 hierarchical sampling 思想一致; - 渲染器使用
RGBRenderer、AccumulationRenderer、DepthRenderer; - 评估指标为 PSNR / SSIM / LPIPS。
配置参数详解:TensoRFModelConfig
原文档未展开参数细节,这里结合 TensoRFModelConfig 的源码逐一说明,它们都可以通过 CLI 覆盖,例如ns-train tensorf --pipeline.model.num_den_components 32:
| 参数 | 默认值 | 含义与作用 |
|---|---|---|
init_resolution | 128 | 初始体素网格分辨率,训练开始时使用的低分辨率 |
final_resolution | 300 | 最终目标分辨率,配合上采样逐步提升 |
upsampling_iters | (2000, 3000, 4000, 5500, 7000) | 触发网格上采样的迭代步数列表 |
num_samples | 50 | 精细阶段(PDF 采样)在每条光线上的样本数 |
num_uniform_samples | 200 | 粗阶段(均匀采样)在每条光线上的样本数 |
num_den_components | 16 | 密度编码的分量数 |
num_color_components | 48 | 颜色编码的分量数 |
appearance_dim | 27 | 颜色编码的输出通道数(外观嵌入维度) |
tensorf_encoding | "vm" | 张量编码类型:"triplane"/"vm"/"cp" |
regularization | "l1" | 正则化方法:"none"/"l1"/"tv" |
use_gradient_scaling | False | 是否按距离平方缩放梯度(近处点梯度更小) |
background_color | "white" | 背景色策略:"random"/"last_sample"/"black"/"white" |
camera_optimizer | SO3xR3模式 | 可选相机位姿优化器 |
注意:内置的method_configs["tensorf"](method_configs.py)对默认配置做了两处覆盖——将regularization设为"tv",并将camera_optimizer设为mode="off"(关闭相机优化)。也就是说,直接ns-train tensorf使用的是 TV 正则 + VM 编码。
渐进式分辨率上采样机制
TensoRF 不直接在高分辨率网格上从头训练,而是从init_resolution起步、在训练过程中按upsampling_iters指定的迭代步逐步把网格插值到更高分辨率,从而加速收敛。这一机制在 tensorf.py 的get_training_callbacks中实现:
- 在
__init__中,用对数空间线性插值从init_resolution生成到final_resolution的len(upsampling_iters)个中间分辨率(tensorf.py),例如默认配置下约为 128 → 168 → 221 → 290 → 300; - 训练到达
upsampling_iters中的某个迭代步后,回调reinitialize_optimizer触发:调用density_encoding.upsample_grid(resolution)与color_encoding.upsample_grid(resolution); - 上采样本身通过双线性插值完成(
F.interpolate,见 encodings.py 的TensorCPEncoding.upsample_grid与 encodings.py 的TensorVMEncoding.upsample_grid),旧的平面/线系数作为新网格的初始化; - 上采样后重建 encodings 优化器(保留学习率与调度器),使更高分辨率的参数获得独立优化状态。
update_to_step(tensorf.py)还支持从任意中间检查点恢复时同步恢复网格分辨率,保证断点续训的一致性。
损失函数与正则化
TensoRF 的损失在 get_loss_dict 中构建,由三部分组成,并通过loss_coefficients加权:
loss_coefficients = { "rgb_loss": 1.0, # RGB 重建损失(MSE)权重 "tv_reg_density": 1e-3, # 密度场 TV 正则权重 "tv_reg_color": 1e-4, # 颜色场 TV 正则权重 "l1_reg": 5e-4, # L1 稀疏正则权重 }rgb_loss:预测 RGB 与真值图像之间的 MSE(MSELoss),计算前会按背景色混合逻辑对齐预测与真值的背景(blend_background_for_loss_computation);l1_reg(regularization="l1"):对所有密度编码参数取绝对值的均值,促使分解分量稀疏化、进一步压缩模型;tv_reg_density/tv_reg_color(regularization="tv"):对平面系数计算总变差(Total Variation)损失,约束相邻体素特征平滑。tv_loss的实现位于 losses.py,对平面网格的行/列相邻像素差平方求均值,其注释直接引用了 TensoRF 原论文官方代码库中的对应实现。
需要特别注意的是正则化与编码类型的兼容性:在populate_modules中有显式断言(tensorf.py)——regularization="tv"不支持 CP 分解,因为 CP 编码没有plane_coef属性,运行时会被RuntimeError拦截。同理,TV 分支中对plane_coef的isinstance断言也说明 TV 仅适用于含平面系数的 VM / Triplane 编码。
前向渲染流程
get_outputs(tensorf.py)完整描述了每批光线的推理管线:
- 训练阶段先将相机优化器参数应用到光线束(
camera_optimizer.apply_to_raybundle); UniformSampler在每条光线上均匀采样 200 个点,经field.get_density得到密度、get_weights计算权重,再由AccumulationRenderer得到粗累积,生成有效区域掩码(累积小于 0.0001 视为空区域);PDFSampler依据粗权重做重要性采样,在密度高的区域集中采样 50 个点;- 精细阶段字段前向(
field.forward)计算密度与 RGB,其中掩码区域直接填充白色背景以跳过无效计算、加速推理(tensorf_field.py); RGBRenderer合成最终颜色,同时输出累积图与深度图。
评估阶段通过get_image_metrics_and_images(tensorf.py)计算 PSNR、SSIM、LPIPS 三类指标,并生成img(真值+预测拼接)、accumulation、depth三张可视化图。
优化器配置与训练建议
内置的 tensorf 训练配置(method_configs.py)将参数分为两组分别优化:
| 参数组 | 优化器 | 学习率 | 调度器 |
|---|---|---|---|
fields(MLP 头、颜色线性层) | Adam | 0.001 | 指数衰减至 0.0001(30000 步) |
encodings(张量编码) | Adam | 0.02 | 指数衰减至 0.002(30000 步) |
默认max_num_iterations=30000,每 500 步评估一次、每 2000 步保存一次 checkpoint。编码器学习率显著高于字段学习率,这与 TensoRF 论文“显式特征网格需要更高学习率”的设定一致;每次网格上采样后优化器会被重新初始化(见上采样机制一节),保持较高的学习率继续收敛。
总结与阅读路径
TensoRF 以显式体素张量 + 低秩分解为核心,用 CP / VM / Triplane 三种紧凑编码在模型体积、重建速度与渲染质量之间取得了很好的平衡,是 nerfstudio 中"非 MLP 类"快速重建方法的代表之一。想要深入源码的读者可以按以下路径继续探索:
- docs/nerfology/methods/tensorf.md:本文对应的原始方法文档;
- nerfstudio/models/tensorf.py:模型装配、损失与训练回调;
- nerfstudio/fields/tensorf_field.py:密度/颜色前向推理;
- nerfstudio/field_components/encodings.py:三种张量编码的实现与上采样;
- nerfstudio/configs/method_configs.py:
method_configs["tensorf"]完整默认配置; - nerfstudio/model_components/losses.py:TV 正则损失实现。
实际操作时,从ns-train tensorf --data <数据集>起步即可复现文档描述的快速重建流程;如需追求更高渲染质量可保持默认的 VM 编码并配合 TV 正则,如需极限压缩模型体积可切换--pipeline.model.tensorf_encoding cp并搭配 L1 稀疏正则。
【免费下载链接】nerfstudioA collaboration friendly studio for NeRFs项目地址: https://gitcode.com/GitHub_Trending/ne/nerfstudio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考