mirror of
https://github.com/nerfstudio-project/nerfstudio.git
synced 2026-11-13 03:14:00 +08:00
Update Instant-NGP & Density Grid with CUDA supports. Much faster and better PSNR. (#193)
This commit is contained in:
1 parent
31b52ae186
commit
12cd321e1a
39 files changed
+1721
-650
No files matched your search
@@ -0,0 +1,3 @@
|
||||
if __name__ == "__main__":
|
||||
# TODO(ruilongli): write tests
|
||||
pass
|
||||
@@ -1,102 +0,0 @@
|
||||
"""
|
||||
Test the CUDA bindings.
|
||||
"""
|
||||
import torch
|
||||
from pyrad.cuda.sampler import Sampler
|
||||
import time
|
||||
import pyrad_cuda
|
||||
import os
|
||||
|
||||
|
||||
def test_gradients():
|
||||
"""_summary_"""
|
||||
pass
|
||||
|
||||
|
||||
def test_outputs():
|
||||
"""_summary_"""
|
||||
pass
|
||||
|
||||
|
||||
def pytorch_sample_uniformly_along_ray_bundle(origins, directions, nears, fars, range_offsets):
|
||||
"""Sample along every ray with a constant step size."""
|
||||
time_steps = nears[:, None] + range_offsets[None, :] # (num_rays, max_num_samples)
|
||||
samples = origins[:, None, :] + directions[:, None, :] * time_steps[:, :, None]
|
||||
time_steps_mask = (time_steps <= fars[:, None]).float()
|
||||
return time_steps, samples, time_steps_mask
|
||||
|
||||
|
||||
def get_rgb_density(samples, time_steps_mask):
|
||||
num_rays, max_num_samples = time_steps_mask.shape
|
||||
total_max_num_samples = num_rays * max_num_samples
|
||||
|
||||
time_steps_mask_flat = time_steps_mask.view(total_max_num_samples) == 1.0
|
||||
samples_flat = samples.view(total_max_num_samples, 3)
|
||||
samples_flat_masked = samples_flat[time_steps_mask_flat]
|
||||
|
||||
# TODO: this goes through the forward pass of the MLP
|
||||
|
||||
rgb = torch.zeros((num_rays, max_num_samples, 3))
|
||||
density = torch.zeros((num_rays, max_num_samples))
|
||||
rgb.view(total_max_num_samples, 3)[time_steps_mask_flat] = 1.0
|
||||
density.view(total_max_num_samples)[time_steps_mask_flat] = 1.0
|
||||
return rgb, density
|
||||
|
||||
|
||||
def test_benchmark():
|
||||
"""The test cases assume that rays can be at most of length 1.0."""
|
||||
|
||||
device = torch.device("cuda")
|
||||
dtype = torch.float32
|
||||
|
||||
near_range = [0, 0.2]
|
||||
far_range = [0.8, 1.0]
|
||||
max_num_samples = 128 * 8
|
||||
offset = 1.0 / max_num_samples
|
||||
|
||||
print("offset is", offset)
|
||||
# import sys; sys.exit()
|
||||
|
||||
print("Running ray sampling tests.")
|
||||
# origins = torch.tensor()
|
||||
# we want these to be dtype=torch.float32 and device="cuda"
|
||||
num_rays = 1024 * 8
|
||||
print("num_rays:", num_rays)
|
||||
print("max_num_samples:", max_num_samples)
|
||||
origins = torch.zeros((num_rays, 3)).to(device)
|
||||
directions = torch.ones((num_rays, 3)).to(device)
|
||||
nears = torch.rand((num_rays)).to(device) * (near_range[1] - near_range[0]) + near_range[0]
|
||||
fars = torch.rand((num_rays)).to(device) * (far_range[1] - far_range[0]) + far_range[0]
|
||||
offsets = torch.ones(max_num_samples).to(device) * offset
|
||||
range_offsets = torch.arange(0, max_num_samples).to(device) * offset
|
||||
|
||||
start = time.time()
|
||||
time_steps_pt, samples_pt, time_steps_mask_pt = pytorch_sample_uniformly_along_ray_bundle(
|
||||
origins, directions, nears, fars, range_offsets
|
||||
)
|
||||
PYTORCH_SAMPLE_TIME = time.time() - start
|
||||
print("PYTORCH_SAMPLE_TIME:", PYTORCH_SAMPLE_TIME)
|
||||
|
||||
start = time.time()
|
||||
time_steps_cu, samples_cu, time_steps_mask_cu = pyrad_cuda.sample_uniformly_along_ray_bundle(
|
||||
origins, directions, nears, fars, offsets, max_num_samples
|
||||
)
|
||||
CUDA_SAMPLE_TIME = time.time() - start
|
||||
print("CUDA_SAMPLE_TIME: ", CUDA_SAMPLE_TIME)
|
||||
|
||||
# assert torch.allclose(time_steps_pt, time_steps_cu)
|
||||
# assert torch.allclose(samples_pt, samples_cu)
|
||||
# assert torch.allclose(time_steps_mask_pt, time_steps_mask_cu)
|
||||
|
||||
# rgb_pt, density_pt = get_rgb_density(samples_pt, time_steps_mask_pt)
|
||||
# rgb_cu, density_cu = get_rgb_density(samples_cu, time_steps_mask_cu)
|
||||
|
||||
perc_samples_used = float(time_steps_mask_pt.sum() / (time_steps_mask_pt.shape[0] * time_steps_mask_pt.shape[1]))
|
||||
perc_samples_used_str = str(round(perc_samples_used * 100.0, 2))
|
||||
print(f"Using field network for %{perc_samples_used_str} of samples in this ray bundle.")
|
||||
|
||||
# TODO: rendering of rgb, density, and deltas with pytorch vs. cuda
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_benchmark()
|
||||
@@ -0,0 +1,26 @@
|
||||
"""
|
||||
Code to test the density grid.
|
||||
"""
|
||||
|
||||
# import torch
|
||||
|
||||
# from pyrad.fields.density_fields.density_grid import DensityGrid
|
||||
|
||||
|
||||
def test_density_grid():
|
||||
"""For testing the density grid."""
|
||||
# TODO(ruilongli): currently the DensityGrid only supports GPU init.
|
||||
# after we support for CPU init then we re-enable this test
|
||||
|
||||
# device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||
# num_cascades = 1
|
||||
# resolution = 128
|
||||
# aabb = torch.tensor([[-1, -1, -1], [1, 1, 1]], dtype=torch.float32).to(device)
|
||||
# grid = DensityGrid(num_cascades, resolution, aabb)
|
||||
# grid.to(device)
|
||||
# density_eval_func = lambda x: x[..., 0:1] # xyz (..., 3) => density (...,)
|
||||
# grid.update_density_grid(density_eval_func=density_eval_func, step=0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_density_grid()
|
||||
@@ -1,22 +0,0 @@
|
||||
"""
|
||||
Code to test the occupancy grid.
|
||||
"""
|
||||
|
||||
import torch
|
||||
from pyrad.fields.occupancy_fields.occupancy_grid import OccupancyGrid
|
||||
|
||||
|
||||
def test_occupancy_grid():
|
||||
"""For testing the occupancy grid."""
|
||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||
num_cascades = 1
|
||||
resolution = 128
|
||||
aabb = torch.tensor([[-1, -1, -1], [1, 1, 1]], dtype=torch.float32).to(device)
|
||||
grid = OccupancyGrid(num_cascades, resolution, aabb)
|
||||
grid.to(device)
|
||||
density_fn = lambda x: x[..., 0:1] # xyz (..., 3) => density (...,)
|
||||
grid.update_occupancy_grid(density_fn=density_fn)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_occupancy_grid()
|
||||
@@ -10,7 +10,7 @@ from omegaconf import DictConfig
|
||||
|
||||
from scripts.run_train import main
|
||||
|
||||
BLACKLIST = ["graph_semantic_nerf.yaml", "graph_mipnerf_360.yaml"]
|
||||
BLACKLIST = ["graph_semantic_nerf.yaml", "graph_mipnerf_360.yaml", "graph_instant_ngp.yaml"]
|
||||
|
||||
|
||||
def set_reduced_config(config: DictConfig):
|
||||
@@ -19,7 +19,7 @@ def set_reduced_config(config: DictConfig):
|
||||
config.trainer.max_num_iterations = 2
|
||||
# reduce dataset factors; set dataset to test
|
||||
# switch to using the vanilla ImageDataset class
|
||||
config.data.image_dataset_train._target_ = ( # pylint: disable=protected-access
|
||||
config.data.image_dataset_train._target_ = ( # pylint: disable=protected-access
|
||||
"pyrad.data.image_dataset.ImageDataset"
|
||||
)
|
||||
config.data.dataset_inputs_train.data_directory = "tests/data/lego_test"
|
||||
@@ -27,7 +27,7 @@ def set_reduced_config(config: DictConfig):
|
||||
config.data.dataset_inputs_train.downscale_factor = 16
|
||||
config.data.dataloader_train.image_sampler.num_images_to_sample_from = 1
|
||||
config.data.dataloader_train.pixel_sampler.num_rays_per_batch = 4
|
||||
config.data.image_dataset_eval._target_ = ( # pylint: disable=protected-access
|
||||
config.data.image_dataset_eval._target_ = ( # pylint: disable=protected-access
|
||||
"pyrad.data.image_dataset.ImageDataset"
|
||||
)
|
||||
config.data.dataset_inputs_eval.data_directory = "tests/data/lego_test"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Test tensor dataclass
|
||||
"""
|
||||
from dataclasses import dataclass
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
|
||||
Reference in new issue
Block a user