Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
OpenPCDet
Commits
950c6712
Commit
950c6712
authored
Jul 03, 2020
by
Shaoshuai Shi
Browse files
support nuscene evaluation
parent
c7f6de36
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
345 additions
and
8 deletions
+345
-8
pcdet/datasets/nuscenes/nuscenes_dataset.py
pcdet/datasets/nuscenes/nuscenes_dataset.py
+97
-0
pcdet/datasets/nuscenes/nuscenes_utils.py
pcdet/datasets/nuscenes/nuscenes_utils.py
+237
-1
tools/cfgs/dataset_configs/nuscenes_dataset.yaml
tools/cfgs/dataset_configs/nuscenes_dataset.yaml
+6
-1
tools/cfgs/nuscenes_models/second.yaml
tools/cfgs/nuscenes_models/second.yaml
+1
-1
tools/cfgs/nuscenes_models/second_multihead.yaml
tools/cfgs/nuscenes_models/second_multihead.yaml
+1
-1
tools/eval_utils/eval_utils.py
tools/eval_utils/eval_utils.py
+3
-4
No files found.
pcdet/datasets/nuscenes/nuscenes_dataset.py
View file @
950c6712
...
@@ -77,6 +77,7 @@ class NuScenesDataset(DatasetTemplate):
...
@@ -77,6 +77,7 @@ class NuScenesDataset(DatasetTemplate):
input_dict
=
{
input_dict
=
{
'points'
:
points
,
'points'
:
points
,
'frame_id'
:
Path
(
info
[
'lidar_path'
]).
stem
,
'frame_id'
:
Path
(
info
[
'lidar_path'
]).
stem
,
'metadata'
:
{
'token'
:
info
[
'token'
]}
}
}
if
'gt_boxes'
in
info
:
if
'gt_boxes'
in
info
:
...
@@ -92,6 +93,102 @@ class NuScenesDataset(DatasetTemplate):
...
@@ -92,6 +93,102 @@ class NuScenesDataset(DatasetTemplate):
return
data_dict
return
data_dict
@
staticmethod
def
generate_prediction_dicts
(
batch_dict
,
pred_dicts
,
class_names
,
output_path
=
None
):
"""
Args:
batch_dict:
frame_id:
pred_dicts: list of pred_dicts
pred_boxes: (N, 7), Tensor
pred_scores: (N), Tensor
pred_labels: (N), Tensor
class_names:
output_path:
Returns:
"""
def
get_template_prediction
(
num_samples
):
ret_dict
=
{
'name'
:
np
.
zeros
(
num_samples
),
'score'
:
np
.
zeros
(
num_samples
),
'boxes_lidar'
:
np
.
zeros
([
num_samples
,
7
])
}
return
ret_dict
def
generate_single_sample_dict
(
box_dict
):
pred_scores
=
box_dict
[
'pred_scores'
].
cpu
().
numpy
()
pred_boxes
=
box_dict
[
'pred_boxes'
].
cpu
().
numpy
()
pred_labels
=
box_dict
[
'pred_labels'
].
cpu
().
numpy
()
pred_dict
=
get_template_prediction
(
pred_scores
.
shape
[
0
])
if
pred_scores
.
shape
[
0
]
==
0
:
return
pred_dict
pred_dict
[
'name'
]
=
np
.
array
(
class_names
)[
pred_labels
-
1
]
pred_dict
[
'score'
]
=
pred_scores
pred_dict
[
'boxes_lidar'
]
=
pred_boxes
pred_dict
[
'pred_labels'
]
=
pred_labels
return
pred_dict
annos
=
[]
for
index
,
box_dict
in
enumerate
(
pred_dicts
):
single_pred_dict
=
generate_single_sample_dict
(
box_dict
)
single_pred_dict
[
'frame_id'
]
=
batch_dict
[
'frame_id'
][
index
]
single_pred_dict
[
'metadata'
]
=
batch_dict
[
'metadata'
][
index
]
annos
.
append
(
single_pred_dict
)
return
annos
def
evaluation
(
self
,
det_annos
,
class_names
,
**
kwargs
):
import
json
from
nuscenes.nuscenes
import
NuScenes
from
.
import
nuscenes_utils
nusc
=
NuScenes
(
version
=
self
.
dataset_cfg
.
VERSION
,
dataroot
=
str
(
self
.
root_path
),
verbose
=
True
)
nusc_annos
=
nuscenes_utils
.
transform_det_annos_to_nusc_annos
(
det_annos
,
nusc
)
nusc_annos
[
'meta'
]
=
{
'use_camera'
:
False
,
'use_lidar'
:
True
,
'use_radar'
:
False
,
'use_map'
:
False
,
'use_external'
:
False
,
}
output_path
=
Path
(
kwargs
[
'output_path'
])
output_path
.
mkdir
(
exist_ok
=
True
,
parents
=
True
)
res_path
=
str
(
output_path
/
'results_nusc.json'
)
with
open
(
res_path
,
'w'
)
as
f
:
json
.
dump
(
nusc_annos
,
f
)
self
.
logger
.
info
(
f
'The predictions of NuScenes have been saved to
{
res_path
}
'
)
if
self
.
dataset_cfg
.
VERSION
==
'v1.0-test'
:
return
'No ground-truth annotations for evaluation'
,
{}
from
nuscenes.eval.detection.config
import
config_factory
from
nuscenes.eval.detection.evaluate
import
NuScenesEval
eval_version
=
'cvpr_2019'
eval_set_map
=
{
'v1.0-mini'
:
'mini_val'
,
'v1.0-trainval'
:
'val'
,
'v1.0-test'
:
'test'
}
nusc_eval
=
NuScenesEval
(
nusc
,
config
=
config_factory
(
eval_version
),
result_path
=
res_path
,
eval_set
=
eval_set_map
[
self
.
dataset_cfg
.
VERSION
],
output_dir
=
str
(
output_path
),
verbose
=
True
,
)
metrics_summary
=
nusc_eval
.
main
(
plot_examples
=
2
,
render_curves
=
False
)
with
open
(
output_path
/
'metrics_summary.json'
,
'r'
)
as
f
:
metrics
=
json
.
load
(
f
)
result_str
,
result_dict
=
nuscenes_utils
.
format_nuscene_results
(
metrics
,
self
.
class_names
,
version
=
eval_version
)
return
result_str
,
result_dict
def
create_groundtruth_database
(
self
,
used_classes
=
None
,
max_sweeps
=
10
):
def
create_groundtruth_database
(
self
,
used_classes
=
None
,
max_sweeps
=
10
):
import
torch
import
torch
...
...
pcdet/datasets/nuscenes/nuscenes_utils.py
View file @
950c6712
"""
"""
The NuScenes data pre-processing
is borrow
ed from
The NuScenes data pre-processing
and evaluation is modifi
ed from
https://github.com/traveller59/second.pytorch and https://github.com/poodarchu/Det3D
https://github.com/traveller59/second.pytorch and https://github.com/poodarchu/Det3D
"""
"""
from
pathlib
import
Path
from
pathlib
import
Path
import
tqdm
import
tqdm
import
numpy
as
np
import
numpy
as
np
import
operator
from
functools
import
reduce
from
functools
import
reduce
from
nuscenes.utils.geometry_utils
import
transform_matrix
from
nuscenes.utils.geometry_utils
import
transform_matrix
from
pyquaternion
import
Quaternion
from
pyquaternion
import
Quaternion
from
nuscenes.utils.data_classes
import
Box
map_name_from_general_to_detection
=
{
map_name_from_general_to_detection
=
{
...
@@ -38,6 +40,120 @@ map_name_from_general_to_detection = {
...
@@ -38,6 +40,120 @@ map_name_from_general_to_detection = {
}
}
cls_attr_dist
=
{
'barrier'
:
{
'cycle.with_rider'
:
0
,
'cycle.without_rider'
:
0
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
0
,
'vehicle.parked'
:
0
,
'vehicle.stopped'
:
0
,
},
'bicycle'
:
{
'cycle.with_rider'
:
2791
,
'cycle.without_rider'
:
8946
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
0
,
'vehicle.parked'
:
0
,
'vehicle.stopped'
:
0
,
},
'bus'
:
{
'cycle.with_rider'
:
0
,
'cycle.without_rider'
:
0
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
9092
,
'vehicle.parked'
:
3294
,
'vehicle.stopped'
:
3881
,
},
'car'
:
{
'cycle.with_rider'
:
0
,
'cycle.without_rider'
:
0
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
114304
,
'vehicle.parked'
:
330133
,
'vehicle.stopped'
:
46898
,
},
'construction_vehicle'
:
{
'cycle.with_rider'
:
0
,
'cycle.without_rider'
:
0
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
882
,
'vehicle.parked'
:
11549
,
'vehicle.stopped'
:
2102
,
},
'ignore'
:
{
'cycle.with_rider'
:
307
,
'cycle.without_rider'
:
73
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
165
,
'vehicle.parked'
:
400
,
'vehicle.stopped'
:
102
,
},
'motorcycle'
:
{
'cycle.with_rider'
:
4233
,
'cycle.without_rider'
:
8326
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
0
,
'vehicle.parked'
:
0
,
'vehicle.stopped'
:
0
,
},
'pedestrian'
:
{
'cycle.with_rider'
:
0
,
'cycle.without_rider'
:
0
,
'pedestrian.moving'
:
157444
,
'pedestrian.sitting_lying_down'
:
13939
,
'pedestrian.standing'
:
46530
,
'vehicle.moving'
:
0
,
'vehicle.parked'
:
0
,
'vehicle.stopped'
:
0
,
},
'traffic_cone'
:
{
'cycle.with_rider'
:
0
,
'cycle.without_rider'
:
0
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
0
,
'vehicle.parked'
:
0
,
'vehicle.stopped'
:
0
,
},
'trailer'
:
{
'cycle.with_rider'
:
0
,
'cycle.without_rider'
:
0
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
3421
,
'vehicle.parked'
:
19224
,
'vehicle.stopped'
:
1895
,
},
'truck'
:
{
'cycle.with_rider'
:
0
,
'cycle.without_rider'
:
0
,
'pedestrian.moving'
:
0
,
'pedestrian.sitting_lying_down'
:
0
,
'pedestrian.standing'
:
0
,
'vehicle.moving'
:
21339
,
'vehicle.parked'
:
55626
,
'vehicle.stopped'
:
11097
,
},
}
def
get_available_scenes
(
nusc
):
def
get_available_scenes
(
nusc
):
available_scenes
=
[]
available_scenes
=
[]
print
(
'total scene num:'
,
len
(
nusc
.
scene
))
print
(
'total scene num:'
,
len
(
nusc
.
scene
))
...
@@ -259,3 +375,123 @@ def fill_trainval_infos(data_path, nusc, train_scenes, val_scenes, test=False, m
...
@@ -259,3 +375,123 @@ def fill_trainval_infos(data_path, nusc, train_scenes, val_scenes, test=False, m
progress_bar
.
close
()
progress_bar
.
close
()
return
train_nusc_infos
,
val_nusc_infos
return
train_nusc_infos
,
val_nusc_infos
def
boxes_lidar_to_nusenes
(
det_info
):
boxes3d
=
det_info
[
'boxes_lidar'
]
scores
=
det_info
[
'score'
]
labels
=
det_info
[
'pred_labels'
]
box_list
=
[]
for
k
in
range
(
boxes3d
.
shape
[
0
]):
quat
=
Quaternion
(
axis
=
[
0
,
0
,
1
],
radians
=
boxes3d
[
k
,
6
])
velocity
=
(
*
boxes3d
[
k
,
7
:
9
],
0.0
)
if
boxes3d
.
shape
[
1
]
==
9
else
(
0.0
,
0.0
,
0.0
)
box
=
Box
(
boxes3d
[
k
,
:
3
],
boxes3d
[
k
,
[
4
,
3
,
5
]],
# wlh
quat
,
label
=
labels
[
k
],
score
=
scores
[
k
],
velocity
=
velocity
,
)
box_list
.
append
(
box
)
return
box_list
def
lidar_nusc_box_to_global
(
nusc
,
boxes
,
sample_token
):
s_record
=
nusc
.
get
(
'sample'
,
sample_token
)
sample_data_token
=
s_record
[
'data'
][
'LIDAR_TOP'
]
sd_record
=
nusc
.
get
(
'sample_data'
,
sample_data_token
)
cs_record
=
nusc
.
get
(
'calibrated_sensor'
,
sd_record
[
'calibrated_sensor_token'
])
sensor_record
=
nusc
.
get
(
'sensor'
,
cs_record
[
'sensor_token'
])
pose_record
=
nusc
.
get
(
'ego_pose'
,
sd_record
[
'ego_pose_token'
])
data_path
=
nusc
.
get_sample_data_path
(
sample_data_token
)
box_list
=
[]
for
box
in
boxes
:
# Move box to ego vehicle coord system
box
.
rotate
(
Quaternion
(
cs_record
[
'rotation'
]))
box
.
translate
(
np
.
array
(
cs_record
[
'translation'
]))
# Move box to global coord system
box
.
rotate
(
Quaternion
(
pose_record
[
'rotation'
]))
box
.
translate
(
np
.
array
(
pose_record
[
'translation'
]))
box_list
.
append
(
box
)
return
box_list
def
transform_det_annos_to_nusc_annos
(
det_annos
,
nusc
):
nusc_annos
=
{
'results'
:
{},
'meta'
:
None
,
}
for
det
in
det_annos
:
annos
=
[]
box_list
=
boxes_lidar_to_nusenes
(
det
)
box_list
=
lidar_nusc_box_to_global
(
nusc
=
nusc
,
boxes
=
box_list
,
sample_token
=
det
[
'metadata'
][
'token'
]
)
for
k
,
box
in
enumerate
(
box_list
):
name
=
det
[
'name'
][
k
]
if
np
.
sqrt
(
box
.
velocity
[
0
]
**
2
+
box
.
velocity
[
1
]
**
2
)
>
0.2
:
if
name
in
[
'car'
,
'construction_vehicle'
,
'bus'
,
'truck'
,
'trailer'
]:
attr
=
'vehicle.moving'
elif
name
in
[
'bicycle'
,
'motorcycle'
]:
attr
=
'cycle.with_rider'
else
:
attr
=
None
else
:
if
name
in
[
'pedestrian'
]:
attr
=
'pedestrian.standing'
elif
name
in
[
'bus'
]:
attr
=
'vehicle.stopped'
else
:
attr
=
None
attr
=
attr
if
attr
is
not
None
else
max
(
cls_attr_dist
[
name
].
items
(),
key
=
operator
.
itemgetter
(
1
))[
0
]
nusc_anno
=
{
'sample_token'
:
det
[
'metadata'
][
'token'
],
'translation'
:
box
.
center
.
tolist
(),
'size'
:
box
.
wlh
.
tolist
(),
'rotation'
:
box
.
orientation
.
elements
.
tolist
(),
'velocity'
:
box
.
velocity
[:
2
].
tolist
(),
'detection_name'
:
name
,
'detection_score'
:
box
.
score
,
'attribute_name'
:
attr
}
annos
.
append
(
nusc_anno
)
nusc_annos
[
'results'
].
update
({
det
[
"metadata"
][
"token"
]:
annos
})
return
nusc_annos
def
format_nuscene_results
(
metrics
,
class_names
,
version
=
'default'
):
result
=
'----------------Nuscene %s results-----------------
\n
'
%
version
for
name
in
class_names
:
threshs
=
', '
.
join
(
list
(
metrics
[
'label_aps'
][
name
].
keys
()))
ap_list
=
list
(
metrics
[
'label_aps'
][
name
].
values
())
err_name
=
', '
.
join
([
x
.
split
(
'_'
)[
0
]
for
x
in
list
(
metrics
[
'label_tp_errors'
][
name
].
keys
())])
error_list
=
list
(
metrics
[
'label_tp_errors'
][
name
].
values
())
result
+=
f
'***
{
name
}
error@
{
err_name
}
| AP@
{
threshs
}
\n
'
result
+=
', '
.
join
([
'%.2f'
%
x
for
x
in
error_list
])
+
' | '
result
+=
', '
.
join
([
'%.2f'
%
(
x
*
100
)
for
x
in
ap_list
])
result
+=
f
" | mean AP:
{
metrics
[
'mean_dist_aps'
][
name
]
}
"
result
+=
'
\n
'
result
+=
'--------------average performance-------------
\n
'
details
=
{}
for
key
,
val
in
metrics
[
'tp_errors'
].
items
():
result
+=
'%s:
\t
%.4f
\n
'
%
(
key
,
val
)
details
[
key
]
=
val
result
+=
'mAP:
\t
%.4f
\n
'
%
metrics
[
'mean_ap'
]
result
+=
'NDS:
\t
%.4f
\n
'
%
metrics
[
'nd_score'
]
details
.
update
({
'mAP'
:
metrics
[
'mean_ap'
],
'NDS'
:
metrics
[
'nd_score'
],
})
return
result
,
details
tools/cfgs/dataset_configs/nuscenes_dataset.yaml
View file @
950c6712
...
@@ -5,9 +5,14 @@ VERSION: 'v1.0-trainval'
...
@@ -5,9 +5,14 @@ VERSION: 'v1.0-trainval'
MAX_SWEEPS
:
10
MAX_SWEEPS
:
10
PRED_VELOCITY
:
False
PRED_VELOCITY
:
False
DATA_SPLIT
:
{
'
train'
:
train
,
'
test'
:
val
}
INFO_PATH
:
{
INFO_PATH
:
{
'
train'
:
[
nuscenes_infos_10sweeps_train.pkl
],
'
train'
:
[
nuscenes_infos_10sweeps_train.pkl
],
'
test'
:
[
nuscenes_infos_10sweeps_
train
.pkl
],
'
test'
:
[
nuscenes_infos_10sweeps_
val
.pkl
],
}
}
POINT_CLOUD_RANGE
:
[
-51.2
,
-51.2
,
-5.0
,
51.2
,
51.2
,
3.0
]
POINT_CLOUD_RANGE
:
[
-51.2
,
-51.2
,
-5.0
,
51.2
,
51.2
,
3.0
]
...
...
tools/cfgs/nuscenes_models/second.yaml
View file @
950c6712
...
@@ -165,7 +165,7 @@ MODEL:
...
@@ -165,7 +165,7 @@ MODEL:
NMS_CONFIG
:
NMS_CONFIG
:
MULTI_CLASSES_NMS
:
False
MULTI_CLASSES_NMS
:
False
NMS_TYPE
:
nms_gpu
NMS_TYPE
:
nms_gpu
NMS_THRESH
:
0.
01
NMS_THRESH
:
0.
2
NMS_PRE_MAXSIZE
:
4096
NMS_PRE_MAXSIZE
:
4096
NMS_POST_MAXSIZE
:
500
NMS_POST_MAXSIZE
:
500
...
...
tools/cfgs/nuscenes_models/second_multihead.yaml
View file @
950c6712
...
@@ -217,7 +217,7 @@ MODEL:
...
@@ -217,7 +217,7 @@ MODEL:
NMS_CONFIG
:
NMS_CONFIG
:
MULTI_CLASSES_NMS
:
False
MULTI_CLASSES_NMS
:
False
NMS_TYPE
:
nms_gpu
NMS_TYPE
:
nms_gpu
NMS_THRESH
:
0.
01
NMS_THRESH
:
0.
2
NMS_PRE_MAXSIZE
:
4096
NMS_PRE_MAXSIZE
:
4096
NMS_POST_MAXSIZE
:
500
NMS_POST_MAXSIZE
:
500
...
...
tools/eval_utils/eval_utils.py
View file @
950c6712
...
@@ -20,11 +20,9 @@ def statistics_info(cfg, ret_dict, metric, disp_dict):
...
@@ -20,11 +20,9 @@ def statistics_info(cfg, ret_dict, metric, disp_dict):
def
eval_one_epoch
(
cfg
,
model
,
dataloader
,
epoch_id
,
logger
,
dist_test
=
False
,
save_to_file
=
False
,
result_dir
=
None
):
def
eval_one_epoch
(
cfg
,
model
,
dataloader
,
epoch_id
,
logger
,
dist_test
=
False
,
save_to_file
=
False
,
result_dir
=
None
):
result_dir
.
mkdir
(
parents
=
True
,
exist_ok
=
True
)
result_dir
.
mkdir
(
parents
=
True
,
exist_ok
=
True
)
final_output_dir
=
result_dir
/
'final_result'
/
'data'
if
save_to_file
:
if
save_to_file
:
final_output_dir
=
result_dir
/
'final_result'
/
'data'
final_output_dir
.
mkdir
(
parents
=
True
,
exist_ok
=
True
)
final_output_dir
.
mkdir
(
parents
=
True
,
exist_ok
=
True
)
else
:
final_output_dir
=
None
metric
=
{
metric
=
{
'gt_num'
:
0
,
'gt_num'
:
0
,
...
@@ -109,7 +107,8 @@ def eval_one_epoch(cfg, model, dataloader, epoch_id, logger, dist_test=False, sa
...
@@ -109,7 +107,8 @@ def eval_one_epoch(cfg, model, dataloader, epoch_id, logger, dist_test=False, sa
result_str
,
result_dict
=
dataset
.
evaluation
(
result_str
,
result_dict
=
dataset
.
evaluation
(
det_annos
,
class_names
,
det_annos
,
class_names
,
eval_metric
=
cfg
.
MODEL
.
POST_PROCESSING
.
EVAL_METRIC
eval_metric
=
cfg
.
MODEL
.
POST_PROCESSING
.
EVAL_METRIC
,
output_path
=
final_output_dir
)
)
logger
.
info
(
result_str
)
logger
.
info
(
result_str
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment