Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Support PGD and multi-view FCOS3D++ on Waymo #2835

Merged
merged 41 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b10c39a
support training dsvt
JingweiZhang12 Jun 20, 2023
b00d3fe
Merge remote-tracking branch 'jingwei/dsvt_train' into dsvt_train
sunjiahao1999 Jul 12, 2023
7fecc0f
fix batch_size
sunjiahao1999 Aug 9, 2023
232c3b8
chage cam to lidar
Aug 10, 2023
a81529e
add cam instances
Aug 14, 2023
84d9fc7
add cam_instances
sunjiahao1999 Aug 16, 2023
b7b3b62
add description for skip
sunjiahao1999 Aug 16, 2023
1995b5a
fix num_ins_per_cat
Aug 18, 2023
a9c7cd3
refactor waymo create
sunjiahao1999 Aug 21, 2023
257bcb3
fix waymo create
sunjiahao1999 Aug 23, 2023
53620aa
remove some function not use
sunjiahao1999 Aug 24, 2023
061d9e6
fix cam_instances after refactor
sunjiahao1999 Aug 24, 2023
3c7d4e9
remove unused .py
sunjiahao1999 Aug 24, 2023
38e47b1
add fast eval
sunjiahao1999 Aug 28, 2023
8c6e8c0
add prallel eval
sunjiahao1999 Aug 29, 2023
eadd6fc
fail use parallel
sunjiahao1999 Aug 30, 2023
1705540
remove unused code
sunjiahao1999 Aug 30, 2023
76c9b6f
Merge from waymo_speed
sunjiahao1999 Sep 4, 2023
180d6df
fix create gt database bug
sunjiahao1999 Sep 11, 2023
8342685
fix train iter
sunjiahao1999 Sep 12, 2023
2c9b333
fix dis aug and model init
sunjiahao1999 Sep 15, 2023
9824778
train align
sunjiahao1999 Sep 18, 2023
681423f
fix lint
sunjiahao1999 Sep 18, 2023
fd0825a
fix basepoints in_range_3d
sunjiahao1999 Sep 18, 2023
13affc6
fix idx_all and add description
sunjiahao1999 Sep 18, 2023
e8166b3
Merge branch 'dev-1.x' into waymo_speed
sunjiahao1999 Sep 18, 2023
73b33c6
fix defualt pipeline
sunjiahao1999 Sep 18, 2023
fd2448a
10.27 Merge branch 'dev-1.x' into waymo_speed
sunjiahao1999 Oct 27, 2023
651dbf1
fix pgd fov
sunjiahao1999 Nov 20, 2023
bfb10b6
add mvfcos3d
sunjiahao1999 Dec 4, 2023
943d0ff
merge dsvt
sunjiahao1999 Dec 5, 2023
80a7a77
merge dev-1.x
sunjiahao1999 Dec 27, 2023
d714153
fix pgd config
sunjiahao1999 Dec 28, 2023
43963f8
fix mvfoc3d config && add doc
sunjiahao1999 Dec 28, 2023
3ea3f9f
merge dev-1.x
sunjiahao1999 Dec 28, 2023
6c00213
fix lint & delete unused
sunjiahao1999 Dec 28, 2023
31a59df
del unused
sunjiahao1999 Dec 28, 2023
0ecf88c
resolve comments
sunjiahao1999 Jan 4, 2024
ab31f64
del unused in pgd head
sunjiahao1999 Jan 4, 2024
5ff1df8
fix config comments bug and update waymo infos & mini link
sunjiahao1999 Jan 4, 2024
be43c4d
fix doc
sunjiahao1999 Jan 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions mmdet3d/engine/hooks/visualization_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ def __init__(self,
'needs to be excluded.')
self.vis_task = vis_task

if wait_time == -1:
if show and wait_time == -1:
print_log(
'Manual control mode, press [Right] to next sample.',
logger='current')
else:
elif show:
print_log(
'Autoplay mode, press [SPACE] to pause.', logger='current')
self.wait_time = wait_time
Expand Down
37 changes: 9 additions & 28 deletions mmdet3d/evaluation/functional/waymo_utils/prediction_to_waymo.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
'Please run "pip install waymo-open-dataset-tf-2-1-0==1.2.0" '
'to install the official devkit first.')

from typing import List, Optional
from typing import List

import mmengine
from mmengine import print_log
Expand All @@ -28,37 +28,22 @@ class Prediction2Waymo(object):

Args:
results (list[dict]): Prediction results.
waymo_tfrecords_dir (str): Directory to load waymo raw data.
waymo_results_save_dir (str): Directory to save converted predictions
in waymo format (.bin files).
waymo_results_final_path (str): Path to save combined
predictions in waymo format (.bin file), like 'a/b/c.bin'.
prefix (str): Prefix of filename. In general, 0 for training, 1 for
validation and 2 for testing.
classes (dict): A list of class name.
workers (str): Number of parallel processes. Defaults to 2.
backend_args (dict, optional): Arguments to instantiate the
corresponding backend. Defaults to None.
from_kitti_format (bool, optional): Whether the reuslts are kitti
format. Defaults to False.
num_workers (str): Number of parallel processes. Defaults to 4.
"""

def __init__(self,
results: List[dict],
waymo_results_save_dir: str,
waymo_results_final_path: str,
classes: dict,
workers: int = 4,
backend_args: Optional[dict] = None):

num_workers: int = 4):
self.results = results
self.waymo_results_save_dir = waymo_results_save_dir
self.waymo_results_final_path = waymo_results_final_path
self.classes = classes
self.workers = int(workers)
self.backend_args = backend_args

self.name2idx = {}
self.num_workers = num_workers

self.k2w_cls_map = {
'Car': label_pb2.Label.TYPE_VEHICLE,
Expand All @@ -67,13 +52,7 @@ def __init__(self,
'Cyclist': label_pb2.Label.TYPE_CYCLIST,
}

self.create_folder()

def create_folder(self):
"""Create folder for data conversion."""
mmengine.mkdir_or_exist(self.waymo_results_save_dir)

def convert_one_fast(self, res_index: int):
def convert_one(self, res_index: int):
"""Convert action for single file. It read the metainfo from the
preprocessed file offline and will be faster.

Expand Down Expand Up @@ -139,9 +118,11 @@ def convert(self):
"""Convert action."""
print_log('Start converting ...', logger='current')

# TODO: use parallel processes.
# objects_list = mmengine.track_parallel_progress(
# self.convert_one_fast, range(len(self)), self.workers)
objects_list = mmengine.track_progress(self.convert_one_fast,
# self.convert_one, range(len(self)), self.num_workers)

objects_list = mmengine.track_progress(self.convert_one,
range(len(self)))

combined = metrics_pb2.Objects()
Expand Down
143 changes: 33 additions & 110 deletions mmdet3d/evaluation/metrics/waymo_metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,109 +6,61 @@
import numpy as np
import torch
from mmengine import Config
from mmengine.evaluator import BaseMetric
from mmengine.logging import MMLogger, print_log

from mmdet3d.models.layers import box3d_multiclass_nms
from mmdet3d.registry import METRICS
from mmdet3d.structures import (Box3DMode, CameraInstance3DBoxes,
LiDARInstance3DBoxes, points_cam2img,
xywhr2xyxyr)
from .kitti_metric import KittiMetric


@METRICS.register_module()
class WaymoMetric(KittiMetric):
class WaymoMetric(BaseMetric):
"""Waymo evaluation metric.

Args:
ann_file (str): The path of the annotation file in kitti format.
waymo_bin_file (str): The path of the annotation file in waymo format.
split (str): The split of the evaluation set. Defaults to 'training'.
metric (str or List[str]): Metrics to be evaluated. Defaults to 'mAP'.
pcd_limit_range (List[float]): The range of point cloud used to filter
invalid predicted boxes. Defaults to [-85, -85, -5, 85, 85, 5].
convert_kitti_format (bool): Whether to convert the results to kitti
format. Now, in order to be compatible with camera-based methods,
defaults to True.
prefix (str, optional): The prefix that will be added in the metric
names to disambiguate homonymous metrics of different evaluators.
If prefix is not provided in the argument, self.default_prefix will
be used instead. Defaults to 'Waymo metric'.
format_only (bool): Format the output results without perform
evaluation. It is useful when you want to format the result to a
specific format and submit it to the test server.
Defaults to False.
pklfile_prefix (str, optional): The prefix of pkl files, including the
file path and the prefix of filename, e.g., "a/b/prefix". If not
specified, a temp file will be created. Defaults to None.
submission_prefix (str, optional): The prefix of submission data. If
not specified, the submission data will not be generated.
Defaults to None.
load_type (str): Type of loading mode during training.

- 'frame_based': Load all of the instances in the frame.
- 'mv_image_based': Load all of the instances in the frame and need
to convert to the FOV-based data type to support image-based
detector.
- 'fov_image_based': Only load the instances inside the default cam
and need to convert to the FOV-based data type to support image-
based detector.
default_cam_key (str): The default camera for lidar to camera
conversion. By default, KITTI: 'CAM2', Waymo: 'CAM_FRONT'.
Defaults to 'CAM_FRONT'.
use_pred_sample_idx (bool): In formating results, use the sample index
from the prediction or from the load annotations. By default,
KITTI: True, Waymo: False, Waymo has a conversion process, which
needs to use the sample idx from load annotation.
result_prefix (str, optional): The prefix of result '*.bin' file,
including the file path and the prefix of filename, e.g.,
"a/b/prefix". If not specified, a temp file will be created.
Defaults to None.
format_only (bool): Format the output results without perform
evaluation. It is useful when you want to format the result to a
specific format and submit it to the test server.
Defaults to False.
collect_device (str): Device name used for collecting results from
different ranks during distributed training. Must be 'cpu' or
'gpu'. Defaults to 'cpu'.
backend_args (dict, optional): Arguments to instantiate the
corresponding backend. Defaults to None.
"""
num_cams = 5
default_prefix = 'Waymo metric'

def __init__(self,
ann_file: str,
waymo_bin_file: str,
split: str = 'training',
metric: Union[str, List[str]] = 'mAP',
pcd_limit_range: List[float] = [-85, -85, -5, 85, 85, 5],
convert_kitti_format: bool = True,
prefix: Optional[str] = 'Waymo metric',
format_only: bool = False,
pklfile_prefix: Optional[str] = None,
submission_prefix: Optional[str] = None,
load_type: str = 'frame_based',
default_cam_key: str = 'CAM_FRONT',
use_pred_sample_idx: bool = False,
collect_device: str = 'cpu',
backend_args: Optional[dict] = None) -> None:
result_prefix: Optional[str] = None,
format_only: bool = False,
**kwargs) -> None:
super().__init__(**kwargs)
self.waymo_bin_file = waymo_bin_file
self.split = split
self.metrics = metric if isinstance(metric, list) else [metric]
self.load_type = load_type
self.use_pred_sample_idx = use_pred_sample_idx
self.convert_kitti_format = convert_kitti_format

super(WaymoMetric, self).__init__(
ann_file=ann_file,
metric=metric,
pcd_limit_range=pcd_limit_range,
prefix=prefix,
pklfile_prefix=pklfile_prefix,
submission_prefix=submission_prefix,
default_cam_key=default_cam_key,
collect_device=collect_device,
backend_args=backend_args)
self.format_only = format_only
self.result_prefix = result_prefix
if self.format_only:
assert pklfile_prefix is not None, 'pklfile_prefix must be not '
assert result_prefix is not None, 'result_prefix must be not '
'None when format_only is True, otherwise the result files will '
'be saved to a temp directory which will be cleaned up at the end.'

self.default_prefix = 'Waymo metric'

def process(self, data_batch: dict, data_samples: Sequence[dict]) -> None:
"""Process one batch of data samples and predictions.

Expand Down Expand Up @@ -187,43 +139,39 @@ def compute_metrics(self, results: List[dict]) -> Dict[str, float]:
]
results = self.merge_multi_view_boxes(frame_results)

if self.pklfile_prefix is None:
if self.result_prefix is None:
eval_tmp_dir = tempfile.TemporaryDirectory()
pklfile_prefix = osp.join(eval_tmp_dir.name, 'results')
result_prefix = osp.join(eval_tmp_dir.name, 'results')
else:
eval_tmp_dir = None
pklfile_prefix = self.pklfile_prefix
result_prefix = self.result_prefix

self.format_results(
results,
pklfile_prefix=pklfile_prefix,
submission_prefix=self.submission_prefix,
classes=self.classes)
self.format_results(results, result_prefix=result_prefix)

metric_dict = {}

if self.format_only:
logger.info('results are saved in '
f'{osp.dirname(self.pklfile_prefix)}')
f'{osp.dirname(self.result_prefix)}')
return metric_dict

for metric in self.metrics:
ap_dict = self.waymo_evaluate(
pklfile_prefix, metric=metric, logger=logger)
result_prefix, metric=metric, logger=logger)
metric_dict.update(ap_dict)
if eval_tmp_dir is not None:
eval_tmp_dir.cleanup()

return metric_dict

def waymo_evaluate(self,
pklfile_prefix: str,
result_prefix: str,
metric: Optional[str] = None,
logger: Optional[MMLogger] = None) -> Dict[str, float]:
"""Evaluation in Waymo protocol.

Args:
pklfile_prefix (str): The location that stored the prediction
result_prefix (str): The location that stored the prediction
results.
metric (str, optional): Metric to be evaluated. Defaults to None.
logger (MMLogger, optional): Logger used for printing related
Expand All @@ -237,7 +185,7 @@ def waymo_evaluate(self,

if metric == 'mAP':
eval_str = 'mmdet3d/evaluation/functional/waymo_utils/' + \
f'compute_detection_metrics_main {pklfile_prefix}.bin ' + \
f'compute_detection_metrics_main {result_prefix}.bin ' + \
f'{self.waymo_bin_file}'
print(eval_str)
ret_bytes = subprocess.check_output(eval_str, shell=True)
Expand Down Expand Up @@ -288,7 +236,7 @@ def waymo_evaluate(self,
ap_dict['Cyclist/L2 mAPH']) / 3
elif metric == 'LET_mAP':
eval_str = 'mmdet3d/evaluation/functional/waymo_utils/' + \
f'compute_detection_let_metrics_main {pklfile_prefix}.bin ' + \
f'compute_detection_let_metrics_main {result_prefix}.bin ' + \
f'{self.waymo_bin_file}'

print(eval_str)
Expand Down Expand Up @@ -338,49 +286,24 @@ def waymo_evaluate(self,
def format_results(
self,
results: List[dict],
pklfile_prefix: Optional[str] = None,
submission_prefix: Optional[str] = None,
classes: Optional[List[str]] = None
result_prefix: Optional[str] = None
) -> Tuple[dict, Union[tempfile.TemporaryDirectory, None]]:
"""Format the results to bin file.

Args:
results (List[dict]): Testing results of the dataset.
pklfile_prefix (str, optional): The prefix of pkl files. It
result_prefix (str, optional): The prefix of result file. It
includes the file path and the prefix of filename, e.g.,
"a/b/prefix". If not specified, a temp file will be created.
Defaults to None.
submission_prefix (str, optional): The prefix of submitted files.
It includes the file path and the prefix of filename, e.g.,
"a/b/prefix". If not specified, a temp file will be created.
Defaults to None.
classes (List[str], optional): A list of class name.
Defaults to None.

Returns:
tuple: (result_dict, tmp_dir), result_dict is a dict containing the
formatted result, tmp_dir is the temporal directory created for
saving json files when jsonfile_prefix is not specified.
"""
waymo_save_tmp_dir = tempfile.TemporaryDirectory()
waymo_results_save_dir = waymo_save_tmp_dir.name
waymo_results_final_path = f'{pklfile_prefix}.bin'

if self.convert_kitti_format:
results_kitti_format, tmp_dir = super().format_results(
results, pklfile_prefix, submission_prefix, classes)
results = results_kitti_format['pred_instances_3d']
waymo_results_final_path = f'{result_prefix}.bin'

from ..functional.waymo_utils.prediction_to_waymo import \
Prediction2Waymo
converter = Prediction2Waymo(
results,
waymo_results_save_dir,
waymo_results_final_path,
classes,
backend_args=self.backend_args)
converter = Prediction2Waymo(results, waymo_results_final_path,
self.classes)
converter.convert()
waymo_save_tmp_dir.cleanup()

def merge_multi_view_boxes(self, frame_results) -> dict:
"""Merge bounding boxes predicted from multi-view images.
Expand All @@ -391,7 +314,7 @@ def merge_multi_view_boxes(self, frame_results) -> dict:
cam0_info (dict): Store the sample idx for the given frame.

Returns:
dict: Merged results.
Dict: Merged results.
"""
merged_results = []
for frame_result in frame_results:
Expand Down
4 changes: 2 additions & 2 deletions mmdet3d/models/dense_heads/centerpoint_head.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def forward(self, x):
Returns:
dict[str: torch.Tensor]: contains the following keys:

-reg torch.Tensor): 2D regression value with the
-reg (torch.Tensor): 2D regression value with the
shape of [B, 2, H, W].
-height (torch.Tensor): Height value with the
shape of [B, 1, H, W].
Expand Down Expand Up @@ -217,7 +217,7 @@ def forward(self, x):
Returns:
dict[str: torch.Tensor]: contains the following keys:

-reg torch.Tensor): 2D regression value with the
-reg (torch.Tensor): 2D regression value with the
shape of [B, 2, H, W].
-height (torch.Tensor): Height value with the
shape of [B, 1, H, W].
Expand Down
Loading
Loading