diff --git a/.github/workflows/core_code_checks.yml b/.github/workflows/core_code_checks.yml index 1eb0612702..b3421c22d3 100644 --- a/.github/workflows/core_code_checks.yml +++ b/.github/workflows/core_code_checks.yml @@ -15,10 +15,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.8.13 + - name: Set up Python 3.11.13 uses: actions/setup-python@v4 with: - python-version: '3.8.13' + python-version: '3.11.13' - uses: actions/cache@v3 with: path: ${{ env.pythonLocation }} diff --git a/nerfstudio/cameras/camera_utils.py b/nerfstudio/cameras/camera_utils.py index e9e194543e..54fc6c2d5d 100644 --- a/nerfstudio/cameras/camera_utils.py +++ b/nerfstudio/cameras/camera_utils.py @@ -172,7 +172,7 @@ def get_interpolated_poses(pose_a: NDArray, pose_b: NDArray, steps: int = 10) -> quat_b = quaternion_from_matrix(pose_b[:3, :3]) ts = np.linspace(0, 1, steps) - quats = [quaternion_slerp(quat_a, quat_b, t) for t in ts] + quats = [quaternion_slerp(quat_a, quat_b, float(t)) for t in ts] trans = [(1 - t) * pose_a[:3, 3] + t * pose_b[:3, 3] for t in ts] poses_ab = [] @@ -199,7 +199,7 @@ def get_interpolated_k( List of interpolated camera poses """ Ks: List[Float[Tensor, "3 3"]] = [] - ts = np.linspace(0, 1, steps) + ts = torch.linspace(0, 1, steps, dtype=k_a.dtype, device=k_a.device) for t in ts: new_k = k_a * (1.0 - t) + k_b * t Ks.append(new_k) @@ -218,7 +218,7 @@ def get_interpolated_time( steps: number of steps the interpolated pose path should contain """ times: List[Float[Tensor, "1"]] = [] - ts = np.linspace(0, 1, steps) + ts = torch.linspace(0, 1, steps, dtype=time_a.dtype, device=time_a.device) for t in ts: new_t = time_a * (1.0 - t) + time_b * t times.append(new_t) diff --git a/nerfstudio/cameras/rays.py b/nerfstudio/cameras/rays.py index a9c38d8e61..f4f1086993 100644 --- a/nerfstudio/cameras/rays.py +++ b/nerfstudio/cameras/rays.py @@ -136,6 +136,7 @@ def get_weights(self, densities: Float[Tensor, "*batch num_samples 1"]) -> Float Weights for each sample """ + assert self.deltas is not None, "Deltas must be set to compute weights" delta_density = self.deltas * densities alphas = 1 - torch.exp(-delta_density) diff --git a/nerfstudio/data/dataparsers/colmap_dataparser.py b/nerfstudio/data/dataparsers/colmap_dataparser.py index 837794ce18..e9bfd4bb4a 100644 --- a/nerfstudio/data/dataparsers/colmap_dataparser.py +++ b/nerfstudio/data/dataparsers/colmap_dataparser.py @@ -455,6 +455,7 @@ def _load_3D_points(self, colmap_path: Path, transform_matrix: torch.Tensor, sca points3D_image_ids.append( torch.cat((nids, torch.full((max_num_points - len(nids),), -1, dtype=torch.int64))) ) + assert downscale_factor is not None points3D_image_xy.append( torch.cat((nxy, torch.full((max_num_points - len(nxy), nxy.shape[-1]), 0, dtype=torch.float32))) / downscale_factor diff --git a/nerfstudio/data/dataparsers/dycheck_dataparser.py b/nerfstudio/data/dataparsers/dycheck_dataparser.py index 42ce6afce7..19d5d8a59f 100644 --- a/nerfstudio/data/dataparsers/dycheck_dataparser.py +++ b/nerfstudio/data/dataparsers/dycheck_dataparser.py @@ -289,8 +289,8 @@ def process_frames(self, frame_names: List[str], time_ids: np.ndarray) -> Tuple[ cam_json = load_from_json(self.data / f"camera/{frame}.json") c2w = torch.as_tensor(cam_json["orientation"]).T position = torch.as_tensor(cam_json["position"]) - position -= self._center # some scenes look weird (wheel) - position *= self._scale * self.config.scale_factor + position -= torch.as_tensor(self._center) # some scenes look weird (wheel) + position *= torch.as_tensor(self._scale) * self.config.scale_factor pose = torch.zeros([3, 4]) pose[:3, :3] = c2w pose[:3, 3] = position diff --git a/nerfstudio/data/dataparsers/nerfstudio_dataparser.py b/nerfstudio/data/dataparsers/nerfstudio_dataparser.py index 24dc456d15..3512d31ca2 100644 --- a/nerfstudio/data/dataparsers/nerfstudio_dataparser.py +++ b/nerfstudio/data/dataparsers/nerfstudio_dataparser.py @@ -484,6 +484,7 @@ def _get_fname(self, filepath: Path, data_dir: Path, downsample_folder_prefix="i CONSOLE.log(f"Auto image downscale factor of {self.downscale_factor}") else: self.downscale_factor = self.config.downscale_factor + assert self.downscale_factor is not None if self.downscale_factor > 1: return data_dir / f"{downsample_folder_prefix}{self.downscale_factor}" / filepath.name diff --git a/nerfstudio/data/pixel_samplers.py b/nerfstudio/data/pixel_samplers.py index d4ca82d030..8b97120b57 100644 --- a/nerfstudio/data/pixel_samplers.py +++ b/nerfstudio/data/pixel_samplers.py @@ -227,6 +227,7 @@ def sample_method_fisheye( rand_samples = torch.rand((samples_needed, 2), device=device) # Convert random samples to radius and theta. + assert self.config.fisheye_crop_radius is not None radii = self.config.fisheye_crop_radius * torch.sqrt(rand_samples[:, 0]) theta = 2.0 * torch.pi * rand_samples[:, 1] diff --git a/nerfstudio/data/utils/data_utils.py b/nerfstudio/data/utils/data_utils.py index e79f169034..d1a6721844 100644 --- a/nerfstudio/data/utils/data_utils.py +++ b/nerfstudio/data/utils/data_utils.py @@ -116,7 +116,7 @@ def get_depth_image_from_path( else: image = cv2.imread(str(filepath.absolute()), cv2.IMREAD_ANYDEPTH) image = image.astype(np.float32) * scale_factor - image = cv2.resize(image, (width, height), interpolation=interpolation) + image = cv2.resize(image, (width, height), interpolation=interpolation) # type: ignore return torch.from_numpy(image[:, :, np.newaxis]) diff --git a/nerfstudio/exporter/exporter_utils.py b/nerfstudio/exporter/exporter_utils.py index 49b7994d5f..3cd1fc2872 100644 --- a/nerfstudio/exporter/exporter_utils.py +++ b/nerfstudio/exporter/exporter_utils.py @@ -345,6 +345,7 @@ def collect_camera_poses(pipeline: VanillaPipeline) -> Tuple[List[Dict[str, Any] camera_optimizer = None if hasattr(pipeline.model, "camera_optimizer"): camera_optimizer = pipeline.model.camera_optimizer + assert isinstance(camera_optimizer, CameraOptimizer) train_frames = collect_camera_poses_for_dataset(train_dataset, camera_optimizer) # Note: returning original poses, even if --eval-mode=all diff --git a/nerfstudio/field_components/encodings.py b/nerfstudio/field_components/encodings.py index 48845748bd..7bc18100b5 100644 --- a/nerfstudio/field_components/encodings.py +++ b/nerfstudio/field_components/encodings.py @@ -45,11 +45,6 @@ def __init__(self, in_dim: int) -> None: raise ValueError("Input dimension should be greater than zero") super().__init__(in_dim=in_dim) - @classmethod - def get_tcnn_encoding_config(cls) -> dict: - """Get the encoding configuration for tcnn if implemented""" - raise NotImplementedError("Encoding does not have a TCNN implementation") - @abstractmethod def forward(self, in_tensor: Shaped[Tensor, "*bs input_dim"]) -> Shaped[Tensor, "*bs output_dim"]: """Call forward and returns and processed tensor @@ -217,6 +212,7 @@ def __init__( self.min_freq = min_freq_exp self.max_freq = max_freq_exp self.register_buffer(name="b_matrix", tensor=basis) + self.b_matrix: Tensor self.include_input = include_input def get_out_dim(self) -> int: diff --git a/nerfstudio/fields/sdf_field.py b/nerfstudio/fields/sdf_field.py index ed936d4b2b..8f53f55a0f 100644 --- a/nerfstudio/fields/sdf_field.py +++ b/nerfstudio/fields/sdf_field.py @@ -328,6 +328,7 @@ def get_alpha( ) # always non-positive # Estimate signed distances at section points + assert ray_samples.deltas is not None, "Ray samples must have deltas for alpha computation." estimated_next_sdf = sdf + iter_cos * ray_samples.deltas * 0.5 estimated_prev_sdf = sdf - iter_cos * ray_samples.deltas * 0.5 diff --git a/nerfstudio/models/generfacto.py b/nerfstudio/models/generfacto.py index 5c1316ab79..9a8d4e81b1 100644 --- a/nerfstudio/models/generfacto.py +++ b/nerfstudio/models/generfacto.py @@ -19,7 +19,7 @@ from __future__ import annotations from dataclasses import dataclass, field -from typing import Dict, List, Optional, Tuple, Type +from typing import Dict, List, Optional, Tuple, Type, cast import numpy as np import torch @@ -444,7 +444,7 @@ def get_loss_dict(self, outputs, batch, metrics_dict=None) -> Dict[str, torch.Te loss_dict = misc.scale_dict(loss_dict, self.config.loss_coefficients) if self.train_normals: # orientation loss for computed normals - loss_dict["orientation_loss"] = self.orientation_loss_mult * torch.mean( + loss_dict["orientation_loss"] = cast(float, self.orientation_loss_mult) * torch.mean( outputs["rendered_orientation_loss"] ) else: diff --git a/nerfstudio/models/instant_ngp.py b/nerfstudio/models/instant_ngp.py index 1dd00af8da..6686b556cd 100644 --- a/nerfstudio/models/instant_ngp.py +++ b/nerfstudio/models/instant_ngp.py @@ -19,7 +19,7 @@ from __future__ import annotations from dataclasses import dataclass, field -from typing import Dict, List, Literal, Optional, Tuple, Type, Union +from typing import Dict, List, Literal, Optional, Tuple, Type, Union, cast import nerfacc import torch @@ -152,7 +152,7 @@ def get_training_callbacks( def update_occupancy_grid(step: int): self.occupancy_grid.update_every_n_steps( step=step, - occ_eval_fn=lambda x: self.field.density_fn(x) * self.config.render_step_size, + occ_eval_fn=lambda x: self.field.density_fn(x) * cast(float, self.config.render_step_size), ) return [ @@ -170,7 +170,7 @@ def get_param_groups(self) -> Dict[str, List[Parameter]]: param_groups["fields"] = list(self.field.parameters()) return param_groups - def get_outputs(self, ray_bundle: RayBundle): + def get_outputs(self, ray_bundle: RayBundle): # type: ignore assert self.field is not None num_rays = len(ray_bundle) diff --git a/nerfstudio/models/splatfacto.py b/nerfstudio/models/splatfacto.py index 136a3168e6..475cc5c388 100644 --- a/nerfstudio/models/splatfacto.py +++ b/nerfstudio/models/splatfacto.py @@ -291,7 +291,7 @@ def populate_modules(self): ) self.strategy_state = self.strategy.initialize_state() else: - raise ValueError(f"""Splatfacto does not support strategy {self.config.strategy} + raise ValueError(f"""Splatfacto does not support strategy {self.config.strategy} Currently, the supported strategies include default and mcmc.""") @property @@ -552,7 +552,7 @@ def get_outputs(self, camera: Cameras) -> Dict[str, Union[torch.Tensor, List]]: colors_crop = torch.sigmoid(colors_crop).squeeze(1) # [N, 1, 3] -> [N, 3] sh_degree_to_use = None - render, alpha, self.info = rasterization( + render, alpha, self.info = rasterization( # type: ignore[reportPossiblyUnboundVariable] means=means_crop, quats=quats_crop, # rasterization does normalization internally scales=torch.exp(scales_crop), diff --git a/nerfstudio/process_data/process_data_utils.py b/nerfstudio/process_data/process_data_utils.py index 89f78ed53f..75878d6a5f 100644 --- a/nerfstudio/process_data/process_data_utils.py +++ b/nerfstudio/process_data/process_data_utils.py @@ -21,7 +21,7 @@ import sys from enum import Enum from pathlib import Path -from typing import List, Literal, Optional, OrderedDict, Tuple, Union +from typing import List, Literal, Optional, OrderedDict, Tuple, Union, cast import cv2 import imageio @@ -95,7 +95,7 @@ def get_image_filenames(directory: Path, max_num_images: int = -1) -> Tuple[List else: idx = np.arange(num_orig_images) - image_filenames = list(np.array(image_paths)[idx]) + image_filenames = cast(List[Path], list(np.array(image_paths)[idx])) return image_filenames, num_orig_images @@ -596,7 +596,7 @@ def generate_circle_mask(height: int, width: int, percent_radius) -> Optional[np mask = np.zeros((height, width), dtype=np.uint8) center = (width // 2, height // 2) radius = int(percent_radius * np.sqrt(width**2 + height**2) / 2.0) - cv2.circle(mask, center, radius, 1, -1) + cv2.circle(mask, center, radius, 1, -1) # type: ignore return mask diff --git a/nerfstudio/scripts/downloads/eyeful_tower.py b/nerfstudio/scripts/downloads/eyeful_tower.py index b9d5d8c26e..40ca0f259e 100644 --- a/nerfstudio/scripts/downloads/eyeful_tower.py +++ b/nerfstudio/scripts/downloads/eyeful_tower.py @@ -120,7 +120,7 @@ def scale_metashape_transform(xml_tree: ET.ElementTree, target_width: int, targe root = transformed.getroot() assert len(root) == 1 - chunk = root[0] + chunk = root[0] # type: ignore[reportOptionalSubscript] sensors = chunk.find("sensors") assert sensors is not None diff --git a/nerfstudio/scripts/process_data.py b/nerfstudio/scripts/process_data.py index 1fdd36f7f2..4825bfc786 100644 --- a/nerfstudio/scripts/process_data.py +++ b/nerfstudio/scripts/process_data.py @@ -19,7 +19,7 @@ import zipfile from dataclasses import dataclass from pathlib import Path -from typing import Optional, Union +from typing import List, Optional, Union, cast import numpy as np import tyro @@ -90,7 +90,7 @@ def main(self) -> None: record3d_image_filenames = list(np.array(record3d_image_filenames)[idx]) # Copy images to output directory copied_image_paths = process_data_utils.copy_images_list( - record3d_image_filenames, + cast(List[Path], record3d_image_filenames), image_dir=image_dir, verbose=self.verbose, num_downscales=self.num_downscales, diff --git a/nerfstudio/scripts/train.py b/nerfstudio/scripts/train.py index dd2300568a..bcaf92aba7 100644 --- a/nerfstudio/scripts/train.py +++ b/nerfstudio/scripts/train.py @@ -215,6 +215,7 @@ def launch( process_context.join() except KeyboardInterrupt: for i, process in enumerate(process_context.processes): + assert process is not None if process.is_alive(): CONSOLE.log(f"Terminating process {i}...") process.terminate() diff --git a/nerfstudio/utils/colormaps.py b/nerfstudio/utils/colormaps.py index 0a790e1237..c771178c2a 100644 --- a/nerfstudio/utils/colormaps.py +++ b/nerfstudio/utils/colormaps.py @@ -111,7 +111,10 @@ def apply_float_colormap(image: Float[Tensor, "*bs 1"], colormap: Colormaps = "v image_long_max = torch.max(image_long) assert image_long_min >= 0, f"the min value is {image_long_min}" assert image_long_max <= 255, f"the max value is {image_long_max}" - return torch.tensor(matplotlib.colormaps[colormap].colors, device=image.device)[image_long[..., 0]] + return torch.tensor( + matplotlib.colormaps[colormap].colors, # type: ignore + device=image.device, + )[image_long[..., 0]] def apply_depth_colormap( diff --git a/nerfstudio/utils/misc.py b/nerfstudio/utils/misc.py index f55e1259a3..3f71adb7ed 100644 --- a/nerfstudio/utils/misc.py +++ b/nerfstudio/utils/misc.py @@ -44,7 +44,7 @@ def get_dict_to_torch(stuff: T, device: Union[torch.device, str] = "cpu", exclud stuff[k] = get_dict_to_torch(v, device) return stuff if isinstance(stuff, torch.Tensor): - return stuff.to(device) + return stuff.to(device) # type: ignore[reportReturnType] return stuff @@ -59,7 +59,7 @@ def get_dict_to_cpu(stuff: T) -> T: stuff[k] = get_dict_to_cpu(v) return stuff if isinstance(stuff, torch.Tensor): - return stuff.detach().cpu() + return stuff.detach().cpu() # type: ignore[reportReturnType] return stuff diff --git a/nerfstudio/utils/profiler.py b/nerfstudio/utils/profiler.py index b3046aa73f..48a8be96dc 100644 --- a/nerfstudio/utils/profiler.py +++ b/nerfstudio/utils/profiler.py @@ -58,7 +58,7 @@ def time_function(name_or_func: Union[CallableT, str]) -> Union[CallableT, Conte Returns: A wrapped function or context to use in a `with` statement. """ - return _TimeFunction(name_or_func) + return _TimeFunction(name_or_func) # type: ignore[reportReturnType] class _TimeFunction(ContextDecorator): diff --git a/nerfstudio/viewer/render_panel.py b/nerfstudio/viewer/render_panel.py index 83e3407576..9369336e89 100644 --- a/nerfstudio/viewer/render_panel.py +++ b/nerfstudio/viewer/render_panel.py @@ -367,7 +367,9 @@ def update_spline(self) -> None: points_array = self._position_spline.evaluate( self.spline_t_from_t_sec(np.linspace(0, transition_times_cumsum[-1], num_frames)) ) - colors_array = np.array([colorsys.hls_to_rgb(h, 0.5, 1.0) for h in np.linspace(0.0, 1.0, len(points_array))]) + colors_array = np.array( + [colorsys.hls_to_rgb(float(h), 0.5, 1.0) for h in np.linspace(0.0, 1.0, len(points_array))], + ) # Clear prior spline nodes. for node in self._spline_nodes: @@ -377,7 +379,7 @@ def update_spline(self) -> None: self._spline_nodes.append( self._server.scene.add_spline_catmull_rom( "/render_camera_spline", - positions=points_array, + points=points_array, color=(220, 220, 220), closed=self.loop, line_width=1.0, diff --git a/nerfstudio/viewer/render_state_machine.py b/nerfstudio/viewer/render_state_machine.py index 32448d9bc8..ced692d453 100644 --- a/nerfstudio/viewer/render_state_machine.py +++ b/nerfstudio/viewer/render_state_machine.py @@ -147,10 +147,9 @@ def _render_img(self, camera_state: CameraState): [color[0] / 255.0, color[1] / 255.0, color[2] / 255.0], device=self.viewer.get_model().device, ) - self.viewer.get_model().set_background(background_color) + self.viewer.get_model().set_background(background_color) # type: ignore[reportCallIssue] was_training = self.viewer.get_model().training self.viewer.get_model().eval() - step = self.viewer.step try: if self.viewer.control_panel.crop_viewport: color = self.viewer.control_panel.background_color @@ -201,7 +200,10 @@ def _render_img(self, camera_state: CameraState): render_time = vis_t.duration if writer.is_initialized() and render_time != 0: writer.put_time( - name=EventName.VIS_RAYS_PER_SEC, duration=num_rays / render_time, step=step, avg_over_steps=True + name=EventName.VIS_RAYS_PER_SEC, + duration=num_rays / render_time, + step=self.viewer.step, + avg_over_steps=True, ) return outputs diff --git a/pyproject.toml b/pyproject.toml index 7509ba1290..585eee4f9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,7 +58,7 @@ dependencies = [ "torchvision>=0.14.1", "torchmetrics[image]>=1.0.1", "typing_extensions>=4.4.0", - "viser==0.2.7", + "viser==1.0.0", "nuscenes-devkit>=1.1.1", "wandb>=0.13.3", "xatlas", @@ -93,7 +93,7 @@ dev = [ "pre-commit==3.3.2", "pytest==7.1.2", "pytest-xdist==2.5.0", - "ruff>=0.6.1", + "ruff==0.12.2", "sshconf==0.2.5", "pycolmap>=0.3.0", # NOTE: pycolmap==0.3.0 is not available on newer python versions "diffusers==0.16.1", @@ -103,8 +103,7 @@ dev = [ # NOTE: Disabling projectaria-tools because it doesn't have prebuilt windows wheels # Syntax comes from here: https://pip.pypa.io/en/stable/reference/requirement-specifiers/ "projectaria-tools>=1.3.1; sys_platform != 'win32'", - # pin torch to <=2.1 to fix https://github.com/pytorch/pytorch/issues/118736 - "torch>=1.13.1,<2.2", + "torch==2.7.1", "awscli==1.33.18" ] @@ -161,7 +160,6 @@ reportMissingImports = "warning" reportMissingTypeStubs = false reportPrivateImportUsage = false -pythonVersion = "3.8" pythonPlatform = "Linux" [tool.ruff] @@ -185,6 +183,7 @@ lint.ignore = [ "PLR0915", # Too many statements. "PLR0913", # Too many arguments. "PLC0414", # Import alias does not rename variable. (this is used for exporting names) + "PLC0415", # `import` should be at the top-level of a file "PLC1901", # Use falsey strings. "PLR5501", # Use `elif` instead of `else if`. "PLR0911", # Too many return statements.