Files
nerfstudio/nerfstudio/fields/density_fields.py
T
Fernando Rivas-ManzanequeandMatthew Tancik 9053643932 Volinga model and NVOL documentation (#1486)
* added volinga model to NeRFStudio

* Removed unused dependencies

* Modified dockerfile to match main

* Corrected typo in core_code_checks.yml

* Corrected typo in core_code_checks.yml

* updated test with Volinga

* Added conversion to NVOL documentation

* [WIP] Refactor documentation and removing Volinga config

* Volinga use existing NerfactoModelConfig

* Added Unreal Engine documentation to extensions

* removed unused field class import

* Updated docs

* Documentation ready

* Update Dockerfile

---------

Co-authored-by: Matthew Tancik <tancik@berkeley.edu>
2023-02-25 14:49:53 -08:00

129 lines
4.7 KiB
Python

# Copyright 2022 The Nerfstudio Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Proposal network field.
"""
from typing import Optional
import numpy as np
import torch
from torchtyping import TensorType
from nerfstudio.cameras.rays import RaySamples
from nerfstudio.data.scene_box import SceneBox
from nerfstudio.field_components.activations import trunc_exp
from nerfstudio.field_components.spatial_distortions import SpatialDistortion
from nerfstudio.fields.base_field import Field
try:
import tinycudann as tcnn
except ImportError:
# tinycudann module doesn't exist
pass
class HashMLPDensityField(Field):
"""A lightweight density field module.
Args:
aabb: parameters of scene aabb bounds
num_layers: number of hidden layers
hidden_dim: dimension of hidden layers
spatial_distortion: spatial distortion module
use_linear: whether to skip the MLP and use a single linear layer instead
"""
def __init__(
self,
aabb,
num_layers: int = 2,
hidden_dim: int = 64,
spatial_distortion: Optional[SpatialDistortion] = None,
use_linear=False,
num_levels=8,
max_res=1024,
base_res=16,
log2_hashmap_size=18,
features_per_level=2,
) -> None:
super().__init__()
self.register_buffer("aabb", aabb)
self.spatial_distortion = spatial_distortion
self.use_linear = use_linear
growth_factor = np.exp((np.log(max_res) - np.log(base_res)) / (num_levels - 1))
self.register_buffer("max_res", torch.tensor(max_res))
self.register_buffer("num_levels", torch.tensor(num_levels))
self.register_buffer("log2_hashmap_size", torch.tensor(log2_hashmap_size))
config = {
"encoding": {
"otype": "HashGrid",
"n_levels": num_levels,
"n_features_per_level": features_per_level,
"log2_hashmap_size": log2_hashmap_size,
"base_resolution": base_res,
"per_level_scale": growth_factor,
},
"network": {
"otype": "FullyFusedMLP",
"activation": "ReLU",
"output_activation": "None",
"n_neurons": hidden_dim,
"n_hidden_layers": num_layers - 1,
},
}
if not self.use_linear:
self.mlp_base = tcnn.NetworkWithInputEncoding(
n_input_dims=3,
n_output_dims=1,
encoding_config=config["encoding"],
network_config=config["network"],
)
else:
self.encoding = tcnn.Encoding(n_input_dims=3, encoding_config=config["encoding"])
self.linear = torch.nn.Linear(self.encoding.n_output_dims, 1)
def get_density(self, ray_samples: RaySamples):
if self.spatial_distortion is not None:
positions = self.spatial_distortion(ray_samples.frustums.get_positions())
positions = (positions + 2.0) / 4.0
else:
positions = SceneBox.get_normalized_positions(ray_samples.frustums.get_positions(), self.aabb)
# Make sure the tcnn gets inputs between 0 and 1.
selector = ((positions > 0.0) & (positions < 1.0)).all(dim=-1)
positions = positions * selector[..., None]
positions_flat = positions.view(-1, 3)
if not self.use_linear:
density_before_activation = (
self.mlp_base(positions_flat).view(*ray_samples.frustums.shape, -1).to(positions)
)
else:
x = self.encoding(positions_flat).to(positions)
density_before_activation = self.linear(x).view(*ray_samples.frustums.shape, -1)
# Rectifying the density with an exponential is much more stable than a ReLU or
# softplus, because it enables high post-activation (float32) density outputs
# from smaller internal (float16) parameters.
density = trunc_exp(density_before_activation)
density = density * selector[..., None]
return density, None
def get_outputs(self, ray_samples: RaySamples, density_embedding: Optional[TensorType] = None):
return {}