Update Instant-NGP & Density Grid with CUDA supports. Much faster and better PSNR. (#193)

This commit is contained in:
Ruilong Li(李瑞龙) authored and GitHub committed 2022-07-24 22:22:44 -07:00
1 parent 31b52ae186
commit 12cd321e1a
39 files changed
+1721 -650

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
if __name__ == "__main__":
# TODO(ruilongli): write tests
pass
-102
View File
@@ -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()
+26
View File
@@ -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()
+3 -3
View File
@@ -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"
+1
View File
@@ -2,6 +2,7 @@
Test tensor dataclass
"""
from dataclasses import dataclass
import pytest
import torch