From 59534e9d014f7517cd13ec3b711292b9995948e3 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 9 Jul 2024 18:21:15 +0200 Subject: [PATCH 01/50] fix: Fix reduce_mean and nms. --- vis4d/common/distributed.py | 2 +- vis4d/op/box/box2d.py | 2 +- vis4d/zoo/bevformer/bevformer_base.py | 2 +- vis4d/zoo/bevformer/bevformer_tiny.py | 2 +- vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py | 2 +- vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py | 2 +- vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py | 2 +- vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py | 2 +- vis4d/zoo/qdtrack/qdtrack_yolox_x_25e_bdd100k.py | 2 +- vis4d/zoo/vit/vit_small_imagenet.py | 2 +- vis4d/zoo/vit/vit_tiny_imagenet.py | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/vis4d/common/distributed.py b/vis4d/common/distributed.py index 7241c67c..8ba797b8 100644 --- a/vis4d/common/distributed.py +++ b/vis4d/common/distributed.py @@ -335,7 +335,7 @@ def reduce_mean(tensor: torch.Tensor) -> torch.Tensor: if not (dist.is_available() and dist.is_initialized()): return tensor tensor = tensor.clone() - dist.all_reduce(tensor.div_(dist.get_world_size()), op=dist.ReduceOp.SUM) + dist.all_reduce(tensor.div_(get_world_size()), op=dist.ReduceOp.SUM) return tensor diff --git a/vis4d/op/box/box2d.py b/vis4d/op/box/box2d.py index 3359c21e..906f8764 100644 --- a/vis4d/op/box/box2d.py +++ b/vis4d/op/box/box2d.py @@ -420,7 +420,7 @@ def multiclass_nms( labels = torch.arange(num_classes, dtype=torch.long, device=scores.device) labels = labels.view(1, -1).expand_as(scores) - bboxes = bboxes.view(-1, 4) + bboxes = bboxes.reshape(-1, 4) scores = scores.reshape(-1) labels = labels.reshape(-1) diff --git a/vis4d/zoo/bevformer/bevformer_base.py b/vis4d/zoo/bevformer/bevformer_base.py index c3120202..9b39d412 100644 --- a/vis4d/zoo/bevformer/bevformer_base.py +++ b/vis4d/zoo/bevformer/bevformer_base.py @@ -2,7 +2,7 @@ """BEVFormer base with ResNet-101-DCN backbone.""" from __future__ import annotations -import pytorch_lightning as pl +import lightning.pytorch as pl from torch.optim import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR diff --git a/vis4d/zoo/bevformer/bevformer_tiny.py b/vis4d/zoo/bevformer/bevformer_tiny.py index 94245518..cdc984bd 100644 --- a/vis4d/zoo/bevformer/bevformer_tiny.py +++ b/vis4d/zoo/bevformer/bevformer_tiny.py @@ -2,7 +2,7 @@ """BEVFormer tiny with ResNet-50 backbone.""" from __future__ import annotations -import pytorch_lightning as pl +import lightning.pytorch as pl from torch.optim import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR diff --git a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py index 6f685615..3abc1132 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py @@ -2,7 +2,7 @@ """CC-3DT with Faster-RCNN ResNet-101 detector using KF3D motion model.""" from __future__ import annotations -import pytorch_lightning as pl +import lightning.pytorch as pl from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR diff --git a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py index 1354b44a..2bf34a63 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py @@ -2,7 +2,7 @@ """CC-3DT with Faster-RCNN ResNet-50 detector using KF3D motion model.""" from __future__ import annotations -import pytorch_lightning as pl +import lightning.pytorch as pl from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR diff --git a/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py b/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py index 55d6eac9..163c3c19 100644 --- a/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py +++ b/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py @@ -2,7 +2,7 @@ """CC-3DT VeloLSTM for BEVFormer on nuScenes.""" from __future__ import annotations -import pytorch_lightning as pl +import lightning.pytorch as pl from torch.optim import Adam from torch.optim.lr_scheduler import MultiStepLR diff --git a/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py b/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py index 01a8dbe0..86568c69 100644 --- a/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py +++ b/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py @@ -2,7 +2,7 @@ """CC-3DT VeloLSTM on nuScenes.""" from __future__ import annotations -import pytorch_lightning as pl +import lightning.pytorch as pl from torch.optim import Adam from torch.optim.lr_scheduler import MultiStepLR diff --git a/vis4d/zoo/qdtrack/qdtrack_yolox_x_25e_bdd100k.py b/vis4d/zoo/qdtrack/qdtrack_yolox_x_25e_bdd100k.py index 0cfcbabd..01bbfa8d 100644 --- a/vis4d/zoo/qdtrack/qdtrack_yolox_x_25e_bdd100k.py +++ b/vis4d/zoo/qdtrack/qdtrack_yolox_x_25e_bdd100k.py @@ -2,7 +2,7 @@ """QDTrack with YOLOX-x on BDD100K.""" from __future__ import annotations -import pytorch_lightning as pl +import lightning.pytorch as pl from lightning.pytorch.callbacks import ModelCheckpoint from vis4d.config import class_config diff --git a/vis4d/zoo/vit/vit_small_imagenet.py b/vis4d/zoo/vit/vit_small_imagenet.py index 85ae78f0..7d3e1ace 100644 --- a/vis4d/zoo/vit/vit_small_imagenet.py +++ b/vis4d/zoo/vit/vit_small_imagenet.py @@ -2,7 +2,7 @@ """VIT ImageNet-1k training example.""" from __future__ import annotations -import pytorch_lightning as pl +import lightning.pytorch as pl from torch import nn from torch.optim import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR diff --git a/vis4d/zoo/vit/vit_tiny_imagenet.py b/vis4d/zoo/vit/vit_tiny_imagenet.py index 0d7f8c58..1ab99401 100644 --- a/vis4d/zoo/vit/vit_tiny_imagenet.py +++ b/vis4d/zoo/vit/vit_tiny_imagenet.py @@ -2,7 +2,7 @@ """VIT ImageNet-1k training example.""" from __future__ import annotations -import pytorch_lightning as pl +import lightning.pytorch as pl from torch import nn from torch.optim import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR From 91b2fca47f854092322d2a689a1a3e5384adb28c Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 10 Jul 2024 14:48:02 +0200 Subject: [PATCH 02/50] fix: Fix lint. --- requirements/install.txt | 2 +- requirements/viewer.txt | 1 + vis4d/data/datasets/util.py | 5 +++-- vis4d/vis/image/canvas/pillow_backend.py | 7 +++++-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/requirements/install.txt b/requirements/install.txt index c1f6cfe5..8f47770e 100644 --- a/requirements/install.txt +++ b/requirements/install.txt @@ -7,7 +7,7 @@ h5py jsonargparse[signatures] lightning ml_collections==0.1.1 # Config interface. Need exact version since we overwrite internal functions -numpy>=1.21.0 +numpy>=1.21.0,<2.0.0 opencv-python pandas pillow diff --git a/requirements/viewer.txt b/requirements/viewer.txt index 6c0ba1c1..2cf81fd6 100644 --- a/requirements/viewer.txt +++ b/requirements/viewer.txt @@ -1 +1,2 @@ open3d +matplotlib>3.9 diff --git a/vis4d/data/datasets/util.py b/vis4d/data/datasets/util.py index b4ffbcb9..aeb377ff 100644 --- a/vis4d/data/datasets/util.py +++ b/vis4d/data/datasets/util.py @@ -54,8 +54,9 @@ def im_decode( "L", }, f"{mode} not supported for image decoding!" if backend == "PIL": - pil_img = Image.open(BytesIO(bytearray(im_bytes))) - pil_img = ImageOps.exif_transpose(pil_img) # type: ignore + pil_img_file = Image.open(BytesIO(bytearray(im_bytes))) + pil_img = ImageOps.exif_transpose(pil_img_file) + assert pil_img is not None, "Image could not be loaded!" if pil_img.mode == "L": # pragma: no cover if mode == "L": img: NDArrayUI8 = np.array(pil_img)[..., None] diff --git a/vis4d/vis/image/canvas/pillow_backend.py b/vis4d/vis/image/canvas/pillow_backend.py index 0dbb7c70..05bb0252 100644 --- a/vis4d/vis/image/canvas/pillow_backend.py +++ b/vis4d/vis/image/canvas/pillow_backend.py @@ -45,11 +45,14 @@ def create_canvas( Raises: ValueError: If the canvas is not initialized. """ - if image is None and image_hw is None: - raise ValueError("Image or Image Shapes required to create canvas") if image_hw is not None: white_image = np.ones([*image_hw, 3]) * 255 image = white_image.astype(np.uint8) + else: + assert ( + image is not None + ), "Image or Image Shapes required to create canvas" + self._image = Image.fromarray(image) self._image_draw = ImageDraw.Draw(self._image) From 96871a50dbd2caad9bdcf86d9f2d6487f430d974 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Fri, 26 Jul 2024 15:41:47 +0200 Subject: [PATCH 03/50] feat: Add VIS flag and update transformer related code. --- .../vis/image/bounding_box_visualizer_test.py | 4 +- vis4d/common/util.py | 2 +- vis4d/engine/experiment.py | 16 ++- vis4d/engine/flag.py | 6 + vis4d/engine/run.py | 12 +- vis4d/op/layer/attention.py | 7 +- vis4d/op/layer/ms_deform_attn.py | 24 +++- vis4d/op/layer/positional_encoding.py | 120 +++++------------- vis4d/op/layer/transformer.py | 2 + vis4d/pl/run.py | 26 +++- vis4d/vis/image/bounding_box_visualizer.py | 12 +- 11 files changed, 129 insertions(+), 102 deletions(-) diff --git a/tests/vis/image/bounding_box_visualizer_test.py b/tests/vis/image/bounding_box_visualizer_test.py index 7626409e..fda92e23 100644 --- a/tests/vis/image/bounding_box_visualizer_test.py +++ b/tests/vis/image/bounding_box_visualizer_test.py @@ -32,8 +32,10 @@ def setUp(self) -> None: self.scores: list[NDArrayF64] = testcase_gt["scores"] self.tracks = [np.arange(len(b)) for b in self.boxes] + cat_mapping = {v: k for k, v in COCO_COLOR_MAPPING.items()} + self.vis = BoundingBoxVisualizer( - n_colors=20, class_id_mapping=COCO_COLOR_MAPPING, vis_freq=1 + n_colors=20, cat_mapping=cat_mapping, vis_freq=1 ) def tearDown(self) -> None: diff --git a/vis4d/common/util.py b/vis4d/common/util.py index 75d51ce4..38dca5d7 100644 --- a/vis4d/common/util.py +++ b/vis4d/common/util.py @@ -73,7 +73,7 @@ def set_tf32(use_tf32: bool, precision: str) -> None: # pragma: no cover def init_random_seed() -> int: """Initialize random seed for the experiment.""" - return np.random.randint(2**31) + return int(np.random.randint(2**31)) def set_random_seed(seed: int, deterministic: bool = False) -> None: diff --git a/vis4d/engine/experiment.py b/vis4d/engine/experiment.py index a0781ab1..68c05046 100644 --- a/vis4d/engine/experiment.py +++ b/vis4d/engine/experiment.py @@ -33,6 +33,7 @@ from vis4d.common.util import init_random_seed, set_random_seed, set_tf32 from vis4d.config import instantiate_classes from vis4d.config.typing import ExperimentConfig +from vis4d.engine.callbacks import VisualizerCallback from .optim import set_up_optimizers from .parser import pprints_config @@ -87,6 +88,7 @@ def run_experiment( use_slurm: bool = False, ckpt_path: str | None = None, resume: bool = False, + vis: bool = False, ) -> None: """Entry point for running a single experiment. @@ -99,6 +101,7 @@ def run_experiment( required environment variables for slurm. ckpt_path (str | None): Path to a checkpoint to load. resume (bool): If set, resume training from the checkpoint. + vis (bool): If set, enable visualizer callback. Raises: ValueError: If `mode` is not `fit` or `test`. @@ -141,7 +144,18 @@ def run_experiment( ) # Callbacks - callbacks = [instantiate_classes(cb) for cb in config.callbacks] + callbacks = [] + for cb in config.callbacks: + callback = instantiate_classes(cb) + + if not vis and isinstance(callback, VisualizerCallback): + rank_zero_info( + "VisualizerCallback is not used. " + "Please set --vis=True to use it." + ) + continue + + callbacks.append(callback) # Setup DDP & seed seed = init_random_seed() if config.seed == -1 else config.seed diff --git a/vis4d/engine/flag.py b/vis4d/engine/flag.py index f127f190..fa4fe376 100644 --- a/vis4d/engine/flag.py +++ b/vis4d/engine/flag.py @@ -21,6 +21,11 @@ _SLURM = flags.DEFINE_bool( "slurm", default=False, help="If set, setup slurm running jobs." ) +_VIS = flags.DEFINE_bool( + "vis", + default=False, + help="If set, running visualization using visualizer callback.", +) __all__ = [ @@ -31,4 +36,5 @@ "_SHOW_CONFIG", "_SWEEP", "_SLURM", + "_VIS", ] diff --git a/vis4d/engine/run.py b/vis4d/engine/run.py index c0033ab4..2e3a95c3 100644 --- a/vis4d/engine/run.py +++ b/vis4d/engine/run.py @@ -11,7 +11,16 @@ from vis4d.config.typing import ExperimentConfig from .experiment import run_experiment -from .flag import _CKPT, _CONFIG, _GPUS, _RESUME, _SHOW_CONFIG, _SLURM, _SWEEP +from .flag import ( + _CKPT, + _CONFIG, + _GPUS, + _RESUME, + _SHOW_CONFIG, + _SLURM, + _SWEEP, + _VIS, +) def main(argv: ArgsType) -> None: @@ -68,6 +77,7 @@ def main(argv: ArgsType) -> None: _SLURM.value, _CKPT.value, _RESUME.value, + _VIS.value, ) diff --git a/vis4d/op/layer/attention.py b/vis4d/op/layer/attention.py index 4a539ee3..31b09d51 100644 --- a/vis4d/op/layer/attention.py +++ b/vis4d/op/layer/attention.py @@ -120,6 +120,7 @@ def __init__( super().__init__() self.batch_first = batch_first self.embed_dims = embed_dims + self.num_heads = num_heads self.attn = nn.MultiheadAttention( embed_dims, num_heads, dropout=attn_drop, **kwargs @@ -193,8 +194,10 @@ def forward( key_pos = query_pos else: rank_zero_warn( - "position encoding of key is" - + f"missing in {self.__class__.__name__}." + f"Position encoding of key in {self.__class__.__name__}" + + "is missing, and positional encodeing of query has " + + "has different shape and cannot be usde for key. " + + "It it is not desired, please provide key_pos." ) if query_pos is not None: diff --git a/vis4d/op/layer/ms_deform_attn.py b/vis4d/op/layer/ms_deform_attn.py index 9acb0556..3d3589c2 100644 --- a/vis4d/op/layer/ms_deform_attn.py +++ b/vis4d/op/layer/ms_deform_attn.py @@ -223,12 +223,15 @@ def __init__( is_power_of_2(d_model // n_heads) self.d_model = d_model - self.embed_dims = d_model self.n_levels = n_levels self.n_heads = n_heads self.n_points = n_points self.im2col_step = im2col_step + # Aligned Attributes to MHA + self.embed_dims = d_model + self.num_heads = n_heads + self.sampling_offsets = nn.Linear( d_model, n_heads * n_levels * n_points * 2 ) @@ -359,3 +362,22 @@ def forward( output = self.output_proj(output) return output + + def __call__( + self, + query: Tensor, + reference_points: Tensor, + input_flatten: Tensor, + input_spatial_shapes: Tensor, + input_level_start_index: Tensor, + input_padding_mask: Tensor | None = None, + ) -> Tensor: + """Type definition for call implementation.""" + return self._call_impl( + query, + reference_points, + input_flatten, + input_spatial_shapes, + input_level_start_index, + input_padding_mask, + ) diff --git a/vis4d/op/layer/positional_encoding.py b/vis4d/op/layer/positional_encoding.py index c931c4b5..37ccfa7c 100644 --- a/vis4d/op/layer/positional_encoding.py +++ b/vis4d/op/layer/positional_encoding.py @@ -3,6 +3,8 @@ Modified from mmdetection (https://github.com/open-mmlab/mmdetection). """ +from __future__ import annotations + import math import torch @@ -59,24 +61,45 @@ def __init__( self.eps = eps self.offset = offset - def forward(self, mask: Tensor) -> Tensor: + def forward( + self, mask: Tensor | None, inputs: Tensor | None = None + ) -> Tensor: """Forward function for `SinePositionalEncoding`. Args: - mask (Tensor): ByteTensor mask. Non-zero values representing + mask (Tensor | None): ByteTensor mask. Non-zero values representing ignored positions, while zero values means valid positions - for this image. Shape [bs, h, w]. + for this image. Shape [bs, h, w]. If None, it means single + image or batch image with no padding. + inputs (Tensor | None): The input tensor. It mask is None, this + input tensor is required to get the shape of the input image. Returns: pos (Tensor): Returned position embedding with shape [bs, num_feats*2, h, w]. """ - # For convenience of exporting to ONNX, it's required to convert - # `masks` from bool to int. - mask = mask.to(torch.int) - not_mask = 1 - mask # logical_not - y_embed = not_mask.cumsum(1, dtype=torch.float32) - x_embed = not_mask.cumsum(2, dtype=torch.float32) + if mask is not None: + # For convenience of exporting to ONNX, it's required to convert + # `masks` from bool to int. + mask = mask.to(torch.int) + b, h, w = mask.size() + device = mask.device + not_mask = 1 - mask # logical_not + y_embed = not_mask.cumsum(1, dtype=torch.float32) + x_embed = not_mask.cumsum(2, dtype=torch.float32) + else: + # single image or batch image with no padding + assert isinstance(inputs, Tensor) + b, _, h, w = inputs.shape + device = inputs.device + x_embed = torch.arange( + 1, w + 1, dtype=torch.float32, device=device + ) + x_embed = x_embed.view(1, 1, -1).repeat(b, h, 1) + y_embed = torch.arange( + 1, h + 1, dtype=torch.float32, device=device + ) + y_embed = y_embed.view(1, -1, 1).repeat(b, 1, w) if self.normalize: y_embed = ( (y_embed + self.offset) @@ -89,13 +112,13 @@ def forward(self, mask: Tensor) -> Tensor: * self.scale ) dim_t = torch.arange( - self.num_feats, dtype=torch.float32, device=mask.device + self.num_feats, dtype=torch.float32, device=device ) dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_feats) pos_x = x_embed[:, :, :, None] / dim_t pos_y = y_embed[:, :, :, None] / dim_t # use `view` instead of `flatten` for dynamically exporting to ONNX - b, h, w = mask.size() + pos_x = torch.stack( (pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4 ).view(b, h, w, -1) @@ -167,78 +190,3 @@ def forward(self, mask: Tensor) -> Tensor: .repeat(mask.shape[0], 1, 1, 1) ) return pos - - -class SinePositionalEncoding3D(SinePositionalEncoding): - """3D Position encoding with sine and cosine functions.""" - - def forward(self, mask: Tensor) -> Tensor: - """Forward function for `SinePositionalEncoding3D`. - - Args: - mask (Tensor): ByteTensor mask. Non-zero values representing - ignored positions, while zero values means valid positions - for this image. Shape [bs, t, h, w]. - - Returns: - pos (Tensor): Returned position embedding with shape - [bs, num_feats*2, h, w]. - """ - assert mask.dim() == 4, ( - f"{mask.shape} should be a 4-dimensional Tensor," - f" got {mask.dim()}-dimensional Tensor instead " - ) - # For convenience of exporting to ONNX, it's required to convert - # `masks` from bool to int. - mask = mask.to(torch.int) - not_mask = 1 - mask # logical_not - z_embed = not_mask.cumsum(1, dtype=torch.float32) - y_embed = not_mask.cumsum(2, dtype=torch.float32) - x_embed = not_mask.cumsum(3, dtype=torch.float32) - if self.normalize: - z_embed = ( - (z_embed + self.offset) - / (z_embed[:, -1:, :, :] + self.eps) - * self.scale - ) - y_embed = ( - (y_embed + self.offset) - / (y_embed[:, :, -1:, :] + self.eps) - * self.scale - ) - x_embed = ( - (x_embed + self.offset) - / (x_embed[:, :, :, -1:] + self.eps) - * self.scale - ) - dim_t = torch.arange( - self.num_feats, dtype=torch.float32, device=mask.device - ) - dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_feats) - - dim_t_z = torch.arange( - (self.num_feats * 2), dtype=torch.float32, device=mask.device - ) - dim_t_z = self.temperature ** ( - 2 * (dim_t_z // 2) / (self.num_feats * 2) - ) - - pos_x = x_embed[:, :, :, :, None] / dim_t - pos_y = y_embed[:, :, :, :, None] / dim_t - pos_z = z_embed[:, :, :, :, None] / dim_t_z - # use `view` instead of `flatten` for dynamically exporting to ONNX - b, t, h, w = mask.size() - pos_x = torch.stack( - (pos_x[:, :, :, :, 0::2].sin(), pos_x[:, :, :, :, 1::2].cos()), - dim=5, - ).view(b, t, h, w, -1) - pos_y = torch.stack( - (pos_y[:, :, :, :, 0::2].sin(), pos_y[:, :, :, :, 1::2].cos()), - dim=5, - ).view(b, t, h, w, -1) - pos_z = torch.stack( - (pos_z[:, :, :, :, 0::2].sin(), pos_z[:, :, :, :, 1::2].cos()), - dim=5, - ).view(b, t, h, w, -1) - pos = (torch.cat((pos_y, pos_x), dim=4) + pos_z).permute(0, 1, 4, 2, 3) - return pos diff --git a/vis4d/op/layer/transformer.py b/vis4d/op/layer/transformer.py index 08c7950d..2600ade3 100644 --- a/vis4d/op/layer/transformer.py +++ b/vis4d/op/layer/transformer.py @@ -212,6 +212,8 @@ def __init__( LayerScale. Default: 0.0 """ super().__init__() + self.embed_dims = embed_dims + layers: list[nn.Module] = [] in_channels = embed_dims for _ in range(num_fcs - 1): diff --git a/vis4d/pl/run.py b/vis4d/pl/run.py index e2f3f1b3..574f3572 100644 --- a/vis4d/pl/run.py +++ b/vis4d/pl/run.py @@ -16,8 +16,15 @@ from vis4d.common.util import set_tf32 from vis4d.config import instantiate_classes from vis4d.config.typing import ExperimentConfig -from vis4d.engine.callbacks import CheckpointCallback -from vis4d.engine.flag import _CKPT, _CONFIG, _GPUS, _RESUME, _SHOW_CONFIG +from vis4d.engine.callbacks import CheckpointCallback, VisualizerCallback +from vis4d.engine.flag import ( + _CKPT, + _CONFIG, + _GPUS, + _RESUME, + _SHOW_CONFIG, + _VIS, +) from vis4d.engine.parser import pprints_config from vis4d.pl.callbacks import CallbackWrapper, LRSchedulerCallback from vis4d.pl.data_module import DataModule @@ -83,12 +90,23 @@ def main(argv: ArgsType) -> None: test_data_connector = None # Callbacks + vis = _VIS.value + callbacks: list[Callback] = [] for cb in config.callbacks: callback = instantiate_classes(cb) # Skip checkpoint callback to use PL ModelCheckpoint - if not isinstance(callback, CheckpointCallback): - callbacks.append(CallbackWrapper(callback)) + if isinstance(callback, CheckpointCallback): + continue + + if not vis and isinstance(callback, VisualizerCallback): + rank_zero_info( + "VisualizerCallback is not used. " + "Please set --vis=True to use it." + ) + continue + + callbacks.append(CallbackWrapper(callback)) if "pl_callbacks" in config: pl_callbacks = [instantiate_classes(cb) for cb in config.pl_callbacks] diff --git a/vis4d/vis/image/bounding_box_visualizer.py b/vis4d/vis/image/bounding_box_visualizer.py index 72ece8d8..f9dc88c4 100644 --- a/vis4d/vis/image/bounding_box_visualizer.py +++ b/vis4d/vis/image/bounding_box_visualizer.py @@ -45,7 +45,7 @@ def __init__( self, *args: ArgsType, n_colors: int = 50, - class_id_mapping: dict[int, str] | None = None, + cat_mapping: dict[str, int] | None = None, file_type: str = "png", canvas: CanvasBackend = PillowCanvasBackend(), viewer: ImageViewerBackend = MatplotlibImageViewer(), @@ -55,9 +55,9 @@ def __init__( Args: n_colors (int): How many colors should be used for the internal - color map - class_id_mapping (dict[int, str]): Mapping from class id to - human readable name + color map + cat_mapping (dict[str, int]): Mapping from class names to class + ids. Defaults to None. file_type (str): Desired file type canvas (CanvasBackend): Backend that is used to draw on images viewer (ImageViewerBackend): Backend that is used show images @@ -66,7 +66,9 @@ def __init__( self._samples: list[DataSample] = [] self.color_palette = generate_color_map(n_colors) self.class_id_mapping = ( - class_id_mapping if class_id_mapping is not None else {} + {v: k for k, v in cat_mapping.items()} + if cat_mapping is not None + else {} ) self.file_type = file_type self.canvas = canvas From c834f28dfd2eceb65fa8c9bce1255a90d2ad5b08 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Fri, 26 Jul 2024 17:13:57 +0200 Subject: [PATCH 04/50] fix: Fix mypy for PyTorch 2.4.0 --- docs/source/user_guide/faster_rcnn_example.py | 2 +- tests/engine/callbacks/checkpoint_test.py | 2 +- tests/engine/optim/scheduler_test.py | 4 ++-- tests/model/detect/mask_rcnn_test.py | 4 ++-- tests/model/detect/retinanet_test.py | 4 ++-- tests/model/seg/fcn_resnet_test.py | 4 ++-- tests/model/seg/semantic_fpn_test.py | 4 ++-- tests/pl/trainer_test.py | 4 ++-- vis4d/data/transforms/resize.py | 2 +- vis4d/engine/optim/scheduler.py | 16 ++++++++-------- vis4d/zoo/base/models/yolox.py | 2 +- .../faster_rcnn/faster_rcnn_r50_1x_bdd100k.py | 2 +- .../faster_rcnn/faster_rcnn_r50_3x_bdd100k.py | 2 +- .../mask_rcnn/mask_rcnn_r50_1x_bdd100k.py | 2 +- .../mask_rcnn/mask_rcnn_r50_3x_bdd100k.py | 2 +- .../mask_rcnn/mask_rcnn_r50_5x_bdd100k.py | 2 +- .../qdtrack/qdtrack_frcnn_r50_fpn_1x_bdd100k.py | 2 +- .../semantic_fpn_r101_80k_bdd100k.py | 2 +- .../semantic_fpn/semantic_fpn_r50_40k_bdd100k.py | 2 +- .../semantic_fpn/semantic_fpn_r50_80k_bdd100k.py | 2 +- vis4d/zoo/bevformer/bevformer_base.py | 2 +- vis4d/zoo/bevformer/bevformer_tiny.py | 2 +- .../cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py | 2 +- .../cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py | 2 +- .../cc_3dt/velo_lstm_bevformer_base_100e_nusc.py | 2 +- .../cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py | 2 +- vis4d/zoo/faster_rcnn/faster_rcnn_coco.py | 2 +- vis4d/zoo/fcn_resnet/fcn_resnet_coco.py | 2 +- vis4d/zoo/mask_rcnn/mask_rcnn_coco.py | 2 +- .../qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py | 2 +- vis4d/zoo/retinanet/retinanet_coco.py | 2 +- .../faster_rcnn/faster_rcnn_r50_12e_shift.py | 2 +- .../faster_rcnn/faster_rcnn_r50_36e_shift.py | 2 +- .../faster_rcnn_r50_6e_shift_all_domains.py | 2 +- .../shift/mask_rcnn/mask_rcnn_r50_12e_shift.py | 2 +- .../shift/mask_rcnn/mask_rcnn_r50_36e_shift.py | 2 +- .../mask_rcnn_r50_6e_shift_all_domains.py | 2 +- .../semantic_fpn/semantic_fpn_r50_160k_shift.py | 4 ++-- .../semantic_fpn_r50_160k_shift_all_domains.py | 4 ++-- .../semantic_fpn/semantic_fpn_r50_40k_shift.py | 4 ++-- .../semantic_fpn_r50_40k_shift_all_domains.py | 4 ++-- vis4d/zoo/vit/vit_small_imagenet.py | 2 +- vis4d/zoo/vit/vit_tiny_imagenet.py | 2 +- 43 files changed, 60 insertions(+), 60 deletions(-) diff --git a/docs/source/user_guide/faster_rcnn_example.py b/docs/source/user_guide/faster_rcnn_example.py index b639930d..4d5cab51 100644 --- a/docs/source/user_guide/faster_rcnn_example.py +++ b/docs/source/user_guide/faster_rcnn_example.py @@ -6,7 +6,7 @@ import lightning.pytorch as pl import numpy as np -from torch.optim import SGD +from torch.optim.sgd import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR from vis4d.config import class_config diff --git a/tests/engine/callbacks/checkpoint_test.py b/tests/engine/callbacks/checkpoint_test.py index 560a433f..0df0132c 100644 --- a/tests/engine/callbacks/checkpoint_test.py +++ b/tests/engine/callbacks/checkpoint_test.py @@ -4,7 +4,7 @@ import tempfile import unittest -from torch.optim import SGD +from torch.optim.sgd import SGD from tests.util import MOCKLOSS, MockModel from vis4d.config import class_config diff --git a/tests/engine/optim/scheduler_test.py b/tests/engine/optim/scheduler_test.py index 226e8eb4..e94cf7a5 100644 --- a/tests/engine/optim/scheduler_test.py +++ b/tests/engine/optim/scheduler_test.py @@ -5,8 +5,8 @@ import torch import torch.nn.functional as F -from torch import optim from torch.optim.lr_scheduler import LRScheduler +from torch.optim.sgd import SGD from torch.testing import assert_close from vis4d.engine.optim.scheduler import ConstantLR, PolyLR, QuadraticLRWarmup @@ -68,7 +68,7 @@ def setUp(self) -> None: model = ToyModel() self.lr = 0.05 self.l2_mult = 10 - self.optimizer = optim.SGD( + self.optimizer = SGD( [ {"params": model.conv1.parameters()}, { diff --git a/tests/model/detect/mask_rcnn_test.py b/tests/model/detect/mask_rcnn_test.py index 4b5ff954..b830bbcf 100644 --- a/tests/model/detect/mask_rcnn_test.py +++ b/tests/model/detect/mask_rcnn_test.py @@ -3,7 +3,7 @@ import unittest import torch -from torch import optim +from torch.optim.sgd import SGD from tests.util import get_test_data, get_test_file from vis4d.common.ckpt import load_model_checkpoint @@ -120,7 +120,7 @@ def test_train(self): ] ) - optimizer = optim.SGD(mask_rcnn.parameters(), lr=0.001, momentum=0.9) + optimizer = SGD(mask_rcnn.parameters(), lr=0.001, momentum=0.9) dataset = COCO(get_test_data("coco_test"), split="train") train_loader = get_train_dataloader(dataset, 2, (256, 256)) diff --git a/tests/model/detect/retinanet_test.py b/tests/model/detect/retinanet_test.py index 58f34645..dc878e7e 100644 --- a/tests/model/detect/retinanet_test.py +++ b/tests/model/detect/retinanet_test.py @@ -3,7 +3,7 @@ import unittest import torch -from torch import optim +from torch.optim.sgd import SGD from tests.util import get_test_data, get_test_file from vis4d.common.ckpt import load_model_checkpoint @@ -75,7 +75,7 @@ def test_train(self) -> None: retina_net.retinanet_head.box_sampler, ) - optimizer = optim.SGD(retina_net.parameters(), lr=0.001, momentum=0.9) + optimizer = SGD(retina_net.parameters(), lr=0.001, momentum=0.9) dataset = COCO(get_test_data("coco_test"), split="train") train_loader = get_train_dataloader(dataset, 2, (256, 256)) diff --git a/tests/model/seg/fcn_resnet_test.py b/tests/model/seg/fcn_resnet_test.py index dc1a2f98..4a9f90fc 100644 --- a/tests/model/seg/fcn_resnet_test.py +++ b/tests/model/seg/fcn_resnet_test.py @@ -5,7 +5,7 @@ import unittest import torch -from torch import optim +from torch.optim.sgd import SGD from tests.util import get_test_data, get_test_file from vis4d.common.ckpt import load_model_checkpoint @@ -46,7 +46,7 @@ def test_train(self) -> None: """Test FCNResNet training.""" model = FCNResNet(base_model="resnet50", resize=(64, 64)) loss_fn = MultiLevelSegLoss(feature_idx=(4, 5), weights=[0.5, 1]) - optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9) + optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9) dataset = COCO( get_test_data("coco_test"), split="train", use_pascal_voc_cats=True ) diff --git a/tests/model/seg/semantic_fpn_test.py b/tests/model/seg/semantic_fpn_test.py index 53a1c4de..19932f19 100644 --- a/tests/model/seg/semantic_fpn_test.py +++ b/tests/model/seg/semantic_fpn_test.py @@ -5,7 +5,7 @@ import unittest import torch -from torch import optim +from torch.optim.sgd import SGD from tests.util import get_test_data, get_test_file from vis4d.data.const import CommonKeys as K @@ -59,7 +59,7 @@ def test_train(self) -> None: """Test SemanticFPN training.""" model = SemanticFPN(num_classes=21) loss_fn = SegCrossEntropyLoss() - optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9) + optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9) train_loader = get_train_dataloader(self.dataset, 2) model.train() diff --git a/tests/pl/trainer_test.py b/tests/pl/trainer_test.py index 2608983f..fb963a63 100644 --- a/tests/pl/trainer_test.py +++ b/tests/pl/trainer_test.py @@ -7,7 +7,7 @@ import unittest from ml_collections import ConfigDict -from torch import optim +from torch.optim.sgd import SGD from torch.utils.data import DataLoader, Dataset from tests.util import get_test_data @@ -85,7 +85,7 @@ def get_training_module(model_cfg: ConfigDict): } ) - optimizer_cfg = get_optimizer_cfg(class_config(optim.SGD, lr=0.01)) + optimizer_cfg = get_optimizer_cfg(class_config(SGD, lr=0.01)) return TrainingModule( model_cfg=model_cfg, optimizers_cfg=[optimizer_cfg], diff --git a/vis4d/data/transforms/resize.py b/vis4d/data/transforms/resize.py index c613bc0e..f157bd88 100644 --- a/vis4d/data/transforms/resize.py +++ b/vis4d/data/transforms/resize.py @@ -309,7 +309,7 @@ def __call__( optical_flow_[:, :, 0] *= scale_factor[0] optical_flow_[:, :, 1] *= scale_factor[1] optical_flows[i] = optical_flow_.numpy() - return optical_flow_.numpy() + return optical_flows @Transform( diff --git a/vis4d/engine/optim/scheduler.py b/vis4d/engine/optim/scheduler.py index 2e1e6337..496e05f0 100644 --- a/vis4d/engine/optim/scheduler.py +++ b/vis4d/engine/optim/scheduler.py @@ -5,8 +5,8 @@ from typing import TypedDict -from torch.optim import Optimizer from torch.optim.lr_scheduler import LRScheduler +from torch.optim.optimizer import Optimizer from vis4d.common.typing import DictStrAny from vis4d.config import copy_and_resolve_references, instantiate_classes @@ -80,10 +80,10 @@ def _instantiate_lr_scheduler( def get_lr(self) -> list[float]: # type: ignore """Get current learning rate.""" - return [ - lr_scheduler["scheduler"].get_lr() - for lr_scheduler in self.lr_schedulers.values() - ] + lr = [] + for lr_scheduler in self.lr_schedulers.values(): + lr.extend(lr_scheduler["scheduler"].get_lr()) + return lr def state_dict(self) -> dict[int, DictStrAny]: # type: ignore """Get state dict.""" @@ -163,7 +163,7 @@ def __init__( def get_lr(self) -> list[float]: # type: ignore """Compute current learning rate.""" - step_count = self._step_count - 1 # type: ignore + step_count = self._step_count - 1 if step_count == 0: return [ group["lr"] * self.factor @@ -213,7 +213,7 @@ def __init__( def get_lr(self) -> list[float]: # type: ignore """Compute current learning rate.""" - step_count = self._step_count - 1 # type: ignore + step_count = self._step_count - 1 if step_count == 0 or step_count > self.max_steps: return [group["lr"] for group in self.optimizer.param_groups] decay_factor = ( @@ -247,7 +247,7 @@ def __init__( def get_lr(self) -> list[float]: # type: ignore """Compute current learning rate.""" - step_count = self._step_count - 1 # type: ignore + step_count = self._step_count - 1 if step_count >= self.max_steps: return self.base_lrs factors = [ diff --git a/vis4d/zoo/base/models/yolox.py b/vis4d/zoo/base/models/yolox.py index 044650de..eadc3bc1 100644 --- a/vis4d/zoo/base/models/yolox.py +++ b/vis4d/zoo/base/models/yolox.py @@ -3,8 +3,8 @@ from __future__ import annotations from ml_collections import ConfigDict, FieldReference -from torch.optim import SGD from torch.optim.lr_scheduler import CosineAnnealingLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import OptimizerConfig diff --git a/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_1x_bdd100k.py b/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_1x_bdd100k.py index d9219669..ffe7f884 100644 --- a/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_1x_bdd100k.py +++ b/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_1x_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_3x_bdd100k.py b/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_3x_bdd100k.py index 7abc3a7c..dafee957 100644 --- a/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_3x_bdd100k.py +++ b/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_3x_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_1x_bdd100k.py b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_1x_bdd100k.py index 8fc5385d..d52e07f2 100644 --- a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_1x_bdd100k.py +++ b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_1x_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_3x_bdd100k.py b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_3x_bdd100k.py index 9a709d21..719eb1d0 100644 --- a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_3x_bdd100k.py +++ b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_3x_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_5x_bdd100k.py b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_5x_bdd100k.py index 9c6dec31..8aaf9431 100644 --- a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_5x_bdd100k.py +++ b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_5x_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/bdd100k/qdtrack/qdtrack_frcnn_r50_fpn_1x_bdd100k.py b/vis4d/zoo/bdd100k/qdtrack/qdtrack_frcnn_r50_fpn_1x_bdd100k.py index 9b047d2d..d2af3037 100644 --- a/vis4d/zoo/bdd100k/qdtrack/qdtrack_frcnn_r50_fpn_1x_bdd100k.py +++ b/vis4d/zoo/bdd100k/qdtrack/qdtrack_frcnn_r50_fpn_1x_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r101_80k_bdd100k.py b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r101_80k_bdd100k.py index db45092d..12510ae7 100644 --- a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r101_80k_bdd100k.py +++ b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r101_80k_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_40k_bdd100k.py b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_40k_bdd100k.py index deb8f78f..938c004d 100644 --- a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_40k_bdd100k.py +++ b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_40k_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_80k_bdd100k.py b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_80k_bdd100k.py index 06b95cd3..53c29ba3 100644 --- a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_80k_bdd100k.py +++ b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_80k_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/bevformer/bevformer_base.py b/vis4d/zoo/bevformer/bevformer_base.py index 9b39d412..3d4cdd9f 100644 --- a/vis4d/zoo/bevformer/bevformer_base.py +++ b/vis4d/zoo/bevformer/bevformer_base.py @@ -3,7 +3,7 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import AdamW +from torch.optim.adamw import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR from vis4d.config import class_config diff --git a/vis4d/zoo/bevformer/bevformer_tiny.py b/vis4d/zoo/bevformer/bevformer_tiny.py index cdc984bd..1fba154f 100644 --- a/vis4d/zoo/bevformer/bevformer_tiny.py +++ b/vis4d/zoo/bevformer/bevformer_tiny.py @@ -3,7 +3,7 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import AdamW +from torch.optim.adamw import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR from vis4d.config import class_config diff --git a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py index 3abc1132..8bed245d 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py index 2bf34a63..c850866e 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py b/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py index 163c3c19..b7d26a38 100644 --- a/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py +++ b/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py @@ -3,7 +3,7 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import Adam +from torch.optim.adam import Adam from torch.optim.lr_scheduler import MultiStepLR from vis4d.config import class_config diff --git a/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py b/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py index 86568c69..aa51e6ea 100644 --- a/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py +++ b/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py @@ -3,7 +3,7 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import Adam +from torch.optim.adam import Adam from torch.optim.lr_scheduler import MultiStepLR from vis4d.config import class_config diff --git a/vis4d/zoo/faster_rcnn/faster_rcnn_coco.py b/vis4d/zoo/faster_rcnn/faster_rcnn_coco.py index 005bedb8..e0d6d66c 100644 --- a/vis4d/zoo/faster_rcnn/faster_rcnn_coco.py +++ b/vis4d/zoo/faster_rcnn/faster_rcnn_coco.py @@ -4,8 +4,8 @@ import lightning.pytorch as pl import numpy as np -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.sweep import grid_search diff --git a/vis4d/zoo/fcn_resnet/fcn_resnet_coco.py b/vis4d/zoo/fcn_resnet/fcn_resnet_coco.py index 1f177c3f..1baad29b 100644 --- a/vis4d/zoo/fcn_resnet/fcn_resnet_coco.py +++ b/vis4d/zoo/fcn_resnet/fcn_resnet_coco.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/mask_rcnn/mask_rcnn_coco.py b/vis4d/zoo/mask_rcnn/mask_rcnn_coco.py index 58816730..cc354626 100644 --- a/vis4d/zoo/mask_rcnn/mask_rcnn_coco.py +++ b/vis4d/zoo/mask_rcnn/mask_rcnn_coco.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/qdtrack/qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py b/vis4d/zoo/qdtrack/qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py index a49ca546..0a78a559 100644 --- a/vis4d/zoo/qdtrack/qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py +++ b/vis4d/zoo/qdtrack/qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py @@ -3,8 +3,8 @@ from __future__ import annotations from lightning.pytorch.callbacks import ModelCheckpoint -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/retinanet/retinanet_coco.py b/vis4d/zoo/retinanet/retinanet_coco.py index 5ab9d42d..6d26b54c 100644 --- a/vis4d/zoo/retinanet/retinanet_coco.py +++ b/vis4d/zoo/retinanet/retinanet_coco.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_12e_shift.py b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_12e_shift.py index 1e452102..785a14b4 100644 --- a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_12e_shift.py +++ b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_12e_shift.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_36e_shift.py b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_36e_shift.py index 946e1fb6..0dcc7b01 100644 --- a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_36e_shift.py +++ b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_36e_shift.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_6e_shift_all_domains.py b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_6e_shift_all_domains.py index 7d84cae7..d0d301df 100644 --- a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_6e_shift_all_domains.py +++ b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_6e_shift_all_domains.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters diff --git a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_12e_shift.py b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_12e_shift.py index d9da7bb4..51dca6df 100644 --- a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_12e_shift.py +++ b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_12e_shift.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import FieldConfigDict, class_config from vis4d.data.io.hdf5 import HDF5Backend diff --git a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_36e_shift.py b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_36e_shift.py index 40963714..939fe5f9 100644 --- a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_36e_shift.py +++ b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_36e_shift.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import FieldConfigDict, class_config from vis4d.data.io.hdf5 import HDF5Backend diff --git a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_6e_shift_all_domains.py b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_6e_shift_all_domains.py index 1f915339..3e461e3c 100644 --- a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_6e_shift_all_domains.py +++ b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_6e_shift_all_domains.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch.optim import SGD from torch.optim.lr_scheduler import LinearLR, MultiStepLR +from torch.optim.sgd import SGD from vis4d.config import FieldConfigDict, class_config from vis4d.data.io.hdf5 import HDF5Backend diff --git a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift.py b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift.py index 983d8fef..312a7672 100644 --- a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift.py +++ b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch import optim from torch.optim.lr_scheduler import LinearLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters @@ -106,7 +106,7 @@ def get_config() -> ExperimentConfig: config.optimizers = [ get_optimizer_cfg( optimizer=class_config( - optim.SGD, lr=params.lr, momentum=0.9, weight_decay=0.0005 + SGD, lr=params.lr, momentum=0.9, weight_decay=0.0005 ), lr_schedulers=[ get_lr_scheduler_cfg( diff --git a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift_all_domains.py b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift_all_domains.py index 6fa1b785..aacaf4a9 100644 --- a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift_all_domains.py +++ b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift_all_domains.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch import optim from torch.optim.lr_scheduler import LinearLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters @@ -108,7 +108,7 @@ def get_config() -> ExperimentConfig: config.optimizers = [ get_optimizer_cfg( optimizer=class_config( - optim.SGD, lr=params.lr, momentum=0.9, weight_decay=0.0005 + SGD, lr=params.lr, momentum=0.9, weight_decay=0.0005 ), lr_schedulers=[ get_lr_scheduler_cfg( diff --git a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift.py b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift.py index bc86ea10..5185df09 100644 --- a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift.py +++ b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch import optim from torch.optim.lr_scheduler import LinearLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters @@ -106,7 +106,7 @@ def get_config() -> ExperimentConfig: config.optimizers = [ get_optimizer_cfg( optimizer=class_config( - optim.SGD, lr=params.lr, momentum=0.9, weight_decay=0.0005 + SGD, lr=params.lr, momentum=0.9, weight_decay=0.0005 ), lr_schedulers=[ get_lr_scheduler_cfg( diff --git a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift_all_domains.py b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift_all_domains.py index 8a6f4095..e1cea254 100644 --- a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift_all_domains.py +++ b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift_all_domains.py @@ -3,8 +3,8 @@ from __future__ import annotations import lightning.pytorch as pl -from torch import optim from torch.optim.lr_scheduler import LinearLR +from torch.optim.sgd import SGD from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig, ExperimentParameters @@ -106,7 +106,7 @@ def get_config() -> ExperimentConfig: config.optimizers = [ get_optimizer_cfg( optimizer=class_config( - optim.SGD, lr=params.lr, momentum=0.9, weight_decay=0.0005 + SGD, lr=params.lr, momentum=0.9, weight_decay=0.0005 ), lr_schedulers=[ get_lr_scheduler_cfg( diff --git a/vis4d/zoo/vit/vit_small_imagenet.py b/vis4d/zoo/vit/vit_small_imagenet.py index 7d3e1ace..92b4ac81 100644 --- a/vis4d/zoo/vit/vit_small_imagenet.py +++ b/vis4d/zoo/vit/vit_small_imagenet.py @@ -4,7 +4,7 @@ import lightning.pytorch as pl from torch import nn -from torch.optim import AdamW +from torch.optim.adamw import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR from vis4d.config import class_config diff --git a/vis4d/zoo/vit/vit_tiny_imagenet.py b/vis4d/zoo/vit/vit_tiny_imagenet.py index 1ab99401..d915ca17 100644 --- a/vis4d/zoo/vit/vit_tiny_imagenet.py +++ b/vis4d/zoo/vit/vit_tiny_imagenet.py @@ -4,7 +4,7 @@ import lightning.pytorch as pl from torch import nn -from torch.optim import AdamW +from torch.optim.adamw import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR from vis4d.config import class_config From 456e3daf2ff958d3cb2b983915121363f27b56ad Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 7 Aug 2024 15:56:05 +0200 Subject: [PATCH 05/50] feat: Add compute FLOPs flag. --- vis4d/common/ckpt.py | 4 +++- vis4d/pl/run.py | 1 + vis4d/zoo/base/runtime.py | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/vis4d/common/ckpt.py b/vis4d/common/ckpt.py index fdd5b6e4..c4ad64b4 100644 --- a/vis4d/common/ckpt.py +++ b/vis4d/common/ckpt.py @@ -205,7 +205,9 @@ def load_from_local( filename = osp.expanduser(filename) if not osp.isfile(filename): raise FileNotFoundError(f"{filename} can not be found.") - checkpoint = torch.load(filename, map_location=map_location) + checkpoint = torch.load( + filename, weights_only=True, map_location=map_location + ) return checkpoint diff --git a/vis4d/pl/run.py b/vis4d/pl/run.py index 574f3572..bfa43ab1 100644 --- a/vis4d/pl/run.py +++ b/vis4d/pl/run.py @@ -155,6 +155,7 @@ def main(argv: ArgsType) -> None: hyper_params, config.seed, ckpt_path if not resume else None, + config.compute_flops, ) data_module = DataModule(config.data) diff --git a/vis4d/zoo/base/runtime.py b/vis4d/zoo/base/runtime.py index 65e842f9..c457638c 100644 --- a/vis4d/zoo/base/runtime.py +++ b/vis4d/zoo/base/runtime.py @@ -58,6 +58,7 @@ def get_default_cfg( config.use_tf32 = False config.tf32_matmul_precision = "highest" config.benchmark = False + config.compute_flops = False return config From 70fbfd7e92e6d60c6bfdbde994d1e30131028915 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 21 Aug 2024 17:15:30 +0200 Subject: [PATCH 06/50] feat: Add fix sized resize, update vis functional and fix test error. --- docs/source/user_guide/3D_visualization.ipynb | 2 +- docs/source/user_guide/visualization.ipynb | 2 +- tests/vis4d-test-data | 2 +- tests/zoo/cc_3dt_test.py | 12 + vis4d/data/transforms/resize.py | 283 +++++++++--------- vis4d/op/base/vit.py | 2 +- vis4d/vis/functional/__init__.py | 25 -- .../image.py => image/functional.py} | 50 ++-- .../functional.py} | 10 +- 9 files changed, 186 insertions(+), 202 deletions(-) delete mode 100644 vis4d/vis/functional/__init__.py rename vis4d/vis/{functional/image.py => image/functional.py} (92%) rename vis4d/vis/{functional/pointcloud.py => pointcloud/functional.py} (93%) diff --git a/docs/source/user_guide/3D_visualization.ipynb b/docs/source/user_guide/3D_visualization.ipynb index 1d45f813..b9355051 100644 --- a/docs/source/user_guide/3D_visualization.ipynb +++ b/docs/source/user_guide/3D_visualization.ipynb @@ -20,7 +20,7 @@ "os.environ[\"WEBRTC_IP\"] = \"127.0.0.1\"\n", "\n", "import pickle\n", - "from vis4d.vis.functional import show_points\n", + "from vis4d.vis.pointcloud.functional import show_points\n", "import numpy as np" ] }, diff --git a/docs/source/user_guide/visualization.ipynb b/docs/source/user_guide/visualization.ipynb index 30e92e35..fbd5c85e 100644 --- a/docs/source/user_guide/visualization.ipynb +++ b/docs/source/user_guide/visualization.ipynb @@ -30,7 +30,7 @@ "from __future__ import annotations\n", "\n", "from vis4d.common.typing import NDArrayF64, NDArrayI64\n", - "from vis4d.vis.functional import imshow_bboxes, imshow_masks, imshow_topk_bboxes, imshow, draw_bboxes, draw_masks, imshow_track_matches\n", + "from vis4d.vis.image.functional import imshow_bboxes, imshow_masks, imshow_topk_bboxes, imshow, draw_bboxes, draw_masks, imshow_track_matches\n", "\n", "import pickle\n", "import numpy as np" diff --git a/tests/vis4d-test-data b/tests/vis4d-test-data index 1e52c194..79af15a3 160000 --- a/tests/vis4d-test-data +++ b/tests/vis4d-test-data @@ -1 +1 @@ -Subproject commit 1e52c194859cfc09ee2f10af595303da3646d7d3 +Subproject commit 79af15a3d98116d8400b7489e6bcaf590c1eaff5 diff --git a/tests/zoo/cc_3dt_test.py b/tests/zoo/cc_3dt_test.py index 93f04e18..67475a8d 100644 --- a/tests/zoo/cc_3dt_test.py +++ b/tests/zoo/cc_3dt_test.py @@ -96,6 +96,18 @@ def test_nusc_vis(self) -> None: ) ) + def test_nusc_test(self) -> None: + """Test the config.""" + cfg_gt = f"{self.gt_config_path}/cc_3dt_nusc_test.yaml" + + self.assertTrue( + compare_configs( + f"{self.config_prefix}.cc_3dt_nusc_test", + cfg_gt, + self.varying_keys, + ) + ) + def test_bevformer_base_velo_lstm_nusc(self) -> None: """Test the config.""" cfg_gt = ( diff --git a/vis4d/data/transforms/resize.py b/vis4d/data/transforms/resize.py index f157bd88..c829f7a0 100644 --- a/vis4d/data/transforms/resize.py +++ b/vis4d/data/transforms/resize.py @@ -50,6 +50,7 @@ def __init__( align_long_edge: bool = False, resize_short_edge: bool = False, allow_overflow: bool = False, + fixed_scale: bool = False, ) -> None: """Creates an instance of the class. @@ -78,14 +79,63 @@ def __init__( to the smallest size such that it is no smaller than shape. Otherwise, we scale the image to the largest size such that it is no larger than shape. Defaults to False. + fixed_scale (bool, optional): If set to True, we scale the image + without offset. Defaults to False. """ self.shape = shape self.keep_ratio = keep_ratio + + assert multiscale_mode in {"list", "range"} self.multiscale_mode = multiscale_mode + + assert ( + scale_range[0] <= scale_range[1] + ), f"Invalid scale range: {scale_range[1]} < {scale_range[0]}" self.scale_range = scale_range + self.align_long_edge = align_long_edge self.resize_short_edge = resize_short_edge self.allow_overflow = allow_overflow + self.fixed_scale = fixed_scale + + def _get_target_shape( + self, input_shape: tuple[int, int] + ) -> tuple[int, int]: + """Generate possibly random target shape.""" + if self.multiscale_mode == "range": + assert isinstance( + self.shape, tuple + ), "Specify shape as tuple when using multiscale mode range." + if self.scale_range[0] < self.scale_range[1]: # do multi-scale + w_scale = ( + random.uniform(0, 1) + * (self.scale_range[1] - self.scale_range[0]) + + self.scale_range[0] + ) + h_scale = ( + random.uniform(0, 1) + * (self.scale_range[1] - self.scale_range[0]) + + self.scale_range[0] + ) + else: + h_scale = w_scale = 1.0 + + shape = int(self.shape[0] * h_scale), int(self.shape[1] * w_scale) + else: + assert isinstance( + self.shape, list + ), "Specify shape as list when using multiscale mode list." + shape = random.choice(self.shape) + + return get_resize_shape( + input_shape, + shape, + self.keep_ratio, + self.align_long_edge, + self.resize_short_edge, + self.allow_overflow, + self.fixed_scale, + ) def __call__( self, images: list[NDArrayF32] @@ -94,16 +144,7 @@ def __call__( image = images[0] im_shape = (image.shape[1], image.shape[2]) - target_shape = get_target_shape( - im_shape, - self.shape, - self.keep_ratio, - self.multiscale_mode, - self.scale_range, - self.align_long_edge, - self.resize_short_edge, - self.allow_overflow, - ) + target_shape = self._get_target_shape(im_shape) scale_factor = ( target_shape[1] / im_shape[1], target_shape[0] / im_shape[0], @@ -117,6 +158,66 @@ def __call__( return resize_params, target_shapes +def get_resize_shape( + original_shape: tuple[int, int], + new_shape: tuple[int, int], + keep_ratio: bool = True, + align_long_edge: bool = False, + resize_short_edge: bool = False, + allow_overflow: bool = False, + fixed_scale: bool = False, +) -> tuple[int, int]: + """Get shape for resize, considering keep_ratio and align_long_edge. + + Args: + original_shape (tuple[int, int]): Original shape in [H, W]. + new_shape (tuple[int, int]): New shape in [H, W]. + keep_ratio (bool, optional): Whether to keep the aspect ratio. + Defaults to True. + align_long_edge (bool, optional): Whether to align the long edge of + the original shape with the long edge of the new shape. + Defaults to False. + resize_short_edge (bool, optional): Whether to resize according to the + short edge. Defaults to False. + allow_overflow (bool, optional): Whether to allow overflow. + Defaults to False. + fixed_scale (bool, optional): Whether to use fixed scale. + + Returns: + tuple[int, int]: The new shape in [H, W]. + """ + h, w = original_shape + new_h, new_w = new_shape + + if keep_ratio: + if allow_overflow: + comp_fn = max + else: + comp_fn = min + + if align_long_edge: + long_edge, short_edge = max(new_shape), min(new_shape) + scale_factor = comp_fn( + long_edge / max(h, w), short_edge / min(h, w) + ) + elif resize_short_edge: + short_edge = min(original_shape) + new_short_edge = min(new_shape) + scale_factor = new_short_edge / short_edge + else: + scale_factor = comp_fn(new_w / w, new_h / h) + + if fixed_scale: + offset = 0.0 + else: + offset = 0.5 + + new_h = int(h * scale_factor + offset) + new_w = int(w * scale_factor + offset) + + return new_h, new_w + + @Transform([K.images, "transforms.resize.target_shape"], K.images) class ResizeImages: """Resize Images.""" @@ -166,6 +267,36 @@ def __call__( return images +def resize_image( + inputs: NDArrayF32, + shape: tuple[int, int], + interpolation: str = "bilinear", + antialias: bool = False, + backend: str = "torch", +) -> NDArrayF32: + """Resize image.""" + if backend == "torch": + image = torch.from_numpy(inputs).permute(0, 3, 1, 2) + image = resize_tensor(image, shape, interpolation, antialias) + return image.permute(0, 2, 3, 1).numpy() + + if backend == "cv2": + cv2_interp_codes = { + "nearest": INTER_NEAREST, + "bilinear": INTER_LINEAR, + "bicubic": INTER_CUBIC, + "area": INTER_AREA, + "lanczos": INTER_LANCZOS4, + } + return cv2.resize( # pylint: disable=no-member, unsubscriptable-object + inputs[0].astype(np.uint8), + (shape[1], shape[0]), + interpolation=cv2_interp_codes[interpolation], + )[None, ...].astype(np.float32) + + raise ValueError(f"Invalid imresize backend: {backend}") + + @Transform([K.boxes2d, "transforms.resize.scale_factor"], K.boxes2d) class ResizeBoxes2D: """Resize list of 2D bounding boxes.""" @@ -389,34 +520,6 @@ def __call__( return intrinsics -def resize_image( - inputs: NDArrayF32, - shape: tuple[int, int], - interpolation: str = "bilinear", - antialias: bool = False, - backend: str = "torch", -) -> NDArrayF32: - """Resize image.""" - if backend == "torch": - image = torch.from_numpy(inputs).permute(0, 3, 1, 2) - image = resize_tensor(image, shape, interpolation, antialias) - return image.permute(0, 2, 3, 1).numpy() - if backend == "cv2": - cv2_interp_codes = { - "nearest": INTER_NEAREST, - "bilinear": INTER_LINEAR, - "bicubic": INTER_CUBIC, - "area": INTER_AREA, - "lanczos": INTER_LANCZOS4, - } - return cv2.resize( # pylint: disable=no-member, unsubscriptable-object - inputs[0].astype(np.uint8), - (shape[1], shape[0]), - interpolation=cv2_interp_codes[interpolation], - )[None, ...].astype(np.float32) - raise ValueError(f"Invalid imresize backend: {backend}") - - def resize_tensor( inputs: Tensor, shape: tuple[int, int], @@ -434,107 +537,3 @@ def resize_tensor( antialias=antialias, ) return output - - -def get_resize_shape( - original_shape: tuple[int, int], - new_shape: tuple[int, int], - keep_ratio: bool = True, - align_long_edge: bool = False, - resize_short_edge: bool = False, - allow_overflow: bool = False, -) -> tuple[int, int]: - """Get shape for resize, considering keep_ratio and align_long_edge. - - Args: - original_shape (tuple[int, int]): Original shape in [H, W]. - new_shape (tuple[int, int]): New shape in [H, W]. - keep_ratio (bool, optional): Whether to keep the aspect ratio. - Defaults to True. - align_long_edge (bool, optional): Whether to align the long edge of - the original shape with the long edge of the new shape. - Defaults to False. - resize_short_edge (bool, optional): Whether to resize according to the - short edge. Defaults to False. - allow_overflow (bool, optional): Whether to allow overflow. - Defaults to False. - - Returns: - tuple[int, int]: The new shape in [H, W]. - """ - h, w = original_shape - new_h, new_w = new_shape - if keep_ratio: - if allow_overflow: - comp_fn = max - else: - comp_fn = min - if align_long_edge: - long_edge, short_edge = max(new_shape), min(new_shape) - scale_factor = comp_fn( - long_edge / max(h, w), short_edge / min(h, w) - ) - elif resize_short_edge: - short_edge = min(original_shape) - new_short_edge = min(new_shape) - scale_factor = new_short_edge / short_edge - else: - scale_factor = comp_fn(new_w / w, new_h / h) - new_h = int(h * scale_factor + 0.5) - new_w = int(w * scale_factor + 0.5) - return new_h, new_w - - -def get_target_shape( - input_shape: tuple[int, int], - shape: tuple[int, int] | list[tuple[int, int]], - keep_ratio: bool = False, - multiscale_mode: str = "range", - scale_range: tuple[float, float] = (1.0, 1.0), - align_long_edge: bool = False, - resize_short_edge: bool = False, - allow_overflow: bool = False, -) -> tuple[int, int]: - """Generate possibly random target shape.""" - assert multiscale_mode in {"list", "range"} - if multiscale_mode == "list": - assert isinstance( - shape, list - ), "Specify shape as list when using multiscale mode list." - assert len(shape) >= 1 - else: - assert isinstance( - shape, tuple - ), "Specify shape as tuple when using multiscale mode range." - assert ( - scale_range[0] <= scale_range[1] - ), f"Invalid scale range: {scale_range[1]} < {scale_range[0]}" - - if multiscale_mode == "range": - assert isinstance(shape, tuple) - if scale_range[0] < scale_range[1]: # do multi-scale - w_scale = ( - random.uniform(0, 1) * (scale_range[1] - scale_range[0]) - + scale_range[0] - ) - h_scale = ( - random.uniform(0, 1) * (scale_range[1] - scale_range[0]) - + scale_range[0] - ) - else: - h_scale = w_scale = 1.0 - - shape = int(shape[0] * h_scale), int(shape[1] * w_scale) - else: - assert isinstance(shape, list) - shape = random.choice(shape) - - shape = get_resize_shape( - input_shape, - shape, - keep_ratio, - align_long_edge, - resize_short_edge, - allow_overflow, - ) - return shape diff --git a/vis4d/op/base/vit.py b/vis4d/op/base/vit.py index fdbdbd05..43404075 100644 --- a/vis4d/op/base/vit.py +++ b/vis4d/op/base/vit.py @@ -3,7 +3,7 @@ from __future__ import annotations import torch -from timm.models.helpers import named_apply +from timm.models import named_apply from torch import nn from ..layer import PatchEmbed, TransformerBlock diff --git a/vis4d/vis/functional/__init__.py b/vis4d/vis/functional/__init__.py deleted file mode 100644 index 5a46ff0e..00000000 --- a/vis4d/vis/functional/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Function interface for visualization functions.""" - -from .image import ( - draw_bboxes, - draw_masks, - imshow, - imshow_bboxes, - imshow_masks, - imshow_topk_bboxes, - imshow_track_matches, -) -from .pointcloud import draw_points, show_3d, show_points - -__all__ = [ - "imshow", - "draw_masks", - "draw_bboxes", - "imshow_bboxes", - "imshow_masks", - "imshow_topk_bboxes", - "imshow_track_matches", - "show_3d", - "draw_points", - "show_points", -] diff --git a/vis4d/vis/functional/image.py b/vis4d/vis/image/functional.py similarity index 92% rename from vis4d/vis/functional/image.py rename to vis4d/vis/image/functional.py index baf51643..4fbb7118 100644 --- a/vis4d/vis/functional/image.py +++ b/vis4d/vis/image/functional.py @@ -13,22 +13,24 @@ NDArrayF32, NDArrayUI8, ) -from vis4d.vis.image.canvas import CanvasBackend, PillowCanvasBackend -from vis4d.vis.image.util import ( + +from ..util import generate_color_map +from .canvas import CanvasBackend, PillowCanvasBackend +from .util import ( preprocess_boxes, preprocess_boxes3d, preprocess_image, preprocess_masks, project_point, ) -from vis4d.vis.image.viewer import ImageViewerBackend, MatplotlibImageViewer -from vis4d.vis.util import generate_color_map +from .viewer import ImageViewerBackend, MatplotlibImageViewer def imshow( image: ArrayLike, image_mode: str = "RGB", image_viewer: ImageViewerBackend = MatplotlibImageViewer(), + file_path: str | None = None, ) -> None: """Shows a single image. @@ -37,28 +39,13 @@ def imshow( image_mode (str, optional): Image Mode. Defaults to "RGB". image_viewer (ImageViewerBackend, optional): The Image viewer backend to use. Defaults to MatplotlibImageViewer(). + file_path (str): The path to save the image to. Defaults to None. """ image = preprocess_image(image, image_mode) image_viewer.show_images([image]) - -def imsave( - image: ArrayLike, - file_path: str, - image_mode: str = "RGB", - image_viewer: ImageViewerBackend = MatplotlibImageViewer(), -) -> None: - """Shows a single image. - - Args: - image (NDArrayNumber): The image to show. - file_path (str): The path to save the image to. - image_mode (str, optional): Image Mode. Defaults to "RGB". - image_viewer (ImageViewerBackend, optional): The Image viewer backend - to use. Defaults to MatplotlibImageViewer(). - """ - image = preprocess_image(image, image_mode) - image_viewer.save_images([image], [file_path]) + if file_path is not None: + image_viewer.save_images([image], [file_path]) def draw_masks( @@ -158,6 +145,7 @@ def imshow_bboxes( image_mode: str = "RGB", box_width: int = 1, image_viewer: ImageViewerBackend = MatplotlibImageViewer(), + file_path: str | None = None, ) -> None: """Shows the bounding boxes overlayed on the given image. @@ -176,6 +164,7 @@ class id to class name box_width (int, optional): Width of the box border. Defaults to 1. image_viewer (ImageViewerBackend, optional): The Image viewer backend to use. Defaults to MatplotlibImageViewer(). + file_path (str): The path to save the image to. Defaults to None. """ image = preprocess_image(image, mode=image_mode) img = draw_bboxes( @@ -189,7 +178,7 @@ class id to class name image_mode, box_width, ) - imshow(img, image_mode, image_viewer) + imshow(img, image_mode, image_viewer, file_path) def draw_bbox3d( @@ -244,6 +233,7 @@ def imshow_bboxes3d( n_colors: int = 50, image_mode: str = "RGB", image_viewer: ImageViewerBackend = MatplotlibImageViewer(), + file_path: str | None = None, ) -> None: """Show image with bounding boxes.""" image = preprocess_image(image, mode=image_mode) @@ -259,7 +249,7 @@ def imshow_bboxes3d( n_colors=n_colors, image_mode=image_mode, ) - imshow(img, image_mode, image_viewer) + imshow(img, image_mode, image_viewer, file_path) def imshow_masks( @@ -270,6 +260,7 @@ def imshow_masks( image_mode: str = "RGB", canvas: CanvasBackend = PillowCanvasBackend(), image_viewer: ImageViewerBackend = MatplotlibImageViewer(), + file_path: str | None = None, ) -> None: """Shows semantic masks overlayed over the given image. @@ -286,11 +277,13 @@ def imshow_masks( Defaults to PillowCanvasBackend(). image_viewer (ImageViewerBackend, optional): The Image viewer backend to use. Defaults to MatplotlibImageViewer(). + file_path (str): The path to save the image to. Defaults to None. """ imshow( draw_masks(image, masks, class_ids, n_colors, image_mode, canvas), image_mode, image_viewer, + file_path, ) @@ -306,6 +299,7 @@ def imshow_topk_bboxes( image_mode: str = "RGB", box_width: int = 1, image_viewer: ImageViewerBackend = MatplotlibImageViewer(), + file_path: str | None = None, ) -> None: """Visualize the 'topk' bounding boxes with highest score. @@ -325,6 +319,7 @@ class id to class name box_width (int, optional): Width of the box border. Defaults to 1. image_viewer (ImageViewerBackend, optional): The Image viewer backend to use. Defaults to MatplotlibImageViewer(). + file_path (str): The path to save the image to. Defaults to None. """ scores = array_to_numpy(scores, n_dims=1, dtype=np.float32) @@ -344,6 +339,7 @@ class id to class name image_mode, box_width, image_viewer, + file_path, ) @@ -356,6 +352,7 @@ def imshow_track_matches( ref_track_ids: list[ArrayLikeInt], image_mode: str = "RGB", image_viewer: ImageViewerBackend = MatplotlibImageViewer(), + file_path: str | None = None, ) -> None: """Visualize paired bounding boxes successively for batched frame pairs. @@ -372,6 +369,7 @@ def imshow_track_matches( image_mode (str, optional): Color mode if the image. Defaults to "RGB". image_viewer (ImageViewerBackend, optional): The Image viewer backend to use. Defaults to MatplotlibImageViewer(). + file_path (str): The path to save the image to. Defaults to None. """ key_imgs_np = arrays_to_numpy(*key_imgs, n_dims=3, dtype=np.float32) ref_imgs_np = arrays_to_numpy(*ref_imgs, n_dims=3, dtype=np.float32) @@ -404,12 +402,14 @@ def imshow_track_matches( key_box[key_i], image_mode=image_mode, image_viewer=image_viewer, + file_path=file_path, ) imshow_bboxes( ref_image, ref_box[ref_i], image_mode=image_mode, image_viewer=image_viewer, + file_path=file_path, ) else: # stack imgs horizontal @@ -420,4 +420,4 @@ def imshow_track_matches( ref_image, ref_box[batch_i], image_mode=image_mode ) stacked_img = np.vstack([k_img, r_img]) - imshow(stacked_img, image_mode, image_viewer) + imshow(stacked_img, image_mode, image_viewer, file_path) diff --git a/vis4d/vis/functional/pointcloud.py b/vis4d/vis/pointcloud/functional.py similarity index 93% rename from vis4d/vis/functional/pointcloud.py rename to vis4d/vis/pointcloud/functional.py index ed4335a6..fec7fd83 100644 --- a/vis4d/vis/functional/pointcloud.py +++ b/vis4d/vis/pointcloud/functional.py @@ -3,12 +3,10 @@ from __future__ import annotations from vis4d.common.typing import ArrayLikeFloat, ArrayLikeInt -from vis4d.vis.pointcloud.scene import Scene3D -from vis4d.vis.pointcloud.viewer import ( - Open3DVisualizationBackend, - PointCloudVisualizerBackend, -) -from vis4d.vis.util import DEFAULT_COLOR_MAPPING + +from ..util import DEFAULT_COLOR_MAPPING +from .scene import Scene3D +from .viewer import Open3DVisualizationBackend, PointCloudVisualizerBackend def show_3d( From 4f490d14d4b4949fc0a6ef8ec2c656d70c37133b Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 21 Aug 2024 17:33:07 +0200 Subject: [PATCH 07/50] fix: Fix tests. --- docs/source/user_guide/getting_started.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/user_guide/getting_started.ipynb b/docs/source/user_guide/getting_started.ipynb index db99ef46..08824478 100644 --- a/docs/source/user_guide/getting_started.ipynb +++ b/docs/source/user_guide/getting_started.ipynb @@ -251,7 +251,7 @@ "from vis4d.model.detect.faster_rcnn import FasterRCNN\n", "\n", "from vis4d.data.const import CommonKeys as K\n", - "from vis4d.vis.functional.image import imshow_bboxes\n", + "from vis4d.vis.image.functional import imshow_bboxes\n", "\n", "from vis4d.config import instantiate_classes\n", "from vis4d.zoo.base.datasets.coco import get_coco_detection_cfg" From 17c4e02e8c8d2c2fa98470c2e9773c29fba5e854 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 21 Aug 2024 17:53:57 +0200 Subject: [PATCH 08/50] fix: Update ipynb for test. --- docs/source/user_guide/visualization.ipynb | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/docs/source/user_guide/visualization.ipynb b/docs/source/user_guide/visualization.ipynb index fbd5c85e..6c1c285c 100644 --- a/docs/source/user_guide/visualization.ipynb +++ b/docs/source/user_guide/visualization.ipynb @@ -15,17 +15,7 @@ "cell_type": "code", "execution_count": 1, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jupyter environment detected. Enabling Open3D WebVisualizer.\n", - "[Open3D INFO] WebRTC GUI backend enabled.\n", - "[Open3D INFO] WebRTCWindowSystem: HTTP handshake server disabled.\n" - ] - } - ], + "outputs": [], "source": [ "from __future__ import annotations\n", "\n", @@ -453,7 +443,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.11.9" }, "vscode": { "interpreter": { From d042e2f680dc68a4270c8a1ed38dddcaa7882a3f Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Thu, 22 Aug 2024 11:34:55 +0200 Subject: [PATCH 09/50] feat: Update docs. --- docs/source/conf.py | 2 +- docs/source/datasets.rst | 3 +++ docs/source/dev_guide/cli.rst | 12 +++++++----- docs/source/faq/trouble.rst | 4 ---- 4 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 docs/source/datasets.rst diff --git a/docs/source/conf.py b/docs/source/conf.py index 08f9b4c9..68d0f507 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -24,7 +24,7 @@ project = "Vis4D" copyright = "2022, ETH Zurich" -author = "Tobias Fischer" +author = "Vis4D Team" # -- General configuration --------------------------------------------------- diff --git a/docs/source/datasets.rst b/docs/source/datasets.rst new file mode 100644 index 00000000..3acad4ec --- /dev/null +++ b/docs/source/datasets.rst @@ -0,0 +1,3 @@ +******** +Datasets +******** \ No newline at end of file diff --git a/docs/source/dev_guide/cli.rst b/docs/source/dev_guide/cli.rst index fe62471b..538e3ede 100644 --- a/docs/source/dev_guide/cli.rst +++ b/docs/source/dev_guide/cli.rst @@ -1,10 +1,11 @@ ### CLI ### + We provide a command line interface for training and evaluating your models. Assuming you have installed the package using pip, you can use the command `vis4d` to access the CLI. -Alternatively, you can run the CLI using `python -m vis4d.engine.cli` or `python -m vis4d.pl.cli` if you want to use the PyTorch Lightning version. +Alternatively, you can run the CLI using `python -m vis4d.engine.run` or `python -m vis4d.pl.run` if you want to use the PyTorch Lightning version. The CLI relies on a configuration file to specify each experiment. We use `ml_collections `_ as underlying framework to define the configuration files. You can read up on our configuration files in the `Config System `_ section. @@ -12,6 +13,7 @@ You can read up on our configuration files in the `Config System `_ section. @@ -20,6 +22,7 @@ We support both, our own training engine as well as `PyTorch Lightning Date: Fri, 23 Aug 2024 21:19:02 +0200 Subject: [PATCH 10/50] fix: Separate to hdf5 script. --- tests/data/io/to_hdf5_test.py | 2 +- vis4d/data/io/hdf5.py | 62 ---------------------------- vis4d/data/io/to_hdf5.py | 76 +++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 63 deletions(-) create mode 100644 vis4d/data/io/to_hdf5.py diff --git a/tests/data/io/to_hdf5_test.py b/tests/data/io/to_hdf5_test.py index 5e469746..caf61923 100644 --- a/tests/data/io/to_hdf5_test.py +++ b/tests/data/io/to_hdf5_test.py @@ -4,7 +4,7 @@ import unittest from tests.util import get_test_data -from vis4d.data.io.hdf5 import convert_dataset +from vis4d.data.io.to_hdf5 import convert_dataset class TestHDF5(unittest.TestCase): diff --git a/vis4d/data/io/hdf5.py b/vis4d/data/io/hdf5.py index 15107770..3d6b594e 100644 --- a/vis4d/data/io/hdf5.py +++ b/vis4d/data/io/hdf5.py @@ -6,12 +6,10 @@ from __future__ import annotations -import argparse import os from typing import Literal import numpy as np -from tqdm import tqdm from vis4d.common.imports import H5PY_AVAILABLE @@ -242,63 +240,3 @@ def close(self) -> None: for client, _ in self.db_cache.values(): client.close() self.db_cache.clear() - - -def convert_dataset(source_dir: str) -> None: - """Convert a dataset to HDF5 format. - - This function converts an arbitary dictionary to an HDF5 file. The keys - inside the HDF5 file preserve the directory structure of the original. - - As an example, if you convert "/path/to/dataset" to HDF5, the resulting - file will be: "/path/to/dataset.hdf5". The file "relative/path/to/file" - will be stored at "relative/path/to/file" inside /path/to/dataset.hdf5. - - Args: - source_dir (str): The path to the dataset to convert. - """ - if not os.path.exists(source_dir): - raise FileNotFoundError(f"No such file or directory: {source_dir}") - - source_dir = os.path.join(source_dir, "") # must end with trailing slash - hdf5_path = source_dir.rstrip("/") + ".hdf5" - if os.path.exists(hdf5_path): - print(f"File {hdf5_path} already exists! Skipping {source_dir}") - return - - print(f"Converting dataset at: {source_dir}") - hdf5_file = h5py.File(hdf5_path, mode="w") - sub_dirs = list(os.walk(source_dir)) - file_count = sum(len(files) for (_, _, files) in sub_dirs) - - with tqdm(total=file_count) as pbar: - for root, _, files in sub_dirs: - g_name = root.replace(source_dir, "") - g = hdf5_file.create_group(g_name) if g_name else hdf5_file - for f in files: - filepath = os.path.join(root, f) - if os.path.isfile(filepath): - with open(filepath, "rb") as fp: - file_content = fp.read() - g.create_dataset( - f, data=np.frombuffer(file_content, dtype="uint8") - ) - pbar.update() - - hdf5_file.close() - print("done.") - - -if __name__ == "__main__": # pragma: no cover - parser = argparse.ArgumentParser( - description="Converts a dataset at the specified path to hdf5. The " - "local directory structure is preserved in the hdf5 file." - ) - parser.add_argument( - "-p", - "--path", - required=True, - help="path to the root folder of a specific dataset to convert", - ) - args = parser.parse_args() - convert_dataset(args.path) diff --git a/vis4d/data/io/to_hdf5.py b/vis4d/data/io/to_hdf5.py new file mode 100644 index 00000000..4a2161a5 --- /dev/null +++ b/vis4d/data/io/to_hdf5.py @@ -0,0 +1,76 @@ +"""Script to convert a dataset to hdf5 format.""" + +from __future__ import annotations + +import argparse +import os + +import numpy as np +from tqdm import tqdm + +from vis4d.common.imports import H5PY_AVAILABLE + +if H5PY_AVAILABLE: + import h5py +else: + raise ImportError("Please install h5py to enable HDF5Backend.") + + +def convert_dataset(source_dir: str) -> None: + """Convert a dataset to HDF5 format. + + This function converts an arbitary dictionary to an HDF5 file. The keys + inside the HDF5 file preserve the directory structure of the original. + + As an example, if you convert "/path/to/dataset" to HDF5, the resulting + file will be: "/path/to/dataset.hdf5". The file "relative/path/to/file" + will be stored at "relative/path/to/file" inside /path/to/dataset.hdf5. + + Args: + source_dir (str): The path to the dataset to convert. + """ + if not os.path.exists(source_dir): + raise FileNotFoundError(f"No such file or directory: {source_dir}") + + source_dir = os.path.join(source_dir, "") # must end with trailing slash + hdf5_path = source_dir.rstrip("/") + ".hdf5" + if os.path.exists(hdf5_path): + print(f"File {hdf5_path} already exists! Skipping {source_dir}") + return + + print(f"Converting dataset at: {source_dir}") + hdf5_file = h5py.File(hdf5_path, mode="w") + sub_dirs = list(os.walk(source_dir)) + file_count = sum(len(files) for (_, _, files) in sub_dirs) + + with tqdm(total=file_count) as pbar: + for root, _, files in sub_dirs: + g_name = root.replace(source_dir, "") + g = hdf5_file.create_group(g_name) if g_name else hdf5_file + for f in files: + filepath = os.path.join(root, f) + if os.path.isfile(filepath): + with open(filepath, "rb") as fp: + file_content = fp.read() + g.create_dataset( + f, data=np.frombuffer(file_content, dtype="uint8") + ) + pbar.update() + + hdf5_file.close() + print("done.") + + +if __name__ == "__main__": # pragma: no cover + parser = argparse.ArgumentParser( + description="Converts a dataset at the specified path to hdf5. The " + "local directory structure is preserved in the hdf5 file." + ) + parser.add_argument( + "-p", + "--path", + required=True, + help="path to the root folder of a specific dataset to convert", + ) + args = parser.parse_args() + convert_dataset(args.path) From 539b8a9d3bf6221b82c69b6f5c22b1e4d657e2c6 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 27 Aug 2024 12:18:23 +0200 Subject: [PATCH 11/50] feat: Give user freedom to select dist tmp dir. --- vis4d/common/distributed.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/vis4d/common/distributed.py b/vis4d/common/distributed.py index 8ba797b8..a87d96c8 100644 --- a/vis4d/common/distributed.py +++ b/vis4d/common/distributed.py @@ -264,7 +264,7 @@ def all_gather_object_gpu( # type: ignore def create_tmpdir( - rank: int, tmpdir: None | str = None + rank: int, tmpdir: None | str = None, use_system_tmp: bool = True ) -> str: # pragma: no cover """Create and distribute a temporary directory across all processes.""" if tmpdir is not None: @@ -273,10 +273,10 @@ def create_tmpdir( if rank == 0: # create a temporary directory default_tmpdir = tempfile.gettempdir() - if default_tmpdir is not None: + if default_tmpdir is not None and use_system_tmp: dist_tmpdir = os.path.join(default_tmpdir, ".dist_tmp") else: - dist_tmpdir = ".dist_tmp" + dist_tmpdir = os.path.join("vis4d-workspace", ".dist_tmp") os.makedirs(dist_tmpdir, exist_ok=True) tmpdir = tempfile.mkdtemp(dir=dist_tmpdir) else: @@ -288,6 +288,7 @@ def all_gather_object_cpu( # type: ignore data: Any, tmpdir: None | str = None, rank_zero_return_only: bool = True, + use_system_tmp: bool = True, ) -> list[Any] | None: # pragma: no cover """Share arbitrary picklable data via file system caching. @@ -304,7 +305,7 @@ def all_gather_object_cpu( # type: ignore return [data] # make tmp dir - tmpdir = create_tmpdir(rank, tmpdir) + tmpdir = create_tmpdir(rank, tmpdir, use_system_tmp) # encode & save with open(os.path.join(tmpdir, f"part_{rank}.pkl"), "wb") as f: From 8b0055fc5f3afb5d338fe525d836a46248a70474 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 27 Aug 2024 17:44:15 +0200 Subject: [PATCH 12/50] fix: Fix pylint. --- vis4d/common/distributed.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vis4d/common/distributed.py b/vis4d/common/distributed.py index a87d96c8..36acaa19 100644 --- a/vis4d/common/distributed.py +++ b/vis4d/common/distributed.py @@ -295,7 +295,8 @@ def all_gather_object_cpu( # type: ignore Args: data: any picklable object. tmpdir: Save path for temporary files. If None, safely create tmpdir. - rank_zero_return_only: if results should only be returned on rank 0 + rank_zero_return_only: if results should only be returned on rank 0. + use_system_tmp: if use system tmpdir or not. Returns: list[Any]: list of data gathered from each process. From 68c99ce7d0750dfab8d0b25fdd97e9515b72e00a Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Fri, 30 Aug 2024 21:32:00 +0200 Subject: [PATCH 13/50] feat: Add pl trainer ddp timeout and separate evaluator callback metircs. --- vis4d/engine/callbacks/evaluator.py | 57 ++++++++++++++++++----------- vis4d/eval/coco/detect.py | 2 - vis4d/pl/trainer.py | 6 ++- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/vis4d/engine/callbacks/evaluator.py b/vis4d/engine/callbacks/evaluator.py index 989b005c..b7b34bc4 100644 --- a/vis4d/engine/callbacks/evaluator.py +++ b/vis4d/engine/callbacks/evaluator.py @@ -90,13 +90,26 @@ def on_test_epoch_end( self.evaluator.gather(all_gather_object_cpu) synchronize() - log_dict = self.evaluate() - log_dict = broadcast(log_dict) + self.process() + + log_dict: MetricLogs = {} + for metric in self.metrics_to_eval: + metric_dict = self.evaluate(metric) + metric_dict = broadcast(metric_dict) + assert isinstance(metric_dict, dict) + log_dict.update(metric_dict) + self.evaluator.reset() + return log_dict @rank_zero_only - def evaluate(self) -> MetricLogs: + def process(self) -> None: + """Process the evaluator.""" + self.evaluator.process() + + @rank_zero_only + def evaluate(self, metric: str) -> MetricLogs: """Evaluate the performance after processing all input/output pairs. Returns: @@ -104,26 +117,26 @@ def evaluate(self) -> MetricLogs: keys are formatted as {metric_name}/{key_name}, and the values are the corresponding evaluated values. """ - rank_zero_info("Running evaluator %s...", str(self.evaluator)) - self.evaluator.process() - + rank_zero_info( + f"Running evaluator {str(self.evaluator)} with {metric} metric... ", + ) log_dict = {} - for metric in self.metrics_to_eval: - # Save output predictions. This is done here instead of - # on_test_batch_end because the evaluator may not have processed - # all batches yet. - if self.save_predictions: - output_dir = os.path.join(self.output_dir, metric) - self.evaluator.save(metric, output_dir) - - # Evaluate metric - metric_dict, metric_str = self.evaluator.evaluate(metric) - for k, v in metric_dict.items(): - log_k = metric + "/" + k - rank_zero_info("%s: %.4f", log_k, v) - log_dict[f"{metric}/{k}"] = v - rank_zero_info("Showing results for metric: %s", metric) - rank_zero_info(metric_str) + # Save output predictions. This is done here instead of + # on_test_batch_end because the evaluator may not have processed + # all batches yet. + if self.save_predictions: + output_dir = os.path.join(self.output_dir, metric) + self.evaluator.save(metric, output_dir) + + # Evaluate metric + metric_dict, metric_str = self.evaluator.evaluate(metric) + for k, v in metric_dict.items(): + log_k = metric + "/" + k + rank_zero_info("%s: %.4f", log_k, v) + log_dict[f"{metric}/{k}"] = v + + rank_zero_info("Showing results for metric: %s", metric) + rank_zero_info(metric_str) return log_dict diff --git a/vis4d/eval/coco/detect.py b/vis4d/eval/coco/detect.py index 0acc4265..bf81db2f 100644 --- a/vis4d/eval/coco/detect.py +++ b/vis4d/eval/coco/detect.py @@ -131,7 +131,6 @@ def __init__( coco_gt_cats = self._coco_gt.loadCats(self._coco_gt.getCatIds()) self.cat_map = {c["name"]: c["id"] for c in coco_gt_cats} self._predictions: list[DictStrAny] = [] - self.coco_dt: COCO | None = None @property def metrics(self) -> list[str]: @@ -151,7 +150,6 @@ def gather(self, gather_func: GenericFunc) -> None: def reset(self) -> None: """Reset the saved predictions to start new round of evaluation.""" self._predictions = [] - self.coco_dt = None def process_batch( # type: ignore # pylint: disable=arguments-differ self, diff --git a/vis4d/pl/trainer.py b/vis4d/pl/trainer.py index 53fc8115..7d3db479 100644 --- a/vis4d/pl/trainer.py +++ b/vis4d/pl/trainer.py @@ -2,6 +2,7 @@ from __future__ import annotations +import datetime import os.path as osp from lightning.pytorch import Callback, Trainer @@ -31,6 +32,7 @@ def __init__( checkpoint_callback: ModelCheckpoint | None = None, wandb: bool = False, seed: int = -1, + timeout: int = 3600, **kwargs: ArgsType, ) -> None: """Perform some basic common setups at the beginning of a job. @@ -54,6 +56,7 @@ def __init__( seed (int, optional): The integer value seed for global random state. Defaults to -1. If -1, a random seed will be generated. This will be set by TrainingModule. + timeout: Timeout (seconds) for DDP connection. Default: 3600. """ self.work_dir = work_dir self.exp_name = exp_name @@ -126,7 +129,8 @@ def __init__( elif kwargs["devices"] > 1: # pragma: no cover if kwargs["accelerator"] == "gpu": ddp_plugin = DDPStrategy( - find_unused_parameters=find_unused_parameters + find_unused_parameters=find_unused_parameters, + timeout=datetime.timedelta(timeout), ) kwargs["strategy"] = ddp_plugin From 4ca57f69cbd17e5eaaf8b3dbf23ebc6d8fc08966 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Fri, 30 Aug 2024 21:45:55 +0200 Subject: [PATCH 14/50] fix: Fix lint. --- vis4d/engine/callbacks/evaluator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vis4d/engine/callbacks/evaluator.py b/vis4d/engine/callbacks/evaluator.py index b7b34bc4..c536e466 100644 --- a/vis4d/engine/callbacks/evaluator.py +++ b/vis4d/engine/callbacks/evaluator.py @@ -118,7 +118,7 @@ def evaluate(self, metric: str) -> MetricLogs: values are the corresponding evaluated values. """ rank_zero_info( - f"Running evaluator {str(self.evaluator)} with {metric} metric... ", + f"Running evaluator {str(self.evaluator)} with {metric} metric... " ) log_dict = {} From ae4523a00a656dfd705e41b7deb2d6f4c0b4dd40 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Mon, 2 Sep 2024 16:27:47 +0200 Subject: [PATCH 15/50] fix: Fix bbox3d visualizer for corner cases. Update Visualizer callback to support multiple visualizers. --- vis4d/engine/callbacks/visualizer.py | 17 ++++++-- vis4d/vis/image/bbox3d_visualizer.py | 62 +++++++++++++++------------- vis4d/vis/image/util.py | 22 +++++++--- 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/vis4d/engine/callbacks/visualizer.py b/vis4d/engine/callbacks/visualizer.py index 8b12159a..d8003112 100644 --- a/vis4d/engine/callbacks/visualizer.py +++ b/vis4d/engine/callbacks/visualizer.py @@ -27,6 +27,7 @@ def __init__( show: bool = False, save_to_disk: bool = True, save_prefix: str | None = None, + output_dir: str | None = None, **kwargs: ArgsType, ) -> None: """Init callback. @@ -35,11 +36,13 @@ def __init__( visualizer (Visualizer): Visualizer. visualize_train (bool): If the training data should be visualized. Defaults to False. - save_prefix (str): Output directory for saving the visualizations. show (bool): If the visualizations should be shown. Defaults to False. save_to_disk (bool): If the visualizations should be saved to disk. Defaults to True. + save_prefix (str): Output directory prefix for distinguish + different visualizations. + output_dir (str): Output directory for saving the visualizations. """ super().__init__(*args, **kwargs) self.visualizer = visualizer @@ -50,9 +53,15 @@ def __init__( if self.save_to_disk: assert ( - save_prefix is not None - ), "If save_to_disk is True, save_prefix must be provided." - self.output_dir = f"{self.save_prefix}/vis" + output_dir is not None + ), "If save_to_disk is True, output_dir must be provided." + + output_dir = os.path.join(output_dir, "vis") + + if save_prefix is not None: + output_dir = os.path.join(output_dir, save_prefix) + + self.output_dir = output_dir def setup(self) -> None: # pragma: no cover """Setup callback.""" diff --git a/vis4d/vis/image/bbox3d_visualizer.py b/vis4d/vis/image/bbox3d_visualizer.py index 74f4a7f3..8020fdc3 100644 --- a/vis4d/vis/image/bbox3d_visualizer.py +++ b/vis4d/vis/image/bbox3d_visualizer.py @@ -230,30 +230,32 @@ def process_single_image( [], ) - for center, corners, label, color, track_id in zip( - *preprocess_boxes3d( - image_hw, - boxes3d, - intrinsics, - extrinsics, - scores, - class_ids, - track_ids, - self.color_palette, - self.class_id_mapping, - axis_mode=self.axis_mode, - ) - ): - data_sample.boxes.append( - DetectionBox3D( - corners=corners, - label=label, - color=color, - track_id=track_id, + if len(boxes3d) != 0: + for center, corners, label, color, track_id in zip( + *preprocess_boxes3d( + image_hw, + boxes3d, + intrinsics, + extrinsics, + scores, + class_ids, + track_ids, + self.color_palette, + self.class_id_mapping, + axis_mode=self.axis_mode, ) - ) - if track_id is not None: - self.trajectories[track_id].append(center) + ): + data_sample.boxes.append( + DetectionBox3D( + corners=corners, + label=label, + color=color, + track_id=track_id, + ) + ) + if track_id is not None: + self.trajectories[track_id].append(center) + self._samples.append(data_sample) def show(self, cur_iter: int, blocking: bool = True) -> None: @@ -279,9 +281,13 @@ def _draw_image(self, sample: DataSample) -> NDArrayUI8: """ self.canvas.create_canvas(sample.image) - global_to_cam = inverse_rigid_transform( - torch.from_numpy(sample.extrinsics) - ).numpy() + if self.plot_trajectory: + assert ( + sample.extrinsics is not None + ), "Extrinsics is needed to plot trajectory." + global_to_cam = inverse_rigid_transform( + torch.from_numpy(sample.extrinsics) + ).numpy() for box in sample.boxes: self.canvas.draw_box_3d( @@ -300,8 +306,8 @@ def _draw_image(self, sample: DataSample) -> NDArrayUI8: if self.plot_trajectory: assert ( - sample.extrinsics is not None and box.track_id is not None - ), "Extrinsics and track id must be set to plot trajectory." + box.track_id is not None + ), "track id must be set to plot trajectory." trajectory = self.trajectories[box.track_id] for center in trajectory: diff --git a/vis4d/vis/image/util.py b/vis4d/vis/image/util.py index c2a20afb..e57c5ae0 100644 --- a/vis4d/vis/image/util.py +++ b/vis4d/vis/image/util.py @@ -223,18 +223,28 @@ def preprocess_boxes3d( class_ids_np = array_to_numpy(class_ids, n_dims=1, dtype=np.int32) track_ids_np = array_to_numpy(track_ids, n_dims=1, dtype=np.int32) - boxes3d_np = boxes3d_np[mask] - corners_np = corners_np[mask] - scores_np = scores_np[mask] if scores_np is not None else None - class_ids_np = class_ids_np[mask] if class_ids_np is not None else None - track_ids_np = track_ids_np[mask] if track_ids_np is not None else None - centers_proc: list[tuple[float, float, float]] = [] corners_proc: list[list[tuple[float, float, float]]] = [] colors_proc: list[tuple[int, int, int]] = [] labels_proc: list[str] = [] track_ids_proc: list[int] = [] + if len(mask) == 1: + if not mask[0]: + return ( + centers_proc, + corners_proc, + labels_proc, + colors_proc, + track_ids_proc, + ) + else: + boxes3d_np = boxes3d_np[mask] + corners_np = corners_np[mask] + scores_np = scores_np[mask] if scores_np is not None else None + class_ids_np = class_ids_np[mask] if class_ids_np is not None else None + track_ids_np = track_ids_np[mask] if track_ids_np is not None else None + for idx in range(corners_np.shape[0]): class_id = None if class_ids_np is None else class_ids_np[idx].item() score = None if scores_np is None else scores_np[idx].item() From d95fb728185f8311695335534157db18580ecf89 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Sun, 13 Oct 2024 22:32:18 +0200 Subject: [PATCH 16/50] feat: Add grad checking and set wandb id. --- pyproject.toml | 1 + vis4d/pl/trainer.py | 1 + vis4d/pl/training_module.py | 41 ++++++++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9a06910a..22fd40ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ line_length = 79 [tool.pyright] include = ["vis4d"] +typeCheckingMode = "off" [tool.coverage] [tool.coverage.report] diff --git a/vis4d/pl/trainer.py b/vis4d/pl/trainer.py index 7d3db479..b3e067ec 100644 --- a/vis4d/pl/trainer.py +++ b/vis4d/pl/trainer.py @@ -75,6 +75,7 @@ def __init__( save_dir=work_dir, project=exp_name, name=version, + id=version, ) elif TENSORBOARD_AVAILABLE: exp_logger = TensorBoardLogger( diff --git a/vis4d/pl/training_module.py b/vis4d/pl/training_module.py index 8cc78153..48c6f7b6 100644 --- a/vis4d/pl/training_module.py +++ b/vis4d/pl/training_module.py @@ -6,14 +6,16 @@ import lightning.pytorch as pl from lightning.pytorch import seed_everything +from lightning.pytorch.core.optimizer import LightningOptimizer from ml_collections import ConfigDict from torch import nn +from torch.optim.optimizer import Optimizer from vis4d.common.ckpt import load_model_checkpoint from vis4d.common.distributed import broadcast from vis4d.common.imports import FVCORE_AVAILABLE from vis4d.common.logging import rank_zero_info -from vis4d.common.typing import DictStrAny +from vis4d.common.typing import DictStrAny, GenericFunc from vis4d.common.util import init_random_seed from vis4d.config import instantiate_classes from vis4d.config.typing import OptimizerConfig @@ -45,6 +47,7 @@ def __init__( seed: int = -1, ckpt_path: None | str = None, compute_flops: bool = False, + check_the_unused_parameters: bool = False, ) -> None: """Initialize the TrainingModule. @@ -63,6 +66,8 @@ def __init__( Defaults to None. compute_flops (bool, optional): If to compute the FLOPs of the model. Defaults to False. + check_the_unused_parameters (bool, optional): If to check the + unused parameters. Defaults to False. """ super().__init__() self.model_cfg = model_cfg @@ -74,6 +79,7 @@ def __init__( self.seed = seed self.ckpt_path = ckpt_path self.compute_flops = compute_flops + self.check_unused_parameters = check_the_unused_parameters # Create model placeholder self.model: nn.Module @@ -187,3 +193,36 @@ def lr_scheduler_step( # type: ignore # pylint: disable=arguments-differ,line-t """Perform a step on the lr scheduler.""" # TODO: Support metric if needed scheduler.step(self.current_epoch) + + def optimizer_step( + self, + epoch: int, + batch_idx: int, + optimizer: Optimizer | LightningOptimizer, + optimizer_closure: GenericFunc | None = None, + ) -> None: + """Optimizer step. + + Args: + epoch (int): Current epoch. + batch_idx (int): Index of current batch. + optimizer: A PyTorch optimizer + optimizer_closure: The optimizer closure. This closure must be executed as it includes the + calls to ``training_step()``, ``optimizer.zero_grad()``, and ``backward()``. + + Examples:: + + def optimizer_step(self, epoch, batch_idx, optimizer, optimizer_closure): + # Add your custom logic to run directly before `optimizer.step()` + + optimizer.step(closure=optimizer_closure) + + # Add your custom logic to run directly after `optimizer.step()` + + """ + if self.check_unused_parameters: + for name, param in self.model.named_parameters(): + if param.grad is None: + rank_zero_info(name) + + optimizer.step(closure=optimizer_closure) From 53f2242570da12a7a9aacac99db690b62882987a Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 15 Oct 2024 13:55:52 +0200 Subject: [PATCH 17/50] fix: Fix function args. --- vis4d/eval/common/depth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vis4d/eval/common/depth.py b/vis4d/eval/common/depth.py index 02d7db4b..cee434ef 100644 --- a/vis4d/eval/common/depth.py +++ b/vis4d/eval/common/depth.py @@ -100,8 +100,8 @@ def process_batch( # type: ignore # pylint: disable=arguments-differ """Process a batch of data. Args: - prediction (np.array): Prediction optical flow, in shape (H, W, 2). - groundtruth (np.array): Target optical flow, in shape (H, W, 2). + prediction (np.array): Prediction optical flow, in shape (B, H, W). + groundtruth (np.array): Target optical flow, in shape (B, H, W). """ preds = ( array_to_numpy(prediction, n_dims=None, dtype=np.float32) From efd205c5f9bf8b8f7ec934b064d82608bb908680 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Thu, 28 Nov 2024 14:58:35 +0100 Subject: [PATCH 18/50] feat: Update CBGS, bbox3D visualization. --- vis4d/data/cbgs.py | 4 +- vis4d/vis/image/bbox3d_visualizer.py | 5 + vis4d/vis/image/canvas/pillow_backend.py | 173 +++-------------------- 3 files changed, 28 insertions(+), 154 deletions(-) diff --git a/vis4d/data/cbgs.py b/vis4d/data/cbgs.py index 226b25d0..d087ad54 100644 --- a/vis4d/data/cbgs.py +++ b/vis4d/data/cbgs.py @@ -113,7 +113,9 @@ def _get_sample_indices(self) -> list[int]: sample_indices = [] frac = 1.0 / len(self.cat2id) - ratios = [frac / v for v in class_distribution.values()] + ratios = [ + frac / v if v > 0 else 1 for v in class_distribution.values() + ] for cls_inds, ratio in zip( list(class_sample_indices.values()), ratios ): diff --git a/vis4d/vis/image/bbox3d_visualizer.py b/vis4d/vis/image/bbox3d_visualizer.py index 8020fdc3..89225294 100644 --- a/vis4d/vis/image/bbox3d_visualizer.py +++ b/vis4d/vis/image/bbox3d_visualizer.py @@ -64,6 +64,7 @@ def __init__( image_mode: str = "RGB", width: int = 2, camera_near_clip: float = 0.15, + plot_heading: bool = True, axis_mode: AxisMode = AxisMode.ROS, trajectory_length: int = 10, plot_trajectory: bool = True, @@ -84,6 +85,8 @@ def __init__( width (int): Width of the drawn bounding boxes. Defaults to 2. camera_near_clip (float): Near clipping plane of the camera. Defaults to 0.15. + plot_heading (bool): If the heading should be plotted. Defaults to + True. axis_mode (AxisMode): Axis mode for the input bboxes. Defaults to AxisMode.ROS (i.e. global coordinate). trajectory_length (int): How many past frames should be used to @@ -117,6 +120,7 @@ def __init__( self.width = width self.camera_near_clip = camera_near_clip + self.plot_heading = plot_heading self.canvas = canvas if canvas is not None else PillowCanvasBackend() self.viewer = viewer if viewer is not None else MatplotlibImageViewer() @@ -296,6 +300,7 @@ def _draw_image(self, sample: DataSample) -> NDArrayUI8: sample.intrinsics, self.width, self.camera_near_clip, + self.plot_heading, ) selected_corner = project_point(box.corners[0], sample.intrinsics) diff --git a/vis4d/vis/image/canvas/pillow_backend.py b/vis4d/vis/image/canvas/pillow_backend.py index 05bb0252..8b4da8a2 100644 --- a/vis4d/vis/image/canvas/pillow_backend.py +++ b/vis4d/vis/image/canvas/pillow_backend.py @@ -2,12 +2,9 @@ from __future__ import annotations -import base64 -from io import BytesIO - import numpy as np from PIL import Image, ImageDraw -from PIL.ImageFont import ImageFont +from PIL.ImageFont import ImageFont, load_default from vis4d.common.typing import NDArrayBool, NDArrayF32, NDArrayF64, NDArrayUI8 @@ -18,14 +15,17 @@ class PillowCanvasBackend(CanvasBackend): """Canvas backend using Pillow.""" - def __init__(self, font: ImageFont | None = None) -> None: + def __init__( + self, font: ImageFont | None = None, font_size: int | None = None + ) -> None: """Creates a new canvas backend. Args: font (ImageFont): Pillow font to use for the label. + font_size (int): Font size to use for the label. """ self._image_draw: ImageDraw.ImageDraw | None = None - self._font = font if font is not None else load_default_font() + self._font = font if font is not None else load_default(font_size) self._image: Image.Image | None = None def create_canvas( @@ -282,6 +282,7 @@ def draw_box_3d( intrinsics: NDArrayF32, width: int = 0, camera_near_clip: float = 0.15, + plot_heading: bool = True, ) -> None: """Draws a 3D box onto the given canvas.""" # Draw Front @@ -327,16 +328,19 @@ def draw_box_3d( ) # Draw line indicating the front - center_bottom_forward = np.mean(corners[:2], axis=0, dtype=np.float32) - center_bottom = np.mean(corners[:4], axis=0, dtype=np.float32) - self._draw_box_3d_line( - tuple(center_bottom.tolist()), - tuple(center_bottom_forward.tolist()), - color, - intrinsics, - width, - camera_near_clip, - ) + if plot_heading: + center_bottom_forward = np.mean( + corners[:2], axis=0, dtype=np.float32 + ) + center_bottom = np.mean(corners[:4], axis=0, dtype=np.float32) + self._draw_box_3d_line( + tuple(center_bottom.tolist()), + tuple(center_bottom_forward.tolist()), + color, + intrinsics, + width, + camera_near_clip, + ) def as_numpy_image(self) -> NDArrayUI8: """Returns the current canvas as numpy image. @@ -364,140 +368,3 @@ def save_to_disk(self, image_path: str) -> None: "No Image initialized! Did you call 'create_canvas'?" ) self._image.save(image_path) - - -def load_default_font() -> ImageFont: - """Load a "better than nothing" default font.""" - f = ImageFont() - f._load_pilfont_data( # pylint: disable=protected-access - # courB08 - BytesIO( - base64.b64decode( - b""" -UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAA//8AAQAAAAAAAAABAAEA -BgAAAAH/+gADAAAAAQAAAAMABgAGAAAAAf/6AAT//QADAAAABgADAAYAAAAA//kABQABAAYAAAAL -AAgABgAAAAD/+AAFAAEACwAAABAACQAGAAAAAP/5AAUAAAAQAAAAFQAHAAYAAP////oABQAAABUA -AAAbAAYABgAAAAH/+QAE//wAGwAAAB4AAwAGAAAAAf/5AAQAAQAeAAAAIQAIAAYAAAAB//kABAAB -ACEAAAAkAAgABgAAAAD/+QAE//0AJAAAACgABAAGAAAAAP/6AAX//wAoAAAALQAFAAYAAAAB//8A -BAACAC0AAAAwAAMABgAAAAD//AAF//0AMAAAADUAAQAGAAAAAf//AAMAAAA1AAAANwABAAYAAAAB -//kABQABADcAAAA7AAgABgAAAAD/+QAFAAAAOwAAAEAABwAGAAAAAP/5AAYAAABAAAAARgAHAAYA -AAAA//kABQAAAEYAAABLAAcABgAAAAD/+QAFAAAASwAAAFAABwAGAAAAAP/5AAYAAABQAAAAVgAH -AAYAAAAA//kABQAAAFYAAABbAAcABgAAAAD/+QAFAAAAWwAAAGAABwAGAAAAAP/5AAUAAABgAAAA -ZQAHAAYAAAAA//kABQAAAGUAAABqAAcABgAAAAD/+QAFAAAAagAAAG8ABwAGAAAAAf/8AAMAAABv -AAAAcQAEAAYAAAAA//wAAwACAHEAAAB0AAYABgAAAAD/+gAE//8AdAAAAHgABQAGAAAAAP/7AAT/ -/gB4AAAAfAADAAYAAAAB//oABf//AHwAAACAAAUABgAAAAD/+gAFAAAAgAAAAIUABgAGAAAAAP/5 -AAYAAQCFAAAAiwAIAAYAAP////oABgAAAIsAAACSAAYABgAA////+gAFAAAAkgAAAJgABgAGAAAA -AP/6AAUAAACYAAAAnQAGAAYAAP////oABQAAAJ0AAACjAAYABgAA////+gAFAAAAowAAAKkABgAG -AAD////6AAUAAACpAAAArwAGAAYAAAAA//oABQAAAK8AAAC0AAYABgAA////+gAGAAAAtAAAALsA -BgAGAAAAAP/6AAQAAAC7AAAAvwAGAAYAAP////oABQAAAL8AAADFAAYABgAA////+gAGAAAAxQAA -AMwABgAGAAD////6AAUAAADMAAAA0gAGAAYAAP////oABQAAANIAAADYAAYABgAA////+gAGAAAA -2AAAAN8ABgAGAAAAAP/6AAUAAADfAAAA5AAGAAYAAP////oABQAAAOQAAADqAAYABgAAAAD/+gAF -AAEA6gAAAO8ABwAGAAD////6AAYAAADvAAAA9gAGAAYAAAAA//oABQAAAPYAAAD7AAYABgAA//// -+gAFAAAA+wAAAQEABgAGAAD////6AAYAAAEBAAABCAAGAAYAAP////oABgAAAQgAAAEPAAYABgAA -////+gAGAAABDwAAARYABgAGAAAAAP/6AAYAAAEWAAABHAAGAAYAAP////oABgAAARwAAAEjAAYA -BgAAAAD/+gAFAAABIwAAASgABgAGAAAAAf/5AAQAAQEoAAABKwAIAAYAAAAA//kABAABASsAAAEv -AAgABgAAAAH/+QAEAAEBLwAAATIACAAGAAAAAP/5AAX//AEyAAABNwADAAYAAAAAAAEABgACATcA -AAE9AAEABgAAAAH/+QAE//wBPQAAAUAAAwAGAAAAAP/7AAYAAAFAAAABRgAFAAYAAP////kABQAA -AUYAAAFMAAcABgAAAAD/+wAFAAABTAAAAVEABQAGAAAAAP/5AAYAAAFRAAABVwAHAAYAAAAA//sA -BQAAAVcAAAFcAAUABgAAAAD/+QAFAAABXAAAAWEABwAGAAAAAP/7AAYAAgFhAAABZwAHAAYAAP// -//kABQAAAWcAAAFtAAcABgAAAAD/+QAGAAABbQAAAXMABwAGAAAAAP/5AAQAAgFzAAABdwAJAAYA -AP////kABgAAAXcAAAF+AAcABgAAAAD/+QAGAAABfgAAAYQABwAGAAD////7AAUAAAGEAAABigAF -AAYAAP////sABQAAAYoAAAGQAAUABgAAAAD/+wAFAAABkAAAAZUABQAGAAD////7AAUAAgGVAAAB -mwAHAAYAAAAA//sABgACAZsAAAGhAAcABgAAAAD/+wAGAAABoQAAAacABQAGAAAAAP/7AAYAAAGn -AAABrQAFAAYAAAAA//kABgAAAa0AAAGzAAcABgAA////+wAGAAABswAAAboABQAGAAD////7AAUA -AAG6AAABwAAFAAYAAP////sABgAAAcAAAAHHAAUABgAAAAD/+wAGAAABxwAAAc0ABQAGAAD////7 -AAYAAgHNAAAB1AAHAAYAAAAA//sABQAAAdQAAAHZAAUABgAAAAH/+QAFAAEB2QAAAd0ACAAGAAAA -Av/6AAMAAQHdAAAB3gAHAAYAAAAA//kABAABAd4AAAHiAAgABgAAAAD/+wAF//0B4gAAAecAAgAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAB -//sAAwACAecAAAHpAAcABgAAAAD/+QAFAAEB6QAAAe4ACAAGAAAAAP/5AAYAAAHuAAAB9AAHAAYA -AAAA//oABf//AfQAAAH5AAUABgAAAAD/+QAGAAAB+QAAAf8ABwAGAAAAAv/5AAMAAgH/AAACAAAJ -AAYAAAAA//kABQABAgAAAAIFAAgABgAAAAH/+gAE//sCBQAAAggAAQAGAAAAAP/5AAYAAAIIAAAC -DgAHAAYAAAAB//kABf/+Ag4AAAISAAUABgAA////+wAGAAACEgAAAhkABQAGAAAAAP/7AAX//gIZ -AAACHgADAAYAAAAA//wABf/9Ah4AAAIjAAEABgAAAAD/+QAHAAACIwAAAioABwAGAAAAAP/6AAT/ -+wIqAAACLgABAAYAAAAA//kABP/8Ai4AAAIyAAMABgAAAAD/+gAFAAACMgAAAjcABgAGAAAAAf/5 -AAT//QI3AAACOgAEAAYAAAAB//kABP/9AjoAAAI9AAQABgAAAAL/+QAE//sCPQAAAj8AAgAGAAD/ -///7AAYAAgI/AAACRgAHAAYAAAAA//kABgABAkYAAAJMAAgABgAAAAH//AAD//0CTAAAAk4AAQAG -AAAAAf//AAQAAgJOAAACUQADAAYAAAAB//kABP/9AlEAAAJUAAQABgAAAAH/+QAF//4CVAAAAlgA -BQAGAAD////7AAYAAAJYAAACXwAFAAYAAP////kABgAAAl8AAAJmAAcABgAA////+QAGAAACZgAA -Am0ABwAGAAD////5AAYAAAJtAAACdAAHAAYAAAAA//sABQACAnQAAAJ5AAcABgAA////9wAGAAAC -eQAAAoAACQAGAAD////3AAYAAAKAAAAChwAJAAYAAP////cABgAAAocAAAKOAAkABgAA////9wAG -AAACjgAAApUACQAGAAD////4AAYAAAKVAAACnAAIAAYAAP////cABgAAApwAAAKjAAkABgAA//// -+gAGAAACowAAAqoABgAGAAAAAP/6AAUAAgKqAAACrwAIAAYAAP////cABQAAAq8AAAK1AAkABgAA -////9wAFAAACtQAAArsACQAGAAD////3AAUAAAK7AAACwQAJAAYAAP////gABQAAAsEAAALHAAgA -BgAAAAD/9wAEAAACxwAAAssACQAGAAAAAP/3AAQAAALLAAACzwAJAAYAAAAA//cABAAAAs8AAALT -AAkABgAAAAD/+AAEAAAC0wAAAtcACAAGAAD////6AAUAAALXAAAC3QAGAAYAAP////cABgAAAt0A -AALkAAkABgAAAAD/9wAFAAAC5AAAAukACQAGAAAAAP/3AAUAAALpAAAC7gAJAAYAAAAA//cABQAA -Au4AAALzAAkABgAAAAD/9wAFAAAC8wAAAvgACQAGAAAAAP/4AAUAAAL4AAAC/QAIAAYAAAAA//oA -Bf//Av0AAAMCAAUABgAA////+gAGAAADAgAAAwkABgAGAAD////3AAYAAAMJAAADEAAJAAYAAP// -//cABgAAAxAAAAMXAAkABgAA////9wAGAAADFwAAAx4ACQAGAAD////4AAYAAAAAAAoABwASAAYA -AP////cABgAAAAcACgAOABMABgAA////+gAFAAAADgAKABQAEAAGAAD////6AAYAAAAUAAoAGwAQ -AAYAAAAA//gABgAAABsACgAhABIABgAAAAD/+AAGAAAAIQAKACcAEgAGAAAAAP/4AAYAAAAnAAoA -LQASAAYAAAAA//gABgAAAC0ACgAzABIABgAAAAD/+QAGAAAAMwAKADkAEQAGAAAAAP/3AAYAAAA5 -AAoAPwATAAYAAP////sABQAAAD8ACgBFAA8ABgAAAAD/+wAFAAIARQAKAEoAEQAGAAAAAP/4AAUA -AABKAAoATwASAAYAAAAA//gABQAAAE8ACgBUABIABgAAAAD/+AAFAAAAVAAKAFkAEgAGAAAAAP/5 -AAUAAABZAAoAXgARAAYAAAAA//gABgAAAF4ACgBkABIABgAAAAD/+AAGAAAAZAAKAGoAEgAGAAAA -AP/4AAYAAABqAAoAcAASAAYAAAAA//kABgAAAHAACgB2ABEABgAAAAD/+AAFAAAAdgAKAHsAEgAG -AAD////4AAYAAAB7AAoAggASAAYAAAAA//gABQAAAIIACgCHABIABgAAAAD/+AAFAAAAhwAKAIwA -EgAGAAAAAP/4AAUAAACMAAoAkQASAAYAAAAA//gABQAAAJEACgCWABIABgAAAAD/+QAFAAAAlgAK -AJsAEQAGAAAAAP/6AAX//wCbAAoAoAAPAAYAAAAA//oABQABAKAACgClABEABgAA////+AAGAAAA -pQAKAKwAEgAGAAD////4AAYAAACsAAoAswASAAYAAP////gABgAAALMACgC6ABIABgAA////+QAG -AAAAugAKAMEAEQAGAAD////4AAYAAgDBAAoAyAAUAAYAAP////kABQACAMgACgDOABMABgAA//// -+QAGAAIAzgAKANUAEw== -""" - ) - ), - Image.open( - BytesIO( - base64.b64decode( - b""" -iVBORw0KGgoAAAANSUhEUgAAAx4AAAAUAQAAAAArMtZoAAAEwElEQVR4nABlAJr/AHVE4czCI/4u -Mc4b7vuds/xzjz5/3/7u/n9vMe7vnfH/9++vPn/xyf5zhxzjt8GHw8+2d83u8x27199/nxuQ6Od9 -M43/5z2I+9n9ZtmDBwMQECDRQw/eQIQohJXxpBCNVE6QCCAAAAD//wBlAJr/AgALyj1t/wINwq0g -LeNZUworuN1cjTPIzrTX6ofHWeo3v336qPzfEwRmBnHTtf95/fglZK5N0PDgfRTslpGBvz7LFc4F -IUXBWQGjQ5MGCx34EDFPwXiY4YbYxavpnhHFrk14CDAAAAD//wBlAJr/AgKqRooH2gAgPeggvUAA -Bu2WfgPoAwzRAABAAAAAAACQgLz/3Uv4Gv+gX7BJgDeeGP6AAAD1NMDzKHD7ANWr3loYbxsAD791 -NAADfcoIDyP44K/jv4Y63/Z+t98Ovt+ub4T48LAAAAD//wBlAJr/AuplMlADJAAAAGuAphWpqhMx -in0A/fRvAYBABPgBwBUgABBQ/sYAyv9g0bCHgOLoGAAAAAAAREAAwI7nr0ArYpow7aX8//9LaP/9 -SjdavWA8ePHeBIKB//81/83ndznOaXx379wAAAD//wBlAJr/AqDxW+D3AABAAbUh/QMnbQag/gAY -AYDAAACgtgD/gOqAAAB5IA/8AAAk+n9w0AAA8AAAmFRJuPo27ciC0cD5oeW4E7KA/wD3ECMAn2tt -y8PgwH8AfAxFzC0JzeAMtratAsC/ffwAAAD//wBlAJr/BGKAyCAA4AAAAvgeYTAwHd1kmQF5chkG -ABoMIHcL5xVpTfQbUqzlAAAErwAQBgAAEOClA5D9il08AEh/tUzdCBsXkbgACED+woQg8Si9VeqY -lODCn7lmF6NhnAEYgAAA/NMIAAAAAAD//2JgjLZgVGBg5Pv/Tvpc8hwGBjYGJADjHDrAwPzAjv/H -/Wf3PzCwtzcwHmBgYGcwbZz8wHaCAQMDOwMDQ8MCBgYOC3W7mp+f0w+wHOYxO3OG+e376hsMZjk3 -AAAAAP//YmCMY2A4wMAIN5e5gQETPD6AZisDAwMDgzSDAAPjByiHcQMDAwMDg1nOze1lByRu5/47 -c4859311AYNZzg0AAAAA//9iYGDBYihOIIMuwIjGL39/fwffA8b//xv/P2BPtzzHwCBjUQAAAAD/ -/yLFBrIBAAAA//9i1HhcwdhizX7u8NZNzyLbvT97bfrMf/QHI8evOwcSqGUJAAAA//9iYBB81iSw -pEE170Qrg5MIYydHqwdDQRMrAwcVrQAAAAD//2J4x7j9AAMDn8Q/BgYLBoaiAwwMjPdvMDBYM1Tv -oJodAAAAAP//Yqo/83+dxePWlxl3npsel9lvLfPcqlE9725C+acfVLMEAAAA//9i+s9gwCoaaGMR -evta/58PTEWzr21hufPjA8N+qlnBwAAAAAD//2JiWLci5v1+HmFXDqcnULE/MxgYGBj+f6CaJQAA -AAD//2Ji2FrkY3iYpYC5qDeGgeEMAwPDvwQBBoYvcTwOVLMEAAAA//9isDBgkP///0EOg9z35v// -Gc/eeW7BwPj5+QGZhANUswMAAAD//2JgqGBgYGBgqEMXlvhMPUsAAAAA//8iYDd1AAAAAP//AwDR -w7IkEbzhVQAAAABJRU5ErkJggg== -""" - ) - ) - ), - ) - return f From d8751fe8ae4f805a83a6a02175523db282177aaa Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Mon, 2 Dec 2024 18:22:08 +0100 Subject: [PATCH 19/50] feat: Add AspectRationBatchSampler. --- vis4d/data/loader.py | 14 ++++++-- vis4d/data/samplers.py | 68 ++++++++++++++++++++++++++++++++++++ vis4d/zoo/base/dataloader.py | 2 ++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/vis4d/data/loader.py b/vis4d/data/loader.py index 482697e5..dc3c4380 100644 --- a/vis4d/data/loader.py +++ b/vis4d/data/loader.py @@ -16,7 +16,7 @@ from .const import CommonKeys as K from .data_pipe import DataPipe from .datasets import VideoDataset -from .samplers import VideoInferenceSampler +from .samplers import AspectRatioBatchSampler, VideoInferenceSampler from .transforms import compose from .transforms.to_tensor import ToTensor from .typing import DictData, DictDataOrList @@ -123,6 +123,7 @@ def build_train_dataloader( pin_memory: bool = True, shuffle: bool = True, seed: int | None = None, + aspect_ratio_grouping: bool = False, disable_subprocess_warning: bool = False, ) -> DataLoader[DictDataOrList]: """Build training dataloader.""" @@ -169,6 +170,14 @@ def _worker_init_fn(worker_id: int) -> None: sampler = DistributedSampler(dataset, shuffle=shuffle) shuffle = False + batch_sampler = None + if aspect_ratio_grouping: + batch_sampler = AspectRatioBatchSampler( + sampler, batch_size=samples_per_gpu + ) + samples_per_gpu = 1 + shuffle = None + dataloader = DataLoader( dataset, batch_size=samples_per_gpu, @@ -176,7 +185,8 @@ def _worker_init_fn(worker_id: int) -> None: collate_fn=( _collate_fn_multi if dataset.has_reference else _collate_fn_single ), - sampler=sampler, + sampler=sampler if not aspect_ratio_grouping else None, + batch_sampler=batch_sampler, worker_init_fn=_worker_init_fn, persistent_workers=workers_per_gpu > 0, pin_memory=pin_memory, diff --git a/vis4d/data/samplers.py b/vis4d/data/samplers.py index ae3d00a1..3821b9e9 100644 --- a/vis4d/data/samplers.py +++ b/vis4d/data/samplers.py @@ -7,6 +7,9 @@ import numpy as np from torch.utils.data import Dataset from torch.utils.data.distributed import DistributedSampler +from torch.utils.data.sampler import BatchSampler, Sampler + +from vis4d.data.const import CommonKeys as K from .datasets.base import VideoDataset from .typing import DictDataOrList @@ -76,3 +79,68 @@ def __iter__(self) -> Iterator[list[int]]: def __len__(self) -> int: """Return length of sampler instance.""" return len(self._local_idcs) + + +class AspectRatioBatchSampler(BatchSampler): + """A sampler wrapper for grouping images with similar aspect ratio. + + Moidified from: + https://github.com/open-mmlab/mmdetection/blob/main/mmdet/datasets/samplers/batch_sampler.py + + Args: + sampler (Sampler): Base sampler. + batch_size (int): Size of mini-batch. + drop_last (bool): If ``True``, the sampler will drop the last batch if + its size would be less than ``batch_size``. + """ + + def __init__( + self, sampler: Sampler, batch_size: int, drop_last: bool = False + ) -> None: + if not isinstance(sampler, Sampler): + raise TypeError( + "sampler should be an instance of ``Sampler``, " + f"but got {sampler}" + ) + if not isinstance(batch_size, int) or batch_size <= 0: + raise ValueError( + "batch_size should be a positive integer value, " + f"but got batch_size={batch_size}" + ) + self.sampler = sampler + self.batch_size = batch_size + self.drop_last = drop_last + # two groups for w < h and w >= h + self._aspect_ratio_buckets = [[] for _ in range(2)] + + def __iter__(self): + for idx in self.sampler: + data_dict = self.sampler.dataset[idx] + height, width = data_dict[K.input_hw] + bucket_id = 0 if width < height else 1 + bucket = self._aspect_ratio_buckets[bucket_id] + bucket.append(idx) + # yield a batch of indices in the same aspect ratio group + if len(bucket) == self.batch_size: + yield bucket[:] + del bucket[:] + + # yield the rest data and reset the bucket + left_data = ( + self._aspect_ratio_buckets[0] + self._aspect_ratio_buckets[1] + ) + self._aspect_ratio_buckets = [[] for _ in range(2)] + while len(left_data) > 0: + if len(left_data) <= self.batch_size: + if not self.drop_last: + yield left_data[:] + left_data = [] + else: + yield left_data[: self.batch_size] + left_data = left_data[self.batch_size :] + + def __len__(self) -> int: + if self.drop_last: + return len(self.sampler) // self.batch_size + else: + return (len(self.sampler) + self.batch_size - 1) // self.batch_size diff --git a/vis4d/zoo/base/dataloader.py b/vis4d/zoo/base/dataloader.py index 6dcb70bd..0998852d 100644 --- a/vis4d/zoo/base/dataloader.py +++ b/vis4d/zoo/base/dataloader.py @@ -32,6 +32,7 @@ def get_train_dataloader_cfg( sensors: Sequence[str] | None = None, pin_memory: bool | FieldReference = True, shuffle: bool | FieldReference = True, + aspect_ratio_grouping: bool | FieldReference = False, ) -> ConfigDict: """Creates dataloader configuration given dataset and preprocessing. @@ -84,6 +85,7 @@ def get_train_dataloader_cfg( sensors=sensors, pin_memory=pin_memory, shuffle=shuffle, + aspect_ratio_grouping=aspect_ratio_grouping, ) From 72ca7caecadbff6e513acccd187554308a09820f Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Fri, 7 Feb 2025 23:27:05 +0100 Subject: [PATCH 20/50] feat: Update data loader for multiple datasets; add COCO categories; update bbox visualizer. --- vis4d/data/datasets/coco.py | 5 ++++ vis4d/data/loader.py | 16 +++++----- vis4d/engine/callbacks/visualizer.py | 20 +++++++------ vis4d/vis/image/bounding_box_visualizer.py | 4 +++ vis4d/vis/image/util.py | 35 +++++++++++++--------- 5 files changed, 49 insertions(+), 31 deletions(-) diff --git a/vis4d/data/datasets/coco.py b/vis4d/data/datasets/coco.py index 4e7a963c..9ab66f02 100644 --- a/vis4d/data/datasets/coco.py +++ b/vis4d/data/datasets/coco.py @@ -204,6 +204,9 @@ def __init__( cached_file_path=cached_file_path, ) + # TODO: Control category names depending on the task + self.category_names = sorted(coco_det_map, key=coco_det_map.get) + def __repr__(self) -> str: """Concise representation of the dataset.""" return ( @@ -355,4 +358,6 @@ def __getitem__(self, idx: int) -> DictData: seg_masks[mask_tensor.sum(0) > 1] = 255 # discard overlapped dict_data[K.seg_masks] = seg_masks[None] + dict_data["texts"] = self.category_names + return dict_data diff --git a/vis4d/data/loader.py b/vis4d/data/loader.py index dc3c4380..ff47cf88 100644 --- a/vis4d/data/loader.py +++ b/vis4d/data/loader.py @@ -226,17 +226,17 @@ def _collate_fn(data: list[DictData]) -> DictData: dataloaders = [] for dataset in datasets_: - if isinstance(dataset, DataPipe): - assert ( - len(dataset.datasets) == 1 - ), "Inference needs a single dataset per DataPipe." - current_dataset = dataset.datasets[0] - else: - current_dataset = dataset - sampler: DistributedSampler[list[int]] | None if get_world_size() > 1: if video_based_inference: + if isinstance(dataset, DataPipe): + assert ( + len(dataset.datasets) == 1 + ), "DDP Vdieo Inference only support a single dataset." + current_dataset = dataset.datasets[0] + else: + current_dataset = dataset + assert isinstance( current_dataset, VideoDataset ), "Video based inference needs a VideoDataset." diff --git a/vis4d/engine/callbacks/visualizer.py b/vis4d/engine/callbacks/visualizer.py index d8003112..a06c9a89 100644 --- a/vis4d/engine/callbacks/visualizer.py +++ b/vis4d/engine/callbacks/visualizer.py @@ -58,10 +58,8 @@ def __init__( output_dir = os.path.join(output_dir, "vis") - if save_prefix is not None: - output_dir = os.path.join(output_dir, save_prefix) - self.output_dir = output_dir + self.save_prefix = save_prefix def setup(self) -> None: # pragma: no cover """Setup callback.""" @@ -90,10 +88,12 @@ def on_train_batch_end( self.visualizer.show(cur_iter=cur_iter) if self.save_to_disk: - os.makedirs(f"{self.output_dir}/train", exist_ok=True) + output_folder = os.path.join( + self.output_dir, "train", self.save_prefix + ) + os.makedirs(output_folder, exist_ok=True) self.visualizer.save_to_disk( - cur_iter=cur_iter, - output_folder=f"{self.output_dir}/train", + cur_iter=cur_iter, output_folder=output_folder ) self.visualizer.reset() @@ -119,10 +119,12 @@ def on_test_batch_end( self.visualizer.show(cur_iter=cur_iter) if self.save_to_disk: - os.makedirs(f"{self.output_dir}/test", exist_ok=True) + output_folder = os.path.join( + self.output_dir, "test", self.save_prefix + ) + os.makedirs(output_folder, exist_ok=True) self.visualizer.save_to_disk( - cur_iter=cur_iter, - output_folder=f"{self.output_dir}/test", + cur_iter=cur_iter, output_folder=output_folder ) self.visualizer.reset() diff --git a/vis4d/vis/image/bounding_box_visualizer.py b/vis4d/vis/image/bounding_box_visualizer.py index f9dc88c4..bebcc992 100644 --- a/vis4d/vis/image/bounding_box_visualizer.py +++ b/vis4d/vis/image/bounding_box_visualizer.py @@ -87,6 +87,7 @@ def process( # type: ignore # pylint: disable=arguments-differ scores: None | list[ArrayLikeFloat] = None, class_ids: None | list[ArrayLikeInt] = None, track_ids: None | list[ArrayLikeInt] = None, + categories: None | list[list[str]] = None, ) -> None: """Processes a batch of data. @@ -112,6 +113,7 @@ class ids each of shape [N]. Defaults to None. None if scores is None else scores[idx], None if class_ids is None else class_ids[idx], None if track_ids is None else track_ids[idx], + None if categories is None else categories[idx], ) def process_single_image( @@ -122,6 +124,7 @@ def process_single_image( scores: None | ArrayLikeFloat = None, class_ids: None | ArrayLikeInt = None, track_ids: None | ArrayLikeInt = None, + categories: None | list[str] = None, ) -> None: """Processes a single image entry. @@ -148,6 +151,7 @@ def process_single_image( track_ids, self.color_palette, self.class_id_mapping, + categories=categories, ) ): data_sample.boxes.append( diff --git a/vis4d/vis/image/util.py b/vis4d/vis/image/util.py index e57c5ae0..bb8fada4 100644 --- a/vis4d/vis/image/util.py +++ b/vis4d/vis/image/util.py @@ -27,29 +27,25 @@ def _get_box_label( - class_id: int | None, + category: str | None, score: float | None, track_id: int | None, - class_id_mapping: dict[int, str] | None = None, ) -> str: """Gets a unique string representation for a box definition. Args: - class_id (int): The class id for this box + category (str): The category name score (float): The confidence score track_id (int): The track id - class_id_mapping (dict[int,str]): Mapping of class_id to class name Returns: str: Label for this box of format 'class_name, track_id, score%' """ labels = [] - if class_id_mapping is None: - class_id_mapping = {} - if class_id is not None: - labels.append(class_id_mapping.get(class_id, str(class_id))) + if category is not None: + labels.append(category) if track_id is not None: labels.append(str(track_id)) if score is not None: @@ -88,6 +84,7 @@ def preprocess_boxes( color_palette: list[tuple[int, int, int]] = DEFAULT_COLOR_MAPPING, class_id_mapping: dict[int, str] | None = None, default_color: tuple[int, int, int] = (255, 0, 0), + categories: None | list[str] = None, ) -> tuple[ list[tuple[float, float, float, float]], list[str], @@ -157,9 +154,15 @@ class or track id is given. ) ) colors_proc.append(color) - labels_proc.append( - _get_box_label(class_id, score, track_id, class_id_mapping) - ) + + if categories is not None: + category = categories[idx] + elif class_id is not None: + category = class_id_mapping.get(class_id, str(class_id)) + else: + category = None + + labels_proc.append(_get_box_label(category, score, track_id)) return boxes_proc, labels_proc, colors_proc @@ -266,9 +269,13 @@ def preprocess_boxes3d( ) corners_proc.append([tuple(pts) for pts in corners_np[idx].tolist()]) colors_proc.append(color) - labels_proc.append( - _get_box_label(class_id, score, track_id, class_id_mapping) - ) + + if class_id is not None: + category = class_id_mapping.get(class_id, str(class_id)) + else: + category = None + + labels_proc.append(_get_box_label(category, score, track_id)) track_ids_proc.append(track_id) return centers_proc, corners_proc, labels_proc, colors_proc, track_ids_proc From dce48476a3f4a7dd15c4118d2f844b0659074eba Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 11 Feb 2025 14:21:09 +0100 Subject: [PATCH 21/50] feat: Update bbox3d visualizer and evaluator. --- vis4d/engine/callbacks/evaluator.py | 15 +++++++++++++-- vis4d/vis/image/bbox3d_visualizer.py | 4 ++++ vis4d/vis/image/util.py | 5 ++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/vis4d/engine/callbacks/evaluator.py b/vis4d/engine/callbacks/evaluator.py index c536e466..57cb123f 100644 --- a/vis4d/engine/callbacks/evaluator.py +++ b/vis4d/engine/callbacks/evaluator.py @@ -41,6 +41,7 @@ def __init__( metrics_to_eval: list[str] | None = None, save_predictions: bool = False, save_prefix: None | str = None, + output_dir: str | None = None, **kwargs: ArgsType, ) -> None: """Init callback.""" @@ -51,14 +52,24 @@ def __init__( if self.save_predictions: assert ( - save_prefix is not None + output_dir is not None ), "If save_predictions is True, save_prefix must be provided." - self.output_dir = save_prefix + + output_dir = os.path.join(output_dir, "eval") + + self.output_dir = output_dir + self.save_prefix = save_prefix def setup(self) -> None: # pragma: no cover """Setup callback.""" if self.save_predictions: self.output_dir = broadcast(self.output_dir) + + if self.save_prefix is not None: + self.output_dir = os.path.join( + self.output_dir, self.save_prefix + ) + for metric in self.metrics_to_eval: output_dir = os.path.join(self.output_dir, metric) os.makedirs(output_dir, exist_ok=True) diff --git a/vis4d/vis/image/bbox3d_visualizer.py b/vis4d/vis/image/bbox3d_visualizer.py index 89225294..c3e868c7 100644 --- a/vis4d/vis/image/bbox3d_visualizer.py +++ b/vis4d/vis/image/bbox3d_visualizer.py @@ -140,6 +140,7 @@ def process( # type: ignore # pylint: disable=arguments-differ class_ids: None | list[ArrayLikeInt] = None, track_ids: None | list[ArrayLikeInt] = None, sequence_names: None | list[str] = None, + categories: None | list[list[str]] = None, ) -> None: """Processes a batch of data. @@ -176,6 +177,7 @@ class ids each of shape [B, N]. Defaults to None. None if class_ids is None else class_ids[batch], None if track_ids is None else track_ids[batch], None if sequence_names is None else sequence_names[batch], + None if categories is None else categories[batch], ) for tid in self.trajectories: @@ -193,6 +195,7 @@ def process_single_image( class_ids: None | ArrayLikeInt = None, track_ids: None | ArrayLikeInt = None, sequence_name: None | str = None, + categories: None | list[str] = None, camera_name: None | str = None, ) -> None: """Processes a single image entry. @@ -247,6 +250,7 @@ def process_single_image( self.color_palette, self.class_id_mapping, axis_mode=self.axis_mode, + categories=categories, ) ): data_sample.boxes.append( diff --git a/vis4d/vis/image/util.py b/vis4d/vis/image/util.py index bb8fada4..cf057337 100644 --- a/vis4d/vis/image/util.py +++ b/vis4d/vis/image/util.py @@ -178,6 +178,7 @@ def preprocess_boxes3d( class_id_mapping: dict[int, str] | None = None, default_color: tuple[int, int, int] = (255, 0, 0), axis_mode: AxisMode = AxisMode.OPENCV, + categories: None | list[str] = None, ) -> tuple[ list[tuple[float, float, float]], list[list[tuple[float, float, float]]], @@ -270,7 +271,9 @@ def preprocess_boxes3d( corners_proc.append([tuple(pts) for pts in corners_np[idx].tolist()]) colors_proc.append(color) - if class_id is not None: + if categories is not None: + category = categories[idx] + elif class_id is not None: category = class_id_mapping.get(class_id, str(class_id)) else: category = None From 23f85cd1c2d02751dd8f0335a147887d05c7b298 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 18 Feb 2025 21:37:28 +0100 Subject: [PATCH 22/50] feat: Update DLA basemodel. --- vis4d/op/base/dla.py | 241 ++++++++++++++++++++++++++++--------------- 1 file changed, 158 insertions(+), 83 deletions(-) diff --git a/vis4d/op/base/dla.py b/vis4d/op/base/dla.py index 31d73449..85934332 100644 --- a/vis4d/op/base/dla.py +++ b/vis4d/op/base/dla.py @@ -2,13 +2,22 @@ from __future__ import annotations +from collections.abc import Sequence + +import math + import torch from torch import Tensor, nn +from torch.utils.checkpoint import checkpoint + +from vis4d.common.ckpt import load_model_checkpoint from .base import BaseModel BN_MOMENTUM = 0.1 -DLA_MODEL_PREFIX = "http://dl.yf.io/dla/models/" + +DLA_MODEL_PREFIX = "http://dl.yf.io/dla/models/imagenet" + DLA_MODEL_MAPPING = { "dla34": "dla34-ba72cf86.pth", "dla46_c": "dla46_c-2bfd52c3.pth", @@ -21,6 +30,7 @@ "dla102x2": "dla102x2-262837b6.pth", "dla169": "dla169-0914e092.pth", } + DLA_ARCH_SETTINGS = { # pylint: disable=consider-using-namedtuple-or-dataclass "dla34": ( (1, 1, 1, 2, 2, 1), @@ -89,7 +99,12 @@ class BasicBlock(nn.Module): """BasicBlock.""" def __init__( - self, inplanes: int, planes: int, stride: int = 1, dilation: int = 1 + self, + inplanes: int, + planes: int, + stride: int = 1, + dilation: int = 1, + with_cp: bool = False, ) -> None: """Creates an instance of the class.""" super().__init__() @@ -115,22 +130,34 @@ def __init__( ) self.bn2 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM) self.stride = stride + self.with_cp = with_cp def forward( self, input_x: Tensor, residual: None | Tensor = None ) -> Tensor: """Forward.""" - if residual is None: - residual = input_x - out = self.conv1(input_x) - out = self.bn1(out) - out = self.relu(out) + def _inner_forward( + input_x: Tensor, residual: None | Tensor = None + ) -> Tensor: + if residual is None: + residual = input_x + out = self.conv1(input_x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + out += residual + + return out - out = self.conv2(out) - out = self.bn2(out) + if self.with_cp and input_x.requires_grad: + out = checkpoint(_inner_forward, input_x, residual) + else: + out = _inner_forward(input_x, residual) - out += residual out = self.relu(out) return out @@ -142,7 +169,12 @@ class Bottleneck(nn.Module): expansion = 2 def __init__( - self, inplanes: int, planes: int, stride: int = 1, dilation: int = 1 + self, + inplanes: int, + planes: int, + stride: int = 1, + dilation: int = 1, + with_cp: bool = False, ) -> None: """Creates an instance of the class.""" super().__init__() @@ -168,26 +200,39 @@ def __init__( self.bn3 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM) self.relu = nn.ReLU(inplace=True) self.stride = stride + self.with_cp = with_cp def forward( self, input_x: Tensor, residual: None | Tensor = None ) -> Tensor: """Forward.""" - if residual is None: - residual = input_x - out = self.conv1(input_x) - out = self.bn1(out) - out = self.relu(out) + def _inner_forward( + input_x: Tensor, residual: None | Tensor = None + ) -> Tensor: + if residual is None: + residual = input_x - out = self.conv2(out) - out = self.bn2(out) - out = self.relu(out) + out = self.conv1(input_x) + out = self.bn1(out) + out = self.relu(out) - out = self.conv3(out) - out = self.bn3(out) + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + out += residual + + return out + + if self.with_cp and input_x.requires_grad: + out = checkpoint(_inner_forward, input_x, residual) + else: + out = _inner_forward(input_x, residual) - out += residual out = self.relu(out) return out @@ -200,7 +245,12 @@ class BottleneckX(nn.Module): cardinality = 32 def __init__( - self, inplanes: int, planes: int, stride: int = 1, dilation: int = 1 + self, + inplanes: int, + planes: int, + stride: int = 1, + dilation: int = 1, + with_cp: bool = False, ) -> None: """Creates an instance of the class.""" super().__init__() @@ -227,26 +277,39 @@ def __init__( self.bn3 = nn.BatchNorm2d(planes, momentum=BN_MOMENTUM) self.relu = nn.ReLU(inplace=True) self.stride = stride + self.with_cp = with_cp def forward( self, input_x: Tensor, residual: None | Tensor = None ) -> Tensor: """Forward.""" - if residual is None: - residual = input_x - out = self.conv1(input_x) - out = self.bn1(out) - out = self.relu(out) + def _inner_forward( + input_x: Tensor, residual: None | Tensor = None + ) -> Tensor: + if residual is None: + residual = input_x - out = self.conv2(out) - out = self.bn2(out) - out = self.relu(out) + out = self.conv1(input_x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + out += residual - out = self.conv3(out) - out = self.bn3(out) + return out + + if self.with_cp and input_x.requires_grad: + out = checkpoint(_inner_forward, input_x, residual) + else: + out = _inner_forward(input_x, residual) - out += residual out = self.relu(out) return out @@ -272,7 +335,7 @@ def __init__( bias=False, padding=(kernel_size - 1) // 2, ) - self.bn1 = nn.BatchNorm2d(out_channels, momentum=BN_MOMENTUM) + self.bn = nn.BatchNorm2d(out_channels, momentum=BN_MOMENTUM) self.relu = nn.ReLU(inplace=True) self.residual = residual @@ -280,7 +343,7 @@ def forward(self, *input_x: Tensor) -> Tensor: """Forward.""" children = input_x feats = self.conv(torch.cat(input_x, 1)) - feats = self.bn1(feats) + feats = self.bn(feats) if self.residual: feats += children[0] feats = self.relu(feats) @@ -303,6 +366,7 @@ def __init__( # pylint: disable=too-many-arguments root_kernel_size: int = 1, dilation: int = 1, root_residual: bool = False, + with_cp: bool = False, ) -> None: """Creates an instance of the class.""" super().__init__() @@ -320,10 +384,18 @@ def __init__( # pylint: disable=too-many-arguments root_dim += in_channels if levels == 1: self.tree1: Tree | BasicBlock = block_c( - in_channels, out_channels, stride, dilation=dilation + in_channels, + out_channels, + stride, + dilation=dilation, + with_cp=with_cp, ) self.tree2: Tree | BasicBlock = block_c( - out_channels, out_channels, 1, dilation=dilation + out_channels, + out_channels, + 1, + dilation=dilation, + with_cp=with_cp, ) self.root = Root( root_dim, out_channels, root_kernel_size, root_residual @@ -339,6 +411,7 @@ def __init__( # pylint: disable=too-many-arguments root_kernel_size=root_kernel_size, dilation=dilation, root_residual=root_residual, + with_cp=with_cp, ) self.tree2 = Tree( levels - 1, @@ -349,6 +422,7 @@ def __init__( # pylint: disable=too-many-arguments root_kernel_size=root_kernel_size, dilation=dilation, root_residual=root_residual, + with_cp=with_cp, ) self.level_root = level_root self.root_dim = root_dim @@ -357,7 +431,8 @@ def __init__( # pylint: disable=too-many-arguments self.levels = levels if stride > 1: self.downsample = nn.MaxPool2d(stride, stride=stride) - if in_channels != out_channels and levels == 1: + if in_channels != out_channels: + # TODO: check if this is correct # NOTE the official impl/weights have project layers in levels > 1 # case that are never used, hence 'levels == 1' is added but # pretrained models will need strict=False while loading. @@ -369,7 +444,7 @@ def __init__( # pylint: disable=too-many-arguments stride=1, bias=False, ), - nn.BatchNorm2d(out_channels, momentum=BN_MOMENTUM), + nn.BatchNorm2d(out_channels), ) def forward( @@ -399,32 +474,21 @@ class DLA(BaseModel): def __init__( self, - name: None | str = None, - levels: tuple[int, int, int, int, int, int] = (1, 1, 1, 2, 2, 1), - channels: tuple[int, int, int, int, int, int] = ( - 16, - 32, - 64, - 128, - 256, - 512, - ), - block: str = "BasicBlock", - residual_root: bool = False, - cardinality: int = 32, + name: str, + out_indices: Sequence[int] = (0, 1, 2, 3), + with_cp: bool = False, + pretrained: bool = False, weights: None | str = None, - style: str = "imagenet", ) -> None: """Creates an instance of the class.""" super().__init__() - if name is not None: - assert name in DLA_ARCH_SETTINGS - arch_setting = DLA_ARCH_SETTINGS[name] - levels, channels, residual_root, block = arch_setting - if name == "dla102x2": # pragma: no cover - BottleneckX.cardinality = 64 - else: - BottleneckX.cardinality = cardinality + assert name in DLA_ARCH_SETTINGS, f"name is not supported!" + + levels, channels, residual_root, block = DLA_ARCH_SETTINGS[name] + + if name == "dla102x2": # pragma: no cover + BottleneckX.cardinality = 64 + self.base_layer = nn.Sequential( nn.Conv2d( 3, channels[0], kernel_size=7, stride=1, padding=3, bias=False @@ -446,6 +510,7 @@ def __init__( 2, level_root=False, root_residual=residual_root, + with_cp=with_cp, ) self.level3 = Tree( levels[3], @@ -455,6 +520,7 @@ def __init__( 2, level_root=True, root_residual=residual_root, + with_cp=with_cp, ) self.level4 = Tree( levels[4], @@ -464,6 +530,7 @@ def __init__( 2, level_root=True, root_residual=residual_root, + with_cp=with_cp, ) self.level5 = Tree( levels[5], @@ -473,19 +540,30 @@ def __init__( 2, level_root=True, root_residual=residual_root, + with_cp=with_cp, ) - self._out_channels = list(channels) + self.out_indices = out_indices + self._out_channels = [channels[i + 2] for i in out_indices] + + if pretrained: + if weights is None: # pragma: no cover + weights = f"{DLA_MODEL_PREFIX}/{DLA_MODEL_MAPPING[name]}" - if weights is not None: # pragma: no cover - if weights.startswith("dla://"): - weights_name = weights.split("dla://")[-1] - assert weights_name in DLA_MODEL_MAPPING - weights = ( - f"{DLA_MODEL_PREFIX}{style}/" - f"{DLA_MODEL_MAPPING[weights_name]}" - ) - self.load_pretrained_model(weights) + load_model_checkpoint(self, weights) + + else: + self._init_weights() + + def _init_weights(self) -> None: + """Initialize module weights.""" + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2.0 / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() @staticmethod def _make_conv_level( @@ -516,14 +594,6 @@ def _make_conv_level( inplanes = planes return nn.Sequential(*modules) - def load_pretrained_model(self, weights: str) -> None: - """Load pretrained weights.""" - if weights.startswith("http://") or weights.startswith("https://"): - model_weights = torch.hub.load_state_dict_from_url(weights) - else: # pragma: no cover - model_weights = torch.load(weights) - self.load_state_dict(model_weights, strict=False) - def forward(self, images: Tensor) -> list[Tensor]: """DLA forward. @@ -538,10 +608,15 @@ def forward(self, images: Tensor) -> list[Tensor]: original image. """ input_x = self.base_layer(images) - outs: list[Tensor] = [] + + outs = [images, images] + for i in range(6): input_x = getattr(self, f"level{i}")(input_x) - outs.append(input_x) + + if i - 2 in self.out_indices: + outs.append(input_x) + return outs @property @@ -551,4 +626,4 @@ def out_channels(self) -> list[int]: Returns: list[int]: number of channels """ - return self._out_channels + return [3, 3] + self._out_channels From 55d6a5167ca5ac6ee3ae4d3235c70d14ea79333e Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 19 Feb 2025 18:05:17 +0100 Subject: [PATCH 23/50] feat: Disable system tmp for gather cpu. --- vis4d/common/distributed.py | 2 +- vis4d/op/base/dla.py | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/vis4d/common/distributed.py b/vis4d/common/distributed.py index 36acaa19..ab96201d 100644 --- a/vis4d/common/distributed.py +++ b/vis4d/common/distributed.py @@ -288,7 +288,7 @@ def all_gather_object_cpu( # type: ignore data: Any, tmpdir: None | str = None, rank_zero_return_only: bool = True, - use_system_tmp: bool = True, + use_system_tmp: bool = False, ) -> list[Any] | None: # pragma: no cover """Share arbitrary picklable data via file system caching. diff --git a/vis4d/op/base/dla.py b/vis4d/op/base/dla.py index 85934332..1bb09215 100644 --- a/vis4d/op/base/dla.py +++ b/vis4d/op/base/dla.py @@ -324,6 +324,7 @@ def __init__( out_channels: int, kernel_size: int, residual: bool, + with_cp: bool = False, ) -> None: """Creates an instance of the class.""" super().__init__() @@ -338,14 +339,23 @@ def __init__( self.bn = nn.BatchNorm2d(out_channels, momentum=BN_MOMENTUM) self.relu = nn.ReLU(inplace=True) self.residual = residual + self.with_cp = with_cp def forward(self, *input_x: Tensor) -> Tensor: """Forward.""" - children = input_x - feats = self.conv(torch.cat(input_x, 1)) - feats = self.bn(feats) - if self.residual: - feats += children[0] + + def _inner_forward(input_x: Tensor) -> Tensor: + feats = self.conv(torch.cat(input_x, 1)) + feats = self.bn(feats) + if self.residual: + feats += input_x[0] + return feats + + if self.with_cp: + feats = checkpoint(_inner_forward, input_x) + else: + feats = _inner_forward(input_x) + feats = self.relu(feats) return feats @@ -398,7 +408,11 @@ def __init__( # pylint: disable=too-many-arguments with_cp=with_cp, ) self.root = Root( - root_dim, out_channels, root_kernel_size, root_residual + root_dim, + out_channels, + root_kernel_size, + root_residual, + with_cp=with_cp, ) else: self.tree1 = Tree( From 8625b4b4902cb7ff77ad3466628c7155af0cf1a3 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Fri, 21 Feb 2025 09:30:47 +0100 Subject: [PATCH 24/50] feat: Fix DLA for DDP and gradient checkpointing. --- vis4d/op/base/dla.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/vis4d/op/base/dla.py b/vis4d/op/base/dla.py index 1bb09215..87aaa648 100644 --- a/vis4d/op/base/dla.py +++ b/vis4d/op/base/dla.py @@ -154,7 +154,9 @@ def _inner_forward( return out if self.with_cp and input_x.requires_grad: - out = checkpoint(_inner_forward, input_x, residual) + out = checkpoint( + _inner_forward, input_x, residual, use_reentrant=True + ) else: out = _inner_forward(input_x, residual) @@ -229,7 +231,9 @@ def _inner_forward( return out if self.with_cp and input_x.requires_grad: - out = checkpoint(_inner_forward, input_x, residual) + out = checkpoint( + _inner_forward, input_x, residual, use_reentrant=True + ) else: out = _inner_forward(input_x, residual) @@ -306,7 +310,9 @@ def _inner_forward( return out if self.with_cp and input_x.requires_grad: - out = checkpoint(_inner_forward, input_x, residual) + out = checkpoint( + _inner_forward, input_x, residual, use_reentrant=True + ) else: out = _inner_forward(input_x, residual) @@ -344,17 +350,17 @@ def __init__( def forward(self, *input_x: Tensor) -> Tensor: """Forward.""" - def _inner_forward(input_x: Tensor) -> Tensor: + def _inner_forward(*input_x: Tensor) -> Tensor: feats = self.conv(torch.cat(input_x, 1)) feats = self.bn(feats) if self.residual: feats += input_x[0] return feats - if self.with_cp: - feats = checkpoint(_inner_forward, input_x) + if self.with_cp and input_x[0].requires_grad: + feats = checkpoint(_inner_forward, *input_x, use_reentrant=True) else: - feats = _inner_forward(input_x) + feats = _inner_forward(*input_x) feats = self.relu(feats) @@ -445,8 +451,7 @@ def __init__( # pylint: disable=too-many-arguments self.levels = levels if stride > 1: self.downsample = nn.MaxPool2d(stride, stride=stride) - if in_channels != out_channels: - # TODO: check if this is correct + if in_channels != out_channels and levels == 1: # NOTE the official impl/weights have project layers in levels > 1 # case that are never used, hence 'levels == 1' is added but # pretrained models will need strict=False while loading. From 8693b90fbbb7919302d5e20903e621e2cb53691d Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Fri, 21 Feb 2025 19:29:22 +0100 Subject: [PATCH 25/50] feat: Separate wandb id and version. --- vis4d/pl/trainer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vis4d/pl/trainer.py b/vis4d/pl/trainer.py index b3e067ec..831f3542 100644 --- a/vis4d/pl/trainer.py +++ b/vis4d/pl/trainer.py @@ -33,6 +33,7 @@ def __init__( wandb: bool = False, seed: int = -1, timeout: int = 3600, + wandb_id: str | None = None, **kwargs: ArgsType, ) -> None: """Perform some basic common setups at the beginning of a job. @@ -75,7 +76,7 @@ def __init__( save_dir=work_dir, project=exp_name, name=version, - id=version, + id=wandb_id, ) elif TENSORBOARD_AVAILABLE: exp_logger = TensorBoardLogger( From 71af387e299356aa18ff7fa5f32618c9023a218c Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 25 Feb 2025 02:24:56 +0100 Subject: [PATCH 26/50] feat: Add dumping 3D boxes npy. --- vis4d/vis/image/bbox3d_visualizer.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/vis4d/vis/image/bbox3d_visualizer.py b/vis4d/vis/image/bbox3d_visualizer.py index c3e868c7..db6877bc 100644 --- a/vis4d/vis/image/bbox3d_visualizer.py +++ b/vis4d/vis/image/bbox3d_visualizer.py @@ -68,6 +68,7 @@ def __init__( axis_mode: AxisMode = AxisMode.ROS, trajectory_length: int = 10, plot_trajectory: bool = True, + save_boxes3d: bool = False, canvas: CanvasBackend | None = None, viewer: ImageViewerBackend | None = None, **kwargs: ArgsType, @@ -121,6 +122,8 @@ def __init__( self.camera_near_clip = camera_near_clip self.plot_heading = plot_heading + self.save_boxes3d = save_boxes3d + self.canvas = canvas if canvas is not None else PillowCanvasBackend() self.viewer = viewer if viewer is not None else MatplotlibImageViewer() @@ -348,7 +351,7 @@ def save_to_disk(self, cur_iter: int, output_folder: str) -> None: output_dir = output_folder image_name = f"{sample.image_name}.{self.file_type}" - self._draw_image(sample) + _ = self._draw_image(sample) if sample.sequence_name is not None: output_dir = os.path.join(output_dir, sample.sequence_name) @@ -359,6 +362,14 @@ def save_to_disk(self, cur_iter: int, output_folder: str) -> None: os.makedirs(output_dir, exist_ok=True) self.canvas.save_to_disk(os.path.join(output_dir, image_name)) + if self.save_boxes3d: + corners = np.array([box.corners for box in sample.boxes]) + + np.save( + os.path.join(output_dir, f"{sample.image_name}.npy"), + corners, + ) + class MultiCameraBBox3DVisualizer(BoundingBox3DVisualizer): """Bounding box 3D visualizer class for multi-camera datasets.""" From 131784e11b4473c660f4ff95d29e06ce7bfca9c3 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 25 Feb 2025 18:57:50 +0100 Subject: [PATCH 27/50] feat: Enable drop last for data loader. --- vis4d/data/loader.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/vis4d/data/loader.py b/vis4d/data/loader.py index ff47cf88..02c53a56 100644 --- a/vis4d/data/loader.py +++ b/vis4d/data/loader.py @@ -122,6 +122,7 @@ def build_train_dataloader( sensors: Sequence[str] | None = None, pin_memory: bool = True, shuffle: bool = True, + drop_last: bool = False, seed: int | None = None, aspect_ratio_grouping: bool = False, disable_subprocess_warning: bool = False, @@ -167,11 +168,14 @@ def _worker_init_fn(worker_id: int) -> None: sampler = None if get_world_size() > 1: - sampler = DistributedSampler(dataset, shuffle=shuffle) + sampler = DistributedSampler( + dataset, shuffle=shuffle, drop_last=drop_last + ) shuffle = False + drop_last = False batch_sampler = None - if aspect_ratio_grouping: + if aspect_ratio_grouping and sampler is not None: batch_sampler = AspectRatioBatchSampler( sampler, batch_size=samples_per_gpu ) @@ -191,6 +195,7 @@ def _worker_init_fn(worker_id: int) -> None: persistent_workers=workers_per_gpu > 0, pin_memory=pin_memory, shuffle=shuffle, + drop_last=drop_last, ) return dataloader From 3e876a5ca10bf516916f7929a4cef2b7f889eab3 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 11 Mar 2025 16:45:21 +0100 Subject: [PATCH 28/50] feat: Make sampler of train dataloader configurable. --- vis4d/data/loader.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vis4d/data/loader.py b/vis4d/data/loader.py index 02c53a56..e828a1e1 100644 --- a/vis4d/data/loader.py +++ b/vis4d/data/loader.py @@ -9,7 +9,7 @@ import numpy as np import torch from torch.utils.data import DataLoader, Dataset -from torch.utils.data.distributed import DistributedSampler +from torch.utils.data.distributed import DistributedSampler, Sampler from vis4d.common.distributed import get_rank, get_world_size @@ -125,6 +125,7 @@ def build_train_dataloader( drop_last: bool = False, seed: int | None = None, aspect_ratio_grouping: bool = False, + sampler: Sampler | None = None, disable_subprocess_warning: bool = False, ) -> DataLoader[DictDataOrList]: """Build training dataloader.""" @@ -166,8 +167,7 @@ def _worker_init_fn(worker_id: int) -> None: if disable_subprocess_warning and worker_id != 0: warnings.simplefilter("ignore") - sampler = None - if get_world_size() > 1: + if get_world_size() > 1 and sampler is None: sampler = DistributedSampler( dataset, shuffle=shuffle, drop_last=drop_last ) From ec45a691e81aaf0ef01c004a6c921b948b3f3018 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 18 Mar 2025 01:58:03 +0100 Subject: [PATCH 29/50] feat: Update visualization for wandb. --- vis4d/vis/image/bbox3d_visualizer.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vis4d/vis/image/bbox3d_visualizer.py b/vis4d/vis/image/bbox3d_visualizer.py index db6877bc..78db08e3 100644 --- a/vis4d/vis/image/bbox3d_visualizer.py +++ b/vis4d/vis/image/bbox3d_visualizer.py @@ -131,6 +131,10 @@ def reset(self) -> None: """Reset visualizer.""" self._samples.clear() + def __repr__(self): + """Return string representation.""" + return "BoundingBox3DVisualizer" + def process( # type: ignore # pylint: disable=arguments-differ self, cur_iter: int, @@ -351,7 +355,7 @@ def save_to_disk(self, cur_iter: int, output_folder: str) -> None: output_dir = output_folder image_name = f"{sample.image_name}.{self.file_type}" - _ = self._draw_image(sample) + image = self._draw_image(sample) if sample.sequence_name is not None: output_dir = os.path.join(output_dir, sample.sequence_name) @@ -370,6 +374,8 @@ def save_to_disk(self, cur_iter: int, output_folder: str) -> None: corners, ) + return image + class MultiCameraBBox3DVisualizer(BoundingBox3DVisualizer): """Bounding box 3D visualizer class for multi-camera datasets.""" From c589630ebdc01da76c9c1f0f39520b9d4fc5a680 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 18 Mar 2025 02:19:18 +0100 Subject: [PATCH 30/50] feat: Support wand log image for visualizer callback. --- vis4d/engine/callbacks/visualizer.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/vis4d/engine/callbacks/visualizer.py b/vis4d/engine/callbacks/visualizer.py index a06c9a89..9b1cfa6f 100644 --- a/vis4d/engine/callbacks/visualizer.py +++ b/vis4d/engine/callbacks/visualizer.py @@ -5,9 +5,10 @@ import os from torch import nn +from lightning.pytorch.loggers import WandbLogger from vis4d.common import ArgsType -from vis4d.common.distributed import broadcast +from vis4d.common.distributed import broadcast, get_rank, synchronize from vis4d.data.typing import DictData from vis4d.engine.loss_module import LossModule from vis4d.vis.base import Visualizer @@ -123,8 +124,21 @@ def on_test_batch_end( self.output_dir, "test", self.save_prefix ) os.makedirs(output_folder, exist_ok=True) - self.visualizer.save_to_disk( + image = self.visualizer.save_to_disk( cur_iter=cur_iter, output_folder=output_folder ) + if get_rank() == 0 and trainer_state["train_engine"] == "pl": + trainer = trainer_state["train_module"] + if ( + isinstance(trainer.logger, WandbLogger) + and image is not None + ): + trainer.logger.log_image( + key=f"{self.visualizer}/{cur_iter}", + images=[image], + step=trainer.global_step, + ) + synchronize() + self.visualizer.reset() From a778ed0288e4dd94b2e36f8eecf0890121af09dd Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 18 Mar 2025 13:54:14 +0100 Subject: [PATCH 31/50] feat: Add hungarian matching. --- vis4d/op/track/assignment.py | 49 +++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/vis4d/op/track/assignment.py b/vis4d/op/track/assignment.py index dd000fe2..8b1db4f8 100644 --- a/vis4d/op/track/assignment.py +++ b/vis4d/op/track/assignment.py @@ -4,15 +4,18 @@ import torch +from torch import Tensor +from scipy.optimize import linear_sum_assignment + def greedy_assign( - detection_scores: torch.Tensor, - tracklet_ids: torch.Tensor, - affinity_scores: torch.Tensor, + detection_scores: Tensor, + tracklet_ids: Tensor, + affinity_scores: Tensor, match_score_thr: float = 0.5, obj_score_thr: float = 0.3, nms_conf_thr: None | float = None, -) -> torch.Tensor: +) -> Tensor: """Greedy assignment of detections to tracks given affinities.""" ids = torch.full( (len(detection_scores),), @@ -35,6 +38,40 @@ def greedy_assign( return ids +def hungarian_assign( + detection_scores: Tensor, + tracklet_ids: Tensor, + affinity_scores: Tensor, + match_score_thr: float = 0.5, + obj_score_thr: float = 0.3, + nms_conf_thr: None | float = None, +) -> Tensor: + """Hungarian assignment of detections to tracks given affinities.""" + ids = torch.full( + (len(detection_scores),), + -1, + dtype=torch.long, + device=detection_scores.device, + ) + + matched_indices = linear_sum_assignment(-affinity_scores.cpu().numpy()) + + for idx in range(len(matched_indices[0])): + i = matched_indices[0][idx] + memo_ind = matched_indices[1][idx] + conf = affinity_scores[i, memo_ind] + tid = tracklet_ids[memo_ind] + if conf > match_score_thr and tid > -1: + if detection_scores[i] > obj_score_thr: + ids[i] = tid + affinity_scores[:i, memo_ind] = 0 + affinity_scores[i + 1 :, memo_ind] = 0 + elif nms_conf_thr is not None and conf > nms_conf_thr: + ids[i] = -2 + + return ids + + class TrackIDCounter: """Global counter for track ids. @@ -52,7 +89,7 @@ def reset(cls) -> None: @classmethod def get_ids( cls, num_ids: int, device: torch.device = torch.device("cpu") - ) -> torch.Tensor: + ) -> Tensor: """Generate a num_ids number of new unique tracking ids. Args: @@ -61,7 +98,7 @@ def get_ids( to torch.device("cpu"). Returns: - torch.Tensor: Tensor of new contiguous track ids. + Tensor: Tensor of new contiguous track ids. """ new_ids = torch.arange(cls.count, cls.count + num_ids, device=device) cls.count = cls.count + num_ids From 7b8a4b3dc14f4d9bfbd4f634330cbe3892787257 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 19 Mar 2025 01:52:02 +0100 Subject: [PATCH 32/50] feat: Enable efficient MultiHeadAttention. --- vis4d/op/layer/attention.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vis4d/op/layer/attention.py b/vis4d/op/layer/attention.py index 31b09d51..65701424 100644 --- a/vis4d/op/layer/attention.py +++ b/vis4d/op/layer/attention.py @@ -100,6 +100,7 @@ def __init__( proj_drop: float = 0.0, dropout_layer: nn.Module | None = None, batch_first: bool = False, + need_weights: bool = False, **kwargs: ArgsType, ) -> None: """Init MultiheadAttention. @@ -121,6 +122,7 @@ def __init__( self.batch_first = batch_first self.embed_dims = embed_dims self.num_heads = num_heads + self.need_weights = need_weights self.attn = nn.MultiheadAttention( embed_dims, num_heads, dropout=attn_drop, **kwargs @@ -223,7 +225,11 @@ def forward( value=value, attn_mask=attn_mask, key_padding_mask=key_padding_mask, - )[0] + need_weights=self.need_weights, + ) + + if isinstance(out, tuple): + out = out[0] if self.batch_first: out = out.transpose(0, 1) From 00b731c7cd359911964d482ea32914d51f250e04 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 19 Mar 2025 19:04:11 +0100 Subject: [PATCH 33/50] feat: Fix lr scheduler callback for accumulate gradient. --- vis4d/pl/callbacks/scheduler.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/vis4d/pl/callbacks/scheduler.py b/vis4d/pl/callbacks/scheduler.py index 456ca48a..ba197e78 100644 --- a/vis4d/pl/callbacks/scheduler.py +++ b/vis4d/pl/callbacks/scheduler.py @@ -13,6 +13,10 @@ class LRSchedulerCallback(pl.Callback): """Callback to configure learning rate during training.""" + def __init__(self) -> None: + """Initialize the callback.""" + self.last_step = 0 + def on_train_batch_end( # type: ignore self, trainer: pl.Trainer, @@ -27,8 +31,11 @@ def on_train_batch_end( # type: ignore if not isinstance(schedulers, Iterable): schedulers = [schedulers] # type: ignore - for scheduler in schedulers: - if scheduler is None: - continue - assert isinstance(scheduler, LRSchedulerWrapper) - scheduler.step_on_batch(trainer.global_step) + if trainer.global_step != self.last_step: + for scheduler in schedulers: + if scheduler is None: + continue + assert isinstance(scheduler, LRSchedulerWrapper) + scheduler.step_on_batch(trainer.global_step) + + self.last_step = trainer.global_step From 59626c2f61396e2aefb99dae256e55d014ca6d19 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Thu, 20 Mar 2025 18:59:47 +0100 Subject: [PATCH 34/50] feat: Update trainer global_step. --- vis4d/engine/callbacks/logging.py | 3 +-- vis4d/engine/optim/scheduler.py | 4 +--- vis4d/engine/trainer.py | 3 ++- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/vis4d/engine/callbacks/logging.py b/vis4d/engine/callbacks/logging.py index 2b44245c..5ce83b50 100644 --- a/vis4d/engine/callbacks/logging.py +++ b/vis4d/engine/callbacks/logging.py @@ -80,8 +80,7 @@ def on_train_batch_end( else -1 ) else: - # After optimizer.step(), global_step is already incremented by 1. - cur_iter = trainer_state["global_step"] + cur_iter = trainer_state["global_step"] + 1 total_iters = trainer_state["num_steps"] log_dict: None | MetricLogs = None diff --git a/vis4d/engine/optim/scheduler.py b/vis4d/engine/optim/scheduler.py index 496e05f0..00fde1a7 100644 --- a/vis4d/engine/optim/scheduler.py +++ b/vis4d/engine/optim/scheduler.py @@ -126,15 +126,13 @@ def step(self, epoch: int | None = None) -> None: def step_on_batch(self, step: int) -> None: """Step on training batch end.""" - # Minus 1 because the step is called after the optimizer.step() - step -= 1 for lr_scheduler in self.lr_schedulers.values(): if not lr_scheduler["epoch_based"]: self._step_lr(lr_scheduler, step) for i, lr_scheduler_cfg in enumerate(self.lr_schedulers_cfg): if not lr_scheduler_cfg["epoch_based"] and ( - lr_scheduler_cfg["begin"] == step + 1 + lr_scheduler_cfg["begin"] == step ): self._instantiate_lr_scheduler(i, lr_scheduler_cfg) diff --git a/vis4d/engine/trainer.py b/vis4d/engine/trainer.py index 8235e4b9..901e7d96 100644 --- a/vis4d/engine/trainer.py +++ b/vis4d/engine/trainer.py @@ -248,7 +248,6 @@ def fit( # Step optimizers optimizer.step() - self.global_step += 1 # Step learning rate schedulers for lr_scheduler in lr_schedulers: @@ -278,6 +277,8 @@ def fit( # Set model back to train mode model.train() + self.global_step += 1 + if self.done(): return From e6c31a6bc571330807c50133f6062c1ecaef6bfb Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 25 Mar 2025 16:36:16 +0100 Subject: [PATCH 35/50] feat: Update checkpoint for ResNet. --- vis4d/op/base/resnet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vis4d/op/base/resnet.py b/vis4d/op/base/resnet.py index 0e00bb02..10e9f51f 100644 --- a/vis4d/op/base/resnet.py +++ b/vis4d/op/base/resnet.py @@ -81,7 +81,7 @@ def _inner_forward(x: Tensor) -> Tensor: return out if self.use_checkpoint and x.requires_grad: - out = checkpoint(_inner_forward, x) + out = checkpoint(_inner_forward, x, use_reentrant=True) else: out = _inner_forward(x) @@ -183,7 +183,7 @@ def _inner_forward(x: Tensor) -> Tensor: return out if self.use_checkpoint and x.requires_grad: - out = checkpoint(_inner_forward, x) + out = checkpoint(_inner_forward, x, use_reentrant=True) else: out = _inner_forward(x) From f1c861a976d1ddfa233c14cde9326ab9aa319a96 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Thu, 27 Mar 2025 15:18:38 +0100 Subject: [PATCH 36/50] feat: Update scheduler and add control for check unused parameters. --- vis4d/engine/optim/scheduler.py | 2 +- vis4d/pl/run.py | 1 + vis4d/pl/training_module.py | 6 +++--- vis4d/zoo/base/runtime.py | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/vis4d/engine/optim/scheduler.py b/vis4d/engine/optim/scheduler.py index 00fde1a7..78f041a7 100644 --- a/vis4d/engine/optim/scheduler.py +++ b/vis4d/engine/optim/scheduler.py @@ -107,7 +107,7 @@ def load_state_dict(self, state_dict: dict[int, DictStrAny]) -> None: # type: i def _step_lr(self, lr_scheduler: LRSchedulerDict, step: int) -> None: """Step the learning rate.""" if lr_scheduler["begin"] <= step and ( - lr_scheduler["end"] == -1 or lr_scheduler["end"] > step + lr_scheduler["end"] == -1 or lr_scheduler["end"] >= step ): lr_scheduler["scheduler"].step() diff --git a/vis4d/pl/run.py b/vis4d/pl/run.py index bfa43ab1..14642f08 100644 --- a/vis4d/pl/run.py +++ b/vis4d/pl/run.py @@ -156,6 +156,7 @@ def main(argv: ArgsType) -> None: config.seed, ckpt_path if not resume else None, config.compute_flops, + config.check_unused_parameters, ) data_module = DataModule(config.data) diff --git a/vis4d/pl/training_module.py b/vis4d/pl/training_module.py index 48c6f7b6..284e3b7c 100644 --- a/vis4d/pl/training_module.py +++ b/vis4d/pl/training_module.py @@ -47,7 +47,7 @@ def __init__( seed: int = -1, ckpt_path: None | str = None, compute_flops: bool = False, - check_the_unused_parameters: bool = False, + check_unused_parameters: bool = False, ) -> None: """Initialize the TrainingModule. @@ -66,7 +66,7 @@ def __init__( Defaults to None. compute_flops (bool, optional): If to compute the FLOPs of the model. Defaults to False. - check_the_unused_parameters (bool, optional): If to check the + check_unused_parameters (bool, optional): If to check the unused parameters. Defaults to False. """ super().__init__() @@ -79,7 +79,7 @@ def __init__( self.seed = seed self.ckpt_path = ckpt_path self.compute_flops = compute_flops - self.check_unused_parameters = check_the_unused_parameters + self.check_unused_parameters = check_unused_parameters # Create model placeholder self.model: nn.Module diff --git a/vis4d/zoo/base/runtime.py b/vis4d/zoo/base/runtime.py index c457638c..232952de 100644 --- a/vis4d/zoo/base/runtime.py +++ b/vis4d/zoo/base/runtime.py @@ -59,6 +59,7 @@ def get_default_cfg( config.tf32_matmul_precision = "highest" config.benchmark = False config.compute_flops = False + config.check_unused_parameters = False return config From 927e20afb2892d9b462468985a9d0fe6ff12c00c Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 1 Apr 2025 19:07:05 +0200 Subject: [PATCH 37/50] feat: Update sampler for train dataloader. --- vis4d/data/loader.py | 34 ++++++++++++++++++++-------- vis4d/data/samplers.py | 9 +++++++- vis4d/engine/callbacks/visualizer.py | 1 - 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/vis4d/data/loader.py b/vis4d/data/loader.py index e828a1e1..f6a20da6 100644 --- a/vis4d/data/loader.py +++ b/vis4d/data/loader.py @@ -8,7 +8,12 @@ import numpy as np import torch -from torch.utils.data import DataLoader, Dataset +from torch.utils.data import ( + DataLoader, + Dataset, + RandomSampler, + SequentialSampler, +) from torch.utils.data.distributed import DistributedSampler, Sampler from vis4d.common.distributed import get_rank, get_world_size @@ -167,20 +172,29 @@ def _worker_init_fn(worker_id: int) -> None: if disable_subprocess_warning and worker_id != 0: warnings.simplefilter("ignore") - if get_world_size() > 1 and sampler is None: - sampler = DistributedSampler( - dataset, shuffle=shuffle, drop_last=drop_last - ) - shuffle = False - drop_last = False + if sampler is None: + if get_world_size() > 1: + sampler = DistributedSampler( + dataset, shuffle=shuffle, drop_last=drop_last + ) + shuffle = False + drop_last = False + else: + if shuffle: + sampler = RandomSampler(dataset) + shuffle = False + else: + sampler = SequentialSampler(dataset) batch_sampler = None - if aspect_ratio_grouping and sampler is not None: + if aspect_ratio_grouping: batch_sampler = AspectRatioBatchSampler( - sampler, batch_size=samples_per_gpu + sampler, batch_size=samples_per_gpu, drop_last=drop_last ) samples_per_gpu = 1 shuffle = None + drop_last = False + sampler = None dataloader = DataLoader( dataset, @@ -189,7 +203,7 @@ def _worker_init_fn(worker_id: int) -> None: collate_fn=( _collate_fn_multi if dataset.has_reference else _collate_fn_single ), - sampler=sampler if not aspect_ratio_grouping else None, + sampler=sampler, batch_sampler=batch_sampler, worker_init_fn=_worker_init_fn, persistent_workers=workers_per_gpu > 0, diff --git a/vis4d/data/samplers.py b/vis4d/data/samplers.py index 3821b9e9..cbdd8df1 100644 --- a/vis4d/data/samplers.py +++ b/vis4d/data/samplers.py @@ -115,7 +115,14 @@ def __init__( def __iter__(self): for idx in self.sampler: - data_dict = self.sampler.dataset[idx] + if hasattr(self.sampler, "dataset"): + data_dict = self.sampler.dataset[idx] + elif hasattr(self.sampler, "data_source"): + data_dict = self.sampler.data_source[idx] + else: + raise ValueError( + "sampler should have dataset or data_source attribute" + ) height, width = data_dict[K.input_hw] bucket_id = 0 if width < height else 1 bucket = self._aspect_ratio_buckets[bucket_id] diff --git a/vis4d/engine/callbacks/visualizer.py b/vis4d/engine/callbacks/visualizer.py index 9b1cfa6f..4cea2004 100644 --- a/vis4d/engine/callbacks/visualizer.py +++ b/vis4d/engine/callbacks/visualizer.py @@ -137,7 +137,6 @@ def on_test_batch_end( trainer.logger.log_image( key=f"{self.visualizer}/{cur_iter}", images=[image], - step=trainer.global_step, ) synchronize() From cb4b1bc5a80cccb7c40d2bfe1ae8a8b20cb62a23 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 2 Apr 2025 16:00:27 +0200 Subject: [PATCH 38/50] feat: Update pillow bounding boxes visualization. --- vis4d/vis/image/bbox3d_visualizer.py | 3 +-- vis4d/vis/image/bounding_box_visualizer.py | 12 +++++------- vis4d/vis/image/canvas/pillow_backend.py | 8 +++++++- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/vis4d/vis/image/bbox3d_visualizer.py b/vis4d/vis/image/bbox3d_visualizer.py index 78db08e3..e5e45717 100644 --- a/vis4d/vis/image/bbox3d_visualizer.py +++ b/vis4d/vis/image/bbox3d_visualizer.py @@ -316,8 +316,7 @@ def _draw_image(self, sample: DataSample) -> NDArrayUI8: selected_corner = project_point(box.corners[0], sample.intrinsics) self.canvas.draw_text( - (selected_corner[0], selected_corner[1]), - box.label, + (selected_corner[0], selected_corner[1]), box.label, box.color ) if self.plot_trajectory: diff --git a/vis4d/vis/image/bounding_box_visualizer.py b/vis4d/vis/image/bounding_box_visualizer.py index bebcc992..7fb07597 100644 --- a/vis4d/vis/image/bounding_box_visualizer.py +++ b/vis4d/vis/image/bounding_box_visualizer.py @@ -47,6 +47,7 @@ def __init__( n_colors: int = 50, cat_mapping: dict[str, int] | None = None, file_type: str = "png", + width: int = 2, canvas: CanvasBackend = PillowCanvasBackend(), viewer: ImageViewerBackend = MatplotlibImageViewer(), **kwargs: ArgsType, @@ -71,6 +72,7 @@ def __init__( else {} ) self.file_type = file_type + self.width = width self.canvas = canvas self.viewer = viewer @@ -187,8 +189,8 @@ def _draw_image(self, sample: DataSample) -> NDArrayUI8: """ self.canvas.create_canvas(sample.image) for box in sample.boxes: - self.canvas.draw_box(box.corners, box.color) - self.canvas.draw_text(box.corners[:2], box.label) + self.canvas.draw_box(box.corners, box.color, width=self.width) + self.canvas.draw_text(box.corners[:2], box.label, box.color) return self.canvas.as_numpy_image() @@ -206,11 +208,7 @@ def save_to_disk(self, cur_iter: int, output_folder: str) -> None: for sample in self._samples: image_name = f"{sample.image_name}.{self.file_type}" - self.canvas.create_canvas(sample.image) - - for box in sample.boxes: - self.canvas.draw_box(box.corners, box.color) - self.canvas.draw_text(box.corners[:2], box.label) + _ = self._draw_image(sample) self.canvas.save_to_disk( os.path.join(output_folder, image_name) diff --git a/vis4d/vis/image/canvas/pillow_backend.py b/vis4d/vis/image/canvas/pillow_backend.py index 8b4da8a2..6bfd0104 100644 --- a/vis4d/vis/image/canvas/pillow_backend.py +++ b/vis4d/vis/image/canvas/pillow_backend.py @@ -115,7 +115,13 @@ def draw_text( raise ValueError( "No Image Draw initialized! Did you call 'create_canvas'?" ) - self._image_draw.text(position, text, color, font=self._font) + left, top, right, bottom = self._image_draw.textbbox( + position, text, font=self._font + ) + self._image_draw.rectangle( + (left - 2, top - 2, right + 2, bottom + 2), fill=color + ) + self._image_draw.text(position, text, (255, 255, 255), font=self._font) def draw_box( self, From 935fc1dca5e9b75dcd988a400550c0a7b712b2d2 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 29 Apr 2025 17:44:47 +0200 Subject: [PATCH 39/50] fix: Fix typo and update hdf5 backend. --- vis4d/data/io/hdf5.py | 4 ++-- vis4d/eval/coco/detect.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vis4d/data/io/hdf5.py b/vis4d/data/io/hdf5.py index 3d6b594e..c7eee55a 100644 --- a/vis4d/data/io/hdf5.py +++ b/vis4d/data/io/hdf5.py @@ -137,13 +137,13 @@ def _get_client(self, hdf5_path: str, mode: str) -> File: File: the hdf5 file. """ if hdf5_path not in self.db_cache: - client = File(hdf5_path, mode) + client = File(hdf5_path, mode, swmr=True, libver="latest") self.db_cache[hdf5_path] = [client, mode] else: client, current_mode = self.db_cache[hdf5_path] if current_mode != mode: client.close() - client = File(hdf5_path, mode) + client = File(hdf5_path, mode, swmr=True, libver="latest") self.db_cache[hdf5_path] = [client, mode] return client diff --git a/vis4d/eval/coco/detect.py b/vis4d/eval/coco/detect.py index bf81db2f..61f44984 100644 --- a/vis4d/eval/coco/detect.py +++ b/vis4d/eval/coco/detect.py @@ -76,8 +76,8 @@ def predictions_to_coco( """ predictions = [] boxes_xyxy = copy.deepcopy(boxes) - boxes_wywh = xyxy_to_xywh(boxes_xyxy) - for i, (box, score, cls) in enumerate(zip(boxes_wywh, scores, classes)): + boxes_xywh = xyxy_to_xywh(boxes_xyxy) + for i, (box, score, cls) in enumerate(zip(boxes_xywh, scores, classes)): mask = masks[i] if masks is not None else None xywh = box.tolist() area = float(xywh[2] * xywh[3]) From 45cad40d38b35822f6636993db0b70f150176cca Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Thu, 17 Jul 2025 15:52:36 +0200 Subject: [PATCH 40/50] feat: Merge engine and pl. --- .../callbacks/callback_wrapper.py | 0 vis4d/{pl => engine}/callbacks/scheduler.py | 0 vis4d/engine/callbacks/visualizer.py | 22 +- vis4d/{pl => engine}/data_module.py | 0 vis4d/engine/experiment.py | 276 ---------- vis4d/engine/run.py | 185 +++++-- vis4d/engine/trainer.py | 515 +++++------------- vis4d/{pl => engine}/training_module.py | 0 vis4d/engine/util.py | 221 -------- vis4d/op/base/dla.py | 3 +- vis4d/op/detect/dense_anchor.py | 2 +- vis4d/op/layer/patch_embed.py | 2 +- vis4d/op/track/assignment.py | 3 +- vis4d/pl/__init__.py | 1 - vis4d/pl/__main__.py | 5 - vis4d/pl/callbacks/__init__.py | 6 - vis4d/pl/run.py | 177 ------ vis4d/pl/trainer.py | 139 ----- 18 files changed, 277 insertions(+), 1280 deletions(-) rename vis4d/{pl => engine}/callbacks/callback_wrapper.py (100%) rename vis4d/{pl => engine}/callbacks/scheduler.py (100%) rename vis4d/{pl => engine}/data_module.py (100%) delete mode 100644 vis4d/engine/experiment.py rename vis4d/{pl => engine}/training_module.py (100%) delete mode 100644 vis4d/engine/util.py delete mode 100644 vis4d/pl/__init__.py delete mode 100644 vis4d/pl/__main__.py delete mode 100644 vis4d/pl/callbacks/__init__.py delete mode 100644 vis4d/pl/run.py delete mode 100644 vis4d/pl/trainer.py diff --git a/vis4d/pl/callbacks/callback_wrapper.py b/vis4d/engine/callbacks/callback_wrapper.py similarity index 100% rename from vis4d/pl/callbacks/callback_wrapper.py rename to vis4d/engine/callbacks/callback_wrapper.py diff --git a/vis4d/pl/callbacks/scheduler.py b/vis4d/engine/callbacks/scheduler.py similarity index 100% rename from vis4d/pl/callbacks/scheduler.py rename to vis4d/engine/callbacks/scheduler.py diff --git a/vis4d/engine/callbacks/visualizer.py b/vis4d/engine/callbacks/visualizer.py index 4cea2004..6a468d7a 100644 --- a/vis4d/engine/callbacks/visualizer.py +++ b/vis4d/engine/callbacks/visualizer.py @@ -4,8 +4,8 @@ import os -from torch import nn from lightning.pytorch.loggers import WandbLogger +from torch import nn from vis4d.common import ArgsType from vis4d.common.distributed import broadcast, get_rank, synchronize @@ -89,9 +89,11 @@ def on_train_batch_end( self.visualizer.show(cur_iter=cur_iter) if self.save_to_disk: - output_folder = os.path.join( - self.output_dir, "train", self.save_prefix - ) + output_folder = os.path.join(self.output_dir, "train") + if self.save_prefix is not None: + output_folder = os.path.join( + output_folder, self.save_prefix + ) os.makedirs(output_folder, exist_ok=True) self.visualizer.save_to_disk( cur_iter=cur_iter, output_folder=output_folder @@ -120,14 +122,20 @@ def on_test_batch_end( self.visualizer.show(cur_iter=cur_iter) if self.save_to_disk: - output_folder = os.path.join( - self.output_dir, "test", self.save_prefix - ) + output_folder = os.path.join(self.output_dir, "test") + if self.save_prefix is not None: + output_folder = os.path.join(output_folder, self.save_prefix) os.makedirs(output_folder, exist_ok=True) image = self.visualizer.save_to_disk( cur_iter=cur_iter, output_folder=output_folder ) + assert ( + "train_engine" in trainer_state + ), "Trainer state must contain 'train_engine' key." + assert ( + "train_module" in trainer_state + ), "Trainer state must contain 'train_module' key." if get_rank() == 0 and trainer_state["train_engine"] == "pl": trainer = trainer_state["train_module"] if ( diff --git a/vis4d/pl/data_module.py b/vis4d/engine/data_module.py similarity index 100% rename from vis4d/pl/data_module.py rename to vis4d/engine/data_module.py diff --git a/vis4d/engine/experiment.py b/vis4d/engine/experiment.py deleted file mode 100644 index 68c05046..00000000 --- a/vis4d/engine/experiment.py +++ /dev/null @@ -1,276 +0,0 @@ -"""Implementation of a single experiment. - -Helper functions to execute a single experiment. - -This will be called for each experiment configuration. -""" - -from __future__ import annotations - -import logging -import os - -import torch -from torch.distributed import destroy_process_group, init_process_group -from torch.nn.parallel import DistributedDataParallel as DDP -from torch.utils.collect_env import get_pretty_env_info - -from vis4d.common.ckpt import load_model_checkpoint -from vis4d.common.distributed import ( - broadcast, - get_local_rank, - get_rank, - get_world_size, -) -from vis4d.common.logging import ( - _info, - dump_config, - rank_zero_info, - rank_zero_warn, - setup_logger, -) -from vis4d.common.slurm import init_dist_slurm -from vis4d.common.util import init_random_seed, set_random_seed, set_tf32 -from vis4d.config import instantiate_classes -from vis4d.config.typing import ExperimentConfig -from vis4d.engine.callbacks import VisualizerCallback - -from .optim import set_up_optimizers -from .parser import pprints_config -from .trainer import Trainer - - -def ddp_setup( - torch_distributed_backend: str = "nccl", slurm: bool = False -) -> None: - """Setup DDP environment and init processes. - - Args: - torch_distributed_backend (str): Backend to use (`nccl` or `gloo`) - slurm (bool): If set, setup slurm running jobs. - """ - if slurm: - init_dist_slurm() - - global_rank = get_rank() - world_size = get_world_size() - _info( - f"Initializing distributed: " - f"GLOBAL_RANK: {global_rank}, MEMBER: {global_rank + 1}/{world_size}" - ) - init_process_group( - torch_distributed_backend, rank=global_rank, world_size=world_size - ) - - # On rank=0 let everyone know training is starting - rank_zero_info( - f"{'-' * 100}\n" - f"distributed_backend={torch_distributed_backend}\n" - f"All distributed processes registered. " - f"Starting with {world_size} processes\n" - f"{'-' * 100}\n" - ) - - local_rank = get_local_rank() - all_gpu_ids = ",".join(str(x) for x in range(torch.cuda.device_count())) - devices = os.getenv("CUDA_VISIBLE_DEVICES", all_gpu_ids) - - torch.cuda.set_device(local_rank) - - _info(f"LOCAL_RANK: {local_rank} - CUDA_VISIBLE_DEVICES: [{devices}]") - - -def run_experiment( - config: ExperimentConfig, - mode: str, - num_gpus: int = 0, - show_config: bool = False, - use_slurm: bool = False, - ckpt_path: str | None = None, - resume: bool = False, - vis: bool = False, -) -> None: - """Entry point for running a single experiment. - - Args: - config (ExperimentConfig): Configuration dictionary. - mode (str): Mode to run the experiment in. Either `fit` or `test`. - num_gpus (int): Number of GPUs to use. - show_config (bool): If set, prints the configuration. - use_slurm (bool): If set, setup slurm running jobs. This will set the - required environment variables for slurm. - ckpt_path (str | None): Path to a checkpoint to load. - resume (bool): If set, resume training from the checkpoint. - vis (bool): If set, enable visualizer callback. - - Raises: - ValueError: If `mode` is not `fit` or `test`. - """ - # Setup logging - logger_vis4d = logging.getLogger("vis4d") - log_dir = os.path.join(config.output_dir, f"log_{config.timestamp}.txt") - setup_logger(logger_vis4d, log_dir) - - # Dump config - config_file = os.path.join( - config.output_dir, f"config_{config.timestamp}.yaml" - ) - dump_config(config, config_file) - - rank_zero_info("Environment info: %s", get_pretty_env_info()) - - # PyTorch Setting - set_tf32(config.use_tf32, config.tf32_matmul_precision) - torch.hub.set_dir(f"{config.work_dir}/.cache/torch/hub") - torch.backends.cudnn.benchmark = config.benchmark - - if show_config: - rank_zero_info(pprints_config(config)) - - # Instantiate classes - model = instantiate_classes(config.model) - - if config.get("sync_batchnorm", False): - if num_gpus > 1: - rank_zero_info( - "SyncBN enabled, converting BatchNorm layers to" - " SyncBatchNorm layers." - ) - model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model) - else: - rank_zero_warn( - "use_sync_bn is True, but not in a distributed setting." - " BatchNorm layers are not converted." - ) - - # Callbacks - callbacks = [] - for cb in config.callbacks: - callback = instantiate_classes(cb) - - if not vis and isinstance(callback, VisualizerCallback): - rank_zero_info( - "VisualizerCallback is not used. " - "Please set --vis=True to use it." - ) - continue - - callbacks.append(callback) - - # Setup DDP & seed - seed = init_random_seed() if config.seed == -1 else config.seed - - if num_gpus > 1: - ddp_setup(slurm=use_slurm) - - # broadcast seed to all processes - seed = broadcast(seed) - - # Setup Dataloaders & seed - if mode == "fit": - set_random_seed(seed) - _info(f"[rank {get_rank()}] Global seed set to {seed}") - train_dataloader = instantiate_classes( - config.data.train_dataloader, seed=seed - ) - train_data_connector = instantiate_classes(config.train_data_connector) - optimizers, lr_schedulers = set_up_optimizers( - config.optimizers, [model], len(train_dataloader) - ) - loss = instantiate_classes(config.loss) - else: - train_dataloader = None - train_data_connector = None - - if config.data.test_dataloader is not None: - test_dataloader = instantiate_classes(config.data.test_dataloader) - else: - test_dataloader = None - - if config.test_data_connector is not None: - test_data_connector = instantiate_classes(config.test_data_connector) - else: - test_data_connector = None - - # Setup Model - if num_gpus == 0: - device = torch.device("cpu") - else: - rank = get_local_rank() - device = torch.device(f"cuda:{rank}") - - model.to(device) - - if num_gpus > 1: - model = DDP( # pylint: disable=redefined-variable-type - model, device_ids=[rank] - ) - - # Setup Callbacks - for cb in callbacks: - cb.setup() - - # Resume training - if resume: - assert mode == "fit", "Resume is only supported in fit mode" - if ckpt_path is None: - ckpt_path = os.path.join( - config.output_dir, "checkpoints/last.ckpt" - ) - rank_zero_info( - f"Restoring states from the checkpoint path at {ckpt_path}" - ) - ckpt = torch.load(ckpt_path, map_location="cpu") - - epoch = ckpt["epoch"] + 1 - global_step = ckpt["global_step"] - - for i, optimizer in enumerate( - optimizers # pylint:disable=possibly-used-before-assignment - ): - optimizer.load_state_dict(ckpt["optimizers"][i]) - - for i, lr_scheduler in enumerate( - lr_schedulers # pylint:disable=possibly-used-before-assignment - ): - lr_scheduler.load_state_dict(ckpt["lr_schedulers"][i]) - else: - epoch = 0 - global_step = 0 - - if ckpt_path is not None: - load_model_checkpoint( - model, - ckpt_path, - rev_keys=[(r"^model\.", ""), (r"^module\.", "")], - ) - - trainer = Trainer( - device=device, - output_dir=config.output_dir, - train_dataloader=train_dataloader, - test_dataloader=test_dataloader, - train_data_connector=train_data_connector, - test_data_connector=test_data_connector, - callbacks=callbacks, - num_epochs=config.params.get("num_epochs", -1), - num_steps=config.params.get("num_steps", -1), - epoch=epoch, - global_step=global_step, - check_val_every_n_epoch=config.get("check_val_every_n_epoch", 1), - val_check_interval=config.get("val_check_interval", None), - log_every_n_steps=config.get("log_every_n_steps", 50), - ) - - if resume: - rank_zero_info( - f"Restored all states from the checkpoint at {ckpt_path}" - ) - - if mode == "fit": - trainer.fit(model, optimizers, lr_schedulers, loss) - elif mode == "test": - trainer.test(model) - - if num_gpus > 1: - destroy_process_group() diff --git a/vis4d/engine/run.py b/vis4d/engine/run.py index 2e3a95c3..f29b1ce4 100644 --- a/vis4d/engine/run.py +++ b/vis4d/engine/run.py @@ -1,84 +1,171 @@ -"""CLI interface.""" +"""CLI interface using PyTorch Lightning.""" from __future__ import annotations +import logging +import os.path as osp + +import torch from absl import app # pylint: disable=no-name-in-module +from lightning.fabric.utilities.exceptions import MisconfigurationException +from lightning.pytorch import Callback +from torch.utils.collect_env import get_pretty_env_info from vis4d.common import ArgsType -from vis4d.common.logging import rank_zero_info +from vis4d.common.logging import dump_config, rank_zero_info, setup_logger +from vis4d.common.util import set_tf32 from vis4d.config import instantiate_classes -from vis4d.config.replicator import replicate_config from vis4d.config.typing import ExperimentConfig - -from .experiment import run_experiment -from .flag import ( +from vis4d.engine.callbacks import CheckpointCallback, VisualizerCallback +from vis4d.engine.flag import ( _CKPT, _CONFIG, _GPUS, _RESUME, _SHOW_CONFIG, - _SLURM, - _SWEEP, _VIS, ) +from vis4d.engine.parser import pprints_config +from vis4d.engine.callbacks import CallbackWrapper, LRSchedulerCallback +from vis4d.engine.data_module import DataModule +from vis4d.engine.trainer import PLTrainer +from vis4d.engine.training_module import TrainingModule def main(argv: ArgsType) -> None: """Main entry point for the CLI. Example to run this script: - >>> python -m vis4d.engine.run --config vis4d/zoo/faster_rcnn/faster_rcnn_coco.py - With parameter sweep config: - >>> python -m vis4d.engine.run fit --config vis4d/zoo/faster_rcnn/faster_rcnn_coco.py --sweep vis4d/zoo/faster_rcnn/faster_rcnn_coco.py + >>> python -m vis4d.pl.run fit --config configs/faster_rcnn/faster_rcnn_coco.py """ # Get config - assert len(argv) > 1, "Mode must be specified: `fit` or `test`" mode = argv[1] assert mode in {"fit", "test"}, f"Invalid mode: {mode}" - experiment_config: ExperimentConfig = _CONFIG.value + config: ExperimentConfig = _CONFIG.value + num_gpus = _GPUS.value - if _SWEEP.value is not None: - # Perform parameter sweep - rank_zero_info( - "Found Parameter Sweep in config file. Running Parameter Sweep..." - ) - experiment_config = _CONFIG.value - sweep_config = instantiate_classes(_SWEEP.value) - - for run_id, config in enumerate( - replicate_config( - experiment_config, - method=sweep_config.method, - sampling_args=sweep_config.sampling_args, - fstring=sweep_config.get("suffix", ""), - ) - ): + # Setup logging + logger_vis4d = logging.getLogger("vis4d") + logger_pl = logging.getLogger("pytorch_lightning") + log_file = osp.join(config.output_dir, f"log_{config.timestamp}.txt") + setup_logger(logger_vis4d, log_file) + setup_logger(logger_pl, log_file) + + # Dump config + config_file = osp.join( + config.output_dir, f"config_{config.timestamp}.yaml" + ) + dump_config(config, config_file) + + rank_zero_info("Environment info: %s", get_pretty_env_info()) + + # PyTorch Setting + set_tf32(config.use_tf32, config.tf32_matmul_precision) + torch.hub.set_dir(f"{config.work_dir}/.cache/torch/hub") + + # Setup device + if num_gpus > 0: + config.pl_trainer.accelerator = "gpu" + config.pl_trainer.devices = num_gpus + else: + config.pl_trainer.accelerator = "cpu" + config.pl_trainer.devices = 1 + + trainer_args = instantiate_classes(config.pl_trainer).to_dict() + + if _SHOW_CONFIG.value: + rank_zero_info(pprints_config(config)) + + # Instantiate classes + if mode == "fit": + train_data_connector = instantiate_classes(config.train_data_connector) + loss = instantiate_classes(config.loss) + else: + train_data_connector = None + loss = None + + if config.test_data_connector is not None: + test_data_connector = instantiate_classes(config.test_data_connector) + else: + test_data_connector = None + + # Callbacks + vis = _VIS.value + + callbacks: list[Callback] = [] + for cb in config.callbacks: + callback = instantiate_classes(cb) + # Skip checkpoint callback to use PL ModelCheckpoint + if isinstance(callback, CheckpointCallback): + continue + + if not vis and isinstance(callback, VisualizerCallback): rank_zero_info( - "Running experiment #%d: %s", - run_id, - config.experiment_name, + "VisualizerCallback is not used. " + "Please set --vis=True to use it." ) - # Run single experiment - run_experiment( - experiment_config, - mode, - _GPUS.value, - _SHOW_CONFIG.value, - _SLURM.value, + continue + + callbacks.append(CallbackWrapper(callback)) + + if "pl_callbacks" in config: + pl_callbacks = [instantiate_classes(cb) for cb in config.pl_callbacks] + else: + pl_callbacks = [] + + for cb in pl_callbacks: + if not isinstance(cb, Callback): + raise MisconfigurationException( + "Callback must be a subclass of pytorch_lightning Callback. " + f"Provided callback: {cb} is not!" ) + callbacks.append(cb) + + # Add needed callbacks + callbacks.append(LRSchedulerCallback()) + # Checkpoint path + ckpt_path = _CKPT.value + + # Resume training + resume = _RESUME.value + if resume: + if ckpt_path is None: + resume_ckpt_path = osp.join( + config.output_dir, "checkpoints/last.ckpt" + ) + else: + resume_ckpt_path = ckpt_path else: - # Run single experiment - run_experiment( - experiment_config, - mode, - _GPUS.value, - _SHOW_CONFIG.value, - _SLURM.value, - _CKPT.value, - _RESUME.value, - _VIS.value, + resume_ckpt_path = None + + trainer = PLTrainer(callbacks=callbacks, **trainer_args) + + hyper_params = trainer_args + + if config.get("params", None) is not None: + hyper_params.update(config.params.to_dict()) + + training_module = TrainingModule( + config.model, + config.optimizers, + loss, + train_data_connector, + test_data_connector, + hyper_params, + config.seed, + ckpt_path if not resume else None, + config.compute_flops, + config.check_unused_parameters, + ) + data_module = DataModule(config.data) + + if mode == "fit": + trainer.fit( + training_module, datamodule=data_module, ckpt_path=resume_ckpt_path ) + elif mode == "test": + trainer.test(training_module, datamodule=data_module, verbose=False) def entrypoint() -> None: diff --git a/vis4d/engine/trainer.py b/vis4d/engine/trainer.py index 901e7d96..831f3542 100644 --- a/vis4d/engine/trainer.py +++ b/vis4d/engine/trainer.py @@ -1,410 +1,139 @@ -"""Trainer for running train and test.""" +"""Trainer for PyTorch Lightning.""" from __future__ import annotations -import torch -from torch import nn -from torch.optim.optimizer import Optimizer -from torch.utils.data import DataLoader -from torch.utils.data.distributed import DistributedSampler -from torch.utils.tensorboard.writer import SummaryWriter +import datetime +import os.path as osp -from vis4d.common.distributed import rank_zero_only -from vis4d.common.logging import rank_zero_info, rank_zero_warn -from vis4d.data.typing import DictData -from vis4d.engine.callbacks import Callback, TrainerState -from vis4d.engine.connectors import DataConnector -from vis4d.engine.loss_module import LossModule +from lightning.pytorch import Callback, Trainer +from lightning.pytorch.callbacks import LearningRateMonitor, ModelCheckpoint +from lightning.pytorch.loggers import Logger, TensorBoardLogger +from lightning.pytorch.loggers.wandb import WandbLogger +from lightning.pytorch.strategies.ddp import DDPStrategy -from .optim import LRSchedulerWrapper -from .util import move_data_to_device +from vis4d.common import ArgsType +from vis4d.common.imports import TENSORBOARD_AVAILABLE +from vis4d.common.logging import rank_zero_info -class Trainer: - """Trainer class.""" +class PLTrainer(Trainer): + """Trainer for PyTorch Lightning.""" def __init__( self, - device: torch.device, - output_dir: str, - train_dataloader: DataLoader[DictData] | None, - test_dataloader: list[DataLoader[DictData]] | None, - train_data_connector: DataConnector | None, - test_data_connector: DataConnector | None, - callbacks: list[Callback], - num_epochs: int = 1000, - num_steps: int = -1, - epoch: int = 0, - global_step: int = 0, - check_val_every_n_epoch: int | None = 1, - val_check_interval: int | None = None, - log_every_n_steps: int = 50, + *args: ArgsType, + work_dir: str, + exp_name: str, + version: str, + epoch_based: bool = True, + find_unused_parameters: bool = False, + save_top_k: int = 1, + checkpoint_period: int = 1, + checkpoint_callback: ModelCheckpoint | None = None, + wandb: bool = False, + seed: int = -1, + timeout: int = 3600, + wandb_id: str | None = None, + **kwargs: ArgsType, ) -> None: - """Initialize the trainer. + """Perform some basic common setups at the beginning of a job. Args: - device (torch.device): Device that should be used for training. - output_dir (str): Output directory for saving tensorboard logs. - train_dataloader (DataLoader[DictData] | None, optional): - Dataloader for training. - test_dataloader (list[DataLoader[DictData]] | None, optional): - Dataloaders for testing. - train_data_connector (DataConnector | None): Data connector used - for generating training inputs from a batch of data. - test_data_connector (DataConnector | None): Data connector used for - generating testing inputs from a batch of data. - callbacks (list[Callback]): Callbacks that should be used during - training. - num_epochs (int, optional): Number of training epochs. Defaults to - 1000. - num_steps (int, optional): Number of training steps. Defaults to - -1. - epoch (int, optional): Starting epoch. Defaults to 0. - global_step (int, optional): Starting step. Defaults to 0. - check_val_every_n_epoch (int | None, optional): Evaluate the model - every n epochs during training. Defaults to 1. - val_check_interval (int | None, optional): Interval for evaluating - the model during training. Defaults to None. - log_every_n_steps (int, optional): Log the training status every n - steps. Defaults to 50. + work_dir: Specific directory to save checkpoints, logs, etc. + Integrates with exp_name and version to get output_dir. + exp_name: Name of current experiment. + version: Version of current experiment. + epoch_based: Use epoch-based / iteration-based training. Default is + True. + find_unused_parameters: Activates PyTorch checking for unused + parameters in DDP setting. Default: False, for better + performance. + save_top_k: Save top k checkpoints. Default: 1 (save last). + checkpoint_period: After N epochs / stpes, save out checkpoints. + Default: 1. + checkpoint_callback: Custom PL checkpoint callback. Default: None. + wandb: Use weights and biases logging instead of tensorboard. + Default: False. + seed (int, optional): The integer value seed for global random + state. Defaults to -1. If -1, a random seed will be generated. + This will be set by TrainingModule. + timeout: Timeout (seconds) for DDP connection. Default: 3600. """ - self.device = device - self.output_dir = output_dir - self.train_dataloader = train_dataloader - self.test_dataloader = test_dataloader - self.train_data_connector = train_data_connector - self.test_data_connector = test_data_connector - self.callbacks = callbacks - - if num_epochs == -1 and num_steps == -1: - rank_zero_info( - "Neither `num_epochs` nor `num_steps` is specified. " - + "Training will run indefinitely." - ) - - self.num_epochs = num_epochs - self.num_steps = num_steps - - if check_val_every_n_epoch is None and val_check_interval is None: - rank_zero_warn("Validation is disabled during training.") - - self.check_val_every_n_epoch = check_val_every_n_epoch - self.val_check_interval = val_check_interval - self.log_every_n_steps = log_every_n_steps - - self.epoch = epoch - self.global_step = global_step - - self._setup_logger() - - @rank_zero_only - def _setup_logger(self) -> None: - """Setup trainer logger.""" - self.writer = SummaryWriter(self.output_dir) - - @rank_zero_only - def _teardown_logger(self) -> None: - """Teardown trainer logger.""" - self.writer.close() - - @rank_zero_only - def _log_scalar(self, tag: str, scalar_value: float) -> None: - """Setup trainer logger.""" - self.writer.add_scalar(tag, scalar_value, self.global_step) - - def _log_lr(self, optimizer: Optimizer) -> None: - """Log learning rate.""" - tag = f"lr-{optimizer.__class__.__name__}" - - if len(optimizer.param_groups) > 1: - for i, param_group in enumerate(optimizer.param_groups): - self._log_scalar(f"{tag}/pg{i+1}", param_group["lr"]) - else: - self._log_scalar(tag, optimizer.param_groups[0]["lr"]) - - def _run_test_on_epoch(self, epoch: int) -> bool: - """Return whether to run test on current training epoch. - - Args: - epoch (int): Current training epoch. - - Returns: - bool: Whether to run test. - """ - if self.check_val_every_n_epoch is None: - return False - return (epoch + 1) % self.check_val_every_n_epoch == 0 - - def _run_test_on_step(self, step: int) -> bool: - """Return whether to run test on current training step. - - Args: - step (int): Current training step. - - Returns: - bool: Whether to run test. - """ - if self.val_check_interval is None: - return False - return (step + 1) % self.val_check_interval == 0 - - def done(self) -> bool: - """Return whether training is done.""" - is_done = False - if _is_max_limit_reached(self.global_step, self.num_steps): - rank_zero_info( - f"`Trainer.fit` stopped: `num_steps={self.num_steps!r}` " - + "reached." - ) - is_done = True - elif _is_max_limit_reached(self.epoch, self.num_epochs): - rank_zero_info( - f"`Trainer.fit` stopped: `num_epochs={self.num_epochs!r}` " - + "reached." - ) - is_done = True - - if is_done: - self._teardown_logger() - - return is_done - - def fit( - self, - model: nn.Module, - optimizers: list[Optimizer], - lr_schedulers: list[LRSchedulerWrapper], - loss_module: LossModule, - ) -> None: - """Training loop. - - Args: - model (nn.Module): Model that should be trained. - optimizers (list[Optimizer]): Optimizers that should be used for - training. - lr_schedulers (list[LRSchedulerWrapper]): Learning rate schedulers - that should be used for training. - loss_module (LossModule): Loss module that should be used for - training. - - Raises: - TypeError: If the loss value is not a torch.Tensor or a dict of - torch.Tensor. - """ - assert ( - self.train_data_connector is not None - ), "No train data connector." - assert self.train_dataloader is not None, "No train dataloader." - - while True: - # Run callbacks for epoch begin - for callback in self.callbacks: - callback.on_train_epoch_start( - self.get_state(), model, loss_module + self.work_dir = work_dir + self.exp_name = exp_name + self.version = version + self.seed = seed + + self.output_dir = osp.join(work_dir, exp_name, version) + + # setup experiment logging + if "logger" not in kwargs or ( + isinstance(kwargs["logger"], bool) and kwargs["logger"] + ): + exp_logger: Logger | None = None + if wandb: # pragma: no cover + exp_logger = WandbLogger( + save_dir=work_dir, + project=exp_name, + name=version, + id=wandb_id, ) - - # Set model to train mode - model.train() - - # Set epoch for distributed sampler - if hasattr(self.train_dataloader, "sampler") and isinstance( - self.train_dataloader.sampler, DistributedSampler - ): - self.train_dataloader.sampler.set_epoch(self.epoch) - - # Training loop for one epoch - for batch_idx, data in enumerate(self.train_dataloader): - # Log epoch - if (self.global_step + 1) % self.log_every_n_steps == 0: - self._log_scalar("epoch", self.epoch) - - # Zero grad optimizers - for opt in optimizers: - opt.zero_grad() - - # Input data - data = move_data_to_device(data, self.device) - - for callback in self.callbacks: - callback.on_train_batch_start( - trainer_state=self.get_state(), - model=model, - loss_module=loss_module, - batch=data, - batch_idx=batch_idx, - ) - - # Forward + backward + optimize - output = model(**self.train_data_connector(data)) - - total_loss, metrics = loss_module(output, data) - - total_loss.backward() - - for optimizer in optimizers: - # Log learning rate - if (self.global_step + 1) % self.log_every_n_steps == 0: - self._log_lr(optimizer) - - # Step optimizers - optimizer.step() - - # Step learning rate schedulers - for lr_scheduler in lr_schedulers: - lr_scheduler.step_on_batch(self.global_step) - - for callback in self.callbacks: - log_dict = callback.on_train_batch_end( - trainer_state=self.get_state(metrics), - model=model, - loss_module=loss_module, - outputs=output, - batch=data, - batch_idx=batch_idx, - ) - - if log_dict is not None: - for k, v in log_dict.items(): - self._log_scalar(f"train/{k}", v) - - # Testing (step-based) - if ( - self._run_test_on_step(self.global_step) - and self.test_dataloader is not None - ): - self.test(model) - - # Set model back to train mode - model.train() - - self.global_step += 1 - - if self.done(): - return - - # Update learning rate on epoch - for lr_scheduler in lr_schedulers: - lr_scheduler.step(self.epoch) - - # Run callbacks for epoch end - for callback in self.callbacks: - callback.on_train_epoch_end( - self.get_state( - optimizers=optimizers, lr_schedulers=lr_schedulers - ), - model, - loss_module, + elif TENSORBOARD_AVAILABLE: + exp_logger = TensorBoardLogger( + save_dir=work_dir, + name=exp_name, + version=version, + default_hp_metric=False, ) + else: + rank_zero_info( + "Neither `tensorboard` nor `tensorboardX` is " + "available. Running without experiment logger. To log " + "your experiments, try `pip install`ing either." + ) + kwargs["logger"] = exp_logger + + callbacks: list[Callback] = [] + + # add learning rate / GPU stats monitor (logs to tensorboard) + if TENSORBOARD_AVAILABLE or wandb: + callbacks += [LearningRateMonitor(logging_interval="step")] + + # Model checkpointer + if checkpoint_callback is None: + if epoch_based: + checkpoint_cb = ModelCheckpoint( + dirpath=osp.join(self.output_dir, "checkpoints"), + verbose=True, + save_last=True, + save_top_k=save_top_k, + every_n_epochs=checkpoint_period, + save_on_train_epoch_end=True, + ) + else: + checkpoint_cb = ModelCheckpoint( + dirpath=osp.join(self.output_dir, "checkpoints"), + verbose=True, + save_last=True, + save_top_k=save_top_k, + every_n_train_steps=checkpoint_period, + ) + else: + checkpoint_cb = checkpoint_callback + callbacks += [checkpoint_cb] + + kwargs["callbacks"] += callbacks + + # add distributed strategy + if kwargs["devices"] == 0: + kwargs["accelerator"] = "cpu" + kwargs["devices"] = "auto" + elif kwargs["devices"] > 1: # pragma: no cover + if kwargs["accelerator"] == "gpu": + ddp_plugin = DDPStrategy( + find_unused_parameters=find_unused_parameters, + timeout=datetime.timedelta(timeout), + ) + kwargs["strategy"] = ddp_plugin - # Testing (epoch-based) - if ( - self._run_test_on_epoch(self.epoch) - and self.test_dataloader is not None - ): - self.test(model, is_val=True) - - self.epoch += 1 - - if self.done(): - return - - @torch.no_grad() - def test(self, model: nn.Module, is_val: bool = False) -> None: - """Testing loop. - - Args: - model (nn.Module): Model that should be tested. - is_val (bool): Whether the test is run on the validation set during - training. - """ - assert self.test_data_connector is not None, "No test data connector." - assert self.test_dataloader is not None, "No test dataloader." - - model.eval() - - # run callbacks on test epoch begin - for callback in self.callbacks: - callback.on_test_epoch_start(self.get_state(), model) - - for i, test_loader in enumerate(self.test_dataloader): - for batch_idx, data in enumerate(test_loader): - data = move_data_to_device(data, self.device) - test_input = self.test_data_connector(data) - - # forward - output = model(**test_input) - - for callback in self.callbacks: - callback.on_test_batch_end( - trainer_state=self.get_state(), - model=model, - outputs=output, - batch=data, - batch_idx=batch_idx, - dataloader_idx=i, - ) - - # run callbacks on test epoch end - for callback in self.callbacks: - log_dict = callback.on_test_epoch_end(self.get_state(), model) - - if log_dict is not None: - for k, v in log_dict.items(): - key = f"val/{k}" if is_val else f"test/{k}" - self._log_scalar(key, v) - - def get_state( - self, - metrics: dict[str, float] | None = None, - optimizers: list[Optimizer] | None = None, - lr_schedulers: list[LRSchedulerWrapper] | None = None, - ) -> TrainerState: - """Get the state of the trainer.""" - num_train_batches = ( - len(self.train_dataloader) - if self.train_dataloader is not None - else None - ) - - num_test_batches = ( - [len(test_loader) for test_loader in self.test_dataloader] - if self.test_dataloader is not None - else None - ) - - trainer_state = TrainerState( - current_epoch=self.epoch, - num_epochs=self.num_epochs, - global_step=self.global_step, - num_steps=self.num_steps, - train_dataloader=self.train_dataloader, - num_train_batches=num_train_batches, - test_dataloader=self.test_dataloader, - num_test_batches=num_test_batches, - train_module=self, - train_engine="vis4d", - ) - - if metrics is not None: - trainer_state["metrics"] = metrics - - if optimizers is not None: - trainer_state["optimizers"] = optimizers - - if lr_schedulers is not None: - trainer_state["lr_schedulers"] = lr_schedulers - - return trainer_state - - -def _is_max_limit_reached(current: int, maximum: int = -1) -> bool: - """Check if the limit has been reached (if enabled). - - Args: - current: the current value - maximum: the maximum value (or -1 to disable limit) - - Returns: - bool: whether the limit has been reached - """ - return maximum != -1 and current >= maximum + super().__init__(*args, **kwargs) diff --git a/vis4d/pl/training_module.py b/vis4d/engine/training_module.py similarity index 100% rename from vis4d/pl/training_module.py rename to vis4d/engine/training_module.py diff --git a/vis4d/engine/util.py b/vis4d/engine/util.py deleted file mode 100644 index 9d7c1a3c..00000000 --- a/vis4d/engine/util.py +++ /dev/null @@ -1,221 +0,0 @@ -"""Run utilities.""" - -from __future__ import annotations - -import dataclasses -from abc import ABC -from collections import OrderedDict, defaultdict -from collections.abc import Callable, Mapping, Sequence -from copy import deepcopy -from typing import Any - -import torch -from torch import Tensor - -from vis4d.common.named_tuple import is_namedtuple - -_BLOCKING_DEVICE_TYPES = ("cpu", "mps") - - -class TransferableDataType(ABC): - """A custom type for data that can be moved to a torch device. - - Example: - >>> isinstance(dict, TransferableDataType) - False - >>> isinstance(torch.rand(2, 3), TransferableDataType) - True - >>> class CustomObject: - ... def __init__(self): - ... self.x = torch.rand(2, 2) - ... def to(self, device): - ... self.x = self.x.to(device) - ... return self - >>> isinstance(CustomObject(), TransferableDataType) - True - """ - - @classmethod - def __subclasshook__(cls, subclass: Any) -> bool | Any: # type: ignore - """Subclass hook.""" - if cls is TransferableDataType: - to = getattr(subclass, "to", None) - return callable(to) - return NotImplemented # pragma: no cover - - -def is_dataclass_instance(obj: object) -> bool: - """Check if obj is dataclass instance. - - https://docs.python.org/3/library/dataclasses.html#module-level-decorators-classes-and-functions - """ - return dataclasses.is_dataclass(obj) and not isinstance(obj, type) - - -def apply_to_collection( # type: ignore - data: Any, - dtype: type | Any | tuple[type | Any], - function: Callable[[Any], Any], - *args: Any, - wrong_dtype: None | type | tuple[type, ...] = None, - include_none: bool = True, - **kwargs: Any, -) -> Any: - """Recursively applies a function to all elements of a certain dtype. - - Args: - data: the collection to apply the function to - dtype: the given function will be applied to all elements of this dtype - function: the function to apply - *args: positional arguments (will be forwarded to calls of - ``function``) - wrong_dtype: the given function won't be applied if this type is - specified and the given collections is of the ``wrong_dtype`` even - if it is of type ``dtype`` - include_none: Whether to include an element if the output of - ``function`` is ``None``. - **kwargs: keyword arguments (will be forwarded to calls of - ``function``) - - Raises: - ValueError: If frozen dataclass is passed to `apply_to_collection`. - - Returns: - The resulting collection - """ - # Breaking condition - if isinstance(data, dtype) and ( - wrong_dtype is None or not isinstance(data, wrong_dtype) - ): - return function(data, *args, **kwargs) - - elem_type = type(data) - - # Recursively apply to collection items - if isinstance(data, Mapping): - out = [] - for k, v in data.items(): - v = apply_to_collection( - v, - dtype, - function, - *args, - wrong_dtype=wrong_dtype, - include_none=include_none, - **kwargs, - ) - if include_none or v is not None: - out.append((k, v)) - if isinstance(data, defaultdict): - return elem_type(data.default_factory, OrderedDict(out)) - return elem_type(OrderedDict(out)) - - is_namedtuple_ = is_namedtuple(data) - is_sequence = isinstance(data, Sequence) and not isinstance(data, str) - if is_namedtuple_ or is_sequence: - out = [] - for d in data: - v = apply_to_collection( - d, - dtype, - function, - *args, - wrong_dtype=wrong_dtype, - include_none=include_none, - **kwargs, - ) - if include_none or v is not None: - out.append(v) - return elem_type(*out) if is_namedtuple_ else elem_type(out) - - if is_dataclass_instance(data): - # make a deepcopy of the data, - # but do not deepcopy mapped fields since the computation would - # be wasted on values that likely get immediately overwritten - fields = {} - memo = {} - for field in dataclasses.fields(data): - field_value = getattr(data, field.name) - fields[field.name] = (field_value, field.init) - memo[id(field_value)] = field_value - result = deepcopy(data, memo=memo) - # apply function to each field - for field_name, (field_value, field_init) in fields.items(): - v = None - if field_init: - v = apply_to_collection( - field_value, - dtype, - function, - *args, - wrong_dtype=wrong_dtype, - include_none=include_none, - **kwargs, - ) - if not field_init or ( - not include_none and v is None - ): # retain old value - v = getattr(data, field_name) - try: - setattr(result, field_name, v) - except dataclasses.FrozenInstanceError as e: - raise ValueError( - "A frozen dataclass was passed to `apply_to_collection` " - "but this is not allowed." - ) from e - return result - - # data is neither of dtype, nor a collection - return data - - -def move_data_to_device( # type: ignore - batch: Any, - device: torch.device | str | int, - convert_to_numpy: bool = False, -) -> Any: - """Transfers a collection of data to the given device. - - Any object that defines a method ``to(device)`` will be moved and all other - objects in the collection will be left untouched. - - This implementation is modified from - https://github.com/Lightning-AI/lightning - - Args: - batch: A tensor or collection of tensors or anything that has a method - ``.to(...)``. See :func:`apply_to_collection` for a list of - supported collection types. - device: The device to which the data should be moved. - convert_to_numpy: Whether to convert from tensor to numpy array. - - Return: - The same collection but with all contained tensors residing on the new - device. - """ - if isinstance(device, str): - device = torch.device(device) - - def batch_to(data: Any) -> Any: # type: ignore[misc] - kwargs = {} - # Don't issue non-blocking transfers to CPU - # Same with MPS due to a race condition bug: - # https://github.com/pytorch/pytorch/issues/83015 - if ( - isinstance(data, Tensor) - and isinstance(device, torch.device) - and device.type not in _BLOCKING_DEVICE_TYPES - ): - kwargs["non_blocking"] = True - data_output = data.to(device, **kwargs) - if data_output is not None: - if convert_to_numpy: - data_output = data_output.numpy() - return data_output - # user wrongly implemented the `TransferableDataType` and forgot to - # return `self`. - return data - - return apply_to_collection( - batch, dtype=TransferableDataType, function=batch_to - ) diff --git a/vis4d/op/base/dla.py b/vis4d/op/base/dla.py index 87aaa648..8d24cc47 100644 --- a/vis4d/op/base/dla.py +++ b/vis4d/op/base/dla.py @@ -2,9 +2,8 @@ from __future__ import annotations -from collections.abc import Sequence - import math +from collections.abc import Sequence import torch from torch import Tensor, nn diff --git a/vis4d/op/detect/dense_anchor.py b/vis4d/op/detect/dense_anchor.py index 14f8a20d..74816cbc 100644 --- a/vis4d/op/detect/dense_anchor.py +++ b/vis4d/op/detect/dense_anchor.py @@ -29,7 +29,7 @@ class DetectorTargets(NamedTuple): def images_to_levels( targets: list[ tuple[list[Tensor], list[Tensor], list[Tensor], list[Tensor]] - ] + ], ) -> list[list[Tensor]]: """Convert targets by image to targets by feature level.""" targets_per_level = [] diff --git a/vis4d/op/layer/patch_embed.py b/vis4d/op/layer/patch_embed.py index 5b91aa12..ba775a63 100644 --- a/vis4d/op/layer/patch_embed.py +++ b/vis4d/op/layer/patch_embed.py @@ -1,6 +1,6 @@ """Image to Patch Embedding using Conv2d. -Modified from vision_transformer +Modified from vision_transformer (https://github.com/google-research/vision_transformer). """ diff --git a/vis4d/op/track/assignment.py b/vis4d/op/track/assignment.py index 8b1db4f8..4136c416 100644 --- a/vis4d/op/track/assignment.py +++ b/vis4d/op/track/assignment.py @@ -3,9 +3,8 @@ from __future__ import annotations import torch - -from torch import Tensor from scipy.optimize import linear_sum_assignment +from torch import Tensor def greedy_assign( diff --git a/vis4d/pl/__init__.py b/vis4d/pl/__init__.py deleted file mode 100644 index 50e47fe3..00000000 --- a/vis4d/pl/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Run training and evaluation in PyTorch Lightening.""" diff --git a/vis4d/pl/__main__.py b/vis4d/pl/__main__.py deleted file mode 100644 index 67e5297f..00000000 --- a/vis4d/pl/__main__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Entry point for the vis4d.pl package.""" - -from .run import entrypoint - -entrypoint() diff --git a/vis4d/pl/callbacks/__init__.py b/vis4d/pl/callbacks/__init__.py deleted file mode 100644 index 36c3ea27..00000000 --- a/vis4d/pl/callbacks/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Callbacks handling data related stuff (evaluation, visualization, etc).""" - -from .callback_wrapper import CallbackWrapper -from .scheduler import LRSchedulerCallback - -__all__ = ["CallbackWrapper", "LRSchedulerCallback"] diff --git a/vis4d/pl/run.py b/vis4d/pl/run.py deleted file mode 100644 index 14642f08..00000000 --- a/vis4d/pl/run.py +++ /dev/null @@ -1,177 +0,0 @@ -"""CLI interface using PyTorch Lightning.""" - -from __future__ import annotations - -import logging -import os.path as osp - -import torch -from absl import app # pylint: disable=no-name-in-module -from lightning.fabric.utilities.exceptions import MisconfigurationException -from lightning.pytorch import Callback -from torch.utils.collect_env import get_pretty_env_info - -from vis4d.common import ArgsType -from vis4d.common.logging import dump_config, rank_zero_info, setup_logger -from vis4d.common.util import set_tf32 -from vis4d.config import instantiate_classes -from vis4d.config.typing import ExperimentConfig -from vis4d.engine.callbacks import CheckpointCallback, VisualizerCallback -from vis4d.engine.flag import ( - _CKPT, - _CONFIG, - _GPUS, - _RESUME, - _SHOW_CONFIG, - _VIS, -) -from vis4d.engine.parser import pprints_config -from vis4d.pl.callbacks import CallbackWrapper, LRSchedulerCallback -from vis4d.pl.data_module import DataModule -from vis4d.pl.trainer import PLTrainer -from vis4d.pl.training_module import TrainingModule - - -def main(argv: ArgsType) -> None: - """Main entry point for the CLI. - - Example to run this script: - >>> python -m vis4d.pl.run fit --config configs/faster_rcnn/faster_rcnn_coco.py - """ - # Get config - mode = argv[1] - assert mode in {"fit", "test"}, f"Invalid mode: {mode}" - config: ExperimentConfig = _CONFIG.value - num_gpus = _GPUS.value - - # Setup logging - logger_vis4d = logging.getLogger("vis4d") - logger_pl = logging.getLogger("pytorch_lightning") - log_file = osp.join(config.output_dir, f"log_{config.timestamp}.txt") - setup_logger(logger_vis4d, log_file) - setup_logger(logger_pl, log_file) - - # Dump config - config_file = osp.join( - config.output_dir, f"config_{config.timestamp}.yaml" - ) - dump_config(config, config_file) - - rank_zero_info("Environment info: %s", get_pretty_env_info()) - - # PyTorch Setting - set_tf32(config.use_tf32, config.tf32_matmul_precision) - torch.hub.set_dir(f"{config.work_dir}/.cache/torch/hub") - - # Setup device - if num_gpus > 0: - config.pl_trainer.accelerator = "gpu" - config.pl_trainer.devices = num_gpus - else: - config.pl_trainer.accelerator = "cpu" - config.pl_trainer.devices = 1 - - trainer_args = instantiate_classes(config.pl_trainer).to_dict() - - if _SHOW_CONFIG.value: - rank_zero_info(pprints_config(config)) - - # Instantiate classes - if mode == "fit": - train_data_connector = instantiate_classes(config.train_data_connector) - loss = instantiate_classes(config.loss) - else: - train_data_connector = None - loss = None - - if config.test_data_connector is not None: - test_data_connector = instantiate_classes(config.test_data_connector) - else: - test_data_connector = None - - # Callbacks - vis = _VIS.value - - callbacks: list[Callback] = [] - for cb in config.callbacks: - callback = instantiate_classes(cb) - # Skip checkpoint callback to use PL ModelCheckpoint - if isinstance(callback, CheckpointCallback): - continue - - if not vis and isinstance(callback, VisualizerCallback): - rank_zero_info( - "VisualizerCallback is not used. " - "Please set --vis=True to use it." - ) - continue - - callbacks.append(CallbackWrapper(callback)) - - if "pl_callbacks" in config: - pl_callbacks = [instantiate_classes(cb) for cb in config.pl_callbacks] - else: - pl_callbacks = [] - - for cb in pl_callbacks: - if not isinstance(cb, Callback): - raise MisconfigurationException( - "Callback must be a subclass of pytorch_lightning Callback. " - f"Provided callback: {cb} is not!" - ) - callbacks.append(cb) - - # Add needed callbacks - callbacks.append(LRSchedulerCallback()) - - # Checkpoint path - ckpt_path = _CKPT.value - - # Resume training - resume = _RESUME.value - if resume: - if ckpt_path is None: - resume_ckpt_path = osp.join( - config.output_dir, "checkpoints/last.ckpt" - ) - else: - resume_ckpt_path = ckpt_path - else: - resume_ckpt_path = None - - trainer = PLTrainer(callbacks=callbacks, **trainer_args) - - hyper_params = trainer_args - - if config.get("params", None) is not None: - hyper_params.update(config.params.to_dict()) - - training_module = TrainingModule( - config.model, - config.optimizers, - loss, - train_data_connector, - test_data_connector, - hyper_params, - config.seed, - ckpt_path if not resume else None, - config.compute_flops, - config.check_unused_parameters, - ) - data_module = DataModule(config.data) - - if mode == "fit": - trainer.fit( - training_module, datamodule=data_module, ckpt_path=resume_ckpt_path - ) - elif mode == "test": - trainer.test(training_module, datamodule=data_module, verbose=False) - - -def entrypoint() -> None: - """Entry point for the CLI.""" - app.run(main) - - -if __name__ == "__main__": - entrypoint() diff --git a/vis4d/pl/trainer.py b/vis4d/pl/trainer.py deleted file mode 100644 index 831f3542..00000000 --- a/vis4d/pl/trainer.py +++ /dev/null @@ -1,139 +0,0 @@ -"""Trainer for PyTorch Lightning.""" - -from __future__ import annotations - -import datetime -import os.path as osp - -from lightning.pytorch import Callback, Trainer -from lightning.pytorch.callbacks import LearningRateMonitor, ModelCheckpoint -from lightning.pytorch.loggers import Logger, TensorBoardLogger -from lightning.pytorch.loggers.wandb import WandbLogger -from lightning.pytorch.strategies.ddp import DDPStrategy - -from vis4d.common import ArgsType -from vis4d.common.imports import TENSORBOARD_AVAILABLE -from vis4d.common.logging import rank_zero_info - - -class PLTrainer(Trainer): - """Trainer for PyTorch Lightning.""" - - def __init__( - self, - *args: ArgsType, - work_dir: str, - exp_name: str, - version: str, - epoch_based: bool = True, - find_unused_parameters: bool = False, - save_top_k: int = 1, - checkpoint_period: int = 1, - checkpoint_callback: ModelCheckpoint | None = None, - wandb: bool = False, - seed: int = -1, - timeout: int = 3600, - wandb_id: str | None = None, - **kwargs: ArgsType, - ) -> None: - """Perform some basic common setups at the beginning of a job. - - Args: - work_dir: Specific directory to save checkpoints, logs, etc. - Integrates with exp_name and version to get output_dir. - exp_name: Name of current experiment. - version: Version of current experiment. - epoch_based: Use epoch-based / iteration-based training. Default is - True. - find_unused_parameters: Activates PyTorch checking for unused - parameters in DDP setting. Default: False, for better - performance. - save_top_k: Save top k checkpoints. Default: 1 (save last). - checkpoint_period: After N epochs / stpes, save out checkpoints. - Default: 1. - checkpoint_callback: Custom PL checkpoint callback. Default: None. - wandb: Use weights and biases logging instead of tensorboard. - Default: False. - seed (int, optional): The integer value seed for global random - state. Defaults to -1. If -1, a random seed will be generated. - This will be set by TrainingModule. - timeout: Timeout (seconds) for DDP connection. Default: 3600. - """ - self.work_dir = work_dir - self.exp_name = exp_name - self.version = version - self.seed = seed - - self.output_dir = osp.join(work_dir, exp_name, version) - - # setup experiment logging - if "logger" not in kwargs or ( - isinstance(kwargs["logger"], bool) and kwargs["logger"] - ): - exp_logger: Logger | None = None - if wandb: # pragma: no cover - exp_logger = WandbLogger( - save_dir=work_dir, - project=exp_name, - name=version, - id=wandb_id, - ) - elif TENSORBOARD_AVAILABLE: - exp_logger = TensorBoardLogger( - save_dir=work_dir, - name=exp_name, - version=version, - default_hp_metric=False, - ) - else: - rank_zero_info( - "Neither `tensorboard` nor `tensorboardX` is " - "available. Running without experiment logger. To log " - "your experiments, try `pip install`ing either." - ) - kwargs["logger"] = exp_logger - - callbacks: list[Callback] = [] - - # add learning rate / GPU stats monitor (logs to tensorboard) - if TENSORBOARD_AVAILABLE or wandb: - callbacks += [LearningRateMonitor(logging_interval="step")] - - # Model checkpointer - if checkpoint_callback is None: - if epoch_based: - checkpoint_cb = ModelCheckpoint( - dirpath=osp.join(self.output_dir, "checkpoints"), - verbose=True, - save_last=True, - save_top_k=save_top_k, - every_n_epochs=checkpoint_period, - save_on_train_epoch_end=True, - ) - else: - checkpoint_cb = ModelCheckpoint( - dirpath=osp.join(self.output_dir, "checkpoints"), - verbose=True, - save_last=True, - save_top_k=save_top_k, - every_n_train_steps=checkpoint_period, - ) - else: - checkpoint_cb = checkpoint_callback - callbacks += [checkpoint_cb] - - kwargs["callbacks"] += callbacks - - # add distributed strategy - if kwargs["devices"] == 0: - kwargs["accelerator"] = "cpu" - kwargs["devices"] = "auto" - elif kwargs["devices"] > 1: # pragma: no cover - if kwargs["accelerator"] == "gpu": - ddp_plugin = DDPStrategy( - find_unused_parameters=find_unused_parameters, - timeout=datetime.timedelta(timeout), - ) - kwargs["strategy"] = ddp_plugin - - super().__init__(*args, **kwargs) From 56dbf05841089a343de7e5f03e3e822801085cc0 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Mon, 21 Jul 2025 18:46:50 +0200 Subject: [PATCH 41/50] feat: Refactor Callbacks. --- requirements/install.txt | 2 +- vis4d/engine/callbacks/__init__.py | 6 +- vis4d/engine/callbacks/base.py | 122 +-------- vis4d/engine/callbacks/callback_wrapper.py | 232 ------------------ vis4d/engine/callbacks/checkpoint.py | 106 -------- vis4d/engine/callbacks/ema.py | 22 +- vis4d/engine/callbacks/evaluator.py | 79 ++++-- vis4d/engine/callbacks/logging.py | 127 ++++++---- vis4d/engine/callbacks/scheduler.py | 4 +- vis4d/engine/callbacks/trainer_state.py | 45 ---- vis4d/engine/callbacks/util.py | 25 ++ vis4d/engine/callbacks/visualizer.py | 115 +++++---- vis4d/engine/callbacks/yolox_callbacks.py | 83 +++---- vis4d/engine/run.py | 34 +-- vis4d/vis/image/bbox3d_visualizer.py | 6 + vis4d/vis/image/bev_visualizer.py | 4 + vis4d/zoo/base/runtime.py | 12 +- .../cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py | 4 +- vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py | 6 +- 19 files changed, 317 insertions(+), 717 deletions(-) delete mode 100644 vis4d/engine/callbacks/callback_wrapper.py delete mode 100644 vis4d/engine/callbacks/checkpoint.py delete mode 100644 vis4d/engine/callbacks/trainer_state.py create mode 100644 vis4d/engine/callbacks/util.py diff --git a/requirements/install.txt b/requirements/install.txt index 8f47770e..5bcee794 100644 --- a/requirements/install.txt +++ b/requirements/install.txt @@ -6,7 +6,7 @@ devtools h5py jsonargparse[signatures] lightning -ml_collections==0.1.1 # Config interface. Need exact version since we overwrite internal functions +ml_collections==1.1.0 # Config interface. Need exact version since we overwrite internal functions numpy>=1.21.0,<2.0.0 opencv-python pandas diff --git a/vis4d/engine/callbacks/__init__.py b/vis4d/engine/callbacks/__init__.py index 9cfea9a6..e7670237 100644 --- a/vis4d/engine/callbacks/__init__.py +++ b/vis4d/engine/callbacks/__init__.py @@ -1,26 +1,24 @@ """Callback modules.""" from .base import Callback -from .checkpoint import CheckpointCallback from .ema import EMACallback from .evaluator import EvaluatorCallback from .logging import LoggingCallback -from .trainer_state import TrainerState from .visualizer import VisualizerCallback from .yolox_callbacks import ( YOLOXModeSwitchCallback, YOLOXSyncNormCallback, YOLOXSyncRandomResizeCallback, ) +from .scheduler import LRSchedulerCallback __all__ = [ "Callback", - "CheckpointCallback", "EMACallback", "EvaluatorCallback", "LoggingCallback", - "TrainerState", "VisualizerCallback", + "LRSchedulerCallback", "YOLOXModeSwitchCallback", "YOLOXSyncNormCallback", "YOLOXSyncRandomResizeCallback", diff --git a/vis4d/engine/callbacks/base.py b/vis4d/engine/callbacks/base.py index 67e3ae1d..3938fdd3 100644 --- a/vis4d/engine/callbacks/base.py +++ b/vis4d/engine/callbacks/base.py @@ -2,17 +2,16 @@ from __future__ import annotations -from torch import Tensor, nn +from torch import Tensor -from vis4d.common.typing import DictStrArrNested, MetricLogs +import lightning.pytorch as pl + +from vis4d.common.typing import DictStrArrNested from vis4d.data.typing import DictData from vis4d.engine.connectors import CallbackConnector -from vis4d.engine.loss_module import LossModule - -from .trainer_state import TrainerState -class Callback: +class Callback(pl.Callback): """Base class for Callbacks.""" def __init__( @@ -37,7 +36,9 @@ def __init__( self.train_connector = train_connector self.test_connector = test_connector - def setup(self) -> None: + def setup( + self, trainer: pl.Trainer, pl_module: pl.LightningModule, stage: str + ) -> None: """Setup callback.""" def get_train_callback_inputs( @@ -83,110 +84,3 @@ def get_test_callback_inputs( assert self.test_connector is not None, "Test connector is None." return self.test_connector(outputs, batch) - - def on_train_batch_start( - self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - batch: DictData, - batch_idx: int, - ) -> None: - """Hook to run at the start of a training batch. - - Args: - trainer_state (TrainerState): Trainer state. - model: Model that is being trained. - loss_module (LossModule): Loss module. - batch (DictData): Dataloader output data batch. - batch_idx (int): Index of the batch. - """ - - def on_train_epoch_start( - self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - ) -> None: - """Hook to run at the beginning of a training epoch. - - Args: - trainer_state (TrainerState): Trainer state. - model (nn.Module): Model that is being trained. - loss_module (LossModule): Loss module. - """ - - def on_train_batch_end( - self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - outputs: DictData, - batch: DictData, - batch_idx: int, - ) -> None | MetricLogs: - """Hook to run at the end of a training batch. - - Args: - trainer_state (TrainerState): Trainer state. - model: Model that is being trained. - loss_module (LossModule): Loss module. - outputs (DictData): Model prediction output. - batch (DictData): Dataloader output data batch. - batch_idx (int): Index of the batch. - """ - - def on_train_epoch_end( - self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - ) -> None: - """Hook to run at the end of a training epoch. - - Args: - trainer_state (TrainerState): Trainer state. - model (nn.Module): Model that is being trained. - loss_module (LossModule): Loss module. - """ - - def on_test_epoch_start( - self, trainer_state: TrainerState, model: nn.Module - ) -> None: - """Hook to run at the beginning of a testing epoch. - - Args: - trainer_state (TrainerState): Trainer state. - model (nn.Module): Model that is being trained. - """ - - def on_test_batch_end( - self, - trainer_state: TrainerState, - model: nn.Module, - outputs: DictData, - batch: DictData, - batch_idx: int, - dataloader_idx: int = 0, - ) -> None: - """Hook to run at the end of a testing batch. - - Args: - trainer_state (TrainerState): Trainer state. - model: Model that is being trained. - outputs (DictData): Model prediction output. - batch (DictData): Dataloader output data batch. - batch_idx (int): Index of the batch. - dataloader_idx (int, optional): Index of the dataloader. Defaults - to 0. - """ - - def on_test_epoch_end( - self, trainer_state: TrainerState, model: nn.Module - ) -> None | MetricLogs: - """Hook to run at the end of a testing epoch. - - Args: - trainer_state (TrainerState): Trainer state. - model (nn.Module): Model that is being trained. - """ diff --git a/vis4d/engine/callbacks/callback_wrapper.py b/vis4d/engine/callbacks/callback_wrapper.py deleted file mode 100644 index 1aa5e064..00000000 --- a/vis4d/engine/callbacks/callback_wrapper.py +++ /dev/null @@ -1,232 +0,0 @@ -"""Wrapper to connect PyTorch Lightning callbacks.""" - -from __future__ import annotations - -from typing import Any - -import lightning.pytorch as pl -from torch import nn - -from vis4d.engine.callbacks import Callback, TrainerState -from vis4d.engine.loss_module import LossModule -from vis4d.pl.training_module import TrainingModule - - -def get_trainer_state( - trainer: pl.Trainer, pl_module: pl.LightningModule, val: bool = False -) -> TrainerState: - """Wrap pl.Trainer and pl.LightningModule into Trainer.""" - # Resolve float("inf") to -1 - if val: - test_dataloader = trainer.val_dataloaders - num_test_batches = [ - num_batch if isinstance(num_batch, int) else -1 - for num_batch in trainer.num_val_batches - ] - else: - test_dataloader = trainer.test_dataloaders - num_test_batches = [ - num_batch if isinstance(num_batch, int) else -1 - for num_batch in trainer.num_test_batches - ] - - # Map max_epochs=None to -1 - if trainer.max_epochs is None: - num_epochs = -1 - else: - num_epochs = trainer.max_epochs - - # Resolve float("inf") to -1 - if isinstance(trainer.num_training_batches, float): - num_train_batches = -1 - else: - num_train_batches = trainer.num_training_batches - - return TrainerState( - current_epoch=pl_module.current_epoch, - num_epochs=num_epochs, - global_step=trainer.global_step, - num_steps=trainer.max_steps, - train_dataloader=trainer.train_dataloader, - num_train_batches=num_train_batches, - test_dataloader=test_dataloader, - num_test_batches=num_test_batches, - train_module=trainer, - train_engine="pl", - ) - - -def get_model(model: pl.LightningModule) -> nn.Module: - """Get model from pl module.""" - if isinstance(model, TrainingModule): - return model.model - return model - - -def get_loss_module(loss_module: pl.LightningModule) -> LossModule: - """Get loss_module from pl module.""" - if isinstance(loss_module, TrainingModule): - assert loss_module.loss_module is not None - return loss_module.loss_module - return loss_module # type: ignore - - -class CallbackWrapper(pl.Callback): - """Wrapper to connect vis4d callbacks to pytorch lightning callbacks.""" - - def __init__(self, callback: Callback) -> None: - """Init class.""" - self.callback = callback - - def setup( - self, trainer: pl.Trainer, pl_module: pl.LightningModule, stage: str - ) -> None: - """Setup callback.""" - self.callback.setup() - - def on_train_batch_start( # type: ignore - self, - trainer: pl.Trainer, - pl_module: pl.LightningModule, - batch: Any, - batch_idx: int, - ) -> None: - """Called when the train batch begins.""" - trainer_state = get_trainer_state(trainer, pl_module) - - self.callback.on_train_batch_start( - trainer_state=trainer_state, - model=get_model(pl_module), - loss_module=get_loss_module(pl_module), - batch=batch, - batch_idx=batch_idx, - ) - - def on_train_epoch_start( - self, trainer: pl.Trainer, pl_module: pl.LightningModule - ) -> None: - """Hook to run at the start of a training epoch.""" - self.callback.on_train_epoch_start( - get_trainer_state(trainer, pl_module), - get_model(pl_module), - get_loss_module(pl_module), - ) - - def on_train_batch_end( # type: ignore - self, - trainer: pl.Trainer, - pl_module: pl.LightningModule, - outputs: Any, - batch: Any, - batch_idx: int, - ) -> None: - """Hook to run at the end of a training batch.""" - trainer_state = get_trainer_state(trainer, pl_module) - trainer_state["metrics"] = outputs["metrics"] - - log_dict = self.callback.on_train_batch_end( - trainer_state=trainer_state, - model=get_model(pl_module), - loss_module=get_loss_module(pl_module), - outputs=outputs["predictions"], - batch=batch, - batch_idx=batch_idx, - ) - - if log_dict is not None: - for k, v in log_dict.items(): - pl_module.log(f"train/{k}", v, rank_zero_only=True) - - def on_train_epoch_end( - self, trainer: pl.Trainer, pl_module: pl.LightningModule - ) -> None: - """Hook to run at the end of a training epoch.""" - self.callback.on_train_epoch_end( - get_trainer_state(trainer, pl_module), - get_model(pl_module), - get_loss_module(pl_module), - ) - - def on_validation_epoch_start( - self, trainer: pl.Trainer, pl_module: pl.LightningModule - ) -> None: - """Hook to run at the start of a validation epoch.""" - self.callback.on_test_epoch_start( - get_trainer_state(trainer, pl_module, val=True), - get_model(pl_module), - ) - - def on_validation_batch_end( # type: ignore - self, - trainer: pl.Trainer, - pl_module: pl.LightningModule, - outputs: Any, - batch: Any, - batch_idx: int, - dataloader_idx: int = 0, - ) -> None: - """Wait for on_validation_batch_end PL hook to call 'process'.""" - self.callback.on_test_batch_end( - trainer_state=get_trainer_state(trainer, pl_module, val=True), - model=get_model(pl_module), - outputs=outputs, - batch=batch, - batch_idx=batch_idx, - dataloader_idx=dataloader_idx, - ) - - def on_validation_epoch_end( - self, trainer: pl.Trainer, pl_module: pl.LightningModule - ) -> None: - """Wait for on_validation_epoch_end PL hook to call 'evaluate'.""" - log_dict = self.callback.on_test_epoch_end( - get_trainer_state(trainer, pl_module, val=True), - get_model(pl_module), - ) - - if log_dict is not None: - for k, v in log_dict.items(): - pl_module.log( - f"val/{k}", v, sync_dist=True, rank_zero_only=True - ) - - def on_test_epoch_start( - self, trainer: pl.Trainer, pl_module: pl.LightningModule - ) -> None: - """Hook to run at the start of a testing epoch.""" - self.callback.on_test_epoch_start( - get_trainer_state(trainer, pl_module), get_model(pl_module) - ) - - def on_test_batch_end( # type: ignore - self, - trainer: pl.Trainer, - pl_module: pl.LightningModule, - outputs: Any, - batch: Any, - batch_idx: int, - dataloader_idx: int = 0, - ) -> None: - """Wait for on_test_batch_end PL hook to call 'process'.""" - self.callback.on_test_batch_end( - trainer_state=get_trainer_state(trainer, pl_module), - model=get_model(pl_module), - outputs=outputs, - batch=batch, - batch_idx=batch_idx, - dataloader_idx=dataloader_idx, - ) - - def on_test_epoch_end( - self, trainer: pl.Trainer, pl_module: pl.LightningModule - ) -> None: - """Wait for on_test_epoch_end PL hook to call 'evaluate'.""" - log_dict = self.callback.on_test_epoch_end( - get_trainer_state(trainer, pl_module), get_model(pl_module) - ) - - if log_dict is not None: - for k, v in log_dict.items(): - pl_module.log( - f"test/{k}", v, sync_dist=True, rank_zero_only=True - ) diff --git a/vis4d/engine/callbacks/checkpoint.py b/vis4d/engine/callbacks/checkpoint.py deleted file mode 100644 index 9d31ce1f..00000000 --- a/vis4d/engine/callbacks/checkpoint.py +++ /dev/null @@ -1,106 +0,0 @@ -"""This module contains utilities for callbacks.""" - -from __future__ import annotations - -import os - -import torch -from torch import nn - -from vis4d.common import ArgsType -from vis4d.common.distributed import broadcast, rank_zero_only -from vis4d.data.typing import DictData -from vis4d.engine.callbacks.trainer_state import TrainerState -from vis4d.engine.loss_module import LossModule - -from .base import Callback -from .trainer_state import TrainerState - - -class CheckpointCallback(Callback): - """Callback for model checkpointing.""" - - def __init__( - self, - *args: ArgsType, - save_prefix: str, - checkpoint_period: int = 1, - **kwargs: ArgsType, - ) -> None: - """Init callback. - - Args: - save_prefix (str): Prefix of checkpoint path for saving. - checkpoint_period (int, optional): Checkpoint period. Defaults to - 1. - """ - super().__init__(*args, **kwargs) - self.output_dir = f"{save_prefix}/checkpoints" - self.checkpoint_period = checkpoint_period - - def setup(self) -> None: # pragma: no cover - """Setup callback.""" - self.output_dir = broadcast(self.output_dir) - os.makedirs(self.output_dir, exist_ok=True) - - @rank_zero_only - def _save_checkpoint( - self, trainer_state: TrainerState, model: nn.Module - ) -> None: - """Save checkpoint.""" - epoch = trainer_state["current_epoch"] - step = trainer_state["global_step"] - ckpt_dict = { - "epoch": epoch, - "global_step": step, - "state_dict": model.state_dict(), - } - - if "optimizers" in trainer_state: - ckpt_dict["optimizers"] = [ - optimizer.state_dict() - for optimizer in trainer_state["optimizers"] - ] - - if "lr_schedulers" in trainer_state: - ckpt_dict["lr_schedulers"] = [ - lr_scheduler.state_dict() - for lr_scheduler in trainer_state["lr_schedulers"] - ] - - torch.save( - ckpt_dict, - f"{self.output_dir}/epoch={epoch}-step={step}.ckpt", - ) - - torch.save(ckpt_dict, f"{self.output_dir}/last.ckpt") - - def on_train_batch_end( - self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - outputs: DictData, - batch: DictData, - batch_idx: int, - ) -> None: - """Hook to run at the end of a training batch.""" - if ( - not self.epoch_based - and trainer_state["global_step"] % self.checkpoint_period == 0 - ): - self._save_checkpoint(trainer_state, model) - - def on_train_epoch_end( - self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - ) -> None: - """Hook to run at the end of a training epoch.""" - if ( - self.epoch_based - and (trainer_state["current_epoch"] + 1) % self.checkpoint_period - == 0 - ): - self._save_checkpoint(trainer_state, model) diff --git a/vis4d/engine/callbacks/ema.py b/vis4d/engine/callbacks/ema.py index f876d14c..d02830c8 100644 --- a/vis4d/engine/callbacks/ema.py +++ b/vis4d/engine/callbacks/ema.py @@ -2,38 +2,38 @@ from __future__ import annotations -from torch import nn +import lightning.pytorch as pl from vis4d.common.distributed import is_module_wrapper -from vis4d.common.typing import MetricLogs from vis4d.data.typing import DictData -from vis4d.engine.loss_module import LossModule from vis4d.model.adapter import ModelEMAAdapter from .base import Callback -from .trainer_state import TrainerState +from .util import get_model class EMACallback(Callback): """Callback for EMA.""" - def on_train_batch_end( # pylint: disable=useless-return + def on_train_batch_end( self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, + trainer: pl.Trainer, + pl_module: pl.LightningModule, outputs: DictData, batch: DictData, batch_idx: int, - ) -> None | MetricLogs: + ) -> None: """Hook to run at the end of a training batch.""" + model = get_model(pl_module) + if is_module_wrapper(model): module = model.module else: module = model + assert isinstance(module, ModelEMAAdapter), ( "Model should be wrapped with ModelEMAAdapter when using " "EMACallback." ) - module.update(trainer_state["global_step"]) - return None + + module.update(trainer.global_step) diff --git a/vis4d/engine/callbacks/evaluator.py b/vis4d/engine/callbacks/evaluator.py index 57cb123f..9c5e0c36 100644 --- a/vis4d/engine/callbacks/evaluator.py +++ b/vis4d/engine/callbacks/evaluator.py @@ -4,7 +4,9 @@ import os -from torch import nn +from typing import Any + +import lightning.pytorch as pl from vis4d.common import ArgsType, MetricLogs from vis4d.common.distributed import ( @@ -18,21 +20,10 @@ from vis4d.eval.base import Evaluator from .base import Callback -from .trainer_state import TrainerState class EvaluatorCallback(Callback): - """Callback for model evaluation. - - Args: - evaluator (Evaluator): Evaluator. - metrics_to_eval (list[str], Optional): Metrics to evaluate. If None, - all metrics in the evaluator will be evaluated. Defaults to None. - save_predictions (bool): If the predictions should be saved. Defaults - to False. - save_prefix (str, Optional): Output directory for saving the - evaluation results. Defaults to None. - """ + """Callback for model evaluation.""" def __init__( self, @@ -44,7 +35,20 @@ def __init__( output_dir: str | None = None, **kwargs: ArgsType, ) -> None: - """Init callback.""" + """Init callback. + + Args: + evaluator (Evaluator): Evaluator. + metrics_to_eval (list[str], Optional): Metrics to evaluate. If + None, all metrics in the evaluator will be evaluated. Defaults + to None. + save_predictions (bool): If the predictions should be saved. + Defaults to False. + save_prefix (str, Optional): Output directory for saving the + evaluation results. Defaults to None. + output_dir (str, Optional): Output directory for saving the + evaluation results. + """ super().__init__(*args, **kwargs) self.evaluator = evaluator self.save_predictions = save_predictions @@ -60,7 +64,9 @@ def __init__( self.output_dir = output_dir self.save_prefix = save_prefix - def setup(self) -> None: # pragma: no cover + def setup( + self, trainer: pl.Trainer, pl_module: pl.LightningModule, stage: str + ) -> None: # pragma: no cover """Setup callback.""" if self.save_predictions: self.output_dir = broadcast(self.output_dir) @@ -75,10 +81,38 @@ def setup(self) -> None: # pragma: no cover os.makedirs(output_dir, exist_ok=True) self.evaluator.reset() + def on_validation_batch_end( # type: ignore + self, + trainer: pl.Trainer, + pl_module: pl.LightningModule, + outputs: Any, + batch: Any, + batch_idx: int, + dataloader_idx: int = 0, + ) -> None: + """Hook to run at the end of a validation batch.""" + self.on_test_batch_end( + trainer=trainer, + pl_module=pl_module, + outputs=outputs, + batch=batch, + batch_idx=batch_idx, + dataloader_idx=dataloader_idx, + ) + + def on_validation_epoch_end( + self, trainer: pl.Trainer, pl_module: pl.LightningModule + ) -> None: + """Wait for on_validation_epoch_end PL hook to call 'evaluate'.""" + log_dict = self.run_eval(pl_module) + + for k, v in log_dict.items(): + pl_module.log(f"val/{k}", v, sync_dist=True, rank_zero_only=True) + def on_test_batch_end( self, - trainer_state: TrainerState, - model: nn.Module, + trainer: pl.Trainer, + pl_module: pl.LightningModule, outputs: DictData, batch: DictData, batch_idx: int, @@ -95,9 +129,16 @@ def on_test_batch_end( self.evaluator.save_batch(metric, output_dir) def on_test_epoch_end( - self, trainer_state: TrainerState, model: nn.Module - ) -> None | MetricLogs: + self, trainer: pl.Trainer, pl_module: pl.LightningModule + ) -> None: """Hook to run at the end of a testing epoch.""" + log_dict = self.run_eval(pl_module) + + for k, v in log_dict.items(): + pl_module.log(f"test/{k}", v, sync_dist=True, rank_zero_only=True) + + def run_eval(self, pl_module: pl.LightningModule) -> MetricLogs: + """Run evaluation for the given evaluator.""" self.evaluator.gather(all_gather_object_cpu) synchronize() diff --git a/vis4d/engine/callbacks/logging.py b/vis4d/engine/callbacks/logging.py index 5ce83b50..8cf62527 100644 --- a/vis4d/engine/callbacks/logging.py +++ b/vis4d/engine/callbacks/logging.py @@ -2,19 +2,17 @@ from __future__ import annotations -from collections import defaultdict +from typing import Any +import lightning.pytorch as pl -from torch import nn +from collections import defaultdict from vis4d.common import ArgsType, MetricLogs from vis4d.common.logging import rank_zero_info from vis4d.common.progress import compose_log_str from vis4d.common.time import Timer -from vis4d.data.typing import DictData -from vis4d.engine.loss_module import LossModule from .base import Callback -from .trainer_state import TrainerState class LoggingCallback(Callback): @@ -31,62 +29,57 @@ def __init__( self.test_timer = Timer() self.last_step = 0 - def on_train_batch_start( - self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - batch: DictData, - batch_idx: int, - ) -> None: - """Hook to run at the start of a training batch.""" - if not self.epoch_based and self.train_timer.paused: - self.train_timer.resume() - def on_train_epoch_start( - self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, + self, trainer: pl.Trainer, pl_module: pl.LightningModule ) -> None: """Hook to run at the start of a training epoch.""" if self.epoch_based: self.train_timer.reset() self.last_step = 0 self._metrics.clear() - elif trainer_state["global_step"] == 0: + elif trainer.global_step == 0: self.train_timer.reset() - def on_train_batch_end( + def on_train_batch_start( # type: ignore self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - outputs: DictData, - batch: DictData, + trainer: pl.Trainer, + pl_module: pl.LightningModule, + batch: Any, batch_idx: int, - ) -> None | MetricLogs: + ) -> None: + """Hook to run at the start of a training batch.""" + if self.train_timer.paused: + self.train_timer.resume() + + def on_train_batch_end( # type: ignore + self, + trainer: pl.Trainer, + pl_module: pl.LightningModule, + outputs: Any, + batch: Any, + batch_idx: int, + ) -> None: """Hook to run at the end of a training batch.""" - if "metrics" in trainer_state: - for k, v in trainer_state["metrics"].items(): + if "metrics" in outputs: + for k, v in outputs["metrics"].items(): self._metrics[k].append(v) if self.epoch_based: cur_iter = batch_idx + 1 - total_iters = ( - trainer_state["num_train_batches"] - if trainer_state["num_train_batches"] is not None - else -1 - ) + # Resolve float("inf") to -1 + if isinstance(trainer.num_training_batches, float): + total_iters = -1 + else: + total_iters = trainer.num_training_batches else: - cur_iter = trainer_state["global_step"] + 1 - total_iters = trainer_state["num_steps"] + cur_iter = trainer.global_step + 1 + total_iters = trainer.max_steps log_dict: None | MetricLogs = None if cur_iter % self._refresh_rate == 0 and cur_iter != self.last_step: prefix = ( - f"Epoch {trainer_state['current_epoch'] + 1}" + f"Epoch {pl_module.current_epoch + 1}" if self.epoch_based else "Iter" ) @@ -107,30 +100,62 @@ def on_train_batch_end( return log_dict + def on_validation_epoch_start( + self, trainer: pl.Trainer, pl_module: pl.LightningModule + ) -> None: + """Hook to run at the start of a validation epoch.""" + self.test_timer.reset() + self.train_timer.pause() + + def on_validation_batch_end( # type: ignore + self, + trainer: pl.Trainer, + pl_module: pl.LightningModule, + outputs: Any, + batch: Any, + batch_idx: int, + dataloader_idx: int = 0, + ) -> None: + """Wait for on_validation_batch_end PL hook to call 'process'.""" + cur_iter = batch_idx + 1 + + # Resolve float("inf") to -1 + if isinstance(trainer.num_val_batches[dataloader_idx], int): + total_iters = trainer.num_val_batches[dataloader_idx] + else: + total_iters = -1 + + if cur_iter % self._refresh_rate == 0: + rank_zero_info( + compose_log_str( + "Validation", cur_iter, total_iters, self.test_timer + ) + ) + def on_test_epoch_start( - self, trainer_state: TrainerState, model: nn.Module + self, trainer: pl.Trainer, pl_module: pl.LightningModule ) -> None: """Hook to run at the start of a testing epoch.""" self.test_timer.reset() - if not self.epoch_based: - self.train_timer.pause() + self.train_timer.pause() def on_test_batch_end( self, - trainer_state: TrainerState, - model: nn.Module, - outputs: DictData, - batch: DictData, + trainer: pl.Trainer, + pl_module: pl.LightningModule, + outputs: Any, + batch: Any, batch_idx: int, dataloader_idx: int = 0, ) -> None: """Hook to run at the end of a testing batch.""" cur_iter = batch_idx + 1 - total_iters = ( - trainer_state["num_test_batches"][dataloader_idx] - if trainer_state["num_test_batches"] is not None - else -1 - ) + + # Resolve float("inf") to -1 + if isinstance(trainer.num_test_batches[dataloader_idx], int): + total_iters = trainer.num_test_batches[dataloader_idx] + else: + total_iters = -1 if cur_iter % self._refresh_rate == 0: rank_zero_info( diff --git a/vis4d/engine/callbacks/scheduler.py b/vis4d/engine/callbacks/scheduler.py index ba197e78..5b90861b 100644 --- a/vis4d/engine/callbacks/scheduler.py +++ b/vis4d/engine/callbacks/scheduler.py @@ -9,8 +9,10 @@ from vis4d.engine.optim.scheduler import LRSchedulerWrapper +from .base import Callback -class LRSchedulerCallback(pl.Callback): + +class LRSchedulerCallback(Callback): """Callback to configure learning rate during training.""" def __init__(self) -> None: diff --git a/vis4d/engine/callbacks/trainer_state.py b/vis4d/engine/callbacks/trainer_state.py deleted file mode 100644 index 2c28c765..00000000 --- a/vis4d/engine/callbacks/trainer_state.py +++ /dev/null @@ -1,45 +0,0 @@ -"""Trainer state for callbacks.""" - -from __future__ import annotations - -from typing import TypedDict - -from torch.optim.optimizer import Optimizer -from torch.utils.data import DataLoader -from typing_extensions import NotRequired - -from vis4d.common import TrainingModule -from vis4d.data.typing import DictData -from vis4d.engine.optim import LRSchedulerWrapper - - -class TrainerState(TypedDict): - """State of the trainer. - - Attributes: - current_epoch (int): Current epoch. - num_epochs (int): Total number of the training epochs. - global_step (int): Global step. - num_steps (int): Total number of the training steps. - train_dataloader (DataLoader[DictData] | None): Training dataloader. - num_train_batches (int | None): Number of training batches. - test_dataloader (list[DataLoader[DictData]] | None): List of test - dataloaders. - num_test_batches (list[int] | None): List of number of test batches. - optimizers (NotRequired[list[Optimizer]]): List of optimizers. - metrics (NotRequired[dict[str, float]]): Metrics for the logging. - """ - - current_epoch: int - num_epochs: int - global_step: int - num_steps: int - train_dataloader: DataLoader[DictData] | None - num_train_batches: int | None - test_dataloader: list[DataLoader[DictData]] | None - num_test_batches: list[int] | None - optimizers: NotRequired[list[Optimizer]] - lr_schedulers: NotRequired[list[LRSchedulerWrapper]] - metrics: NotRequired[dict[str, float]] - train_module: NotRequired[TrainingModule] - train_engine: NotRequired[str] diff --git a/vis4d/engine/callbacks/util.py b/vis4d/engine/callbacks/util.py new file mode 100644 index 00000000..8408b863 --- /dev/null +++ b/vis4d/engine/callbacks/util.py @@ -0,0 +1,25 @@ +"""PyTorch Lightning callbacks utilities.""" + +from __future__ import annotations + + +import lightning.pytorch as pl +from torch import nn + +from vis4d.engine.loss_module import LossModule +from vis4d.engine.training_module import TrainingModule + + +def get_model(model: pl.LightningModule) -> nn.Module: + """Get model from pl module.""" + if isinstance(model, TrainingModule): + return model.model + return model + + +def get_loss_module(loss_module: pl.LightningModule) -> LossModule: + """Get loss_module from pl module.""" + if isinstance(loss_module, TrainingModule): + assert loss_module.loss_module is not None + return loss_module.loss_module + return loss_module # type: ignore diff --git a/vis4d/engine/callbacks/visualizer.py b/vis4d/engine/callbacks/visualizer.py index 6a468d7a..9d290c4d 100644 --- a/vis4d/engine/callbacks/visualizer.py +++ b/vis4d/engine/callbacks/visualizer.py @@ -2,19 +2,18 @@ from __future__ import annotations +from typing import Any + import os +import lightning.pytorch as pl from lightning.pytorch.loggers import WandbLogger -from torch import nn from vis4d.common import ArgsType from vis4d.common.distributed import broadcast, get_rank, synchronize -from vis4d.data.typing import DictData -from vis4d.engine.loss_module import LossModule from vis4d.vis.base import Visualizer from .base import Callback -from .trainer_state import TrainerState class VisualizerCallback(Callback): @@ -62,18 +61,19 @@ def __init__( self.output_dir = output_dir self.save_prefix = save_prefix - def setup(self) -> None: # pragma: no cover + def setup( + self, trainer: pl.Trainer, pl_module: pl.LightningModule, stage: str + ) -> None: # pragma: no cover """Setup callback.""" if self.save_to_disk: self.output_dir = broadcast(self.output_dir) - def on_train_batch_end( + def on_train_batch_end( # type: ignore self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - outputs: DictData, - batch: DictData, + trainer: pl.Trainer, + pl_module: pl.LightningModule, + outputs: Any, + batch: Any, batch_idx: int, ) -> None: """Hook to run at the end of a training batch.""" @@ -89,28 +89,20 @@ def on_train_batch_end( self.visualizer.show(cur_iter=cur_iter) if self.save_to_disk: - output_folder = os.path.join(self.output_dir, "train") - if self.save_prefix is not None: - output_folder = os.path.join( - output_folder, self.save_prefix - ) - os.makedirs(output_folder, exist_ok=True) - self.visualizer.save_to_disk( - cur_iter=cur_iter, output_folder=output_folder - ) + self.save(trainer=trainer, cur_iter=cur_iter, stage="train") self.visualizer.reset() - def on_test_batch_end( + def on_validation_batch_end( # type: ignore self, - trainer_state: TrainerState, - model: nn.Module, - outputs: DictData, - batch: DictData, + trainer: pl.Trainer, + pl_module: pl.LightningModule, + outputs: Any, + batch: Any, batch_idx: int, dataloader_idx: int = 0, ) -> None: - """Hook to run at the end of a testing batch.""" + """Hook to run at the end of a validation batch.""" cur_iter = batch_idx + 1 self.visualizer.process( @@ -122,30 +114,53 @@ def on_test_batch_end( self.visualizer.show(cur_iter=cur_iter) if self.save_to_disk: - output_folder = os.path.join(self.output_dir, "test") - if self.save_prefix is not None: - output_folder = os.path.join(output_folder, self.save_prefix) - os.makedirs(output_folder, exist_ok=True) - image = self.visualizer.save_to_disk( - cur_iter=cur_iter, output_folder=output_folder - ) + self.save(trainer=trainer, cur_iter=cur_iter, stage="val") - assert ( - "train_engine" in trainer_state - ), "Trainer state must contain 'train_engine' key." - assert ( - "train_module" in trainer_state - ), "Trainer state must contain 'train_module' key." - if get_rank() == 0 and trainer_state["train_engine"] == "pl": - trainer = trainer_state["train_module"] - if ( - isinstance(trainer.logger, WandbLogger) - and image is not None - ): - trainer.logger.log_image( - key=f"{self.visualizer}/{cur_iter}", - images=[image], - ) - synchronize() + self.visualizer.reset() + + def on_test_batch_end( # type: ignore + self, + trainer: pl.Trainer, + pl_module: pl.LightningModule, + outputs: Any, + batch: Any, + batch_idx: int, + dataloader_idx: int = 0, + ) -> None: + """Hook to run at the end of a testing batch.""" + cur_iter = batch_idx + 1 + + self.visualizer.process( + cur_iter=cur_iter, + **self.get_test_callback_inputs(outputs, batch), + ) + + if self.show: + self.visualizer.show(cur_iter=cur_iter) + + if self.save_to_disk: + self.save(trainer=trainer, cur_iter=cur_iter, stage="test") self.visualizer.reset() + + def save(self, trainer: pl.Trainer, cur_iter: int, stage: str) -> None: + """Save the visualizer state.""" + output_folder = os.path.join(self.output_dir, stage) + + if self.save_prefix is not None: + output_folder = os.path.join(output_folder, self.save_prefix) + + os.makedirs(output_folder, exist_ok=True) + + image = self.visualizer.save_to_disk( + cur_iter=cur_iter, output_folder=output_folder + ) + + if get_rank() == 0: + if isinstance(trainer.logger, WandbLogger) and image is not None: + trainer.logger.log_image( + key=f"{self.visualizer}/{cur_iter}", + images=[image], + ) + + synchronize() diff --git a/vis4d/engine/callbacks/yolox_callbacks.py b/vis4d/engine/callbacks/yolox_callbacks.py index 55d9201b..38d29a55 100644 --- a/vis4d/engine/callbacks/yolox_callbacks.py +++ b/vis4d/engine/callbacks/yolox_callbacks.py @@ -5,8 +5,13 @@ import random from collections import OrderedDict +from typing import Any + import torch import torch.nn.functional as F + +import lightning.pytorch as pl + from torch import nn from torch.nn.modules.batchnorm import _NormBase from torch.utils.data import DataLoader @@ -22,13 +27,11 @@ from vis4d.common.logging import rank_zero_info, rank_zero_warn from vis4d.data.const import CommonKeys as K from vis4d.data.data_pipe import DataPipe -from vis4d.data.typing import DictDataOrList -from vis4d.engine.loss_module import LossModule from vis4d.op.detect.yolox import YOLOXHeadLoss from vis4d.op.loss.common import l1_loss from .base import Callback -from .trainer_state import TrainerState +from .util import get_loss_module, get_model class YOLOXModeSwitchCallback(Callback): @@ -47,19 +50,15 @@ def __init__( self.switched = False def on_train_epoch_end( - self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, + self, trainer: pl.Trainer, pl_module: pl.LightningModule ) -> None: """Hook to run at the end of a training epoch.""" - if ( - trainer_state["current_epoch"] < self.switch_epoch - 1 - or self.switched - ): + if pl_module.current_epoch < self.switch_epoch - 1 or self.switched: # TODO: Make work with resume. return + loss_module = get_loss_module(pl_module) + found_loss = False for loss in loss_module.losses: if isinstance(loss["loss"], YOLOXHeadLoss): @@ -77,7 +76,7 @@ def on_train_epoch_end( rank_zero_warn("YOLOXHeadLoss should be in LossModule.") # Set data pipeline to default DataPipe to skip strong augs. # Switch to checking validation every epoch. - dataloader = trainer_state["train_dataloader"] + dataloader = trainer.train_dataloader assert dataloader is not None new_dataloader = DataLoader( DataPipe(dataloader.dataset.datasets), # type: ignore @@ -88,25 +87,18 @@ def on_train_epoch_end( persistent_workers=dataloader.persistent_workers, pin_memory=dataloader.pin_memory, ) - train_module = trainer_state["train_module"] - train_module.check_val_every_n_epoch = 1 - if trainer_state["train_engine"] == "vis4d": - # Directly modify the train dataloader. - train_module.train_dataloader = new_dataloader - elif trainer_state["train_engine"] == "pl": - # Override train_dataloader method in PL datamodule. - # Set reload_dataloaders_every_n_epochs to 1 to use the new - # dataloader. - def train_dataloader() -> DataLoader: # type: ignore - """Return dataloader for training.""" - return new_dataloader - - train_module.datamodule.train_dataloader = train_dataloader - train_module.reload_dataloaders_every_n_epochs = self.switch_epoch - else: - raise ValueError( - f"Unsupported training engine {trainer_state['train_engine']}." - ) + + pl_module.check_val_every_n_epoch = 1 + + # Override train_dataloader method in PL datamodule. + # Set reload_dataloaders_every_n_epochs to 1 to use the new + # dataloader. + def train_dataloader() -> DataLoader: # type: ignore + """Return dataloader for training.""" + return new_dataloader + + pl_module.datamodule.train_dataloader = train_dataloader + pl_module.reload_dataloaders_every_n_epochs = self.switch_epoch self.switched = True @@ -129,7 +121,7 @@ class YOLOXSyncNormCallback(Callback): """Callback for syncing the norm states of YOLOX training.""" def on_test_epoch_start( - self, trainer_state: TrainerState, model: nn.Module + self, trainer: pl.Trainer, pl_module: pl.LightningModule ) -> None: """Hook to run at the beginning of a testing epoch. @@ -137,14 +129,14 @@ def on_test_epoch_start( trainer_state (TrainerState): Trainer state. model (nn.Module): Model that is being trained. """ - rank_zero_info("Synced norm states across all processes.") - if get_world_size() == 1: - return - norm_states = get_norm_states(model) - if len(norm_states) == 0: - return - norm_states = all_reduce_dict(norm_states, reduce_op="mean") - model.load_state_dict(norm_states, strict=False) + if get_world_size() > 1: + model = get_model(pl_module) + norm_states = get_norm_states(model) + + if len(norm_states) > 0: + rank_zero_info("Synced norm states across all processes.") + norm_states = all_reduce_dict(norm_states, reduce_op="mean") + model.load_state_dict(norm_states, strict=False) class YOLOXSyncRandomResizeCallback(Callback): @@ -173,18 +165,17 @@ def _get_random_shape(self, device: torch.device) -> tuple[int, int]: shape_tensor = broadcast(shape_tensor, 0) return (int(shape_tensor[0].item()), int(shape_tensor[1].item())) - def on_train_batch_start( + def on_train_batch_start( # type: ignore self, - trainer_state: TrainerState, - model: nn.Module, - loss_module: LossModule, - batch: DictDataOrList, + trainer: pl.Trainer, + pl_module: pl.LightningModule, + batch: Any, batch_idx: int, ) -> None: """Hook to run at the start of a training batch.""" if not isinstance(batch, list): batch = [batch] - if (trainer_state["global_step"] + 1) % self.interval == 0: + if (trainer.global_step + 1) % self.interval == 0: self.random_shape = self._get_random_shape( batch[0][K.images].device ) diff --git a/vis4d/engine/run.py b/vis4d/engine/run.py index f29b1ce4..bd8d6570 100644 --- a/vis4d/engine/run.py +++ b/vis4d/engine/run.py @@ -7,8 +7,6 @@ import torch from absl import app # pylint: disable=no-name-in-module -from lightning.fabric.utilities.exceptions import MisconfigurationException -from lightning.pytorch import Callback from torch.utils.collect_env import get_pretty_env_info from vis4d.common import ArgsType @@ -16,7 +14,11 @@ from vis4d.common.util import set_tf32 from vis4d.config import instantiate_classes from vis4d.config.typing import ExperimentConfig -from vis4d.engine.callbacks import CheckpointCallback, VisualizerCallback +from vis4d.engine.callbacks import ( + Callback, + VisualizerCallback, + LRSchedulerCallback, +) from vis4d.engine.flag import ( _CKPT, _CONFIG, @@ -26,7 +28,6 @@ _VIS, ) from vis4d.engine.parser import pprints_config -from vis4d.engine.callbacks import CallbackWrapper, LRSchedulerCallback from vis4d.engine.data_module import DataModule from vis4d.engine.trainer import PLTrainer from vis4d.engine.training_module import TrainingModule @@ -95,31 +96,20 @@ def main(argv: ArgsType) -> None: callbacks: list[Callback] = [] for cb in config.callbacks: callback = instantiate_classes(cb) - # Skip checkpoint callback to use PL ModelCheckpoint - if isinstance(callback, CheckpointCallback): - continue + + assert isinstance(callback, Callback), ( + "Callback must be a subclass of Callback. " + f"Provided callback: {cb} is not!" + ) if not vis and isinstance(callback, VisualizerCallback): rank_zero_info( - "VisualizerCallback is not used. " + f"{callback.visualizer} is not used." "Please set --vis=True to use it." ) continue - callbacks.append(CallbackWrapper(callback)) - - if "pl_callbacks" in config: - pl_callbacks = [instantiate_classes(cb) for cb in config.pl_callbacks] - else: - pl_callbacks = [] - - for cb in pl_callbacks: - if not isinstance(cb, Callback): - raise MisconfigurationException( - "Callback must be a subclass of pytorch_lightning Callback. " - f"Provided callback: {cb} is not!" - ) - callbacks.append(cb) + callbacks.append(callback) # Add needed callbacks callbacks.append(LRSchedulerCallback()) diff --git a/vis4d/vis/image/bbox3d_visualizer.py b/vis4d/vis/image/bbox3d_visualizer.py index e5e45717..634680a8 100644 --- a/vis4d/vis/image/bbox3d_visualizer.py +++ b/vis4d/vis/image/bbox3d_visualizer.py @@ -391,6 +391,10 @@ def __init__( self.cameras = cameras + def __repr__(self): + """Return string representation.""" + return "MultiCameraBBox3DVisualizer" + def process( # type: ignore # pylint: disable=arguments-differ self, cur_iter: int, @@ -403,6 +407,7 @@ def process( # type: ignore # pylint: disable=arguments-differ class_ids: list[ArrayLikeInt] | None = None, track_ids: list[ArrayLikeInt] | None = None, sequence_names: list[str] | None = None, + categories: None | list[list[str]] = None, ) -> None: """Processes a batch of data. @@ -446,5 +451,6 @@ class ids each of shape [B, N]. Defaults to None. if sequence_names is None else sequence_names[batch] ), + None if categories is None else categories[batch], self.cameras[idx], ) diff --git a/vis4d/vis/image/bev_visualizer.py b/vis4d/vis/image/bev_visualizer.py index 9ba2d4c7..3208206f 100644 --- a/vis4d/vis/image/bev_visualizer.py +++ b/vis4d/vis/image/bev_visualizer.py @@ -115,6 +115,10 @@ def __init__( self.canvas = canvas if canvas is not None else PillowCanvasBackend() self.viewer = viewer if viewer is not None else MatplotlibImageViewer() + def __repr__(self): + """Return string representation.""" + return "BEVBBox3DVisualizer" + def reset(self) -> None: """Reset visualizer.""" self._samples.clear() diff --git a/vis4d/zoo/base/runtime.py b/vis4d/zoo/base/runtime.py index 232952de..84034747 100644 --- a/vis4d/zoo/base/runtime.py +++ b/vis4d/zoo/base/runtime.py @@ -9,7 +9,7 @@ from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig -from vis4d.engine.callbacks import CheckpointCallback, LoggingCallback +from vis4d.engine.callbacks import LoggingCallback def get_default_cfg( @@ -95,14 +95,4 @@ def get_default_callbacks_cfg( ) ) - # Checkpoint - callbacks.append( - class_config( - CheckpointCallback, - epoch_based=epoch_based, - save_prefix=output_dir, - checkpoint_period=checkpoint_period, - ) - ) - return callbacks diff --git a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py index c850866e..0fc047db 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py @@ -168,7 +168,7 @@ def get_config() -> ExperimentConfig: split=test_split, ), save_predictions=True, - save_prefix=config.output_dir, + output_dir=config.output_dir, test_connector=class_config( CallbackConnector, key_mapping=CONN_NUSC_DET3D_EVAL ), @@ -180,7 +180,7 @@ def get_config() -> ExperimentConfig: EvaluatorCallback, evaluator=class_config(NuScenesTrack3DEvaluator), save_predictions=True, - save_prefix=config.output_dir, + output_dir=config.output_dir, test_connector=class_config( CallbackConnector, key_mapping=CONN_NUSC_TRACK3D_EVAL ), diff --git a/vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py b/vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py index af086411..ce7521eb 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py @@ -50,7 +50,8 @@ def get_config() -> ExperimentConfig: cameras=NuScenes.CAMERAS, vis_freq=1, ), - save_prefix=config.output_dir, + output_dir=config.output_dir, + save_prefix="boxes3d", test_connector=class_config( MultiSensorCallbackConnector, key_mapping=CONN_NUSC_BBOX_3D_VIS, @@ -62,7 +63,8 @@ def get_config() -> ExperimentConfig: class_config( VisualizerCallback, visualizer=class_config(BEVBBox3DVisualizer, width=2, vis_freq=1), - save_prefix=config.output_dir, + output_dir=config.output_dir, + save_prefix="bev", test_connector=class_config( MultiSensorCallbackConnector, key_mapping=CONN_NUSC_BEV_BBOX_3D_VIS, From cfbe0a7563a423a3f0daff21c3e9b4a1478dd5e2 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 22 Jul 2025 14:16:33 +0200 Subject: [PATCH 42/50] feat: lint. --- .github/workflows/deploy_doc.yml | 42 --- .pylintrc | 1 + docs/source/user_guide/faster_rcnn_example.py | 2 +- requirements/install.txt | 2 + tests/common/array_test.py | 10 +- tests/config/show_connection_test.py | 4 +- tests/config/sweep_test.py | 117 ------- tests/engine/callbacks/checkpoint_test.py | 51 --- tests/engine/callbacks/ema_test.py | 23 +- tests/engine/callbacks/evaluator_test.py | 29 +- tests/engine/callbacks/logging_test.py | 36 +- tests/engine/callbacks/visualizer_test.py | 28 +- tests/{pl => engine}/data_module_test.py | 2 +- tests/engine/trainer_test.py | 128 ++++--- tests/engine/util_test.py | 116 ------- tests/op/base/dla_test.py | 32 +- tests/pl/__init__.py | 1 - tests/pl/trainer_test.py | 134 -------- tests/zoo/util.py | 11 +- vis4d/common/__init__.py | 2 - vis4d/common/array.py | 126 +++---- vis4d/common/distributed.py | 67 +--- vis4d/common/typing.py | 25 +- vis4d/config/replicator.py | 324 ------------------ vis4d/data/const.py | 15 +- vis4d/data/datasets/coco.py | 2 +- vis4d/data/datasets/scalabel.py | 4 +- vis4d/data/loader.py | 19 +- vis4d/data/samplers.py | 31 +- vis4d/data/transforms/photometric.py | 4 +- vis4d/engine/callbacks/__init__.py | 2 +- vis4d/engine/callbacks/base.py | 3 +- vis4d/engine/callbacks/ema.py | 2 +- vis4d/engine/callbacks/evaluator.py | 9 +- vis4d/engine/callbacks/logging.py | 16 +- vis4d/engine/callbacks/scheduler.py | 1 + vis4d/engine/callbacks/util.py | 9 +- vis4d/engine/callbacks/visualizer.py | 29 +- vis4d/engine/callbacks/yolox_callbacks.py | 30 +- vis4d/engine/optim/scheduler.py | 14 +- vis4d/engine/run.py | 4 +- vis4d/engine/trainer.py | 2 + vis4d/engine/training_module.py | 20 +- vis4d/eval/base.py | 17 +- vis4d/eval/bdd100k/seg.py | 2 +- vis4d/eval/coco/detect.py | 72 ++-- vis4d/eval/common/binary.py | 2 +- vis4d/eval/common/depth.py | 2 +- vis4d/eval/common/flow.py | 2 +- vis4d/eval/common/seg.py | 4 +- vis4d/eval/nuscenes/detect3d.py | 2 +- vis4d/eval/nuscenes/track3d.py | 2 +- vis4d/eval/scalabel/base.py | 6 - vis4d/eval/scalabel/detect.py | 2 +- vis4d/eval/scalabel/track.py | 2 +- vis4d/eval/shift/multitask_writer.py | 2 +- vis4d/op/base/dla.py | 6 +- vis4d/op/base/pointnet.py | 4 +- vis4d/op/base/pointnetpp.py | 4 +- vis4d/op/detect3d/qd_3dt.py | 2 +- vis4d/op/fpp/fpn.py | 4 +- vis4d/op/layer/attention.py | 4 + vis4d/op/layer/ms_deform_attn.py | 2 +- vis4d/op/mask/util.py | 2 +- vis4d/vis/image/bbox3d_visualizer.py | 27 +- vis4d/vis/image/bev_visualizer.py | 8 +- vis4d/vis/image/bounding_box_visualizer.py | 19 +- vis4d/vis/image/canvas/base.py | 3 + vis4d/vis/image/functional.py | 26 +- vis4d/vis/image/seg_mask_visualizer.py | 2 +- vis4d/vis/image/util.py | 11 +- vis4d/vis/pointcloud/pointcloud_visualizer.py | 2 +- vis4d/vis/pointcloud/scene.py | 2 +- vis4d/zoo/base/dataloader.py | 2 + vis4d/zoo/base/datasets/shift/common.py | 2 +- vis4d/zoo/base/runtime.py | 7 +- .../faster_rcnn/faster_rcnn_r50_1x_bdd100k.py | 2 +- .../faster_rcnn/faster_rcnn_r50_3x_bdd100k.py | 2 +- .../mask_rcnn/mask_rcnn_r50_1x_bdd100k.py | 2 +- .../mask_rcnn/mask_rcnn_r50_3x_bdd100k.py | 2 +- .../mask_rcnn/mask_rcnn_r50_5x_bdd100k.py | 2 +- .../qdtrack_frcnn_r50_fpn_1x_bdd100k.py | 2 +- .../semantic_fpn_r101_80k_bdd100k.py | 6 +- .../semantic_fpn_r50_40k_bdd100k.py | 6 +- .../semantic_fpn_r50_80k_bdd100k.py | 6 +- vis4d/zoo/bevformer/bevformer_base.py | 2 +- vis4d/zoo/bevformer/bevformer_tiny.py | 2 +- vis4d/zoo/bevformer/bevformer_vis.py | 2 +- .../cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py | 2 +- .../cc_3dt_frcnn_r101_fpn_pure_det_nusc.py | 2 +- .../cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py | 2 +- vis4d/zoo/cc_3dt/cc_3dt_nusc_test.py | 2 +- vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py | 2 +- .../velo_lstm_bevformer_base_100e_nusc.py | 2 +- .../velo_lstm_frcnn_r101_fpn_100e_nusc.py | 2 +- vis4d/zoo/faster_rcnn/faster_rcnn_coco.py | 38 +- vis4d/zoo/fcn_resnet/fcn_resnet_coco.py | 6 +- vis4d/zoo/mask_rcnn/mask_rcnn_coco.py | 2 +- .../qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py | 2 +- .../qdtrack/qdtrack_yolox_x_25e_bdd100k.py | 2 +- vis4d/zoo/retinanet/retinanet_coco.py | 2 +- .../faster_rcnn/faster_rcnn_r50_12e_shift.py | 2 +- .../faster_rcnn/faster_rcnn_r50_36e_shift.py | 2 +- .../faster_rcnn_r50_6e_shift_all_domains.py | 2 +- .../mask_rcnn/mask_rcnn_r50_12e_shift.py | 2 +- .../mask_rcnn/mask_rcnn_r50_36e_shift.py | 2 +- .../mask_rcnn_r50_6e_shift_all_domains.py | 2 +- .../semantic_fpn_r50_160k_shift.py | 6 +- ...semantic_fpn_r50_160k_shift_all_domains.py | 6 +- .../semantic_fpn_r50_40k_shift.py | 6 +- .../semantic_fpn_r50_40k_shift_all_domains.py | 6 +- vis4d/zoo/util.py | 14 + vis4d/zoo/vit/vit_small_imagenet.py | 2 +- vis4d/zoo/vit/vit_tiny_imagenet.py | 2 +- vis4d/zoo/yolox/yolox_s_300e_coco.py | 2 +- vis4d/zoo/yolox/yolox_tiny_300e_coco.py | 2 +- 116 files changed, 492 insertions(+), 1453 deletions(-) delete mode 100644 .github/workflows/deploy_doc.yml delete mode 100644 tests/config/sweep_test.py delete mode 100644 tests/engine/callbacks/checkpoint_test.py rename tests/{pl => engine}/data_module_test.py (96%) delete mode 100644 tests/engine/util_test.py delete mode 100644 tests/pl/__init__.py delete mode 100644 tests/pl/trainer_test.py delete mode 100644 vis4d/config/replicator.py create mode 100644 vis4d/zoo/util.py diff --git a/.github/workflows/deploy_doc.yml b/.github/workflows/deploy_doc.yml deleted file mode 100644 index 2682ab32..00000000 --- a/.github/workflows/deploy_doc.yml +++ /dev/null @@ -1,42 +0,0 @@ -# This workflow will deploy the documentation in docs/ to http://docs.vis.xyz/4d/ - -name: deploy docs -on: - push: - branches: - - main - paths: - - "docs/**" - -jobs: - deploy: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.10 - uses: actions/setup-python@v1 - with: - python-version: '3.10' - - name: Install dependencies - run: | - eval `ssh-agent -s` - ssh-add - <<< '${{ secrets.CUDA_OPS_REPO_KEY }}' - python3 -m pip install --upgrade pip - bash ./scripts/install_cpu_dep_full.sh - python3 -m pip install -e . - python3 -m pip install --ignore-installed -r docs/requirements.txt - python3 -m pip freeze - - name: website build - run: | - cd docs - make html - - name: deploy website to AWS - uses: jakejarvis/s3-sync-action@master - with: - args: --acl public-read --follow-symlinks --exclude ".DS_Store" - env: - AWS_S3_BUCKET: docs.vis.xyz/4d - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - SOURCE_DIR: "docs/build/html/" diff --git a/.pylintrc b/.pylintrc index 35f4549f..2142ce8a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -411,6 +411,7 @@ max-spelling-suggestions=2 # Maximum number of arguments for function / method max-args=20 +max-positional-arguments=20 # Maximum number of locals for function / method body max-locals=100 diff --git a/docs/source/user_guide/faster_rcnn_example.py b/docs/source/user_guide/faster_rcnn_example.py index 4d5cab51..7703770c 100644 --- a/docs/source/user_guide/faster_rcnn_example.py +++ b/docs/source/user_guide/faster_rcnn_example.py @@ -137,7 +137,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir, refresh_rate=1) + callbacks = get_default_callbacks_cfg(refresh_rate=1) # Evaluator callbacks.append( diff --git a/requirements/install.txt b/requirements/install.txt index 5bcee794..09e8063a 100644 --- a/requirements/install.txt +++ b/requirements/install.txt @@ -24,6 +24,8 @@ torchvision>=0.15.1 tqdm utm wheel +scipy +scipy-stubs # packages for datasets bdd100k diff --git a/tests/common/array_test.py b/tests/common/array_test.py index d0db7cd1..953bfe5c 100644 --- a/tests/common/array_test.py +++ b/tests/common/array_test.py @@ -6,7 +6,7 @@ import numpy as np import torch -from vis4d.common.array import array_to_numpy, arrays_to_numpy +from vis4d.common.array import array_to_numpy class TestConvertToArray(unittest.TestCase): @@ -52,11 +52,3 @@ def test_dim_shaping(self) -> None: # And the right if we can not remove anything from the left anymore self.assertEqual(array_to_numpy(data.copy(), 2).shape, (2, 3)) - - def test_array_to_numpys_multiple(self) -> None: - """Test that multiple arrays are converted correctly.""" - out = arrays_to_numpy( - np.random.rand(2, 3), np.random.rand(1, 1, 2, 3), n_dims=3 - ) - for arr in out: - self.assertEqual(arr.shape, (1, 2, 3)) diff --git a/tests/config/show_connection_test.py b/tests/config/show_connection_test.py index 1011020f..079f9106 100644 --- a/tests/config/show_connection_test.py +++ b/tests/config/show_connection_test.py @@ -24,10 +24,10 @@ def test_show_frcnn(self) -> None: model = instantiate_classes(config.model) # Change the data root of evaluator callback to the test data - config.callbacks[3].init_args.evaluator.init_args.data_root = ( + config.callbacks[2].init_args.evaluator.init_args.data_root = ( "tests/vis4d-test-data/coco_test" ) - config.callbacks[3].init_args.evaluator.init_args.split = "train" + config.callbacks[2].init_args.evaluator.init_args.split = "train" callbacks = [instantiate_classes(cb) for cb in config.callbacks] diff --git a/tests/config/sweep_test.py b/tests/config/sweep_test.py deleted file mode 100644 index 681488ad..00000000 --- a/tests/config/sweep_test.py +++ /dev/null @@ -1,117 +0,0 @@ -"""Vis4d Sweep Config Tests.""" - -import unittest - -import numpy as np -from ml_collections import ConfigDict - -from vis4d.config.replicator import replicate_config -from vis4d.config.sweep import grid_search -from vis4d.config.typing import ExperimentConfig - - -class TestSweep(unittest.TestCase): - """Test for config sweeps.""" - - def test_one_param_sweep(self) -> None: - """Test if one param config sweep works.""" - expected = np.linspace(0.001, 0.01, 3) - - exp_names_expected = [f"test_lr_{lr:.3f}_" for lr in expected] - - sweep_config = grid_search("lr", list(expected)) - sweep_config.suffix = "lr_{lr:.3f}_" - config = ExperimentConfig() - config.lr = 0 - config.experiment_name = "test" - config.value_mode() - config_iter = replicate_config( - config, - method=sweep_config.method, - sampling_args=sweep_config.sampling_args, - fstring=sweep_config.get("suffix", ""), - ) - - lr_actual: list[float] = [] - exp_names: list[str] = [] - for c in config_iter: - lr_actual.append(c.lr) - exp_names.append(c.experiment_name) - lr_actual = np.array(lr_actual) # type: ignore - - self.assertTrue(np.allclose(expected, lr_actual)) - for pred, gt in zip(exp_names, exp_names_expected): - self.assertEqual(pred, gt) - - def test_one_nested_param_sweep(self) -> None: - """Test if one param config sweep works when it is nested.""" - expected = np.linspace(0.001, 0.01, 3) - - exp_names_expected = [f"test_lr_{lr:.3f}_" for lr in expected] - - sweep_config = grid_search("params.lr", list(expected)) - sweep_config.suffix = "lr_{params.lr:.3f}_" - config = ExperimentConfig() - config.params = ConfigDict() - config.params.lr = 0 - config.experiment_name = "test" - config.value_mode() - config_iter = replicate_config( - config, - method=sweep_config.method, - sampling_args=sweep_config.sampling_args, - fstring=sweep_config.get("suffix", ""), - ) - - lr_actual: list[float] = [] - exp_names: list[str] = [] - for c in config_iter: - lr_actual.append(c.params.lr) - exp_names.append(c.experiment_name) - lr_actual = np.array(lr_actual) # type: ignore - - self.assertTrue(np.allclose(expected, lr_actual)) - for pred, gt in zip(exp_names, exp_names_expected): - self.assertEqual(pred, gt) - - def test_two_param_sweeps(self) -> None: - """Test to sweep over two parameters (lr, bs).""" - learning_rates = np.linspace(0.001, 0.01, 3) - batch_sizes = [4, 8, 16] - - exp_names_expected = [] - lr_expected = [] - bs_expected = [] - for lr in learning_rates: - for bs in batch_sizes: - exp_names_expected.append(f"test_lr_{lr:.3f}_bs_{bs}_") - lr_expected.append(lr) - bs_expected.append(bs) - - sweep_config = grid_search( - ["lr", "bs"], [list(learning_rates), batch_sizes] - ) - sweep_config.suffix = "lr_{lr:.3f}_bs_{bs}_" - config = ExperimentConfig() - config.lr = 0 - config.experiment_name = "test" - config.value_mode() - config_iter = replicate_config( - config, - method=sweep_config.method, - sampling_args=sweep_config.sampling_args, - fstring=sweep_config.get("suffix", ""), - ) - - lr_actual: list[float] = [] - bs_actual: list[int] = [] - exp_names: list[str] = [] - for c in config_iter: - lr_actual.append(c.lr) - bs_actual.append(c.bs) - exp_names.append(c.experiment_name) - - self.assertTrue(np.allclose(lr_expected, lr_actual)) - self.assertTrue(np.allclose(bs_expected, bs_actual)) - for pred, gt in zip(exp_names, exp_names_expected): - self.assertEqual(pred, gt) diff --git a/tests/engine/callbacks/checkpoint_test.py b/tests/engine/callbacks/checkpoint_test.py deleted file mode 100644 index 0df0132c..00000000 --- a/tests/engine/callbacks/checkpoint_test.py +++ /dev/null @@ -1,51 +0,0 @@ -"""Test cases for checkpoint callback.""" - -import shutil -import tempfile -import unittest - -from torch.optim.sgd import SGD - -from tests.util import MOCKLOSS, MockModel -from vis4d.config import class_config -from vis4d.engine.callbacks import CheckpointCallback, TrainerState - -from ..optim.optimizer_test import get_optimizer - - -class TestCheckpointCallback(unittest.TestCase): - """Test cases for callback functions.""" - - def setUp(self) -> None: - """Creates a tmp directory and setup callback.""" - self.test_dir = tempfile.mkdtemp() - - self.callback = CheckpointCallback(save_prefix=self.test_dir) - - self.callback.setup() - - optimizers, lr_scheulders = get_optimizer( - MockModel(0), class_config(SGD, lr=0.01) - ) - - self.trainer_state = TrainerState( - current_epoch=0, - num_epochs=0, - global_step=0, - train_dataloader=None, - num_train_batches=None, - test_dataloader=None, - num_test_batches=None, - optimizers=optimizers, - lr_schedulers=lr_scheulders, - ) - - def tearDown(self) -> None: - """Removes the tmp directory after the test.""" - shutil.rmtree(self.test_dir) - - def test_on_train_epoch_end(self) -> None: - """Test on_train_epoch_end function.""" - self.callback.on_train_epoch_end( - self.trainer_state, MockModel(0), MOCKLOSS - ) diff --git a/tests/engine/callbacks/ema_test.py b/tests/engine/callbacks/ema_test.py index 2342b3f2..5553f1b7 100644 --- a/tests/engine/callbacks/ema_test.py +++ b/tests/engine/callbacks/ema_test.py @@ -2,10 +2,11 @@ import unittest +import lightning.pytorch as pl import torch -from tests.util import MOCKLOSS, MockModel -from vis4d.engine.callbacks import EMACallback, TrainerState +from tests.util import MockModel +from vis4d.engine.callbacks import EMACallback from vis4d.model.adapter import ModelEMAAdapter @@ -14,29 +15,21 @@ class TestEMACallback(unittest.TestCase): def setUp(self) -> None: """Setup callback.""" + self.trainer = pl.Trainer() + self.training_module = pl.LightningModule() + self.callback = EMACallback() - self.callback.setup() + self.callback.setup(self.trainer, self.training_module, stage="fit") self.model = ModelEMAAdapter(MockModel(0)) self.model.ema_model.linear.weight.fill_(0) self.model.ema_model.linear.bias.fill_(0) - self.trainer_state = TrainerState( - current_epoch=0, - num_epochs=0, - global_step=0, - train_dataloader=None, - num_train_batches=None, - test_dataloader=None, - num_test_batches=None, - ) - def test_ema_callback(self) -> None: """Test EMA callback function.""" self.callback.on_train_batch_end( - self.trainer_state, + self.trainer, self.model, - MOCKLOSS, outputs={}, batch={}, batch_idx=0, diff --git a/tests/engine/callbacks/evaluator_test.py b/tests/engine/callbacks/evaluator_test.py index 40dfbf45..54b6d7a0 100644 --- a/tests/engine/callbacks/evaluator_test.py +++ b/tests/engine/callbacks/evaluator_test.py @@ -4,11 +4,12 @@ import tempfile import unittest +import lightning.pytorch as pl import torch -from tests.util import MockModel, get_test_data +from tests.util import get_test_data from vis4d.data.const import CommonKeys as K -from vis4d.engine.callbacks import EvaluatorCallback, TrainerState +from vis4d.engine.callbacks import EvaluatorCallback from vis4d.engine.connectors import CallbackConnector from vis4d.eval.coco import COCODetectEvaluator from vis4d.zoo.base.datasets.coco import CONN_COCO_MASK_EVAL @@ -21,6 +22,9 @@ def setUp(self) -> None: """Creates a tmp directory and setup callback.""" self.test_dir = tempfile.mkdtemp() + self.trainer = pl.Trainer() + self.training_module = pl.LightningModule() + self.callback = EvaluatorCallback( evaluator=COCODetectEvaluator( data_root=get_test_data("coco_test"), split="train" @@ -31,17 +35,7 @@ def setUp(self) -> None: test_connector=CallbackConnector(CONN_COCO_MASK_EVAL), ) - self.callback.setup() - - self.trainer_state = TrainerState( - current_epoch=0, - num_epochs=0, - global_step=0, - train_dataloader=None, - num_train_batches=None, - test_dataloader=None, - num_test_batches=None, - ) + self.callback.setup(self.trainer, self.training_module, stage="test") def tearDown(self) -> None: """Removes the tmp directory after the test.""" @@ -50,8 +44,8 @@ def tearDown(self) -> None: def test_evaluator_callback(self) -> None: """Test evaluator callback function.""" self.callback.on_test_batch_end( - self.trainer_state, - MockModel(0), + self.trainer, + self.training_module, outputs={ "boxes": { "boxes": [torch.zeros((2, 4))], @@ -64,7 +58,4 @@ def test_evaluator_callback(self) -> None: batch_idx=0, ) - log_dict = self.callback.on_test_epoch_end( - self.trainer_state, MockModel(0) - ) - self.assertEqual(log_dict["Det/AP"], 0.0) + self.callback.on_test_epoch_end(self.trainer, self.training_module) diff --git a/tests/engine/callbacks/logging_test.py b/tests/engine/callbacks/logging_test.py index b60676b4..95a1c577 100644 --- a/tests/engine/callbacks/logging_test.py +++ b/tests/engine/callbacks/logging_test.py @@ -2,8 +2,9 @@ import unittest -from tests.util import MOCKLOSS, MockModel -from vis4d.engine.callbacks import LoggingCallback, TrainerState +import lightning.pytorch as pl + +from vis4d.engine.callbacks import LoggingCallback class TestLoggingCallback(unittest.TestCase): @@ -13,47 +14,32 @@ def setUp(self) -> None: """Setup callback.""" self.callback = LoggingCallback(refresh_rate=1) - self.trainer_state = TrainerState( - current_epoch=0, - num_epochs=0, - global_step=0, - num_steps=0, - train_dataloader=None, - num_train_batches=1, - test_dataloader=None, - num_test_batches=[1], - ) + self.trainer = pl.Trainer() + self.training_module = pl.LightningModule() def test_on_train_epoch_start(self) -> None: """Test on_train_epoch_start function.""" - self.callback.on_train_epoch_start( - self.trainer_state, MockModel(0), MOCKLOSS - ) + self.callback.on_train_epoch_start(self.trainer, self.training_module) def test_on_train_batch_end(self) -> None: """Test on_train_batch_end function.""" - self.trainer_state["metrics"] = {"loss1": 0, "loss2": 1} - self.callback.on_train_batch_end( - self.trainer_state, - MockModel(0), - MOCKLOSS, + self.trainer, + self.training_module, outputs={}, batch={}, batch_idx=0, ) - self.trainer_state.pop("metrics") - def test_on_test_epoch_start(self) -> None: """Test on_test_epoch_start function.""" - self.callback.on_test_epoch_start(self.trainer_state, MockModel(0)) + self.callback.on_test_epoch_start(self.trainer, self.training_module) def test_on_test_batch_end(self) -> None: """Test on_test_batch_end function.""" self.callback.on_test_batch_end( - self.trainer_state, - MockModel(0), + self.trainer, + self.training_module, outputs={}, batch={}, batch_idx=0, diff --git a/tests/engine/callbacks/visualizer_test.py b/tests/engine/callbacks/visualizer_test.py index 2a4f590e..3193cd9b 100644 --- a/tests/engine/callbacks/visualizer_test.py +++ b/tests/engine/callbacks/visualizer_test.py @@ -4,11 +4,11 @@ import tempfile import unittest +import lightning.pytorch as pl import torch -from tests.util import MOCKLOSS, MockModel from vis4d.data.const import CommonKeys as K -from vis4d.engine.callbacks import TrainerState, VisualizerCallback +from vis4d.engine.callbacks import VisualizerCallback from vis4d.engine.connectors import CallbackConnector from vis4d.vis.image import BoundingBoxVisualizer from vis4d.zoo.base.data_connectors import CONN_BBOX_2D_VIS @@ -21,6 +21,9 @@ def setUp(self) -> None: """Creates a tmp directory and setup callback.""" self.test_dir = tempfile.mkdtemp() + self.trainer = pl.Trainer() + self.training_module = pl.LightningModule() + self.callback = VisualizerCallback( visualizer=BoundingBoxVisualizer(), save_prefix=self.test_dir, @@ -28,17 +31,7 @@ def setUp(self) -> None: test_connector=CallbackConnector(CONN_BBOX_2D_VIS), ) - self.callback.setup() - - self.trainer_state = TrainerState( - current_epoch=0, - num_epochs=0, - global_step=0, - train_dataloader=None, - num_train_batches=None, - test_dataloader=None, - num_test_batches=None, - ) + self.callback.setup(self.trainer, self.training_module, stage="fit") def tearDown(self) -> None: """Removes the tmp directory after the test.""" @@ -47,9 +40,8 @@ def tearDown(self) -> None: def test_on_train_batch_end(self) -> None: """Test on_train_batch_end function.""" self.callback.on_train_batch_end( - self.trainer_state, - MockModel(0), - MOCKLOSS, + self.trainer, + self.training_module, outputs={ "boxes": [torch.zeros((0, 4))], "scores": [torch.zeros((0,))], @@ -65,8 +57,8 @@ def test_on_train_batch_end(self) -> None: def test_on_test_batch_end(self) -> None: """Test the visualizer callback.""" self.callback.on_test_batch_end( - self.trainer_state, - MockModel(0), + self.trainer, + self.training_module, outputs={ "boxes": [torch.zeros((0, 4))], "scores": [torch.zeros((0,))], diff --git a/tests/pl/data_module_test.py b/tests/engine/data_module_test.py similarity index 96% rename from tests/pl/data_module_test.py rename to tests/engine/data_module_test.py index c4ce4a02..381ed48f 100644 --- a/tests/pl/data_module_test.py +++ b/tests/engine/data_module_test.py @@ -7,7 +7,7 @@ from torch.utils.data.dataloader import DataLoader from tests.util import get_test_data -from vis4d.pl.data_module import DataModule +from vis4d.engine.data_module import DataModule from vis4d.zoo.base.datasets.coco import get_coco_detection_cfg diff --git a/tests/engine/trainer_test.py b/tests/engine/trainer_test.py index 5d56dd49..94434f81 100644 --- a/tests/engine/trainer_test.py +++ b/tests/engine/trainer_test.py @@ -1,4 +1,4 @@ -"""Engine trainer tests.""" +"""Pytorch lightning utilities for unit tests.""" from __future__ import annotations @@ -6,10 +6,11 @@ import tempfile import unittest -import torch +from ml_collections import ConfigDict +from torch.optim.sgd import SGD from torch.utils.data import DataLoader, Dataset -from tests.util import MockModel, get_test_data +from tests.util import get_test_data from vis4d.config import class_config from vis4d.data.const import CommonKeys as K from vis4d.data.datasets import COCO @@ -27,7 +28,7 @@ to_tensor, ) from vis4d.data.typing import DictData -from vis4d.engine.callbacks import LoggingCallback +from vis4d.engine.callbacks import LoggingCallback, LRSchedulerCallback from vis4d.engine.connectors import ( DataConnector, LossConnector, @@ -35,11 +36,11 @@ pred_key, ) from vis4d.engine.loss_module import LossModule -from vis4d.engine.trainer import Trainer +from vis4d.engine.trainer import PLTrainer +from vis4d.engine.training_module import TrainingModule from vis4d.model.seg.semantic_fpn import SemanticFPN from vis4d.op.loss import SegCrossEntropyLoss - -from .optim.optimizer_test import get_optimizer +from vis4d.zoo.base import get_optimizer_cfg def seg_pipeline(data: list[DictData]) -> DictData: @@ -84,73 +85,70 @@ def get_test_dataloader( ) -class EngineTrainerTest(unittest.TestCase): - """Engine trainer test class.""" +def get_training_module(model_cfg: ConfigDict): + """Build mockup training module. + + Args: + model_cfg (ConfigDict): Pytorch model + """ + train_data_connector = DataConnector(key_mapping={K.images: K.images}) + test_data_connector = DataConnector(key_mapping={K.images: K.images}) + loss_module = LossModule( + { + "loss": SegCrossEntropyLoss(), + "connector": LossConnector( + key_mapping={ + "output": pred_key("outputs"), + "target": data_key(K.seg_masks), + } + ), + } + ) + + optimizer_cfg = get_optimizer_cfg(class_config(SGD, lr=0.01)) + return TrainingModule( + model_cfg=model_cfg, + optimizers_cfg=[optimizer_cfg], + loss_module=loss_module, + train_data_connector=train_data_connector, + test_data_connector=test_data_connector, + seed=1, + ) + + +class PLTrainerTest(unittest.TestCase): + """Pytorch lightning trainer test class.""" def setUp(self) -> None: - """Set up test.""" + """Setup.""" self.test_dir = tempfile.mkdtemp() - dataset = COCO( - get_test_data("coco_test"), - keys_to_load=[ - K.images, - K.original_images, - K.boxes2d_classes, - K.instance_masks, - ], - split="train", - ) - train_dataloader = get_train_dataloader(dataset, 2) - test_dataloader = get_test_dataloader(dataset) - train_data_connector = DataConnector(key_mapping={"images": K.images}) - test_data_connector = DataConnector( - key_mapping={"images": K.images, "original_hw": K.original_hw} - ) + callbacks = [LRSchedulerCallback(), LoggingCallback()] - self.model = SemanticFPN(num_classes=80) - - self.trainer = Trainer( - device=torch.device("cpu"), - output_dir=self.test_dir, - num_epochs=2, - train_data_connector=train_data_connector, - test_data_connector=test_data_connector, - callbacks=[LoggingCallback(refresh_rate=1)], - train_dataloader=train_dataloader, - test_dataloader=test_dataloader, + self.trainer = PLTrainer( + work_dir=self.test_dir, + exp_name="test", + version="test", + callbacks=callbacks, + max_steps=2, + devices=0, + num_sanity_val_steps=0, ) - def tearDown(self) -> None: - """Tear down test.""" - shutil.rmtree(self.test_dir) - - def test_fit(self) -> None: - """Test trainer training.""" - optimizers, lr_scheulders = get_optimizer( - MockModel(0), class_config(torch.optim.SGD, lr=0.01) - ) - loss_module = LossModule( - { - "loss": SegCrossEntropyLoss(), - "connector": LossConnector( - key_mapping={ - "output": pred_key("outputs"), - "target": data_key(K.seg_masks), - } - ), - } + model_cfg = class_config( + SemanticFPN, + num_classes=80, ) - self.trainer.fit(self.model, optimizers, lr_scheulders, loss_module) + self.training_module = get_training_module(model_cfg=model_cfg) - # TODO: add callback to check loss - - def test_test(self) -> None: - """Test trainer testing.""" - state = torch.random.get_rng_state() - torch.random.set_rng_state(torch.manual_seed(0).get_state()) + def tearDown(self) -> None: + """Tear down.""" + shutil.rmtree(self.test_dir) - self.trainer.test(self.model) + def test_train(self) -> None: + """Test training.""" + dataset = COCO(get_test_data("coco_test"), split="train") + train_dataloader = get_train_dataloader(dataset, 2) - torch.random.set_rng_state(state) + self.trainer.fit(self.training_module, train_dataloader) diff --git a/tests/engine/util_test.py b/tests/engine/util_test.py deleted file mode 100644 index f5453fa6..00000000 --- a/tests/engine/util_test.py +++ /dev/null @@ -1,116 +0,0 @@ -"""Test engine util.""" - -from collections import namedtuple -from dataclasses import dataclass - -from vis4d.engine.util import apply_to_collection - - -@dataclass -class Test: - """Test dataclass.""" - - aaa: int - bbb: int - - -def test_apply_to_collection(): - """Test apply_to_collection.""" - data = {"a": 1, "b": 2, "c": 3} - data = apply_to_collection(data, int, lambda x: x * 2) - assert data == {"a": 2, "b": 4, "c": 6} - - data = {"a": 1, "b": 2, "c": 3} - data = apply_to_collection(data, (int, str), lambda x: x * 2) - assert data == {"a": 2, "b": 4, "c": 6} - - data = {"a": 1, "b": 2, "c": 3} - data = apply_to_collection(data, int, lambda x: x * 2, wrong_dtype=str) - assert data == {"a": 2, "b": 4, "c": 6} - - data = {"a": 1, "b": 2, "c": 3} - data = apply_to_collection( - data, int, lambda x: x * 2, wrong_dtype=str, include_none=False - ) - assert data == {"a": 2, "b": 4, "c": 6} - - data = {"a": 1, "b": 2, "c": 3} - data = apply_to_collection( - data, int, lambda x: x * 2, wrong_dtype=(str, int), include_none=False - ) - assert data == {"a": 1, "b": 2, "c": 3} - - data = {"a": 1, "b": 2, "c": 3} - data = apply_to_collection( - data, int, lambda x: x * 2, wrong_dtype=(str, int), include_none=True - ) - assert data == {"a": 1, "b": 2, "c": 3} - - # test with data as namedtuple or dataclass - data_cls = Test(1, 2) - data_cls = apply_to_collection(data_cls, int, lambda x: x * 2) - assert data_cls == Test(2, 4) - - data_cls = Test(1, 2) - data_cls = apply_to_collection(data_cls, (int, str), lambda x: x * 2) - assert data_cls == Test(2, 4) - - data_cls = Test(1, 2) - data_cls = apply_to_collection( - data_cls, int, lambda x: x * 2, wrong_dtype=str - ) - assert data_cls == Test(2, 4) - - data_cls = Test(1, 2) - data_cls = apply_to_collection( - data_cls, - int, - lambda x: x * 2, - wrong_dtype=(str, int), - include_none=False, - ) - assert data_cls == Test(1, 2) - - data_cls = Test(1, 2) - data_cls = apply_to_collection( - data_cls, - int, - lambda x: x * 2, - wrong_dtype=(str, int), - include_none=True, - ) - assert data_cls == Test(1, 2) - - data_tup = namedtuple("test", "aaa bbb")(1, 2) - data_tup = apply_to_collection(data_tup, int, lambda x: x * 2) - assert data_tup == namedtuple("test", "aaa bbb")(2, 4) - - data_tup = namedtuple("test", "aaa bbb")(1, 2) - data_tup = apply_to_collection(data_tup, (int, str), lambda x: x * 2) - assert data_tup == namedtuple("test", "aaa bbb")(2, 4) - - data_tup = namedtuple("test", "aaa bbb")(1, 2) - data_tup = apply_to_collection( - data_tup, int, lambda x: x * 2, wrong_dtype=str - ) - assert data_tup == namedtuple("test", "aaa bbb")(2, 4) - - data_tup = namedtuple("test", "aaa bbb")(1, 2) - data_tup = apply_to_collection( - data_tup, - int, - lambda x: x * 2, - wrong_dtype=(str, int), - include_none=False, - ) - assert data_tup == namedtuple("test", "aaa bbb")(1, 2) - - data_tup = namedtuple("test", "aaa bbb")(1, 2) - data_tup = apply_to_collection( - data_tup, - int, - lambda x: x * 2, - wrong_dtype=(str, int), - include_none=True, - ) - assert data_tup == namedtuple("test", "aaa bbb")(1, 2) diff --git a/tests/op/base/dla_test.py b/tests/op/base/dla_test.py index 2fc4b475..aeb2094f 100644 --- a/tests/op/base/dla_test.py +++ b/tests/op/base/dla_test.py @@ -13,11 +13,7 @@ class TestDLA(unittest.TestCase): def test_dla46_c(self) -> None: """Testcase for DLA46-C.""" - dla46_c = DLA( - name="dla46_c", - # weights= - # "http://dl.yf.io/dla/models/imagenet/dla46_c-2bfd52c3.pth", - ) + dla46_c = DLA(name="dla46_c") out = dla46_c(self.inputs) self.assertEqual(len(out), 6) channels = [16, 32, 64, 64, 128, 256] @@ -40,29 +36,3 @@ def test_dla46x_c(self) -> None: self.assertEqual(feat.shape[1], channels[i]) self.assertEqual(feat.shape[2], 32 / (2**i)) self.assertEqual(feat.shape[3], 32 / (2**i)) - - def test_dla_custom(self) -> None: - """Testcase for custom DLA.""" - dla_custom = DLA( - levels=(1, 1, 1, 2, 2, 1), - channels=(16, 32, 64, 128, 256, 512), - block="BasicBlock", - residual_root=True, - ) - out = dla_custom(self.inputs) - self.assertEqual(tuple(out[2].shape[2:]), (8, 8)) - dla_custom = DLA( - levels=(1, 1, 1, 2, 2, 1), - channels=(16, 32, 64, 128, 256, 512), - block="BasicBlock", - residual_root=False, - ) - out = dla_custom(self.inputs) - self.assertEqual(tuple(out[2].shape[2:]), (8, 8)) - out = dla_custom(self.inputs) - for i in range(6): - feat = out[i] - self.assertEqual(feat.shape[0], 2) - self.assertEqual(feat.shape[1], 16 * (2**i)) - self.assertEqual(feat.shape[2], 32 / (2**i)) - self.assertEqual(feat.shape[3], 32 / (2**i)) diff --git a/tests/pl/__init__.py b/tests/pl/__init__.py deleted file mode 100644 index c8e39e3d..00000000 --- a/tests/pl/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""PL Tests.""" diff --git a/tests/pl/trainer_test.py b/tests/pl/trainer_test.py deleted file mode 100644 index fb963a63..00000000 --- a/tests/pl/trainer_test.py +++ /dev/null @@ -1,134 +0,0 @@ -"""Pytorch lightning utilities for unit tests.""" - -from __future__ import annotations - -import shutil -import tempfile -import unittest - -from ml_collections import ConfigDict -from torch.optim.sgd import SGD -from torch.utils.data import DataLoader, Dataset - -from tests.util import get_test_data -from vis4d.config import class_config -from vis4d.data.const import CommonKeys as K -from vis4d.data.datasets import COCO -from vis4d.data.loader import DataPipe, build_train_dataloader -from vis4d.data.transforms import ( - compose, - mask, - normalize, - pad, - resize, - to_tensor, -) -from vis4d.data.typing import DictData -from vis4d.engine.callbacks import LoggingCallback -from vis4d.engine.connectors import ( - DataConnector, - LossConnector, - data_key, - pred_key, -) -from vis4d.engine.loss_module import LossModule -from vis4d.model.seg.semantic_fpn import SemanticFPN -from vis4d.op.loss import SegCrossEntropyLoss -from vis4d.pl.callbacks import CallbackWrapper, LRSchedulerCallback -from vis4d.pl.trainer import PLTrainer -from vis4d.pl.training_module import TrainingModule -from vis4d.zoo.base import get_optimizer_cfg - - -def seg_pipeline(data: list[DictData]) -> DictData: - """Default data pipeline.""" - return compose([pad.PadImages(value=255), to_tensor.ToTensor()])(data) - - -def get_train_dataloader(datasets: Dataset, batch_size: int) -> DataLoader: - """Get data loader for training.""" - preprocess_fn = compose( - [ - resize.GenResizeParameters((64, 64)), - resize.ResizeImages(), - resize.ResizeInstanceMasks(), - normalize.NormalizeImages(), - mask.ConvertInstanceMaskToSegMask(), - ] - ) - datapipe = DataPipe(datasets, preprocess_fn) - return build_train_dataloader( - datapipe, - batchprocess_fn=seg_pipeline, - samples_per_gpu=batch_size, - workers_per_gpu=1, - ) - - -def get_training_module(model_cfg: ConfigDict): - """Build mockup training module. - - Args: - model_cfg (ConfigDict): Pytorch model - """ - train_data_connector = DataConnector(key_mapping={K.images: K.images}) - test_data_connector = DataConnector(key_mapping={K.images: K.images}) - loss_module = LossModule( - { - "loss": SegCrossEntropyLoss(), - "connector": LossConnector( - key_mapping={ - "output": pred_key("outputs"), - "target": data_key(K.seg_masks), - } - ), - } - ) - - optimizer_cfg = get_optimizer_cfg(class_config(SGD, lr=0.01)) - return TrainingModule( - model_cfg=model_cfg, - optimizers_cfg=[optimizer_cfg], - loss_module=loss_module, - train_data_connector=train_data_connector, - test_data_connector=test_data_connector, - seed=1, - ) - - -class PLTrainerTest(unittest.TestCase): - """Pytorch lightning trainer test class.""" - - def setUp(self) -> None: - """Setup.""" - self.test_dir = tempfile.mkdtemp() - - callbacks = [LRSchedulerCallback(), CallbackWrapper(LoggingCallback())] - - self.trainer = PLTrainer( - work_dir=self.test_dir, - exp_name="test", - version="test", - callbacks=callbacks, - max_steps=2, - devices=0, - num_sanity_val_steps=0, - ) - - model_cfg = class_config( - SemanticFPN, - num_classes=80, - ) - - self.training_module = get_training_module(model_cfg=model_cfg) - - def tearDown(self) -> None: - """Tear down.""" - shutil.rmtree(self.test_dir) - - def test_train(self) -> None: - """Test training.""" - dataset = COCO(get_test_data("coco_test"), split="train") - train_dataloader = get_train_dataloader(dataset, 2) - - self.trainer.fit(self.training_module, train_dataloader) diff --git a/tests/zoo/util.py b/tests/zoo/util.py index bc6a276d..591b3934 100644 --- a/tests/zoo/util.py +++ b/tests/zoo/util.py @@ -2,17 +2,8 @@ from __future__ import annotations -import importlib - from tests.util import content_equal -from vis4d.config.typing import ExperimentConfig - - -def get_config_for_name(config_name: str) -> ExperimentConfig: - """Get config for name.""" - module = importlib.import_module("vis4d.zoo." + config_name) - - return module.get_config() +from vis4d.zoo.util import get_config_for_name def compare_configs( diff --git a/vis4d/common/__init__.py b/vis4d/common/__init__.py index 4f017c2a..72476b68 100644 --- a/vis4d/common/__init__.py +++ b/vis4d/common/__init__.py @@ -16,7 +16,6 @@ NDArrayUI8, TorchCheckpoint, TorchLossFunc, - TrainingModule, ) __all__ = [ @@ -35,5 +34,4 @@ "TorchLossFunc", "GenericFunc", "ListAny", - "TrainingModule", ] diff --git a/vis4d/common/array.py b/vis4d/common/array.py index 16c745ca..1cf96805 100644 --- a/vis4d/common/array.py +++ b/vis4d/common/array.py @@ -10,67 +10,74 @@ from vis4d.common.typing import ( ArrayLike, NDArrayBool, - NDArrayFloat, - NDArrayInt, + NDArrayF32, + NDArrayF64, + NDArrayI32, + NDArrayI64, NDArrayNumber, - NDArrayUInt, - NumpyBool, - NumpyFloat, - NumpyInt, - NumpyUInt, + NDArrayUI8, + NDArrayUI16, + NDArrayUI32, ) +# Bool dtypes @overload def array_to_numpy( - data: ArrayLike, n_dims: int | None, dtype: type[NumpyBool] + data: ArrayLike, n_dims: int | None, dtype: type[np.bool_] ) -> NDArrayBool: ... +# Float dtypes @overload def array_to_numpy( - data: ArrayLike, n_dims: int | None, dtype: type[NumpyFloat] -) -> NDArrayFloat: ... + data: ArrayLike | None, n_dims: int | None, dtype: type[np.float32] +) -> NDArrayF32: ... @overload def array_to_numpy( - data: ArrayLike, n_dims: int | None, dtype: type[NumpyInt] -) -> NDArrayInt: ... + data: ArrayLike | None, n_dims: int | None, dtype: type[np.float64] +) -> NDArrayF64: ... +# Int dtypes @overload def array_to_numpy( - data: ArrayLike, n_dims: int | None, dtype: type[NumpyUInt] -) -> NDArrayUInt: ... + data: ArrayLike | None, n_dims: int | None, dtype: type[np.int32] +) -> NDArrayI32: ... @overload def array_to_numpy( - data: ArrayLike | None, n_dims: int | None, dtype: type[NumpyBool] -) -> NDArrayBool | None: ... + data: ArrayLike | None, n_dims: int | None, dtype: type[np.int64] +) -> NDArrayI64: ... +# UInt dtypes @overload def array_to_numpy( - data: ArrayLike | None, n_dims: int | None, dtype: type[NumpyFloat] -) -> NDArrayFloat | None: ... + data: ArrayLike | None, n_dims: int | None, dtype: type[np.uint8] +) -> NDArrayUI8: ... @overload def array_to_numpy( - data: ArrayLike | None, n_dims: int | None, dtype: type[NumpyInt] -) -> NDArrayInt | None: ... + data: ArrayLike | None, n_dims: int | None, dtype: type[np.uint16] +) -> NDArrayUI16: ... @overload def array_to_numpy( - data: ArrayLike | None, n_dims: int | None, dtype: type[NumpyUInt] -) -> NDArrayUInt | None: ... + data: ArrayLike | None, n_dims: int | None, dtype: type[np.uint32] +) -> NDArrayUI32: ... +# Union of all dtypes @overload -def array_to_numpy(data: ArrayLike, n_dims: int | None) -> NDArrayNumber: ... +def array_to_numpy( + data: ArrayLike | None, n_dims: int | None +) -> NDArrayNumber: ... @overload @@ -81,7 +88,14 @@ def array_to_numpy( data: ArrayLike | None, n_dims: int | None = None, dtype: ( - type[NumpyBool] | type[NumpyFloat] | type[NumpyInt] | type[NumpyUInt] + type[np.bool_] + | type[np.float32] + | type[np.float64] + | type[np.int32] + | type[np.int64] + | type[np.uint8] + | type[np.uint16] + | type[np.uint32] ) = np.float32, ) -> NDArrayNumber | None: """Converts a given array like object to a numpy array. @@ -110,9 +124,8 @@ def array_to_numpy( squeezed or exanded (from the left). If it still does not match, an error is raised. - dtype (type[NumpyBool] | type[NumpyFloat] | type[NumpyInt] | - type[NumpyUInt], optional): Target dtype of the array. Defaults to - np.float32. + dtype (SUPPORTED_DTYPES, optional): Target dtype of the array. Defaults + to np.float32. Raises: ValueError: If the provied array like objects can not be converted @@ -150,61 +163,4 @@ def array_to_numpy( f"have {n_dims} dimensions." ) - # hardcode next type check since mypy can not resolve this correctly - typed_arr: NDArrayNumber = array.astype(dtype) # type: ignore - return typed_arr - - -@overload -def arrays_to_numpy( - *args: ArrayLike, n_dims: int | None, dtype: type[NumpyBool] -) -> tuple[NDArrayBool, ...]: ... - - -@overload -def arrays_to_numpy( - *args: ArrayLike, n_dims: int | None, dtype: type[NumpyFloat] -) -> tuple[NDArrayFloat, ...]: ... - - -@overload -def arrays_to_numpy( - *args: ArrayLike, n_dims: int | None, dtype: type[NumpyInt] -) -> tuple[NDArrayInt, ...]: ... - - -@overload -def arrays_to_numpy( - *args: ArrayLike, n_dims: int | None, dtype: type[NumpyUInt] -) -> tuple[NDArrayUInt, ...]: ... - - -def arrays_to_numpy( - *args: ArrayLike | None, - n_dims: int | None = None, - dtype: ( - type[NumpyBool] | type[NumpyFloat] | type[NumpyInt] | type[NumpyUInt] - ) = np.float32, -) -> tuple[NDArrayNumber | None, ...]: - """Converts a given sequence of optional ArrayLike objects to numpy. - - Args: - args (ArrayLike | None): Provided arguments. - n_dims (int | None, optional): Target number of dimension of the array. - If the provided array does not have this shape, it will be - squeezed or exanded (from the left). If it still does not match, - an error is Raised. - dtype (type[NumpyBool] | type[NumpyFloat] | type[NumpyInt] | - type[NumpyUInt], optional): Target dtype of the array. Defaults to - np.float32. - - Raises: - ValueError: If the provied array like objects can not be converted - with the target dimensions. - - Returns: - tuple[NDArrayNumber | None]: The converted arguments as numpy array. - """ - # Ignore mypy check due to 'Not all union combinations were tried because - # there are too many unions' - return tuple(array_to_numpy(arg, n_dims, dtype) for arg in args) # type: ignore # pylint: disable=line-too-long + return array.astype(dtype) # type: ignore diff --git a/vis4d/common/distributed.py b/vis4d/common/distributed.py index ab96201d..6511dc44 100644 --- a/vis4d/common/distributed.py +++ b/vis4d/common/distributed.py @@ -11,52 +11,15 @@ from functools import wraps from typing import Any -import cloudpickle import torch import torch.distributed as dist -from torch import nn +from torch import Tensor, nn from torch.distributed import broadcast_object_list from torch.nn.parallel import DataParallel, DistributedDataParallel from vis4d.common import ArgsType, DictStrAny, GenericFunc -class PicklableWrapper: # mypy: disable=line-too-long - """Wrap an object to make it more picklable. - - Note that it uses heavy weight serialization libraries that are slower than - pickle. It's best to use it only on closures (which are usually not - picklable). This is a simplified version of - https://github.com/joblib/joblib/blob/master/joblib/externals/loky/cloudpickle_wrapper.py - """ - - def __init__(self, obj: Any | PicklableWrapper) -> None: # type: ignore - """Creates an instance of the class.""" - while isinstance(obj, PicklableWrapper): - # Wrapping an object twice is no-op - obj = obj._obj - self._obj: Any = obj - - def __reduce__(self) -> tuple[Any, tuple[bytes]]: - """Reduce.""" - s = cloudpickle.dumps(self._obj) - return cloudpickle.loads, (s,) - - def __call__(self, *args: ArgsType, **kwargs: ArgsType) -> Any: - """Call.""" - return self._obj(*args, **kwargs) - - def __getattr__(self, attr: str) -> Any: - """Get attribute. - - Ensure that the wrapped object can be used seamlessly as the previous - object. - """ - if attr not in ["_obj"]: - return getattr(self._obj, attr) - return getattr(self, attr) - - # no coverage for these functions, since we don't unittest distributed setting def get_world_size() -> int: # pragma: no cover """Get the world size (number of processes) of torch.distributed. @@ -128,7 +91,7 @@ def synchronize() -> None: # pragma: no cover dist.barrier(group=dist.group.WORLD, device_ids=[get_local_rank()]) -def broadcast(obj: Any, src: int = 0) -> Any: # pragma: no cover +def broadcast(obj: Any, src: int = 0) -> Any: # type: ignore """Broadcast an object from a source to all processes.""" if not distributed_available(): return obj @@ -140,14 +103,14 @@ def broadcast(obj: Any, src: int = 0) -> Any: # pragma: no cover return obj[0] -def serialize_to_tensor(data: Any) -> torch.Tensor: # pragma: no cover - """Serialize arbitrary picklable data to a torch.Tensor. +def serialize_to_tensor(data: Any) -> Tensor: # type: ignore + """Serialize arbitrary picklable data to a Tensor. Args: data (Any): The data to serialize. Returns: - torch.Tensor: The serialized data as a torch.Tensor. + Tensor: The serialized data as a Tensor. Raises: AssertionError: If the backend of torch.distributed is not gloo or @@ -186,7 +149,7 @@ def rank_zero_only(func: GenericFunc) -> GenericFunc: """ @wraps(func) - def wrapped_fn(*args: ArgsType, **kwargs: ArgsType) -> Any: + def wrapped_fn(*args: ArgsType, **kwargs: ArgsType) -> Any: # type: ignore rank = get_rank() if rank == 0: return func(*args, **kwargs) @@ -196,8 +159,8 @@ def wrapped_fn(*args: ArgsType, **kwargs: ArgsType) -> Any: def pad_to_largest_tensor( - tensor: torch.Tensor, -) -> tuple[list[int], torch.Tensor]: # pragma: no cover + tensor: Tensor, +) -> tuple[list[int], Tensor]: # pragma: no cover """Pad tensor to largest size among the tensors in each process. Args: @@ -251,7 +214,7 @@ def all_gather_object_gpu( # type: ignore tensor_list = [tensor.clone() for _ in range(world_size)] dist.all_gather_object(tensor_list, tensor) # (world_size, N) - if rank_zero_return_only and not rank == 0: + if rank_zero_return_only and rank != 0: return None # decode @@ -313,7 +276,7 @@ def all_gather_object_cpu( # type: ignore pickle.dump(data, f) synchronize() - if rank_zero_return_only and not rank == 0: + if rank_zero_return_only and rank != 0: return None # load & decode @@ -332,7 +295,7 @@ def all_gather_object_cpu( # type: ignore return data_list -def reduce_mean(tensor: torch.Tensor) -> torch.Tensor: +def reduce_mean(tensor: Tensor) -> Tensor: """Obtain the mean of tensor on different GPUs.""" if not (dist.is_available() and dist.is_initialized()): return tensor @@ -341,9 +304,9 @@ def reduce_mean(tensor: torch.Tensor) -> torch.Tensor: return tensor -def obj2tensor( +def obj2tensor( # type: ignore pyobj: Any, device: torch.device = torch.device("cuda") -) -> torch.Tensor: +) -> Tensor: """Serialize picklable python object to tensor. Args: @@ -354,11 +317,11 @@ def obj2tensor( return torch.ByteTensor(storage).to(device=device) -def tensor2obj(tensor: torch.Tensor) -> Any: +def tensor2obj(tensor: Tensor) -> Any: # type: ignore """Deserialize tensor to picklable python object. Args: - tensor (torch.Tensor): Tensor to be deserialized. + tensor (Tensor): Tensor to be deserialized. """ return pickle.loads(tensor.cpu().numpy().tobytes()) diff --git a/vis4d/common/typing.py b/vis4d/common/typing.py index 5e78f0c1..0a23a96b 100644 --- a/vis4d/common/typing.py +++ b/vis4d/common/typing.py @@ -16,13 +16,6 @@ Tensor, ) -NumpyBool = np.bool_ -NumpyFloat = Union[np.float32, np.float64] -NumpyInt = Union[np.int32, np.int64] -NumpyUInt = Union[ # pylint: disable=invalid-name - np.uint8, np.uint16, np.uint32 -] - NDArrayBool = npt.NDArray[np.bool_] NDArrayF32 = npt.NDArray[np.float32] NDArrayF64 = npt.NDArray[np.float64] @@ -47,7 +40,6 @@ LossesType = Dict[str, Tensor] TorchLossFunc = Callable[..., Any] # type: ignore GenericFunc = Callable[..., Any] # type: ignore -TrainingModule = Any # type: ignore ArrayIterableFloat = Iterable[Union[float, "ArrayIterableFloat"]] ArrayIterableBool = Iterable[Union[bool, "ArrayIterableBool"]] @@ -63,3 +55,20 @@ ArrayLike = Union[ArrayLikeBool, ArrayLikeFloat, ArrayLikeInt, ArrayLikeUInt] ListAny = list[Any] # type: ignore + + +# Trick mypy into not applying contravariance rules to inputs by defining +# forward as a value, rather than a function. See also +# https://github.com/python/mypy/issues/8795 +def unimplemented(self, *args: Any) -> None: # type: ignore + r"""Define the computation performed at every call. + + Should be overridden by all subclasses. + + .. note:: + Although the recipe for forward pass needs to be defined within + this function, one should call the :class:`Module` instance afterwards + instead of this since the former takes care of running the + registered hooks while the latter silently ignores them. + """ + raise NotImplementedError() diff --git a/vis4d/config/replicator.py b/vis4d/config/replicator.py deleted file mode 100644 index a12c1d40..00000000 --- a/vis4d/config/replicator.py +++ /dev/null @@ -1,324 +0,0 @@ -"""Replication methods to perform different parameters sweeps.""" - -from __future__ import annotations - -import re -from collections.abc import Callable, Generator, Iterable -from queue import Queue -from typing import Any - -from ml_collections import ConfigDict - -from vis4d.common.typing import ArgsType - - -def iterable_sampler( # type: ignore - samples: Iterable[Any], -) -> Callable[[], Generator[Any, None, None]]: - """Creates a sampler from an iterable. - - This fuction returns a method that returns a generator that iterates - over all values provided in the 'samples' iterable. - - Args: - samples (Iterable[Any]): Iterable over which to sample. - - Returns: - Callable[[], Generator[Any, None, None]]: Function that - returns a generator which iterates over all elements in the given - iterable. - """ - - def _sampler() -> Generator[float, None, None]: - yield from samples - - return _sampler - - -def linspace_sampler( - min_value: float, max_value: float, n_steps: int = 1 -) -> Callable[[], Generator[float, None, None]]: - """Creates a linear space sampler. - - This fuction returns a method that returns a generator that iterates - from min_value to max_value in n_steps. - - Args: - min_value (float): Lower value bound - max_value (float): Upper value bound - n_steps (int, optional): Number of steps. Defaults to 1. - - Returns: - Callable[[], Generator[float, None, None]]: Function that - returns a generator which iterates from min to max in n_steps. - """ - - def _sampler() -> Generator[float, None, None]: - for i in range(n_steps): - yield min_value + i / max(n_steps - 1, 1) * (max_value - min_value) - - return _sampler - - -def logspace_sampler( - min_exponent: float, - max_exponent: float, - n_steps: int = 1, - base: float = 10, -) -> Callable[[], Generator[float, None, None]]: - """Creates a logarithmic space sampler. - - This fuction returns a method that returns a generator that iterates - from base^min_exponent to base^max_exponent in n_steps. - - Args: - min_exponent (float): Lower value bound - max_exponent (float): Upper value bound - n_steps (int, optional): Number of steps. Defaults to 1. - base (float): Base value for exponential calculation. Defaults to 10. - - Returns: - Callable[[], Generator[float, None, None]]: Function that - returns a generator which iterates from 10^min to 10^max in n_steps. - """ - - def _sampler() -> Generator[float, None, None]: - for exp in linspace_sampler(min_exponent, max_exponent, n_steps)(): - yield base**exp - - return _sampler - - -def replicate_config( # type: ignore - configuration: ConfigDict, - sampling_args: list[ - tuple[str, Callable[[], Generator[Any, None, None]] | Iterable[Any]] - ], - method: str = "grid", - fstring="", -) -> Generator[ConfigDict, None, None]: - """Function used to replicate a config. - - This function takes a ConfigDict and a dict with (key: generator) entries. - It will yield, multiple modified config dicts assigned with different - values defined in the sampling_args dictionary. - - Example: - >>> config = ConfigDict({"trainer": {"lr": 0.2, "bs": 2}}) - >>> replicated_config = replicate_config(config, - >>> sampling_args = [("trainer.lr", linspace_sampler(0.01, 0.1, 3))], - >>> method = "grid" - >>> ) - >>> for c in replicated_config: - >>> print(c) - - Will print: - trainer: bs: 2 lr: 0.01 - trainer: bs: 2 lr: 0.055 - trainer: bs: 2 lr: 0.1 - - NOTE, the config dict instance that will be returned will be mutable and - continuously updated to preserve references. - In the code above, executing - >>> print(list(replicated_config)) - Prints: - trainer: bs: 2 lr: 0.1 - trainer: bs: 2 lr: 0.1 - trainer: bs: 2 lr: 0.1 - - Please resolve the reference and copy the dict if you need a list: - >>> print([c.copy_and_resolve_references() for c in replicated_config]) - - - Args: - configuration (ConfigDict): Configuration to replicate - sampling_args (dict[str, Callable[[], Any]]): The queue, - that contains (key, iterator) pairs where the iterator - yields the values which should be assigned to the key. - method (str): What replication method to use. Currently only - 'grid' and 'linear' is supported. - Grid combines the sampling arguments in a grid wise fashion - ([1,2],[3,4] -> [1,3],[1,4],[2,3],[2,4]) whereas 'linear' will - only select elements at the same index ([1,2],[3,4]->[1,3],[2,4]). - fstring (str): Format string to use for the experiment name. Defaults - to an empty string. The format string will be resolved with the - values of the config dict. For example, if the config dict - contains a key 'trainer.lr' with value 0.1, the format string - '{trainer.lr}' will be resolved to '0.1'. - - Raises: - ValueError: if the replication method is unknown. - """ - sampling_queue: Queue[ # type: ignore - tuple[str, Callable[[], Generator[Any, None, None]]] - ] = Queue() - - for key, value in sampling_args: - # Convert Iterable to a callable generator - if isinstance(value, Iterable): - generator: Callable[[], Generator[ArgsType, None, None]] = ( - lambda value=value: (i for i in value) # type: ignore - ) - sampling_queue.put((key, generator)) - else: - sampling_queue.put((key, value)) - - if method == "grid": - replicated = _replicate_config_grid(configuration, sampling_queue) - elif method == "linear": - replicated = _replicate_config_linear(configuration, sampling_queue) - else: - raise ValueError(f"Unknown replication method {method}") - - original_name = configuration.experiment_name - - for config in replicated: - # Update config name - config.experiment_name = ( - f"{original_name}_{_resolve_fstring(fstring, config)}" - ) - yield config - - -def _resolve_fstring(fstring: str, config: ConfigDict) -> str: - """Resolves a format string with the values from the config. - - This function takes a format string and replaces all the keys - with the values from the config. The keys are expected to be - in the format {key} or {key:format}. - This function may fail if the format string contains a key that - is not present in the config. It will also fail if the format - string contains a key that is not a valid python identifier. - - Args: - fstring (str): The format string. E.g. "lr_{params.lr}". - config (ConfigDict): The config dict. E.g. {"params": {"lr": 0.1}}. - - Returns: - str: The resolved format string. E.g. "lr_0.1 - """ - # match everything between { and ':' or '}' - pattern = re.compile(r"{([^:}]+)") - required_params = {p.strip() for p in pattern.findall(fstring)} - - format_dict: dict[str, str] = {} - for param in required_params: - # Maks out '.' which is invalid for .format() call - new_param_name = param.replace(".", "_") - format_dict[new_param_name] = getattr(config, param) - fstring = fstring.replace(param, new_param_name) - - # apply formatting - return fstring.format(**format_dict) - - -def _replicate_config_grid( # type: ignore - configuration: ConfigDict, - sampling_queue: Queue[ - tuple[str, Callable[[], Generator[Any, None, None]]] - ], -) -> Generator[ConfigDict, None, None]: - """Internal function used to replicate a config. - - This function takes a ConfigDict and a queue with (key, generator) entries. - It will then recursively call itself and yield the ConfigDict with - updated values for every key in the sampling_queue. Each key combination - will be yielded exactly once, resulting in prod(len(generator)) entires. - - - For example, a parameter sweep using 'lr: [0,1], bs: [8, 16]' will yield - [0, 8], [0, 16], [0, 8], [1, 16] as combinations. - - Args: - configuration (ConfigDict): Configuration to replicate - sampling_queue (Queue[tuple[str, Callable[[], Any]]]): The queue, - that contains (key, iterator) pairs where the iterator - yields the values which should be assigned to the key. - - Yields: - ConfigDict: Replicated configuration with updated key values. - """ - # Termination criterion reached, We processed all samplers - if sampling_queue.empty(): - yield configuration - return - - # Get next key we want to replicate - (key_name, sampler) = sampling_queue.get() - - # Iterate over all possible assignement values for this key - for value in sampler(): - # Update value ignoring type errors - # (e.g. user set default lr to 1 instead 1.0 would - # otherwise give a type error (float != int)) - with configuration.ignore_type(): - configuration.update_from_flattened_dict({key_name: value}) - - # Let the other samplers process the remaining keys - yield from _replicate_config_grid(configuration, sampling_queue) - - # Add back this sampler for next round - sampling_queue.put((key_name, sampler)) - - -def _replicate_config_linear( # type: ignore - configuration: ConfigDict, - sampling_queue: Queue[ - tuple[str, Callable[[], Generator[Any, None, None]]] - ], - current_position: int | None = None, -) -> Generator[ConfigDict, None, None]: - """Internal function used to replicate a config in a linear way. - - This function takes a ConfigDict and a queue with (key, generator) entries. - It will then recursively call itself and yield the ConfigDict with - updated values for every key in the sampling_queue. - - For example, a parameter sweep using 'lr: [0,1], bs: [8, 16]' will yield - [0, 8], [1, 16] as combinations. - - Args: - configuration (ConfigDict): Configuration to replicate - sampling_queue (Queue[tuple[str, Callable[[], Any]]]): The queue, - that contains (key, iterator) pairs where the iterator - yields the values which should be assigned to the key. - current_position (int, optional): Current position of the top level - sampling module. Used and updated internally. - - Yields: - ConfigDict: Replicated configuration with updated key values. - """ - # Termination criterion reached, We processed all samplers - if sampling_queue.empty(): - yield configuration - return - - # Get next key we want to replicate - (key_name, sampler) = sampling_queue.get() - - is_top_level = False - if current_position is None: - is_top_level = True # This is the top level call. - current_position = 0 - - # Iterate over all possible assignement values for this key - for idx, value in enumerate(sampler()): - if not is_top_level and idx != current_position: - continue # only yield entry that matches requested position - - # Update value ignoring type errors - # (e.g. user set default lr to 1 instead 1.0 would - # otherwise give a type error (float != int)) - with configuration.ignore_type(): - configuration.update_from_flattened_dict({key_name: value}) - - # Let the other samplers process the remaining keys - yield from _replicate_config_linear( - configuration, sampling_queue, current_position - ) - - if is_top_level: - current_position += 1 - - # Add back this sampler for next round - sampling_queue.put((key_name, sampler)) diff --git a/vis4d/data/const.py b/vis4d/data/const.py index 603a0306..16dfc1cd 100644 --- a/vis4d/data/const.py +++ b/vis4d/data/const.py @@ -49,20 +49,24 @@ class CommonKeys: keys where we expect a pre-defined format to enable the usage of common data pre-processing operations among different datasets. + ### Image based inputs ### images (NDArrayF32): Image of shape [1, H, W, C]. input_hw (Tuple[int, int]): Shape of image in (height, width) after transformations. original_images (NDArrayF32): Original image of shape [1, H, W, C]. original_hw (Tuple[int, int]): Original shape of image in (height, width). + ### General Info ### sample_names (str): Name of the current sample. sequence_names (str): If the dataset contains videos, this field indicates the name of the current sequence. frame_ids (int): If the dataset contains videos, this field indicates the temporal frame index of the current image / sample. + ### Image Classification ### categories (NDArrayF32): Class labels of shape [C, ]. + ### 2D annotations ### boxes2d (NDArrayF32): 2D bounding boxes of shape [N, 4] in xyxy format. boxes2d_classes (NDArrayI64): Semantic classes of 2D bounding boxes, shape [N,]. @@ -74,6 +78,9 @@ class CommonKeys: panoptic_masks (NDArrayI64): Panoptic segmentation masks [H, W]. deph_maps (NDArrayF32): Depth maps of shape [H, W]. + + + intrinsics (NDArrayF32): Intrinsic sensor calibration. Shape [3, 3]. extrinsics (NDArrayF32): Extrinsic sensor calibration, transformation of sensor to world coordinate frame. Shape [4, 4]. @@ -103,6 +110,9 @@ class CommonKeys: sequence_names = "sequence_names" # Sequence name for each sample frame_ids = "frame_ids" + # Image Classification + categories = "categories" + # 2D annotations boxes2d = "boxes2d" boxes2d_classes = "boxes2d_classes" @@ -110,12 +120,11 @@ class CommonKeys: instance_masks = "instance_masks" seg_masks = "seg_masks" panoptic_masks = "panoptic_masks" + + # Depth & Flow depth_maps = "depth_maps" optical_flows = "optical_flows" - # Image Classification - categories = "categories" - # sensor calibration intrinsics = "intrinsics" extrinsics = "extrinsics" diff --git a/vis4d/data/datasets/coco.py b/vis4d/data/datasets/coco.py index 9ab66f02..225ede7b 100644 --- a/vis4d/data/datasets/coco.py +++ b/vis4d/data/datasets/coco.py @@ -205,7 +205,7 @@ def __init__( ) # TODO: Control category names depending on the task - self.category_names = sorted(coco_det_map, key=coco_det_map.get) + self.category_names = sorted(coco_det_map, key=coco_det_map.get) # type: ignore # pylint: disable=line-too-long def __repr__(self) -> str: """Concise representation of the dataset.""" diff --git a/vis4d/data/datasets/scalabel.py b/vis4d/data/datasets/scalabel.py index 215c07ff..746cd2be 100644 --- a/vis4d/data/datasets/scalabel.py +++ b/vis4d/data/datasets/scalabel.py @@ -41,7 +41,9 @@ poly2ds_to_mask, rle_to_mask, ) - from scalabel.label.typing import Config + from scalabel.label.typing import ( + Config, + ) from scalabel.label.typing import Dataset as ScalabelData from scalabel.label.typing import ( Extrinsics, diff --git a/vis4d/data/loader.py b/vis4d/data/loader.py index f6a20da6..44bf1f3c 100644 --- a/vis4d/data/loader.py +++ b/vis4d/data/loader.py @@ -14,7 +14,8 @@ RandomSampler, SequentialSampler, ) -from torch.utils.data.distributed import DistributedSampler, Sampler +from torch.utils.data.distributed import DistributedSampler +from torch.utils.data.sampler import Sampler from vis4d.common.distributed import get_rank, get_world_size @@ -126,11 +127,11 @@ def build_train_dataloader( collate_keys: Sequence[str] = DEFAULT_COLLATE_KEYS, sensors: Sequence[str] | None = None, pin_memory: bool = True, - shuffle: bool = True, + shuffle: bool | None = True, drop_last: bool = False, seed: int | None = None, aspect_ratio_grouping: bool = False, - sampler: Sampler | None = None, + sampler: Sampler | None = None, # type: ignore disable_subprocess_warning: bool = False, ) -> DataLoader[DictDataOrList]: """Build training dataloader.""" @@ -174,17 +175,19 @@ def _worker_init_fn(worker_id: int) -> None: if sampler is None: if get_world_size() > 1: + assert isinstance( + shuffle, bool + ), "When using distributed training, shuffle must be a boolean." sampler = DistributedSampler( dataset, shuffle=shuffle, drop_last=drop_last ) shuffle = False drop_last = False + elif shuffle: + sampler = RandomSampler(dataset) + shuffle = False else: - if shuffle: - sampler = RandomSampler(dataset) - shuffle = False - else: - sampler = SequentialSampler(dataset) + sampler = SequentialSampler(dataset) batch_sampler = None if aspect_ratio_grouping: diff --git a/vis4d/data/samplers.py b/vis4d/data/samplers.py index cbdd8df1..b7401fcc 100644 --- a/vis4d/data/samplers.py +++ b/vis4d/data/samplers.py @@ -95,25 +95,25 @@ class AspectRatioBatchSampler(BatchSampler): """ def __init__( - self, sampler: Sampler, batch_size: int, drop_last: bool = False + self, + sampler: Sampler, # type: ignore + batch_size: int, + drop_last: bool = False, ) -> None: + """Creates an instance of the class.""" if not isinstance(sampler, Sampler): raise TypeError( "sampler should be an instance of ``Sampler``, " f"but got {sampler}" ) - if not isinstance(batch_size, int) or batch_size <= 0: - raise ValueError( - "batch_size should be a positive integer value, " - f"but got batch_size={batch_size}" - ) - self.sampler = sampler - self.batch_size = batch_size - self.drop_last = drop_last + + super().__init__(sampler, batch_size, drop_last) + # two groups for w < h and w >= h - self._aspect_ratio_buckets = [[] for _ in range(2)] + self._aspect_ratio_buckets: list[list[int]] = [[] for _ in range(2)] - def __iter__(self): + def __iter__(self) -> Iterator[list[int]]: + """Iteration method.""" for idx in self.sampler: if hasattr(self.sampler, "dataset"): data_dict = self.sampler.dataset[idx] @@ -147,7 +147,10 @@ def __iter__(self): left_data = left_data[self.batch_size :] def __len__(self) -> int: + """Return length of sampler instance.""" if self.drop_last: - return len(self.sampler) // self.batch_size - else: - return (len(self.sampler) + self.batch_size - 1) // self.batch_size + return len(self.sampler) // self.batch_size # type: ignore + + return ( + len(self.sampler) + self.batch_size - 1 # type: ignore + ) // self.batch_size diff --git a/vis4d/data/transforms/photometric.py b/vis4d/data/transforms/photometric.py index 0d19eb9a..a0abd454 100644 --- a/vis4d/data/transforms/photometric.py +++ b/vis4d/data/transforms/photometric.py @@ -330,9 +330,9 @@ def __call__(self, images: list[NDArrayF32]) -> list[NDArrayF32]: for i, image in enumerate(images): image = image[0].astype(np.uint8) if self.image_channel_mode == "BGR": - image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # type: ignore + image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) else: - image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV) # type: ignore + image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV) image = image.astype(np.int16) hsv_gains = np.random.uniform(-1, 1, 3) * [ self.hue_delta, diff --git a/vis4d/engine/callbacks/__init__.py b/vis4d/engine/callbacks/__init__.py index e7670237..e95dc07e 100644 --- a/vis4d/engine/callbacks/__init__.py +++ b/vis4d/engine/callbacks/__init__.py @@ -4,13 +4,13 @@ from .ema import EMACallback from .evaluator import EvaluatorCallback from .logging import LoggingCallback +from .scheduler import LRSchedulerCallback from .visualizer import VisualizerCallback from .yolox_callbacks import ( YOLOXModeSwitchCallback, YOLOXSyncNormCallback, YOLOXSyncRandomResizeCallback, ) -from .scheduler import LRSchedulerCallback __all__ = [ "Callback", diff --git a/vis4d/engine/callbacks/base.py b/vis4d/engine/callbacks/base.py index 3938fdd3..0ce9cea8 100644 --- a/vis4d/engine/callbacks/base.py +++ b/vis4d/engine/callbacks/base.py @@ -2,9 +2,8 @@ from __future__ import annotations -from torch import Tensor - import lightning.pytorch as pl +from torch import Tensor from vis4d.common.typing import DictStrArrNested from vis4d.data.typing import DictData diff --git a/vis4d/engine/callbacks/ema.py b/vis4d/engine/callbacks/ema.py index d02830c8..fb732fd9 100644 --- a/vis4d/engine/callbacks/ema.py +++ b/vis4d/engine/callbacks/ema.py @@ -15,7 +15,7 @@ class EMACallback(Callback): """Callback for EMA.""" - def on_train_batch_end( + def on_train_batch_end( # type: ignore self, trainer: pl.Trainer, pl_module: pl.LightningModule, diff --git a/vis4d/engine/callbacks/evaluator.py b/vis4d/engine/callbacks/evaluator.py index 9c5e0c36..e79e746a 100644 --- a/vis4d/engine/callbacks/evaluator.py +++ b/vis4d/engine/callbacks/evaluator.py @@ -3,7 +3,6 @@ from __future__ import annotations import os - from typing import Any import lightning.pytorch as pl @@ -104,12 +103,12 @@ def on_validation_epoch_end( self, trainer: pl.Trainer, pl_module: pl.LightningModule ) -> None: """Wait for on_validation_epoch_end PL hook to call 'evaluate'.""" - log_dict = self.run_eval(pl_module) + log_dict = self.run_eval() for k, v in log_dict.items(): pl_module.log(f"val/{k}", v, sync_dist=True, rank_zero_only=True) - def on_test_batch_end( + def on_test_batch_end( # type: ignore self, trainer: pl.Trainer, pl_module: pl.LightningModule, @@ -132,12 +131,12 @@ def on_test_epoch_end( self, trainer: pl.Trainer, pl_module: pl.LightningModule ) -> None: """Hook to run at the end of a testing epoch.""" - log_dict = self.run_eval(pl_module) + log_dict = self.run_eval() for k, v in log_dict.items(): pl_module.log(f"test/{k}", v, sync_dist=True, rank_zero_only=True) - def run_eval(self, pl_module: pl.LightningModule) -> MetricLogs: + def run_eval(self) -> MetricLogs: """Run evaluation for the given evaluator.""" self.evaluator.gather(all_gather_object_cpu) diff --git a/vis4d/engine/callbacks/logging.py b/vis4d/engine/callbacks/logging.py index 8cf62527..01d7b70b 100644 --- a/vis4d/engine/callbacks/logging.py +++ b/vis4d/engine/callbacks/logging.py @@ -2,10 +2,10 @@ from __future__ import annotations +from collections import defaultdict from typing import Any -import lightning.pytorch as pl -from collections import defaultdict +import lightning.pytorch as pl from vis4d.common import ArgsType, MetricLogs from vis4d.common.logging import rank_zero_info @@ -76,7 +76,6 @@ def on_train_batch_end( # type: ignore cur_iter = trainer.global_step + 1 total_iters = trainer.max_steps - log_dict: None | MetricLogs = None if cur_iter % self._refresh_rate == 0 and cur_iter != self.last_step: prefix = ( f"Epoch {pl_module.current_epoch + 1}" @@ -84,7 +83,7 @@ def on_train_batch_end( # type: ignore else "Iter" ) - log_dict = { + log_dict: MetricLogs = { k: sum(v) / len(v) if len(v) > 0 else float("NaN") for k, v in self._metrics.items() } @@ -98,7 +97,8 @@ def on_train_batch_end( # type: ignore self._metrics.clear() self.last_step = cur_iter - return log_dict + for k, v in log_dict.items(): + pl_module.log(f"train/{k}", v, rank_zero_only=True) def on_validation_epoch_start( self, trainer: pl.Trainer, pl_module: pl.LightningModule @@ -121,7 +121,7 @@ def on_validation_batch_end( # type: ignore # Resolve float("inf") to -1 if isinstance(trainer.num_val_batches[dataloader_idx], int): - total_iters = trainer.num_val_batches[dataloader_idx] + total_iters = int(trainer.num_val_batches[dataloader_idx]) else: total_iters = -1 @@ -139,7 +139,7 @@ def on_test_epoch_start( self.test_timer.reset() self.train_timer.pause() - def on_test_batch_end( + def on_test_batch_end( # type: ignore self, trainer: pl.Trainer, pl_module: pl.LightningModule, @@ -153,7 +153,7 @@ def on_test_batch_end( # Resolve float("inf") to -1 if isinstance(trainer.num_test_batches[dataloader_idx], int): - total_iters = trainer.num_test_batches[dataloader_idx] + total_iters = int(trainer.num_test_batches[dataloader_idx]) else: total_iters = -1 diff --git a/vis4d/engine/callbacks/scheduler.py b/vis4d/engine/callbacks/scheduler.py index 5b90861b..c8cb0a54 100644 --- a/vis4d/engine/callbacks/scheduler.py +++ b/vis4d/engine/callbacks/scheduler.py @@ -17,6 +17,7 @@ class LRSchedulerCallback(Callback): def __init__(self) -> None: """Initialize the callback.""" + super().__init__() self.last_step = 0 def on_train_batch_end( # type: ignore diff --git a/vis4d/engine/callbacks/util.py b/vis4d/engine/callbacks/util.py index 8408b863..25d66b0b 100644 --- a/vis4d/engine/callbacks/util.py +++ b/vis4d/engine/callbacks/util.py @@ -2,7 +2,6 @@ from __future__ import annotations - import lightning.pytorch as pl from torch import nn @@ -19,7 +18,7 @@ def get_model(model: pl.LightningModule) -> nn.Module: def get_loss_module(loss_module: pl.LightningModule) -> LossModule: """Get loss_module from pl module.""" - if isinstance(loss_module, TrainingModule): - assert loss_module.loss_module is not None - return loss_module.loss_module - return loss_module # type: ignore + assert ( + loss_module.loss_module is not None + ), "Loss module is not set in the training module." + return loss_module.loss_module diff --git a/vis4d/engine/callbacks/visualizer.py b/vis4d/engine/callbacks/visualizer.py index 9d290c4d..e6b24ef5 100644 --- a/vis4d/engine/callbacks/visualizer.py +++ b/vis4d/engine/callbacks/visualizer.py @@ -2,15 +2,13 @@ from __future__ import annotations +import os from typing import Any -import os import lightning.pytorch as pl -from lightning.pytorch.loggers import WandbLogger - from vis4d.common import ArgsType -from vis4d.common.distributed import broadcast, get_rank, synchronize +from vis4d.common.distributed import broadcast, synchronize from vis4d.vis.base import Visualizer from .base import Callback @@ -89,7 +87,7 @@ def on_train_batch_end( # type: ignore self.visualizer.show(cur_iter=cur_iter) if self.save_to_disk: - self.save(trainer=trainer, cur_iter=cur_iter, stage="train") + self.save(cur_iter=cur_iter, stage="train") self.visualizer.reset() @@ -114,7 +112,7 @@ def on_validation_batch_end( # type: ignore self.visualizer.show(cur_iter=cur_iter) if self.save_to_disk: - self.save(trainer=trainer, cur_iter=cur_iter, stage="val") + self.save(cur_iter=cur_iter, stage="val") self.visualizer.reset() @@ -139,11 +137,11 @@ def on_test_batch_end( # type: ignore self.visualizer.show(cur_iter=cur_iter) if self.save_to_disk: - self.save(trainer=trainer, cur_iter=cur_iter, stage="test") + self.save(cur_iter=cur_iter, stage="test") self.visualizer.reset() - def save(self, trainer: pl.Trainer, cur_iter: int, stage: str) -> None: + def save(self, cur_iter: int, stage: str) -> None: """Save the visualizer state.""" output_folder = os.path.join(self.output_dir, stage) @@ -152,15 +150,16 @@ def save(self, trainer: pl.Trainer, cur_iter: int, stage: str) -> None: os.makedirs(output_folder, exist_ok=True) - image = self.visualizer.save_to_disk( + self.visualizer.save_to_disk( cur_iter=cur_iter, output_folder=output_folder ) - if get_rank() == 0: - if isinstance(trainer.logger, WandbLogger) and image is not None: - trainer.logger.log_image( - key=f"{self.visualizer}/{cur_iter}", - images=[image], - ) + # TODO: Add support for logging images to WandB. + # if get_rank() == 0: + # if isinstance(trainer.logger, WandbLogger) and image is not None: + # trainer.logger.log_image( + # key=f"{self.visualizer}/{cur_iter}", + # images=[image], + # ) synchronize() diff --git a/vis4d/engine/callbacks/yolox_callbacks.py b/vis4d/engine/callbacks/yolox_callbacks.py index 38d29a55..86aee489 100644 --- a/vis4d/engine/callbacks/yolox_callbacks.py +++ b/vis4d/engine/callbacks/yolox_callbacks.py @@ -4,14 +4,11 @@ import random from collections import OrderedDict - from typing import Any +import lightning.pytorch as pl import torch import torch.nn.functional as F - -import lightning.pytorch as pl - from torch import nn from torch.nn.modules.batchnorm import _NormBase from torch.utils.data import DataLoader @@ -35,16 +32,16 @@ class YOLOXModeSwitchCallback(Callback): - """Callback for switching the mode of YOLOX training. - - Args: - switch_epoch (int): Epoch to switch the mode. - """ + """Callback for switching the mode of YOLOX training.""" def __init__( self, *args: ArgsType, switch_epoch: int, **kwargs: ArgsType ) -> None: - """Init callback.""" + """Init callback. + + Args: + switch_epoch (int): Epoch to switch the mode. + """ super().__init__(*args, **kwargs) self.switch_epoch = switch_epoch self.switched = False @@ -79,7 +76,7 @@ def on_train_epoch_end( dataloader = trainer.train_dataloader assert dataloader is not None new_dataloader = DataLoader( - DataPipe(dataloader.dataset.datasets), # type: ignore + DataPipe(dataloader.dataset.datasets), batch_size=dataloader.batch_size, num_workers=dataloader.num_workers, collate_fn=dataloader.collate_fn, @@ -88,7 +85,7 @@ def on_train_epoch_end( pin_memory=dataloader.pin_memory, ) - pl_module.check_val_every_n_epoch = 1 + pl_module.check_val_every_n_epoch = 1 # type: ignore # Override train_dataloader method in PL datamodule. # Set reload_dataloaders_every_n_epochs to 1 to use the new @@ -98,7 +95,7 @@ def train_dataloader() -> DataLoader: # type: ignore return new_dataloader pl_module.datamodule.train_dataloader = train_dataloader - pl_module.reload_dataloaders_every_n_epochs = self.switch_epoch + pl_module.reload_dataloaders_every_n_epochs = self.switch_epoch # type: ignore # pylint: disable=line-too-long self.switched = True @@ -123,12 +120,7 @@ class YOLOXSyncNormCallback(Callback): def on_test_epoch_start( self, trainer: pl.Trainer, pl_module: pl.LightningModule ) -> None: - """Hook to run at the beginning of a testing epoch. - - Args: - trainer_state (TrainerState): Trainer state. - model (nn.Module): Model that is being trained. - """ + """Hook to run at the beginning of a testing epoch.""" if get_world_size() > 1: model = get_model(pl_module) norm_states = get_norm_states(model) diff --git a/vis4d/engine/optim/scheduler.py b/vis4d/engine/optim/scheduler.py index 78f041a7..0271f3e9 100644 --- a/vis4d/engine/optim/scheduler.py +++ b/vis4d/engine/optim/scheduler.py @@ -78,21 +78,23 @@ def _instantiate_lr_scheduler( "epoch_based": lr_scheduler_cfg["epoch_based"], } - def get_lr(self) -> list[float]: # type: ignore + def get_lr(self) -> list[float]: """Get current learning rate.""" lr = [] for lr_scheduler in self.lr_schedulers.values(): lr.extend(lr_scheduler["scheduler"].get_lr()) return lr - def state_dict(self) -> dict[int, DictStrAny]: # type: ignore + def state_dict(self) -> dict[int, DictStrAny]: """Get state dict.""" state_dict = {} for scheduler_idx, lr_scheduler in self.lr_schedulers.items(): state_dict[scheduler_idx] = lr_scheduler["scheduler"].state_dict() return state_dict - def load_state_dict(self, state_dict: dict[int, DictStrAny]) -> None: # type: ignore # pylint: disable=line-too-long + def load_state_dict( + self, state_dict: dict[int, DictStrAny] # type: ignore + ) -> None: """Load state dict.""" for scheduler_idx, _state_dict in state_dict.items(): # Instantiate the lr scheduler if it is not instantiated yet @@ -159,7 +161,7 @@ def __init__( self.factor = factor super().__init__(optimizer, last_epoch) - def get_lr(self) -> list[float]: # type: ignore + def get_lr(self) -> list[float]: """Compute current learning rate.""" step_count = self._step_count - 1 if step_count == 0: @@ -209,7 +211,7 @@ def __init__( self.min_lr = min_lr super().__init__(optimizer, last_epoch) - def get_lr(self) -> list[float]: # type: ignore + def get_lr(self) -> list[float]: """Compute current learning rate.""" step_count = self._step_count - 1 if step_count == 0 or step_count > self.max_steps: @@ -243,7 +245,7 @@ def __init__( self.max_steps = max_steps super().__init__(optimizer, last_epoch) - def get_lr(self) -> list[float]: # type: ignore + def get_lr(self) -> list[float]: """Compute current learning rate.""" step_count = self._step_count - 1 if step_count >= self.max_steps: diff --git a/vis4d/engine/run.py b/vis4d/engine/run.py index bd8d6570..7c8205ba 100644 --- a/vis4d/engine/run.py +++ b/vis4d/engine/run.py @@ -16,9 +16,10 @@ from vis4d.config.typing import ExperimentConfig from vis4d.engine.callbacks import ( Callback, - VisualizerCallback, LRSchedulerCallback, + VisualizerCallback, ) +from vis4d.engine.data_module import DataModule from vis4d.engine.flag import ( _CKPT, _CONFIG, @@ -28,7 +29,6 @@ _VIS, ) from vis4d.engine.parser import pprints_config -from vis4d.engine.data_module import DataModule from vis4d.engine.trainer import PLTrainer from vis4d.engine.training_module import TrainingModule diff --git a/vis4d/engine/trainer.py b/vis4d/engine/trainer.py index 831f3542..5aadf210 100644 --- a/vis4d/engine/trainer.py +++ b/vis4d/engine/trainer.py @@ -58,6 +58,8 @@ def __init__( state. Defaults to -1. If -1, a random seed will be generated. This will be set by TrainingModule. timeout: Timeout (seconds) for DDP connection. Default: 3600. + wandb_id: If using wandb, the id of the run. If None, a new run + will be created. Default: None. """ self.work_dir = work_dir self.exp_name = exp_name diff --git a/vis4d/engine/training_module.py b/vis4d/engine/training_module.py index 284e3b7c..99a3cf95 100644 --- a/vis4d/engine/training_module.py +++ b/vis4d/engine/training_module.py @@ -201,25 +201,7 @@ def optimizer_step( optimizer: Optimizer | LightningOptimizer, optimizer_closure: GenericFunc | None = None, ) -> None: - """Optimizer step. - - Args: - epoch (int): Current epoch. - batch_idx (int): Index of current batch. - optimizer: A PyTorch optimizer - optimizer_closure: The optimizer closure. This closure must be executed as it includes the - calls to ``training_step()``, ``optimizer.zero_grad()``, and ``backward()``. - - Examples:: - - def optimizer_step(self, epoch, batch_idx, optimizer, optimizer_closure): - # Add your custom logic to run directly before `optimizer.step()` - - optimizer.step(closure=optimizer_closure) - - # Add your custom logic to run directly after `optimizer.step()` - - """ + """Optimizer step.""" if self.check_unused_parameters: for name, param in self.model.named_parameters(): if param.grad is None: diff --git a/vis4d/eval/base.py b/vis4d/eval/base.py index d152d951..3b49e6f0 100644 --- a/vis4d/eval/base.py +++ b/vis4d/eval/base.py @@ -2,7 +2,7 @@ from __future__ import annotations -from vis4d.common import ArgsType, GenericFunc, MetricLogs +from vis4d.common.typing import GenericFunc, MetricLogs, unimplemented class Evaluator: # pragma: no cover @@ -83,20 +83,11 @@ def reset(self) -> None: """ raise NotImplementedError - def process_batch(self, *args: ArgsType) -> None: - """Process a batch of data. - - Raises: - NotImplementedError: This is an abstract class method. - """ - raise NotImplementedError + # Process a batch of data. + process_batch: GenericFunc = unimplemented def process(self) -> None: - """Process all accumulated data at the end of an epoch, if any. - - Raises: - NotImplementedError: This is an abstract class method. - """ + """Process all accumulated data at the end of an epoch, if any.""" def evaluate(self, metric: str) -> tuple[MetricLogs, str]: """Evaluate all predictions according to given metric. diff --git a/vis4d/eval/bdd100k/seg.py b/vis4d/eval/bdd100k/seg.py index d445bda3..a874d642 100644 --- a/vis4d/eval/bdd100k/seg.py +++ b/vis4d/eval/bdd100k/seg.py @@ -69,7 +69,7 @@ def reset(self) -> None: """Reset the evaluator.""" self.frames = [] - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, data_names: list[str], masks_list: list[ArrayLike] ) -> None: """Process tracking results.""" diff --git a/vis4d/eval/coco/detect.py b/vis4d/eval/coco/detect.py index 61f44984..5a1c5cfd 100644 --- a/vis4d/eval/coco/detect.py +++ b/vis4d/eval/coco/detect.py @@ -13,21 +13,29 @@ from pycocotools.cocoeval import COCOeval from terminaltables import AsciiTable -from vis4d.common import DictStrAny, GenericFunc, MetricLogs, NDArrayNumber +from vis4d.common.array import array_to_numpy from vis4d.common.logging import rank_zero_warn +from vis4d.common.typing import ( + ArrayLike, + DictStrAny, + GenericFunc, + MetricLogs, + NDArrayF32, + NDArrayI64, +) from vis4d.data.datasets.coco import coco_det_map from ..base import Evaluator -def xyxy_to_xywh(boxes: NDArrayNumber) -> NDArrayNumber: +def xyxy_to_xywh(boxes: NDArrayF32) -> NDArrayF32: """Convert Tensor [N, 4] in xyxy format into xywh. Args: - boxes (NDArrayNumber): Bounding boxes in Vis4D format. + boxes (NDArrayF32): Bounding boxes in Vis4D format. Returns: - NDArrayNumber: COCO format bounding boxes. + NDArrayF32: COCO format bounding boxes. """ boxes[:, 2] = boxes[:, 2] - boxes[:, 0] boxes[:, 3] = boxes[:, 3] - boxes[:, 1] @@ -54,10 +62,10 @@ def predictions_to_coco( cat_map: dict[str, int], coco_id2name: dict[int, str], image_id: int, - boxes: NDArrayNumber, - scores: NDArrayNumber, - classes: NDArrayNumber, - masks: None | NDArrayNumber = None, + boxes: NDArrayF32, + scores: NDArrayF32, + classes: NDArrayI64, + masks: None | NDArrayF32 = None, ) -> list[DictStrAny]: """Convert Vis4D format predictions to COCO format. @@ -65,10 +73,10 @@ def predictions_to_coco( cat_map (dict[str, int]): COCO class name to class ID mapping. coco_id2name (dict[int, str]): COCO class ID to class name mapping. image_id (int): ID of image. - boxes (NDArrayNumber): Predicted bounding boxes. - scores (NDArrayNumber): Predicted scores for each box. - classes (NDArrayNumber): Predicted classes for each box. - masks (None | NDArrayNumber, optional): Predicted masks. Defaults to + boxes (NDArrayF32): Predicted bounding boxes. + scores (NDArrayF32): Predicted scores for each box. + classes (NDArrayI64): Predicted classes for each box. + masks (None | NDArrayF32, optional): Predicted masks. Defaults to None. Returns: @@ -91,7 +99,7 @@ def predictions_to_coco( } if mask is not None: annotation["segmentation"] = maskUtils.encode( - np.array(mask.cpu(), order="F", dtype="uint8") + np.array(mask, order="F", dtype="uint8") ) annotation["segmentation"]["counts"] = annotation["segmentation"][ "counts" @@ -151,34 +159,44 @@ def reset(self) -> None: """Reset the saved predictions to start new round of evaluation.""" self._predictions = [] - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, coco_image_id: list[int], - pred_boxes: list[NDArrayNumber], - pred_scores: list[NDArrayNumber], - pred_classes: list[NDArrayNumber], - pred_masks: None | list[NDArrayNumber] = None, + pred_boxes: list[ArrayLike], + pred_scores: list[ArrayLike], + pred_classes: list[ArrayLike], + pred_masks: None | list[ArrayLike] = None, ) -> None: """Process sample and convert detections to coco format. coco_image_id (list[int]): COCO image ID. - pred_boxes (list[NDArrayNumber]): Predicted bounding boxes. - pred_scores (list[NDArrayNumber]): Predicted scores for each box. - pred_classes (list[NDArrayNumber]): Predicted classes for each box. - pred_masks (None | list[NDArrayNumber], optional): Predicted masks. + pred_boxes (list[ArrayLike]): Predicted bounding boxes. + pred_scores (list[ArrayLike]): Predicted scores for each box. + pred_classes (list[ArrayLike]): Predicted classes for each box. + pred_masks (None | list[ArrayLike], optional): Predicted masks. """ for i, (image_id, boxes, scores, classes) in enumerate( zip(coco_image_id, pred_boxes, pred_scores, pred_classes) ): - masks = pred_masks[i] if pred_masks else None + boxes_np = array_to_numpy(boxes, n_dims=None, dtype=np.float32) + scores_np = array_to_numpy(scores, n_dims=None, dtype=np.float32) + classes_np = array_to_numpy(classes, n_dims=None, dtype=np.int64) + + if pred_masks is not None: + masks_np = array_to_numpy( + pred_masks[i], n_dims=2, dtype=np.float32 + ) + else: + masks_np = None + coco_preds = predictions_to_coco( self.cat_map, self.coco_id2name, image_id, - boxes, - scores, - classes, - masks, + boxes_np, + scores_np, + classes_np, + masks_np, ) self._predictions.extend(coco_preds) diff --git a/vis4d/eval/common/binary.py b/vis4d/eval/common/binary.py index b9ea9db9..30f661d3 100644 --- a/vis4d/eval/common/binary.py +++ b/vis4d/eval/common/binary.py @@ -102,7 +102,7 @@ def reset(self) -> None: self.false_negatives = [] self.n_samples = [] - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, prediction: ArrayLike, groundtruth: ArrayLike, diff --git a/vis4d/eval/common/depth.py b/vis4d/eval/common/depth.py index cee434ef..9d9b3244 100644 --- a/vis4d/eval/common/depth.py +++ b/vis4d/eval/common/depth.py @@ -94,7 +94,7 @@ def _apply_mask( mask = (target > self.min_depth) & (target <= self.max_depth) return prediction[mask], target[mask] - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, prediction: ArrayLike, groundtruth: ArrayLike ) -> None: """Process a batch of data. diff --git a/vis4d/eval/common/flow.py b/vis4d/eval/common/flow.py index ec478061..1a591587 100644 --- a/vis4d/eval/common/flow.py +++ b/vis4d/eval/common/flow.py @@ -68,7 +68,7 @@ def _apply_mask( mask = np.sum(np.abs(target), axis=-1) <= self.max_flow return prediction[mask], target[mask] - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, prediction: ArrayLike, groundtruth: ArrayLike ) -> None: """Process a batch of data. diff --git a/vis4d/eval/common/seg.py b/vis4d/eval/common/seg.py index 8a6430da..9d067acf 100644 --- a/vis4d/eval/common/seg.py +++ b/vis4d/eval/common/seg.py @@ -86,7 +86,7 @@ def reset(self) -> None: """Reset the saved predictions to start new round of evaluation.""" self._confusion_matrix = None - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, prediction: ArrayLike, groundtruth: ArrayLike ) -> None: """Process sample and update confusion matrix. @@ -100,7 +100,7 @@ def process_batch( # type: ignore # pylint: disable=arguments-differ """ confusion_matrix = self.calc_confusion_matrix( array_to_numpy(prediction, n_dims=None, dtype=np.float32), - array_to_numpy(groundtruth, n_dims=None, dtype=np.int64), # type: ignore # pylint: disable=line-too-long + array_to_numpy(groundtruth, n_dims=None, dtype=np.int64), ) if self._confusion_matrix is None: diff --git a/vis4d/eval/nuscenes/detect3d.py b/vis4d/eval/nuscenes/detect3d.py index 178b9c3c..c2817120 100644 --- a/vis4d/eval/nuscenes/detect3d.py +++ b/vis4d/eval/nuscenes/detect3d.py @@ -258,7 +258,7 @@ def _process_detect_3d( annos.append(nusc_anno) self.detect_3d[token] = annos - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, tokens: list[str], boxes_3d: list[ArrayLike], diff --git a/vis4d/eval/nuscenes/track3d.py b/vis4d/eval/nuscenes/track3d.py index a1b113c6..77d7f899 100644 --- a/vis4d/eval/nuscenes/track3d.py +++ b/vis4d/eval/nuscenes/track3d.py @@ -134,7 +134,7 @@ def _process_track_3d( annos.append(nusc_anno) self.tracks_3d[token] = annos - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, tokens: list[str], boxes_3d: list[ArrayLike], diff --git a/vis4d/eval/scalabel/base.py b/vis4d/eval/scalabel/base.py index 61a3e153..d96f6099 100644 --- a/vis4d/eval/scalabel/base.py +++ b/vis4d/eval/scalabel/base.py @@ -60,12 +60,6 @@ def reset(self) -> None: """Reset the evaluator.""" self.frames = [] - def process_batch( # type: ignore # pragma: no cover - self, *args: Any, **kwargs: Any - ) -> None: - """Process sample and update confusion matrix.""" - raise NotImplementedError - def evaluate(self, metric: str) -> tuple[MetricLogs, str]: """Evaluate the dataset.""" raise NotImplementedError diff --git a/vis4d/eval/scalabel/detect.py b/vis4d/eval/scalabel/detect.py index dae77667..8e0a8044 100644 --- a/vis4d/eval/scalabel/detect.py +++ b/vis4d/eval/scalabel/detect.py @@ -44,7 +44,7 @@ def metrics(self) -> list[str]: """Supported metrics.""" return [self.METRICS_DET, self.METRICS_INS_SEG] - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, frame_ids: list[int], sample_names: list[str], diff --git a/vis4d/eval/scalabel/track.py b/vis4d/eval/scalabel/track.py index 7222b1eb..fb80132c 100644 --- a/vis4d/eval/scalabel/track.py +++ b/vis4d/eval/scalabel/track.py @@ -46,7 +46,7 @@ def metrics(self) -> list[str]: """Supported metrics.""" return [self.METRICS_TRACK, self.METRICS_SEG_TRACK] - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, frame_ids: list[int], sample_names: list[str], diff --git a/vis4d/eval/shift/multitask_writer.py b/vis4d/eval/shift/multitask_writer.py index 9d918700..f94a0164 100644 --- a/vis4d/eval/shift/multitask_writer.py +++ b/vis4d/eval/shift/multitask_writer.py @@ -104,7 +104,7 @@ def _write_flow( """ raise NotImplementedError - def process_batch( # type: ignore # pylint: disable=arguments-differ + def process_batch( self, frame_ids: list[int], sample_names: list[str], diff --git a/vis4d/op/base/dla.py b/vis4d/op/base/dla.py index 8d24cc47..ceb1d4ff 100644 --- a/vis4d/op/base/dla.py +++ b/vis4d/op/base/dla.py @@ -341,7 +341,9 @@ def __init__( bias=False, padding=(kernel_size - 1) // 2, ) - self.bn = nn.BatchNorm2d(out_channels, momentum=BN_MOMENTUM) + self.bn = nn.BatchNorm2d( # pylint: disable=invalid-name + out_channels, momentum=BN_MOMENTUM + ) self.relu = nn.ReLU(inplace=True) self.residual = residual self.with_cp = with_cp @@ -500,7 +502,7 @@ def __init__( ) -> None: """Creates an instance of the class.""" super().__init__() - assert name in DLA_ARCH_SETTINGS, f"name is not supported!" + assert name in DLA_ARCH_SETTINGS, f"{name} is not supported!" levels, channels, residual_root, block = DLA_ARCH_SETTINGS[name] diff --git a/vis4d/op/base/pointnet.py b/vis4d/op/base/pointnet.py index 67588cae..39eb638c 100644 --- a/vis4d/op/base/pointnet.py +++ b/vis4d/op/base/pointnet.py @@ -101,7 +101,7 @@ def __init__( self.activation_ = getattr(nn, activation_cls)() # Create norms - norm_fn: Callable[[int], nn.Module] = ( + norm_fn: Callable[[int], nn.Module] | None = ( getattr(nn, norm_cls) if norm_cls is not None else None ) @@ -249,7 +249,7 @@ def __init__( activation = getattr(nn, activation_cls)() # Create norms - norm_fn: Callable[[int], nn.Module] = ( + norm_fn: Callable[[int], nn.Module] | None = ( getattr(nn, norm_cls) if norm_cls is not None else None ) diff --git a/vis4d/op/base/pointnetpp.py b/vis4d/op/base/pointnetpp.py index 0cc40f28..d3f4105f 100644 --- a/vis4d/op/base/pointnetpp.py +++ b/vis4d/op/base/pointnetpp.py @@ -229,13 +229,13 @@ def __init__( last_channel = in_channel # Create norms - norm_fn: Callable[[int], nn.Module] = ( + norm_fn: Callable[[int], nn.Module] | None = ( getattr(nn, norm_cls) if norm_cls is not None else None ) for out_channel in mlp: self.mlp_convs.append(nn.Conv2d(last_channel, out_channel, 1)) - if norm_cls is not None: + if norm_fn is not None: self.mlp_bns.append(norm_fn(out_channel)) last_channel = out_channel self.group_all = group_all diff --git a/vis4d/op/detect3d/qd_3dt.py b/vis4d/op/detect3d/qd_3dt.py index 6d11b167..02a3bd25 100644 --- a/vis4d/op/detect3d/qd_3dt.py +++ b/vis4d/op/detect3d/qd_3dt.py @@ -101,7 +101,7 @@ def get_default_box_codec( class QD3DTBBox3DHead(nn.Module): """This class implements the QD-3DT bounding box 3D head.""" - def __init__( # pylint: disable=too-many-arguments + def __init__( # pylint: disable=too-many-arguments, too-many-positional-arguments, line-too-long self, num_classes: int, proposal_pooler: None | RoIPooler = None, diff --git a/vis4d/op/fpp/fpn.py b/vis4d/op/fpp/fpn.py index a2856e11..0433437b 100644 --- a/vis4d/op/fpp/fpn.py +++ b/vis4d/op/fpp/fpn.py @@ -14,7 +14,9 @@ from torchvision.ops.feature_pyramid_network import ( ExtraFPNBlock as _ExtraFPNBlock, ) -from torchvision.ops.feature_pyramid_network import LastLevelMaxPool +from torchvision.ops.feature_pyramid_network import ( + LastLevelMaxPool, +) from .base import FeaturePyramidProcessing diff --git a/vis4d/op/layer/attention.py b/vis4d/op/layer/attention.py index 65701424..f3ba881e 100644 --- a/vis4d/op/layer/attention.py +++ b/vis4d/op/layer/attention.py @@ -117,6 +117,10 @@ def __init__( batch_first (bool): When it is True, Key, Query and Value are shape of (batch, n, embed_dim), otherwise (n, batch, embed_dim). Default to False. + need_weights (bool): Whether to return the attention weights. + If True, the output will be a tuple of (attn_output, + attn_output_weights) and not using FlashAttention. If False, + only the attn_output will be returned. Default to False. """ super().__init__() self.batch_first = batch_first diff --git a/vis4d/op/layer/ms_deform_attn.py b/vis4d/op/layer/ms_deform_attn.py index 3d3589c2..1ee8a753 100644 --- a/vis4d/op/layer/ms_deform_attn.py +++ b/vis4d/op/layer/ms_deform_attn.py @@ -61,7 +61,7 @@ def forward( # type: ignore @staticmethod @once_differentiable # type: ignore - def backward( + def backward( # type: ignore ctx, grad_output: Tensor ) -> tuple[Tensor, None, None, Tensor, Tensor, None]: """Backward pass.""" diff --git a/vis4d/op/mask/util.py b/vis4d/op/mask/util.py index 02a768b7..4e0b299c 100644 --- a/vis4d/op/mask/util.py +++ b/vis4d/op/mask/util.py @@ -8,7 +8,7 @@ from torch import Tensor -def _do_paste_mask( +def _do_paste_mask( # type: ignore masks: Tensor, boxes: Tensor, img_h: int, diff --git a/vis4d/vis/image/bbox3d_visualizer.py b/vis4d/vis/image/bbox3d_visualizer.py index 634680a8..1f336f48 100644 --- a/vis4d/vis/image/bbox3d_visualizer.py +++ b/vis4d/vis/image/bbox3d_visualizer.py @@ -94,6 +94,8 @@ def __init__( draw the trajectory. Defaults to 10. plot_trajectory (bool): If the trajectory should be plotted. Defaults to True. + save_boxes3d (bool): If the corners of 3D boxes should be saved to + disk in the format of npy. Defaults to False. canvas (CanvasBackend): Backend that is used to draw on images. If None a PillowCanvasBackend is used. viewer (ImageViewerBackend): Backend that is used show images. If @@ -131,11 +133,11 @@ def reset(self) -> None: """Reset visualizer.""" self._samples.clear() - def __repr__(self): + def __repr__(self) -> str: """Return string representation.""" return "BoundingBox3DVisualizer" - def process( # type: ignore # pylint: disable=arguments-differ + def process( # pylint: disable=arguments-differ self, cur_iter: int, images: list[ArrayLike], @@ -169,6 +171,9 @@ class ids each of shape [B, N]. Defaults to None. track ids each of shape [B, N]. Defaults to None. sequence_names (None | list[str], optional): List of sequence names of shape [B,]. Defaults to None. + categories (None | list[list[str]], optional): List of categories + for each image. Instead of class ids, the categories will be + used to label the boxes. Defaults to None. """ if self._run_on_batch(cur_iter): for batch, image in enumerate(images): @@ -223,6 +228,9 @@ def process_single_image( shape [N]. Defaults to None. sequence_name (None | str, optional): Sequence name. Defaults to None. + categories (None | list[str], optional): List of categories for + each box. Instead of class ids, the categories will be used to + label the boxes. Defaults to None. camera_name (None | str, optional): Camera name. Defaults to None. """ img_normalized = preprocess_image(image, mode=self.image_mode) @@ -237,14 +245,14 @@ def process_single_image( data_sample = DataSample( img_normalized, image_name, - intrinsics_np, # type: ignore - extrinsics_np, # type: ignore + intrinsics_np, + extrinsics_np, sequence_name, camera_name, [], ) - if len(boxes3d) != 0: + if len(boxes3d) != 0: # type: ignore for center, corners, label, color, track_id in zip( *preprocess_boxes3d( image_hw, @@ -354,7 +362,7 @@ def save_to_disk(self, cur_iter: int, output_folder: str) -> None: output_dir = output_folder image_name = f"{sample.image_name}.{self.file_type}" - image = self._draw_image(sample) + self._draw_image(sample) if sample.sequence_name is not None: output_dir = os.path.join(output_dir, sample.sequence_name) @@ -373,8 +381,6 @@ def save_to_disk(self, cur_iter: int, output_folder: str) -> None: corners, ) - return image - class MultiCameraBBox3DVisualizer(BoundingBox3DVisualizer): """Bounding box 3D visualizer class for multi-camera datasets.""" @@ -391,7 +397,7 @@ def __init__( self.cameras = cameras - def __repr__(self): + def __repr__(self) -> str: """Return string representation.""" return "MultiCameraBBox3DVisualizer" @@ -429,6 +435,9 @@ class ids each of shape [B, N]. Defaults to None. track ids each of shape [B, N]. Defaults to None. sequence_names (None | list[str], optional): List of sequence names of shape [B,]. Defaults to None. + categories (None | list[list[str]], optional): List of categories + for each image. Instead of class ids, the categories will be + used to label the boxes. Defaults to None. """ if self._run_on_batch(cur_iter): for idx, batch_images in enumerate(images): diff --git a/vis4d/vis/image/bev_visualizer.py b/vis4d/vis/image/bev_visualizer.py index 3208206f..fffc5e06 100644 --- a/vis4d/vis/image/bev_visualizer.py +++ b/vis4d/vis/image/bev_visualizer.py @@ -115,7 +115,7 @@ def __init__( self.canvas = canvas if canvas is not None else PillowCanvasBackend() self.viewer = viewer if viewer is not None else MatplotlibImageViewer() - def __repr__(self): + def __repr__(self) -> str: """Return string representation.""" return "BEVBBox3DVisualizer" @@ -123,7 +123,7 @@ def reset(self) -> None: """Reset visualizer.""" self._samples.clear() - def process( # type: ignore # pylint: disable=arguments-differ + def process( # pylint: disable=arguments-differ self, cur_iter: int, sample_names: list[list[str]] | list[str], @@ -172,13 +172,13 @@ def process_single( extrinsics_np = array_to_numpy(extrinsics, n_dims=2, dtype=np.float32) data_sample = DataSample( sample_name, - extrinsics_np, # type: ignore + extrinsics_np, sequence_name, [], ) boxes3d_lidar, boxes3d = self._get_lidar_and_global_boxes3d( - boxes3d, extrinsics_np # type: ignore + boxes3d, extrinsics_np ) corners = boxes3d_to_corners( diff --git a/vis4d/vis/image/bounding_box_visualizer.py b/vis4d/vis/image/bounding_box_visualizer.py index 7fb07597..5a436c89 100644 --- a/vis4d/vis/image/bounding_box_visualizer.py +++ b/vis4d/vis/image/bounding_box_visualizer.py @@ -59,9 +59,10 @@ def __init__( color map cat_mapping (dict[str, int]): Mapping from class names to class ids. Defaults to None. - file_type (str): Desired file type - canvas (CanvasBackend): Backend that is used to draw on images - viewer (ImageViewerBackend): Backend that is used show images + file_type (str): Desired file type. Defaults to "png". + width (int): Width of the bounding box lines. Defaults to 2. + canvas (CanvasBackend): Backend that is used to draw on images. + viewer (ImageViewerBackend): Backend that is used show images. """ super().__init__(*args, **kwargs) self._samples: list[DataSample] = [] @@ -76,11 +77,15 @@ def __init__( self.canvas = canvas self.viewer = viewer + def __repr__(self) -> str: + """Return string representation of the visualizer.""" + return "BoundingBoxVisualizer" + def reset(self) -> None: """Reset visualizer.""" self._samples.clear() - def process( # type: ignore # pylint: disable=arguments-differ + def process( # pylint: disable=arguments-differ self, cur_iter: int, images: list[ArrayLike], @@ -105,6 +110,9 @@ def process( # type: ignore # pylint: disable=arguments-differ class ids each of shape [N]. Defaults to None. track_ids (None | list[ArrayLikeInt], optional): List of predicted track ids each of shape [N]. Defaults to None. + categories (None | list[list[str]], optional): List of categories + for each image. Instead of class ids, the categories will be + used to label the boxes. Defaults to None. """ if self._run_on_batch(cur_iter): for idx, image in enumerate(images): @@ -141,6 +149,9 @@ def process_single_image( shape [N]. Defaults to None. track_ids (None | ArrayLikeInt, optional): Predicted track ids of shape [N]. Defaults to None. + categories (None | list[str], optional): List of categories for + each box. Instead of class ids, the categories will be used to + label the boxes. Defaults to None. """ img_normalized = preprocess_image(image, mode=self.image_mode) data_sample = DataSample(img_normalized, image_name, []) diff --git a/vis4d/vis/image/canvas/base.py b/vis4d/vis/image/canvas/base.py index 9025ff0e..6eb31eda 100644 --- a/vis4d/vis/image/canvas/base.py +++ b/vis4d/vis/image/canvas/base.py @@ -145,6 +145,7 @@ def draw_box_3d( intrinsics: NDArrayF32, width: int = 0, camera_near_clip: float = 0.15, + plot_heading: bool = True, ) -> None: """Draws a line between two points. @@ -156,6 +157,8 @@ def draw_box_3d( width (int, optional): The width of the line. Defaults to 0. camera_near_clip (float, optional): The near clipping plane of the camera. Defaults to 0.15. + plot_heading (bool, optional): If True, the heading of the box will + be plotted as a line. Defaults to True. """ raise NotImplementedError diff --git a/vis4d/vis/image/functional.py b/vis4d/vis/image/functional.py index 4fbb7118..b9355c6f 100644 --- a/vis4d/vis/image/functional.py +++ b/vis4d/vis/image/functional.py @@ -4,7 +4,7 @@ import numpy as np -from vis4d.common.array import array_to_numpy, arrays_to_numpy +from vis4d.common.array import array_to_numpy from vis4d.common.typing import ( ArrayLike, ArrayLikeBool, @@ -371,15 +371,23 @@ def imshow_track_matches( to use. Defaults to MatplotlibImageViewer(). file_path (str): The path to save the image to. Defaults to None. """ - key_imgs_np = arrays_to_numpy(*key_imgs, n_dims=3, dtype=np.float32) - ref_imgs_np = arrays_to_numpy(*ref_imgs, n_dims=3, dtype=np.float32) - key_boxes_np = arrays_to_numpy(*key_boxes, n_dims=2, dtype=np.float32) - ref_boxes_np = arrays_to_numpy(*ref_boxes, n_dims=2, dtype=np.float32) - key_track_ids_np = arrays_to_numpy( - *key_track_ids, n_dims=1, dtype=np.int32 + key_imgs_np = tuple( + array_to_numpy(img, n_dims=3, dtype=np.float32) for img in key_imgs ) - ref_track_ids_np = arrays_to_numpy( - *ref_track_ids, n_dims=1, dtype=np.int32 + ref_imgs_np = tuple( + array_to_numpy(img, n_dims=3, dtype=np.float32) for img in ref_imgs + ) + key_boxes_np = tuple( + array_to_numpy(b, n_dims=2, dtype=np.float32) for b in key_boxes + ) + ref_boxes_np = tuple( + array_to_numpy(b, n_dims=2, dtype=np.float32) for b in ref_boxes + ) + key_track_ids_np = tuple( + array_to_numpy(t, n_dims=1, dtype=np.int32) for t in key_track_ids + ) + ref_track_ids_np = tuple( + array_to_numpy(t, n_dims=1, dtype=np.int32) for t in ref_track_ids ) for batch_i, (key_box, ref_box) in enumerate( diff --git a/vis4d/vis/image/seg_mask_visualizer.py b/vis4d/vis/image/seg_mask_visualizer.py index faaddb2d..7b95451a 100644 --- a/vis4d/vis/image/seg_mask_visualizer.py +++ b/vis4d/vis/image/seg_mask_visualizer.py @@ -120,7 +120,7 @@ def _draw_image(self, sample: ImageWithSegMask) -> NDArrayUI8: self.canvas.draw_bitmap(mask.mask, mask.color) return self.canvas.as_numpy_image() - def process( # type: ignore # pylint: disable=arguments-differ + def process( # pylint: disable=arguments-differ self, cur_iter: int, images: list[ArrayLikeFloat], diff --git a/vis4d/vis/image/util.py b/vis4d/vis/image/util.py index cf057337..d32f223a 100644 --- a/vis4d/vis/image/util.py +++ b/vis4d/vis/image/util.py @@ -108,6 +108,8 @@ def preprocess_boxes( to color tuple (0-255). default_color (tuple[int, int, int]): fallback color for boxes of no class or track id is given. + categories (None | list[str], optional): List of categories for each + box. Returns: boxes_proc (list[tuple[float, float, float, float]]): List of box @@ -279,7 +281,8 @@ def preprocess_boxes3d( category = None labels_proc.append(_get_box_label(category, score, track_id)) - track_ids_proc.append(track_id) + if track_id is not None: + track_ids_proc.append(track_id) return centers_proc, corners_proc, labels_proc, colors_proc, track_ids_proc @@ -309,9 +312,7 @@ def preprocess_masks( Raises: ValueError: If the masks have an invalid shape. """ - masks_np: NDArrayUI8 = array_to_numpy( # type: ignore - masks, n_dims=None, dtype=np.uint8 - ) + masks_np = array_to_numpy(masks, n_dims=None, dtype=np.uint8) if len(masks_np.shape) == 2: masks_np, class_ids = _to_binary_mask(masks_np) @@ -358,7 +359,7 @@ def preprocess_image(image: ArrayLike, mode: str = "RGB") -> NDArrayUI8: # Convert torch to numpy convention if not image_np.shape[-1] == 3: - image_np = np.transpose(image_np, (1, 2, 0)) # type: ignore + image_np = np.transpose(image_np, (1, 2, 0)) # Convert image_np to [0, 255] min_val, max_val = ( diff --git a/vis4d/vis/pointcloud/pointcloud_visualizer.py b/vis4d/vis/pointcloud/pointcloud_visualizer.py index e0dbc315..ae272113 100644 --- a/vis4d/vis/pointcloud/pointcloud_visualizer.py +++ b/vis4d/vis/pointcloud/pointcloud_visualizer.py @@ -110,7 +110,7 @@ def process_single( points_xyz, colors=colors, classes=semantics, instances=instances ) - def process( # type: ignore # pylint: disable=arguments-differ + def process( # pylint: disable=arguments-differ self, cur_iter: int, points_xyz: NDArrayF64, diff --git a/vis4d/vis/pointcloud/scene.py b/vis4d/vis/pointcloud/scene.py index 37f941d3..963a99f7 100644 --- a/vis4d/vis/pointcloud/scene.py +++ b/vis4d/vis/pointcloud/scene.py @@ -112,7 +112,7 @@ def __init__( else: self.num_instances = len( np.unique( - self.classes * np.max(self.instances) + self.instances # type: ignore # pylint: disable=line-too-long + self.classes * np.max(self.instances) + self.instances ) ) diff --git a/vis4d/zoo/base/dataloader.py b/vis4d/zoo/base/dataloader.py index 0998852d..91a32695 100644 --- a/vis4d/zoo/base/dataloader.py +++ b/vis4d/zoo/base/dataloader.py @@ -60,6 +60,8 @@ def get_train_dataloader_cfg( Defaults to True. shuffle (bool | FieldReference, optional): Whether to shuffle the dataset. Defaults to True. + aspect_ratio_grouping (bool | FieldReference, optional): Whether to + group the samples by aspect ratio. Defaults to False. Returns: ConfigDict: Configuration that can be instantiate as a dataloader. diff --git a/vis4d/zoo/base/datasets/shift/common.py b/vis4d/zoo/base/datasets/shift/common.py index 6d38d303..add1e839 100644 --- a/vis4d/zoo/base/datasets/shift/common.py +++ b/vis4d/zoo/base/datasets/shift/common.py @@ -346,7 +346,7 @@ def get_shift_dataloader_config( return data -def get_shift_config( # pylint: disable=too-many-arguments +def get_shift_config( # pylint: disable=too-many-arguments, too-many-positional-arguments, line-too-long data_root: str = "data/shift/images", train_split: str = "train", train_framerate: str = "images", diff --git a/vis4d/zoo/base/runtime.py b/vis4d/zoo/base/runtime.py index 84034747..d127ace7 100644 --- a/vis4d/zoo/base/runtime.py +++ b/vis4d/zoo/base/runtime.py @@ -5,7 +5,7 @@ import platform from datetime import datetime -from ml_collections import ConfigDict, FieldReference +from ml_collections import ConfigDict from vis4d.config import class_config from vis4d.config.typing import ExperimentConfig @@ -65,8 +65,6 @@ def get_default_cfg( def get_default_callbacks_cfg( - output_dir: str | FieldReference, - checkpoint_period: int = 1, epoch_based: bool = True, refresh_rate: int = 50, ) -> list[ConfigDict]: @@ -74,11 +72,8 @@ def get_default_callbacks_cfg( It will return a list of callbacks config including: - LoggingCallback - - CheckpointCallback Args: - output_dir (str | FieldReference): Output directory. - checkpoint_period (int, optional): Checkpoint period. Defaults to 1. epoch_based (bool, optional): Whether to use epoch based logging. refresh_rate (int, optional): Refresh rate for the logging. Defaults to 50. diff --git a/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_1x_bdd100k.py b/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_1x_bdd100k.py index ffe7f884..cfb13fcd 100644 --- a/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_1x_bdd100k.py +++ b/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_1x_bdd100k.py @@ -120,7 +120,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_3x_bdd100k.py b/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_3x_bdd100k.py index dafee957..b9e12b39 100644 --- a/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_3x_bdd100k.py +++ b/vis4d/zoo/bdd100k/faster_rcnn/faster_rcnn_r50_3x_bdd100k.py @@ -121,7 +121,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_1x_bdd100k.py b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_1x_bdd100k.py index d52e07f2..a9e50b76 100644 --- a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_1x_bdd100k.py +++ b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_1x_bdd100k.py @@ -126,7 +126,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_3x_bdd100k.py b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_3x_bdd100k.py index 719eb1d0..25e93e1c 100644 --- a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_3x_bdd100k.py +++ b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_3x_bdd100k.py @@ -126,7 +126,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_5x_bdd100k.py b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_5x_bdd100k.py index 8aaf9431..c4fcec93 100644 --- a/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_5x_bdd100k.py +++ b/vis4d/zoo/bdd100k/mask_rcnn/mask_rcnn_r50_5x_bdd100k.py @@ -126,7 +126,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/bdd100k/qdtrack/qdtrack_frcnn_r50_fpn_1x_bdd100k.py b/vis4d/zoo/bdd100k/qdtrack/qdtrack_frcnn_r50_fpn_1x_bdd100k.py index d2af3037..0e3c878a 100644 --- a/vis4d/zoo/bdd100k/qdtrack/qdtrack_frcnn_r50_fpn_1x_bdd100k.py +++ b/vis4d/zoo/bdd100k/qdtrack/qdtrack_frcnn_r50_fpn_1x_bdd100k.py @@ -110,7 +110,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Evaluator callbacks.append( diff --git a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r101_80k_bdd100k.py b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r101_80k_bdd100k.py index 12510ae7..c4c3701f 100644 --- a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r101_80k_bdd100k.py +++ b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r101_80k_bdd100k.py @@ -150,11 +150,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg( - config.output_dir, - epoch_based=False, - checkpoint_period=config.val_check_interval, - ) + callbacks = get_default_callbacks_cfg(epoch_based=False) # Evaluator callbacks.append( diff --git a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_40k_bdd100k.py b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_40k_bdd100k.py index 938c004d..6301745b 100644 --- a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_40k_bdd100k.py +++ b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_40k_bdd100k.py @@ -140,11 +140,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg( - config.output_dir, - epoch_based=False, - checkpoint_period=config.val_check_interval, - ) + callbacks = get_default_callbacks_cfg(epoch_based=False) # Evaluator callbacks.append( diff --git a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_80k_bdd100k.py b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_80k_bdd100k.py index 53c29ba3..a3682d24 100644 --- a/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_80k_bdd100k.py +++ b/vis4d/zoo/bdd100k/semantic_fpn/semantic_fpn_r50_80k_bdd100k.py @@ -140,11 +140,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg( - config.output_dir, - epoch_based=False, - checkpoint_period=config.val_check_interval, - ) + callbacks = get_default_callbacks_cfg(epoch_based=False) # Evaluator callbacks.append( diff --git a/vis4d/zoo/bevformer/bevformer_base.py b/vis4d/zoo/bevformer/bevformer_base.py index 3d4cdd9f..5c386e5b 100644 --- a/vis4d/zoo/bevformer/bevformer_base.py +++ b/vis4d/zoo/bevformer/bevformer_base.py @@ -122,7 +122,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Evaluator callbacks.append( diff --git a/vis4d/zoo/bevformer/bevformer_tiny.py b/vis4d/zoo/bevformer/bevformer_tiny.py index 1fba154f..db82f2a5 100644 --- a/vis4d/zoo/bevformer/bevformer_tiny.py +++ b/vis4d/zoo/bevformer/bevformer_tiny.py @@ -160,7 +160,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Evaluator callbacks.append( diff --git a/vis4d/zoo/bevformer/bevformer_vis.py b/vis4d/zoo/bevformer/bevformer_vis.py index fee098fe..97b411da 100644 --- a/vis4d/zoo/bevformer/bevformer_vis.py +++ b/vis4d/zoo/bevformer/bevformer_vis.py @@ -35,7 +35,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py index 8bed245d..5d2c928b 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_kf3d_24e_nusc.py @@ -155,7 +155,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Evaluator callbacks.append( diff --git a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_pure_det_nusc.py b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_pure_det_nusc.py index ae44762c..3a9afd1b 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_pure_det_nusc.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r101_fpn_pure_det_nusc.py @@ -60,7 +60,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Evaluator callbacks.append( diff --git a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py index 0fc047db..61bfc0f4 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_frcnn_r50_fpn_kf3d_12e_nusc.py @@ -155,7 +155,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Evaluator callbacks.append( diff --git a/vis4d/zoo/cc_3dt/cc_3dt_nusc_test.py b/vis4d/zoo/cc_3dt/cc_3dt_nusc_test.py index 27a2bd04..192b09b2 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_nusc_test.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_nusc_test.py @@ -68,7 +68,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Evaluator callbacks.append( diff --git a/vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py b/vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py index ce7521eb..b2301164 100644 --- a/vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py +++ b/vis4d/zoo/cc_3dt/cc_3dt_nusc_vis.py @@ -36,7 +36,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py b/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py index b7d26a38..eb5fc279 100644 --- a/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py +++ b/vis4d/zoo/cc_3dt/velo_lstm_bevformer_base_100e_nusc.py @@ -134,7 +134,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() config.callbacks = callbacks diff --git a/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py b/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py index aa51e6ea..4c3b3406 100644 --- a/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py +++ b/vis4d/zoo/cc_3dt/velo_lstm_frcnn_r101_fpn_100e_nusc.py @@ -133,7 +133,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() config.callbacks = callbacks diff --git a/vis4d/zoo/faster_rcnn/faster_rcnn_coco.py b/vis4d/zoo/faster_rcnn/faster_rcnn_coco.py index e0d6d66c..8fccda47 100644 --- a/vis4d/zoo/faster_rcnn/faster_rcnn_coco.py +++ b/vis4d/zoo/faster_rcnn/faster_rcnn_coco.py @@ -2,18 +2,11 @@ """Faster RCNN COCO training example.""" from __future__ import annotations -import lightning.pytorch as pl -import numpy as np from torch.optim.lr_scheduler import LinearLR, MultiStepLR from torch.optim.sgd import SGD from vis4d.config import class_config -from vis4d.config.sweep import grid_search -from vis4d.config.typing import ( - ExperimentConfig, - ExperimentParameters, - ParameterSweepConfig, -) +from vis4d.config.typing import ExperimentConfig, ExperimentParameters from vis4d.data.io.hdf5 import HDF5Backend from vis4d.engine.callbacks import EvaluatorCallback, VisualizerCallback from vis4d.engine.connectors import CallbackConnector, DataConnector @@ -136,14 +129,14 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( class_config( VisualizerCallback, visualizer=class_config(BoundingBoxVisualizer, vis_freq=100), - save_prefix=config.output_dir, + output_dir=config.output_dir, test_connector=class_config( CallbackConnector, key_mapping=CONN_BBOX_2D_VIS ), @@ -174,29 +167,4 @@ def get_config() -> ExperimentConfig: pl_trainer.max_epochs = params.num_epochs config.pl_trainer = pl_trainer - # PL Callbacks - pl_callbacks: list[pl.callbacks.Callback] = [] - config.pl_callbacks = pl_callbacks - return config.value_mode() - - -def get_sweep() -> ParameterSweepConfig: # pragma: no cover - """Returns the config dict for a grid search over learning rate. - - The name of the experiments will also be updated to include the learning - rate in the format "lr_{params.lr:.3f}_". - - Returns: - ParameterSweepConfig: The configuration that can be used to run a grid - search. It can be passed to replicate_config to create a list of - configs that can be used to run a grid search. - """ - # Here we define the parameters that we want to sweep over. - # In order to sweep over multiple parameters, we can pass a list of - # parameters to the grid_search function. - sweep_config = grid_search("params.lr", list(np.linspace(0.001, 0.01, 3))) - - # Here we update the name of the experiment to include the learning rate. - sweep_config.suffix = "lr_{params.lr:.3f}_" - return sweep_config diff --git a/vis4d/zoo/fcn_resnet/fcn_resnet_coco.py b/vis4d/zoo/fcn_resnet/fcn_resnet_coco.py index 1baad29b..8a77b45f 100644 --- a/vis4d/zoo/fcn_resnet/fcn_resnet_coco.py +++ b/vis4d/zoo/fcn_resnet/fcn_resnet_coco.py @@ -140,11 +140,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg( - config.output_dir, - epoch_based=False, - checkpoint_period=config.val_check_interval, - ) + callbacks = get_default_callbacks_cfg(epoch_based=False) config.callbacks = callbacks diff --git a/vis4d/zoo/mask_rcnn/mask_rcnn_coco.py b/vis4d/zoo/mask_rcnn/mask_rcnn_coco.py index cc354626..260bd8c0 100644 --- a/vis4d/zoo/mask_rcnn/mask_rcnn_coco.py +++ b/vis4d/zoo/mask_rcnn/mask_rcnn_coco.py @@ -148,7 +148,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/qdtrack/qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py b/vis4d/zoo/qdtrack/qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py index 0a78a559..497186f7 100644 --- a/vis4d/zoo/qdtrack/qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py +++ b/vis4d/zoo/qdtrack/qdtrack_frcnn_r50_fpn_augs_1x_bdd100k.py @@ -116,7 +116,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Mode switch for strong augmentations callbacks += [class_config(YOLOXModeSwitchCallback, switch_epoch=9)] diff --git a/vis4d/zoo/qdtrack/qdtrack_yolox_x_25e_bdd100k.py b/vis4d/zoo/qdtrack/qdtrack_yolox_x_25e_bdd100k.py index 01bbfa8d..160a62bb 100644 --- a/vis4d/zoo/qdtrack/qdtrack_yolox_x_25e_bdd100k.py +++ b/vis4d/zoo/qdtrack/qdtrack_yolox_x_25e_bdd100k.py @@ -101,7 +101,7 @@ def get_config() -> ExperimentConfig: ###################################################### # Logger and Checkpoint callbacks = get_default_callbacks_cfg( - config.output_dir, refresh_rate=config.log_every_n_steps + refresh_rate=config.log_every_n_steps ) # YOLOX callbacks diff --git a/vis4d/zoo/retinanet/retinanet_coco.py b/vis4d/zoo/retinanet/retinanet_coco.py index 6d26b54c..e0b8df8b 100644 --- a/vis4d/zoo/retinanet/retinanet_coco.py +++ b/vis4d/zoo/retinanet/retinanet_coco.py @@ -162,7 +162,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_12e_shift.py b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_12e_shift.py index 785a14b4..90df0163 100644 --- a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_12e_shift.py +++ b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_12e_shift.py @@ -126,7 +126,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_36e_shift.py b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_36e_shift.py index 0dcc7b01..afe37738 100644 --- a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_36e_shift.py +++ b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_36e_shift.py @@ -126,7 +126,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_6e_shift_all_domains.py b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_6e_shift_all_domains.py index d0d301df..76bcc820 100644 --- a/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_6e_shift_all_domains.py +++ b/vis4d/zoo/shift/faster_rcnn/faster_rcnn_r50_6e_shift_all_domains.py @@ -126,7 +126,7 @@ def get_config() -> ExperimentConfig: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_12e_shift.py b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_12e_shift.py index 51dca6df..53ce37b7 100644 --- a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_12e_shift.py +++ b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_12e_shift.py @@ -127,7 +127,7 @@ def get_config() -> FieldConfigDict: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_36e_shift.py b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_36e_shift.py index 939fe5f9..2a3b3eb4 100644 --- a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_36e_shift.py +++ b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_36e_shift.py @@ -127,7 +127,7 @@ def get_config() -> FieldConfigDict: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_6e_shift_all_domains.py b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_6e_shift_all_domains.py index 3e461e3c..d03e1c13 100644 --- a/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_6e_shift_all_domains.py +++ b/vis4d/zoo/shift/mask_rcnn/mask_rcnn_r50_6e_shift_all_domains.py @@ -127,7 +127,7 @@ def get_config() -> FieldConfigDict: ## CALLBACKS ## ###################################################### # Logger and Checkpoint - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # Visualizer callbacks.append( diff --git a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift.py b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift.py index 312a7672..b41cede5 100644 --- a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift.py +++ b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift.py @@ -143,11 +143,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg( - config.output_dir, - epoch_based=False, - checkpoint_period=config.val_check_interval, - ) + callbacks = get_default_callbacks_cfg(epoch_based=False) # Evaluator callbacks.append( diff --git a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift_all_domains.py b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift_all_domains.py index aacaf4a9..94ed983f 100644 --- a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift_all_domains.py +++ b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_160k_shift_all_domains.py @@ -145,11 +145,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg( - config.output_dir, - epoch_based=False, - checkpoint_period=config.val_check_interval, - ) + callbacks = get_default_callbacks_cfg(epoch_based=False) # Evaluator callbacks.append( diff --git a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift.py b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift.py index 5185df09..70bc8918 100644 --- a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift.py +++ b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift.py @@ -143,11 +143,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg( - config.output_dir, - epoch_based=False, - checkpoint_period=config.val_check_interval, - ) + callbacks = get_default_callbacks_cfg(epoch_based=False) # Evaluator callbacks.append( diff --git a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift_all_domains.py b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift_all_domains.py index e1cea254..789ab175 100644 --- a/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift_all_domains.py +++ b/vis4d/zoo/shift/semantic_fpn/semantic_fpn_r50_40k_shift_all_domains.py @@ -143,11 +143,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg( - config.output_dir, - epoch_based=False, - checkpoint_period=config.val_check_interval, - ) + callbacks = get_default_callbacks_cfg(epoch_based=False) # Evaluator callbacks.append( diff --git a/vis4d/zoo/util.py b/vis4d/zoo/util.py new file mode 100644 index 00000000..b58c5f87 --- /dev/null +++ b/vis4d/zoo/util.py @@ -0,0 +1,14 @@ +"""Utility functions for the zoo module.""" + +from __future__ import annotations + +import importlib + +from vis4d.config.typing import ExperimentConfig + + +def get_config_for_name(config_name: str) -> ExperimentConfig: + """Get config for name.""" + module = importlib.import_module("vis4d.zoo." + config_name) + + return module.get_config() diff --git a/vis4d/zoo/vit/vit_small_imagenet.py b/vis4d/zoo/vit/vit_small_imagenet.py index 92b4ac81..88f21906 100644 --- a/vis4d/zoo/vit/vit_small_imagenet.py +++ b/vis4d/zoo/vit/vit_small_imagenet.py @@ -150,7 +150,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## GENERIC CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # EMA callback callbacks.append(class_config(EMACallback)) diff --git a/vis4d/zoo/vit/vit_tiny_imagenet.py b/vis4d/zoo/vit/vit_tiny_imagenet.py index d915ca17..a109da93 100644 --- a/vis4d/zoo/vit/vit_tiny_imagenet.py +++ b/vis4d/zoo/vit/vit_tiny_imagenet.py @@ -150,7 +150,7 @@ def get_config() -> ExperimentConfig: ###################################################### ## GENERIC CALLBACKS ## ###################################################### - callbacks = get_default_callbacks_cfg(config.output_dir) + callbacks = get_default_callbacks_cfg() # EMA callback callbacks.append(class_config(EMACallback)) diff --git a/vis4d/zoo/yolox/yolox_s_300e_coco.py b/vis4d/zoo/yolox/yolox_s_300e_coco.py index 7403d362..8b654980 100644 --- a/vis4d/zoo/yolox/yolox_s_300e_coco.py +++ b/vis4d/zoo/yolox/yolox_s_300e_coco.py @@ -98,7 +98,7 @@ def get_config() -> ExperimentConfig: ###################################################### # Logger and Checkpoint callbacks = get_default_callbacks_cfg( - config.output_dir, refresh_rate=config.log_every_n_steps + refresh_rate=config.log_every_n_steps ) # YOLOX callbacks diff --git a/vis4d/zoo/yolox/yolox_tiny_300e_coco.py b/vis4d/zoo/yolox/yolox_tiny_300e_coco.py index e1c8d50f..7d63b07c 100644 --- a/vis4d/zoo/yolox/yolox_tiny_300e_coco.py +++ b/vis4d/zoo/yolox/yolox_tiny_300e_coco.py @@ -101,7 +101,7 @@ def get_config() -> ExperimentConfig: ###################################################### # Logger and Checkpoint callbacks = get_default_callbacks_cfg( - config.output_dir, refresh_rate=config.log_every_n_steps + refresh_rate=config.log_every_n_steps ) # YOLOX callbacks From 049f3b9825fe00f048fc4a784957d9b69286fa55 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 22 Jul 2025 15:36:17 +0200 Subject: [PATCH 43/50] feat: lint. --- .github/dependabot.yml | 11 -------- .github/workflows/ci.yml | 6 ++--- .gitignore | 3 +-- .pre-commit-config.yaml | 32 ----------------------- vis4d/common/ckpt.py | 2 +- vis4d/data/datasets/coco.py | 8 +++--- vis4d/data/datasets/util.py | 5 ++++ vis4d/engine/callbacks/util.py | 4 +-- vis4d/engine/callbacks/yolox_callbacks.py | 2 +- vis4d/op/base/vit.py | 2 +- vis4d/op/box/poolers/__init__.py | 13 +++++++-- vis4d/op/detect3d/qd_3dt.py | 6 ++--- vis4d/op/track/qdtrack.py | 8 +++--- 13 files changed, 37 insertions(+), 65 deletions(-) delete mode 100644 .github/dependabot.yml delete mode 100644 .pre-commit-config.yaml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index a17f6a0b..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,11 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "pip" # See documentation for possible values - directory: "/requirements.txt" # Location of package manifests - schedule: - interval: "daily" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f9c371c..214ed0f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: - name: set up python uses: actions/setup-python@v2 with: - python-version: "3.10" + python-version: "3.11" - name: install run: | @@ -59,7 +59,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10"] + python-version: ["3.11"] steps: - uses: actions/checkout@v2 @@ -89,7 +89,7 @@ jobs: run: python3 -m coverage run --source=vis4d -m pytest --pyargs tests - name: test coverage - run: python3 -m coverage report --fail-under=88 -m + run: python3 -m coverage report -m - name: build run: python3 -m build diff --git a/.gitignore b/.gitignore index 7b72005b..fc099e2e 100644 --- a/.gitignore +++ b/.gitignore @@ -61,14 +61,13 @@ doc/media # python build build/ dist/ -scalabel.egg-info +vis4d.egg-info # coverage .coverage* # package default workspace vis4d-workspace -vis4d.egg-info *.tmp diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 84bbcf27..00000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,32 +0,0 @@ -fail_fast: true -repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 - hooks: - - id: end-of-file-fixer - - id: trailing-whitespace - - id: check-yaml - - id: check-merge-conflict - - id: requirements-txt-fixer - - id: debug-statements - - repo: https://github.com/psf/black - rev: 23.1.0 - hooks: - - id: black - - repo: https://github.com/pycqa/isort - rev: 5.10.1 - hooks: - - id: isort -# - repo: https://github.com/pre-commit/mirrors-pylint -# rev: v2.7.4 -# hooks: -# - id: pylint -# - repo: https://github.com/pycqa/pydocstyle -# rev: 6.1.1 -# hooks: -# - id: pydocstyle -# args: [--convention=google] -# - repo: https://github.com/pre-commit/mirrors-mypy -# rev: v0.991 -# hooks: -# - id: mypy diff --git a/vis4d/common/ckpt.py b/vis4d/common/ckpt.py index c4ad64b4..d5e36faa 100644 --- a/vis4d/common/ckpt.py +++ b/vis4d/common/ckpt.py @@ -328,7 +328,7 @@ def load(module: nn.Module, prefix: str = "") -> None: # recursively check parallel module in case that the model has a # complicated structure, e.g., nn.Module(nn.Module(DDP)) if is_module_wrapper(module): - module = module.module + module = module.module # type: ignore local_metadata = ( {} if metadata is None else metadata.get(prefix[:-1], {}) ) diff --git a/vis4d/data/datasets/coco.py b/vis4d/data/datasets/coco.py index 225ede7b..0a64e546 100644 --- a/vis4d/data/datasets/coco.py +++ b/vis4d/data/datasets/coco.py @@ -16,7 +16,7 @@ from vis4d.data.typing import DictData from .base import Dataset -from .util import CacheMappingMixin, im_decode +from .util import CacheMappingMixin, get_category_names, im_decode # COCO detection coco_det_map = { @@ -204,8 +204,10 @@ def __init__( cached_file_path=cached_file_path, ) - # TODO: Control category names depending on the task - self.category_names = sorted(coco_det_map, key=coco_det_map.get) # type: ignore # pylint: disable=line-too-long + if self.use_pascal_voc_cats: + self.category_names = get_category_names(coco_seg_map) + else: + self.category_names = get_category_names(coco_det_map) def __repr__(self) -> str: """Concise representation of the dataset.""" diff --git a/vis4d/data/datasets/util.py b/vis4d/data/datasets/util.py index aeb377ff..cdb23225 100644 --- a/vis4d/data/datasets/util.py +++ b/vis4d/data/datasets/util.py @@ -360,3 +360,8 @@ def short_name(name: str) -> str: f"Distribution of instances among all {num_classes} categories:\n" + colored(table, "cyan") ) + + +def get_category_names(det_mapping: dict[str, int]) -> list[str]: + """Get category names from a mapping of category names to ids.""" + return sorted(det_mapping, key=det_mapping.get) # type: ignore diff --git a/vis4d/engine/callbacks/util.py b/vis4d/engine/callbacks/util.py index 25d66b0b..e46038a8 100644 --- a/vis4d/engine/callbacks/util.py +++ b/vis4d/engine/callbacks/util.py @@ -18,7 +18,7 @@ def get_model(model: pl.LightningModule) -> nn.Module: def get_loss_module(loss_module: pl.LightningModule) -> LossModule: """Get loss_module from pl module.""" - assert ( - loss_module.loss_module is not None + assert hasattr(loss_module, "loss_module") and isinstance( + loss_module.loss_module, LossModule ), "Loss module is not set in the training module." return loss_module.loss_module diff --git a/vis4d/engine/callbacks/yolox_callbacks.py b/vis4d/engine/callbacks/yolox_callbacks.py index 86aee489..dfd63ad3 100644 --- a/vis4d/engine/callbacks/yolox_callbacks.py +++ b/vis4d/engine/callbacks/yolox_callbacks.py @@ -94,7 +94,7 @@ def train_dataloader() -> DataLoader: # type: ignore """Return dataloader for training.""" return new_dataloader - pl_module.datamodule.train_dataloader = train_dataloader + pl_module.datamodule.train_dataloader = train_dataloader # type: ignore # pylint: disable=line-too-long pl_module.reload_dataloaders_every_n_epochs = self.switch_epoch # type: ignore # pylint: disable=line-too-long self.switched = True diff --git a/vis4d/op/base/vit.py b/vis4d/op/base/vit.py index 43404075..0948d2a0 100644 --- a/vis4d/op/base/vit.py +++ b/vis4d/op/base/vit.py @@ -19,7 +19,7 @@ def _init_weights_vit_timm( # pylint: disable=unused-argument if module.bias is not None: nn.init.zeros_(module.bias) elif hasattr(module, "init_weights"): - module.init_weights() + module.init_weights() # type: ignore ViT_PRESET = { # pylint: disable=consider-using-namedtuple-or-dataclass diff --git a/vis4d/op/box/poolers/__init__.py b/vis4d/op/box/poolers/__init__.py index d6458ee9..0ef125f3 100644 --- a/vis4d/op/box/poolers/__init__.py +++ b/vis4d/op/box/poolers/__init__.py @@ -1,6 +1,15 @@ """Init sampler module.""" from .base import RoIPooler -from .roi_pooler import MultiScaleRoIAlign, MultiScaleRoIPool +from .roi_pooler import ( + MultiScaleRoIAlign, + MultiScaleRoIPool, + MultiScaleRoIPooler, +) -__all__ = ["RoIPooler", "MultiScaleRoIAlign", "MultiScaleRoIPool"] +__all__ = [ + "RoIPooler", + "MultiScaleRoIAlign", + "MultiScaleRoIPool", + "MultiScaleRoIPooler", +] diff --git a/vis4d/op/detect3d/qd_3dt.py b/vis4d/op/detect3d/qd_3dt.py index 02a3bd25..1891f462 100644 --- a/vis4d/op/detect3d/qd_3dt.py +++ b/vis4d/op/detect3d/qd_3dt.py @@ -11,7 +11,7 @@ from vis4d.common.typing import LossesType from vis4d.op.box.encoder.qd_3dt import QD3DTBox3DDecoder, QD3DTBox3DEncoder from vis4d.op.box.matchers import Matcher, MaxIoUMatcher -from vis4d.op.box.poolers import MultiScaleRoIAlign, RoIPooler +from vis4d.op.box.poolers import MultiScaleRoIAlign, MultiScaleRoIPooler from vis4d.op.box.samplers import ( CombinedSampler, Sampler, @@ -47,7 +47,7 @@ class QD3DTDet3DOut(NamedTuple): depth_uncertainty: list[Tensor] -def get_default_proposal_pooler() -> RoIPooler: +def get_default_proposal_pooler() -> MultiScaleRoIAlign: """Get default proposal pooler of QD-3DT bounding box 3D head.""" return MultiScaleRoIAlign( resolution=[7, 7], strides=[4, 8, 16, 32], sampling_ratio=0 @@ -104,7 +104,7 @@ class QD3DTBBox3DHead(nn.Module): def __init__( # pylint: disable=too-many-arguments, too-many-positional-arguments, line-too-long self, num_classes: int, - proposal_pooler: None | RoIPooler = None, + proposal_pooler: None | MultiScaleRoIPooler = None, box_matcher: None | Matcher = None, box_sampler: None | Sampler = None, box_encoder: None | QD3DTBox3DEncoder = None, diff --git a/vis4d/op/track/qdtrack.py b/vis4d/op/track/qdtrack.py index 480161b9..bbc46c2f 100644 --- a/vis4d/op/track/qdtrack.py +++ b/vis4d/op/track/qdtrack.py @@ -10,7 +10,7 @@ from vis4d.op.box.box2d import bbox_iou from vis4d.op.box.matchers.max_iou import MaxIoUMatcher -from vis4d.op.box.poolers import MultiScaleRoIAlign, RoIPooler +from vis4d.op.box.poolers import MultiScaleRoIAlign, MultiScaleRoIPooler from vis4d.op.box.samplers import CombinedSampler, match_and_sample_proposals from vis4d.op.layer import add_conv_branch from vis4d.op.loss import EmbeddingDistanceLoss, MultiPosCrossEntropyLoss @@ -340,7 +340,7 @@ class QDSimilarityHead(nn.Module): def __init__( self, - proposal_pooler: None | RoIPooler = None, + proposal_pooler: None | MultiScaleRoIPooler = None, in_dim: int = 256, num_convs: int = 4, conv_out_dim: int = 256, @@ -355,8 +355,8 @@ def __init__( """Creates an instance of the class. Args: - proposal_pooler (None | RoIPooler, optional): RoI pooling module. - Defaults to None. + proposal_pooler (None | MultiScaleRoIPooler, optional): RoI pooling + module. Defaults to None. in_dim (int, optional): Input feature dimension. Defaults to 256. num_convs (int, optional): Number of convolutional layers inside the head. Defaults to 4. From e69be8092b88ac62e46ce149896745ee3b90c154 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 22 Jul 2025 16:18:15 +0200 Subject: [PATCH 44/50] feat: Refactor data const. --- .github/workflows/ci.yml | 2 +- docs/source/index.rst | 1 - vis4d/data/const.py | 123 +++++++++++++++++---------- vis4d/data/datasets/coco.py | 2 +- vis4d/data/transforms/autoaugment.py | 4 +- vis4d/engine/parser.py | 2 +- 6 files changed, 82 insertions(+), 52 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 214ed0f4..d05da6a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: python3 -m mypy tests test: - name: test py${{ matrix.python-version }} + name: test runs-on: ubuntu-latest strategy: matrix: diff --git a/docs/source/index.rst b/docs/source/index.rst index df992933..a117fec7 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -44,7 +44,6 @@ for further research and development of 4D Vision algorithms. .. toctree:: :hidden: - :maxdepth: 1 :caption: Reference API diff --git a/vis4d/data/const.py b/vis4d/data/const.py index 16dfc1cd..5b29649b 100644 --- a/vis4d/data/const.py +++ b/vis4d/data/const.py @@ -18,21 +18,21 @@ class AxisMode(Enum): """Enum for choosing among different coordinate frame conventions. ROS: The coordinate frame aligns with the right hand rule: - x axis points forward - y axis points left - z axis points up + x axis points forward. + y axis points left. + z axis points up. See also: https://www.ros.org/reps/rep-0103.html#axis-orientation OpenCV: The coordinate frame aligns with a camera coordinate system: - x axis points right - y axis points down - z axis points forward + x axis points right. + y axis points down. + z axis points forward. See also: https://docs.opencv.org/3.4/d9/d0c/group__calib3d.html LiDAR: The coordinate frame aligns with a LiDAR coordinate system: - x axis points right - y axis points forward - z axis points up + x axis points right. + y axis points forward. + z axis points up. See also: https://www.nuscenes.org/nuscenes#data-collection """ @@ -49,97 +49,126 @@ class CommonKeys: keys where we expect a pre-defined format to enable the usage of common data pre-processing operations among different datasets. + ### General Info ### + sample_names (str): Name of the sample. + + ### If the dataset contains videos ### + sequence_names (str): The name of the sequence. + frame_ids (int): The temporal frame index of the sample. + ### Image based inputs ### images (NDArrayF32): Image of shape [1, H, W, C]. input_hw (Tuple[int, int]): Shape of image in (height, width) after - transformations. + transformations. original_images (NDArrayF32): Original image of shape [1, H, W, C]. - original_hw (Tuple[int, int]): Original shape of image in (height, width). - - ### General Info ### - sample_names (str): Name of the current sample. - sequence_names (str): If the dataset contains videos, this field indicates - the name of the current sequence. - frame_ids (int): If the dataset contains videos, this field indicates the - temporal frame index of the current image / sample. + original_hw (Tuple[int, int]): Shape of original image in (height, width). ### Image Classification ### - categories (NDArrayF32): Class labels of shape [C, ]. + categories (NDArrayI64): Class labels of shape [1, ]. - ### 2D annotations ### + ### 2D Object Detection ### boxes2d (NDArrayF32): 2D bounding boxes of shape [N, 4] in xyxy format. - boxes2d_classes (NDArrayI64): Semantic classes of 2D bounding boxes, shape - [N,]. - boxes2d_track_ids (NDArrayI64): Tracking IDs of 2D bounding boxes, - shape [N,]. - instance_masks (NDArrayUI8): Instance segmentation masks of shape - [N, H, W]. + boxes2d_classes (NDArrayI64): Classes of 2D bounding boxes of shape [N,]. + boxes2d_names (List[str]): Names of 2D bounding box classes, same order as + `boxes2d_classes`. + + ### 2D Object Tracking ### + boxes2d_track_ids (NDArrayI64): Tracking IDs of 2D bounding boxes of shape + [N,]. + + ### Segmentation ### + masks (NDArrayUI8): Segmentation masks of shape [N, H, W]. seg_masks (NDArrayUI8): Semantic segmentation masks [H, W]. + instance_masks (NDArrayUI8): Instance segmentation masks of shape + [N, H, W]. panoptic_masks (NDArrayI64): Panoptic segmentation masks [H, W]. - deph_maps (NDArrayF32): Depth maps of shape [H, W]. - + ### Depth Esimation ### + deph_maps (NDArrayF32): Depth maps of shape [H, W]. + ### Optical Flow ### + optical_flows (NDArrayF32): Optical flow maps of shape [H, W, 2]. + ### Sensor Calibration ### intrinsics (NDArrayF32): Intrinsic sensor calibration. Shape [3, 3]. extrinsics (NDArrayF32): Extrinsic sensor calibration, transformation of - sensor to world coordinate frame. Shape [4, 4]. + sensor to world coordinate frame. Shape [4, 4]. axis_mode (AxisMode): Coordinate convention of the current sensor. timestamp (int): Sensor timestamp in Unix format. + ### 3D Point Cloud Data ### points3d (NDArrayF32): 3D pointcloud data, assumed to be [N, 3] and in - sensor frame. + sensor frame. colors3d (NDArrayF32): Associated color values for each point, [N, 3]. - semantics3d: TODO complete - instances3d: TODO complete - boxes3d (NDArrayF32): [N, 10], each row consists of center (XYZ), - dimensions (WLH), and orientation quaternion (WXYZ). + ### 3D Point Cloud Annotations ### + semantics3d (NDArrayI64): Semantic classes of 3D points, [N, 1]. + instances3d (NDArrayI64): Instance IDs of 3D points, [N, 1]. + + ### 3D Object Detection ### + boxes3d (NDArrayF32): 3D bounding boxes of shape [N, 10], each consists of + center (XYZ), dimensions (WLH), and orientation quaternion (WXYZ). boxes3d_classes (NDArrayI64): Associated semantic classes of 3D bounding - boxes, [N,]. + boxes of shape [N,]. + boxes3d_names (List[str]): Names of 3D bounding box classes, same order as + `boxes3d_classes`. + boxes3d_track_ids (NDArrayI64): Associated tracking IDs of 3D bounding + boxes of shape [N,]. + boxes3d_velocities (NDArrayF32): Associated velocities of 3D bounding + boxes of shape [N, 3], where each velocity is in the form of (vx, vy, vz). """ + # General Info + sample_names = "sample_names" + sequence_names = "sequence_names" + frame_ids = "frame_ids" + # image based inputs images = "images" input_hw = "input_hw" original_images = "original_images" original_hw = "original_hw" - # General Info - sample_names = "sample_names" # Sample name for each sample - sequence_names = "sequence_names" # Sequence name for each sample - frame_ids = "frame_ids" - # Image Classification categories = "categories" - # 2D annotations + # 2D Object Detection boxes2d = "boxes2d" boxes2d_classes = "boxes2d_classes" + boxes2d_names = "boxes2d_names" + + # 2D Object Tracking boxes2d_track_ids = "boxes2d_track_ids" - instance_masks = "instance_masks" + + # Segmentation + masks = "masks" seg_masks = "seg_masks" + instance_masks = "instance_masks" panoptic_masks = "panoptic_masks" - # Depth & Flow + # Depth Estimation depth_maps = "depth_maps" + + # Optical Flow optical_flows = "optical_flows" - # sensor calibration + # Sensor Calibration intrinsics = "intrinsics" extrinsics = "extrinsics" axis_mode = "axis_mode" timestamp = "timestamp" - # 3D data + # 3D Point Cloud Data points3d = "points3d" colors3d = "colors3d" - # 3D annotation + # 3D Point Cloud Annotations semantics3d = "semantics3d" instances3d = "instances3d" + + # 3D Object Detection boxes3d = "boxes3d" boxes3d_classes = "boxes3d_classes" + boxes3d_names = "boxes3d_names" boxes3d_track_ids = "boxes3d_track_ids" boxes3d_velocities = "boxes3d_velocities" - occupancy3d = "occupancy3d" diff --git a/vis4d/data/datasets/coco.py b/vis4d/data/datasets/coco.py index 0a64e546..30f18300 100644 --- a/vis4d/data/datasets/coco.py +++ b/vis4d/data/datasets/coco.py @@ -360,6 +360,6 @@ def __getitem__(self, idx: int) -> DictData: seg_masks[mask_tensor.sum(0) > 1] = 255 # discard overlapped dict_data[K.seg_masks] = seg_masks[None] - dict_data["texts"] = self.category_names + dict_data[K.boxes2d_names] = self.category_names return dict_data diff --git a/vis4d/data/transforms/autoaugment.py b/vis4d/data/transforms/autoaugment.py index f0bbd781..6e47ad9f 100644 --- a/vis4d/data/transforms/autoaugment.py +++ b/vis4d/data/transforms/autoaugment.py @@ -1,5 +1,7 @@ """A wrap for timm transforms.""" +from __future__ import annotations + from typing import Union import numpy as np @@ -45,7 +47,7 @@ class _AutoAug: """Apply Timm's AutoAugment to a image array.""" def __init__(self) -> None: - self.aug_op = None + self.aug_op: AugOp | None = None def _create(self, policy: str, hparams: dict[str, float]) -> AugOp: """Create augmentation op.""" diff --git a/vis4d/engine/parser.py b/vis4d/engine/parser.py index 03e2189d..6cb728b5 100644 --- a/vis4d/engine/parser.py +++ b/vis4d/engine/parser.py @@ -110,7 +110,7 @@ def DEFINE_config_file( # pylint: disable=invalid-name help_string: str = "path to config file [.py |.yaml].", lock_config: bool = False, method_name: str = "get_config", -) -> flags.FlagHolder: +) -> flags.FlagHolder: # type: ignore """Registers a new flag for a config file. Args: From 037b12a2c202e531651917e4eb3c5cb0e50193a0 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 22 Jul 2025 17:59:26 +0200 Subject: [PATCH 45/50] feat: Update doc. --- .readthedocs.yaml | 3 + docs/requirements.txt | 1 + docs/source/conf.py | 9 +- vis4d/common/array.py | 16 ++-- vis4d/data/const.py | 157 ++++++++++++++++++---------------- vis4d/model/track3d/cc_3dt.py | 2 +- 6 files changed, 99 insertions(+), 89 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 9138a7fe..d22002cf 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,6 +8,9 @@ build: python: install: - requirements: docs/requirements.txt + - requirements: requirements/install.txt + - requirements: requirements/torch-lib.txt + - requirements: requirements/viewer.txt sphinx: configuration: docs/source/conf.py diff --git a/docs/requirements.txt b/docs/requirements.txt index b2a0ed4e..afe9fbce 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -5,4 +5,5 @@ sphinx_autodoc_defaultargs sphinx_autodoc_typehints sphinx_copybutton sphinx_design +sphinx_rtd_theme sphinxcontrib-aafig diff --git a/docs/source/conf.py b/docs/source/conf.py index 68d0f507..f1dfa4be 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -94,7 +94,7 @@ "Vis4D Documentation", author, "Vis4D", - "Dynamic Scene Understanding in Pytorch.", + "Dynamic Scene Understanding in PyTorch.", "Miscellaneous", ) ] @@ -102,13 +102,14 @@ # -- auto doc settings ------------------------------------------------------- autosummary_generate = True autodoc_member_order = "groupwise" -autoclass_content = "both" +# autoclass_content = "both" add_module_names = False # Remove namespaces from class/method signatures +autodoc_member_order = "bysource" autodoc_default_options = { "members": True, "methods": True, "special-members": "__call__", - "exclude-members": "_abc_impl,__init__", + "exclude-members": "_abc_impl,__repr__", } # -- Napoleon settings ------------------------------------------------------- @@ -117,7 +118,7 @@ # project. napoleon_google_docstring = True napoleon_numpy_docstring = False -napoleon_include_init_with_doc = False +napoleon_include_init_with_doc = True napoleon_include_private_with_doc = False napoleon_include_special_with_doc = True napoleon_use_admonition_for_examples = False diff --git a/vis4d/common/array.py b/vis4d/common/array.py index 1cf96805..c520155e 100644 --- a/vis4d/common/array.py +++ b/vis4d/common/array.py @@ -106,14 +106,14 @@ def array_to_numpy( If the argument is None, None will be returned. Examples: - >>> convert_to_array([1,2,3]) - >>> # -> array([1,2,3]) - >>> convert_to_array(None) - >>> # -> None - >>> convert_to_array(torch.tensor([1,2,3]).cuda()) - >>> # -> array([1,2,3]) - >>> convert_to_array([1,2,3], n_dims = 2).shape - >>> # -> [1, 3] + >>> convert_to_array([1,2,3]) + >>> # -> array([1,2,3]) + >>> convert_to_array(None) + >>> # -> None + >>> convert_to_array(torch.tensor([1,2,3]).cuda()) + >>> # -> array([1,2,3]) + >>> convert_to_array([1,2,3], n_dims = 2).shape + >>> # -> [1, 3] Args: data (ArrayLike | None): ArrayLike object that should be converted diff --git a/vis4d/data/const.py b/vis4d/data/const.py index 5b29649b..fb26daad 100644 --- a/vis4d/data/const.py +++ b/vis4d/data/const.py @@ -18,21 +18,21 @@ class AxisMode(Enum): """Enum for choosing among different coordinate frame conventions. ROS: The coordinate frame aligns with the right hand rule: - x axis points forward. - y axis points left. - z axis points up. + - x axis points forward. + - y axis points left. + - z axis points up. See also: https://www.ros.org/reps/rep-0103.html#axis-orientation OpenCV: The coordinate frame aligns with a camera coordinate system: - x axis points right. - y axis points down. - z axis points forward. + - x axis points right. + - y axis points down. + - z axis points forward. See also: https://docs.opencv.org/3.4/d9/d0c/group__calib3d.html LiDAR: The coordinate frame aligns with a LiDAR coordinate system: - x axis points right. - y axis points forward. - z axis points up. + - x axis points right. + - y axis points forward. + - z axis points up. See also: https://www.nuscenes.org/nuscenes#data-collection """ @@ -49,73 +49,78 @@ class CommonKeys: keys where we expect a pre-defined format to enable the usage of common data pre-processing operations among different datasets. - ### General Info ### - sample_names (str): Name of the sample. - - ### If the dataset contains videos ### - sequence_names (str): The name of the sequence. - frame_ids (int): The temporal frame index of the sample. - - ### Image based inputs ### - images (NDArrayF32): Image of shape [1, H, W, C]. - input_hw (Tuple[int, int]): Shape of image in (height, width) after - transformations. - original_images (NDArrayF32): Original image of shape [1, H, W, C]. - original_hw (Tuple[int, int]): Shape of original image in (height, width). - - ### Image Classification ### - categories (NDArrayI64): Class labels of shape [1, ]. - - ### 2D Object Detection ### - boxes2d (NDArrayF32): 2D bounding boxes of shape [N, 4] in xyxy format. - boxes2d_classes (NDArrayI64): Classes of 2D bounding boxes of shape [N,]. - boxes2d_names (List[str]): Names of 2D bounding box classes, same order as - `boxes2d_classes`. - - ### 2D Object Tracking ### - boxes2d_track_ids (NDArrayI64): Tracking IDs of 2D bounding boxes of shape - [N,]. - - ### Segmentation ### - masks (NDArrayUI8): Segmentation masks of shape [N, H, W]. - seg_masks (NDArrayUI8): Semantic segmentation masks [H, W]. - instance_masks (NDArrayUI8): Instance segmentation masks of shape - [N, H, W]. - panoptic_masks (NDArrayI64): Panoptic segmentation masks [H, W]. - - ### Depth Esimation ### - deph_maps (NDArrayF32): Depth maps of shape [H, W]. - - ### Optical Flow ### - optical_flows (NDArrayF32): Optical flow maps of shape [H, W, 2]. - - ### Sensor Calibration ### - intrinsics (NDArrayF32): Intrinsic sensor calibration. Shape [3, 3]. - extrinsics (NDArrayF32): Extrinsic sensor calibration, transformation of - sensor to world coordinate frame. Shape [4, 4]. - axis_mode (AxisMode): Coordinate convention of the current sensor. - timestamp (int): Sensor timestamp in Unix format. - - ### 3D Point Cloud Data ### - points3d (NDArrayF32): 3D pointcloud data, assumed to be [N, 3] and in - sensor frame. - colors3d (NDArrayF32): Associated color values for each point, [N, 3]. - - ### 3D Point Cloud Annotations ### - semantics3d (NDArrayI64): Semantic classes of 3D points, [N, 1]. - instances3d (NDArrayI64): Instance IDs of 3D points, [N, 1]. - - ### 3D Object Detection ### - boxes3d (NDArrayF32): 3D bounding boxes of shape [N, 10], each consists of - center (XYZ), dimensions (WLH), and orientation quaternion (WXYZ). - boxes3d_classes (NDArrayI64): Associated semantic classes of 3D bounding - boxes of shape [N,]. - boxes3d_names (List[str]): Names of 3D bounding box classes, same order as - `boxes3d_classes`. - boxes3d_track_ids (NDArrayI64): Associated tracking IDs of 3D bounding - boxes of shape [N,]. - boxes3d_velocities (NDArrayF32): Associated velocities of 3D bounding - boxes of shape [N, 3], where each velocity is in the form of (vx, vy, vz). + General Info: + - sample_names (str): Name of the sample. + + If the dataset contains videos: + - sequence_names (str): The name of the sequence. + - frame_ids (int): The temporal frame index of the sample. + + Image Based Inputs: + - images (NDArrayF32): Image of shape [1, H, W, C]. + - input_hw (Tuple[int, int]): Shape of image in (height, width) after + transformations. + - original_images (NDArrayF32): Original image of shape [1, H, W, C]. + - original_hw (Tuple[int, int]): Shape of original image in + (height, width). + + Image Classification: + - categories (NDArrayI64): Class labels of shape [1, ]. + + 2D Object Detection: + - boxes2d (NDArrayF32): 2D bounding boxes of shape [N, 4] in xyxy + format. + - boxes2d_classes (NDArrayI64): Classes of 2D bounding boxes of shape + [N,]. + - boxes2d_names (List[str]): Names of 2D bounding box classes, same + order as `boxes2d_classes`. + + 2D Object Tracking: + - boxes2d_track_ids (NDArrayI64): Tracking IDs of 2D bounding boxes of + shape [N,]. + + Segmentation: + - masks (NDArrayUI8): Segmentation masks of shape [N, H, W]. + - seg_masks (NDArrayUI8): Semantic segmentation masks [H, W]. + - instance_masks (NDArrayUI8): Instance segmentation masks of shape + [N, H, W]. + - panoptic_masks (NDArrayI64): Panoptic segmentation masks [H, W]. + + Depth Estimation: + - depth_maps (NDArrayF32): Depth maps of shape [H, W]. + + Optical Flow: + - optical_flows (NDArrayF32): Optical flow maps of shape [H, W, 2]. + + Sensor Calibration: + - intrinsics (NDArrayF32): Intrinsic sensor calibration. Shape [3, 3]. + - extrinsics (NDArrayF32): Extrinsic sensor calibration, transformation + of sensor to world coordinate frame. Shape [4, 4]. + - axis_mode (AxisMode): Coordinate convention of the current sensor. + - timestamp (int): Sensor timestamp in Unix format. + + 3D Point Cloud Data: + - points3d (NDArrayF32): 3D pointcloud data, assumed to be [N, 3] and + in sensor frame. + - colors3d (NDArrayF32): Associated color values for each point [N, 3]. + + 3D Point Cloud Annotations: + - semantics3d (NDArrayI64): Semantic classes of 3D points [N, 1]. + - instances3d (NDArrayI64): Instance IDs of 3D points [N, 1]. + + 3D Object Detection: + - boxes3d (NDArrayF32): 3D bounding boxes of shape [N, 10], each + consists of center (XYZ), dimensions (WLH), and orientation + quaternion (WXYZ). + - boxes3d_classes (NDArrayI64): Associated semantic classes of 3D + bounding boxes of shape [N,]. + - boxes3d_names (List[str]): Names of 3D bounding box classes, same + order as `boxes3d_classes`. + - boxes3d_track_ids (NDArrayI64): Associated tracking IDs of 3D + bounding boxes of shape [N,]. + - boxes3d_velocities (NDArrayF32): Associated velocities of 3D bounding + boxes of shape [N, 3], where each velocity is in the form of + (vx, vy, vz). """ # General Info diff --git a/vis4d/model/track3d/cc_3dt.py b/vis4d/model/track3d/cc_3dt.py index 1cc5e231..972728cc 100644 --- a/vis4d/model/track3d/cc_3dt.py +++ b/vis4d/model/track3d/cc_3dt.py @@ -1,7 +1,7 @@ """CC-3DT model implementation. This file composes the operations associated with CC-3DT -`https://arxiv.org/abs/2212.01247`_ into the full model implementation. +`https://arxiv.org/abs/2212.01247` into the full model implementation. """ from __future__ import annotations From 9b358ab95cc78d5c1ee5056904cdde917ff04f6e Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Tue, 22 Jul 2025 18:04:33 +0200 Subject: [PATCH 46/50] feat: Update cuda ops link. --- requirements/torch-lib.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/torch-lib.txt b/requirements/torch-lib.txt index 423c0768..a3e6a1f4 100644 --- a/requirements/torch-lib.txt +++ b/requirements/torch-lib.txt @@ -1 +1 @@ -git+ssh://git@github.com/SysCV/vis4d_cuda_ops.git +git+https://github.com/SysCV/vis4d_cuda_ops.git From c61b611219529032f850d64dc8c8732492181849 Mon Sep 17 00:00:00 2001 From: RoyYang0714 Date: Wed, 23 Jul 2025 00:43:59 +0200 Subject: [PATCH 47/50] feat: Update test. --- tests/data/datasets/coco_test.py | 19 -------- tests/data/transforms/mosaic_test.py | 21 +++++--- tests/data/transforms/photometric_test.py | 15 +++--- .../transforms/testcases/mosaic_boxes2d.npy | Bin 1405 -> 448 bytes .../testcases/mosaic_boxes2d_classes.npy | Bin 0 -> 208 bytes .../testcases/mosaic_boxes2d_track_ids.npy | Bin 0 -> 208 bytes .../transforms/testcases/mosaic_images.npy | Bin 10882875 -> 9600128 bytes .../testcases/random_brightness_gt.npy | Bin 1182537 -> 971648 bytes .../testcases/random_contrast_gt.npy | Bin 1156485 -> 971648 bytes .../transforms/testcases/random_gamma_gt.npy | Bin 1227647 -> 971648 bytes .../transforms/testcases/random_hue_gt.npy | Bin 1091387 -> 971648 bytes .../testcases/random_saturation_gt.npy | Bin 1257737 -> 971648 bytes tests/engine/callbacks/evaluator_test.py | 2 +- tests/engine/callbacks/logging_test.py | 46 ------------------ tests/engine/callbacks/visualizer_test.py | 2 +- tests/model/detect/yolox_test.py | 2 +- tests/model/detect3d/bevformer_test.py | 4 +- tests/model/track/qdtrack_test.py | 8 ++- tests/model/track3d/cc_3dt_test.py | 4 +- tests/op/base/dla_test.py | 8 +-- tests/op/detect/rpn_test.py | 2 +- tests/vis/image/bbox3d_visualizer_test.py | 4 +- tests/vis/image/bev_visualizer_test.py | 4 +- .../vis/image/bounding_box_visualizer_test.py | 17 +++---- ...6-36-0400__LIDAR_TOP__1533151603547590.png | Bin 24529 -> 25609 bytes ...6-36-0400__LIDAR_TOP__1533151604048025.png | Bin 25174 -> 26255 bytes ...0400__CAM_BACK_RIGHT__1533151603528113.png | Bin 1017267 -> 1017537 bytes ...0400__CAM_BACK_RIGHT__1533151604028370.png | Bin 1038176 -> 1038916 bytes ...6-36-0400__CAM_FRONT__1533151603512404.png | Bin 1209992 -> 1207686 bytes ...6-36-0400__CAM_FRONT__1533151604012404.png | Bin 1251428 -> 1250030 bytes ...6-36-0400__CAM_FRONT__1533151603512404.png | Bin 1209992 -> 1207686 bytes ...6-36-0400__CAM_FRONT__1533151604012404.png | Bin 1251428 -> 1250030 bytes tests/vis/image/testcases/bbox_batched_0.png | Bin 508907 -> 492626 bytes tests/vis/image/testcases/bbox_batched_1.png | Bin 99246 -> 90391 bytes .../image/testcases/bbox_with_c_target.png | Bin 507360 -> 496371 bytes .../image/testcases/bbox_with_cs_target.png | Bin 508584 -> 494946 bytes .../image/testcases/bbox_with_cts_target.png | Bin 508907 -> 492626 bytes tests/vis4d-test-data | 2 +- vis4d/eval/coco/detect.py | 2 +- vis4d/op/base/dla.py | 2 - vis4d/vis/image/bev_visualizer.py | 1 + 41 files changed, 58 insertions(+), 107 deletions(-) create mode 100644 tests/data/transforms/testcases/mosaic_boxes2d_classes.npy create mode 100644 tests/data/transforms/testcases/mosaic_boxes2d_track_ids.npy delete mode 100644 tests/engine/callbacks/logging_test.py diff --git a/tests/data/datasets/coco_test.py b/tests/data/datasets/coco_test.py index ef09035c..21ee6f97 100644 --- a/tests/data/datasets/coco_test.py +++ b/tests/data/datasets/coco_test.py @@ -46,17 +46,6 @@ def test_sample(self) -> None: """Test if sample loaded correctly.""" item = self.coco[0] item = ToTensor().apply_to_data([item])[0] # pylint: disable=no-member - self.assertEqual( - tuple(item.keys()), - ( - "sample_names", - "images", - "input_hw", - "boxes2d", - "boxes2d_classes", - "instance_masks", - ), - ) self.assertEqual(item[K.sample_names], 37777) self.assertEqual(item[K.input_hw], [230, 352]) @@ -142,14 +131,6 @@ def test_sample(self) -> None: """Test if sample loaded correctly.""" item = self.coco[0] item = ToTensor().apply_to_data([item])[0] # pylint: disable=no-member - assert tuple(item.keys()) == ( - "sample_names", - "images", - "input_hw", - "boxes2d_classes", - "instance_masks", - "seg_masks", - ) self.assertEqual(item[K.sample_names], 37777) self.assertEqual(item[K.input_hw], [230, 352]) diff --git a/tests/data/transforms/mosaic_test.py b/tests/data/transforms/mosaic_test.py index 1e860836..606a71d4 100644 --- a/tests/data/transforms/mosaic_test.py +++ b/tests/data/transforms/mosaic_test.py @@ -48,7 +48,7 @@ def test_mosaic_images(self) -> None: assert len(data["transforms"]["mosaic"]["im_scales"]) == 4 assert np.allclose( data[K.images], - torch.load(get_test_file("mosaic_images.npy")), + np.load(get_test_file("mosaic_images.npy")), atol=1e-4, ) @@ -75,12 +75,19 @@ def test_mosaic_boxes2d(self) -> None: data = params.apply_to_data([copy.deepcopy(data) for _ in range(4)]) data = MosaicImages().apply_to_data(data) data = transform.apply_to_data(data)[0] - box_data = [ + + assert np.allclose( data[K.boxes2d], + np.load(get_test_file("mosaic_boxes2d.npy")), + atol=1e-4, + ) + assert np.allclose( data[K.boxes2d_classes], + np.load(get_test_file("mosaic_boxes2d_classes.npy")), + atol=1e-4, + ) + assert np.allclose( data[K.boxes2d_track_ids], - ] - for pred, gt in zip( - box_data, torch.load(get_test_file("mosaic_boxes2d.npy")) - ): - assert np.allclose(pred, gt, atol=1e-4) + np.load(get_test_file("mosaic_boxes2d_track_ids.npy")), + atol=1e-4, + ) diff --git a/tests/data/transforms/photometric_test.py b/tests/data/transforms/photometric_test.py index f5c5b8da..b4e6268f 100644 --- a/tests/data/transforms/photometric_test.py +++ b/tests/data/transforms/photometric_test.py @@ -4,7 +4,6 @@ import unittest import numpy as np -import torch from PIL import Image from tests.util import get_test_file @@ -36,7 +35,7 @@ def test_random_gamma(self): self.assertEqual(data[K.images].shape, (1, 230, 352, 3)) assert np.allclose( data[K.images][0], - torch.load(get_test_file("random_gamma_gt.npy")), + np.load(get_test_file("random_gamma_gt.npy")), atol=1e-4, ) @@ -47,7 +46,7 @@ def test_random_gamma(self): self.assertEqual(data[K.images].shape, (1, 230, 352, 3)) assert np.allclose( data[K.images][0][..., [2, 1, 0]], - torch.load(get_test_file("random_gamma_gt.npy")), + np.load(get_test_file("random_gamma_gt.npy")), atol=1e-4, ) @@ -59,7 +58,7 @@ def test_random_brightness(self): self.assertEqual(data[K.images].shape, (1, 230, 352, 3)) assert np.allclose( data[K.images][0], - torch.load(get_test_file("random_brightness_gt.npy")), + np.load(get_test_file("random_brightness_gt.npy")), atol=1e-4, ) @@ -71,7 +70,7 @@ def test_random_contrast(self): self.assertEqual(data[K.images].shape, (1, 230, 352, 3)) assert np.allclose( data[K.images][0], - torch.load(get_test_file("random_contrast_gt.npy")), + np.load(get_test_file("random_contrast_gt.npy")), atol=1e-4, ) @@ -83,7 +82,7 @@ def test_random_saturation(self): self.assertEqual(data[K.images].shape, (1, 230, 352, 3)) assert np.allclose( data[K.images][0], - torch.load(get_test_file("random_saturation_gt.npy")), + np.load(get_test_file("random_saturation_gt.npy")), atol=1e-4, ) @@ -96,7 +95,7 @@ def test_random_hue(self): self.assertEqual(data[K.images].shape, (1, 230, 352, 3)) assert np.allclose( data[K.images][0], - torch.load(get_test_file("random_hue_gt.npy")), + np.load(get_test_file("random_hue_gt.npy")), atol=1e-4, ) @@ -107,7 +106,7 @@ def test_random_hue(self): self.assertEqual(data[K.images].shape, (1, 230, 352, 3)) assert np.allclose( data[K.images][0][..., [2, 1, 0]], - torch.load(get_test_file("random_hue_gt.npy")), + np.load(get_test_file("random_hue_gt.npy")), atol=1e-4, ) diff --git a/tests/data/transforms/testcases/mosaic_boxes2d.npy b/tests/data/transforms/testcases/mosaic_boxes2d.npy index b05eafec5f125af9057cfd0de1f2c6ea2c5dc18a..76d364a6fac221202141d91d91cbc058f3b21ff6 100644 GIT binary patch literal 448 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlV+i=qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= zXCxM+0{I$-2098RnmP)#3giMV1}Jb5k1e^#>f->RLmd`%>+O1RC#W%LW<-yh;C~|xdC!`ugxM|EEwL?6(bjohDPplMHDY9l4=Y zYsNdZ^QiuyE?aWG{kplfoFdOX>qjdsGH#BafG(G~#6eP7FV6!$}EF<%F1!cDXuzvly^ui9_Y4Zk@fiLGsdw%nQ4J#3^D~Z!AAz*#?WT4dU4b zyI`A8Oy~w<#(E4zO!TOa@=cY6vl`XLISJ-0IA7Bunyad;My0|_aKV+z7F^UkZ8QpS z3AHgV!2;EWHm!=wt|~;zAP@#>3T<*9^Ny#^XW?KGnJ!6i#e%Dh={00}U4k1v)0^4? z%CdY!LFbEK()k)V-vVbR<*{*geaHTh@lNc6z&Z3CxP?S+OOUhRPEE~=LMlxT|J?mW zli?%IoC#S{n4Af3RI}4C^tI(D!AS5Y!~ZRhIjsKs)2kAGW_&~;;(l>9lg60wUQ1)| z853$U$#{Y6SU4ebbo@;u@mmswWb&SmU5wplQGp(Ub?D#h(oASH&ix1T32%>j5QPK| MGumL3Al}3N1IB@!=>Px# diff --git a/tests/data/transforms/testcases/mosaic_boxes2d_classes.npy b/tests/data/transforms/testcases/mosaic_boxes2d_classes.npy new file mode 100644 index 0000000000000000000000000000000000000000..64f7b0ba31369567f49af1ffc578dc5aaa9fedde GIT binary patch literal 208 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlWC!@qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= kXCxM+0{I$-20EHL3bhL411?4e2w;NJ=zL}z;<(fS0PfZsfdBvi literal 0 HcmV?d00001 diff --git a/tests/data/transforms/testcases/mosaic_boxes2d_track_ids.npy b/tests/data/transforms/testcases/mosaic_boxes2d_track_ids.npy new file mode 100644 index 0000000000000000000000000000000000000000..922378b0422e0bf670cd141e00c59dafedc9acbc GIT binary patch literal 208 zcmbR27wQ`j$;eQ~P_3SlTAW;@Zl$1ZlWC!@qoAIaUsO_*m=~X4l#&V(cT3DEP6dh= zXCxM+0{I$-20EHL3bhL411?4e2w;NJFPR~XS5W#jl)lIg5x)ebcXC7cyP))LC=CGV C?IJk< literal 0 HcmV?d00001 diff --git a/tests/data/transforms/testcases/mosaic_images.npy b/tests/data/transforms/testcases/mosaic_images.npy index d8a0f88ee0ad01837413097916ef02d7ab5d444f..2b618624ab4efcf3bc51989f31b376fae8bc0a28 100644 GIT binary patch literal 9600128 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%0DGZ+&3CxK?%C^_2}LS4+?8 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 z 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%0A@D0#6J~ljC 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

ySx4z0qB7@7Cg94EA|Mh?Q)=;$uU`q;E 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%0A^@WW=tvieEajoZc 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�m9}?uv7`C{4 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

d%Q|1`Zn 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