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
mmdetection3d
Commits
21a8c818
"...git@developer.sourcefind.cn:OpenDAS/mmdetection3d.git" did not exist on "ac0302ed134f65aa7526ff78b0362a8f233fb4e4"
Commit
21a8c818
authored
May 02, 2020
by
wuyuefeng
Committed by
zhangwenwei
May 02, 2020
Browse files
Feature parta2 head
parent
2a7c24bb
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
760 additions
and
3 deletions
+760
-3
configs/kitti/dv_second_secfpn_2x8_cosine_80e_kitti-3d-3class.py
.../kitti/dv_second_secfpn_2x8_cosine_80e_kitti-3d-3class.py
+1
-1
configs/kitti/hv_PartA2_secfpn_4x8_cosine_80e_kitti-3d-3class.py
.../kitti/hv_PartA2_secfpn_4x8_cosine_80e_kitti-3d-3class.py
+217
-0
mmdet3d/models/anchor_heads/__init__.py
mmdet3d/models/anchor_heads/__init__.py
+2
-1
mmdet3d/models/anchor_heads/parta2_rpn_head.py
mmdet3d/models/anchor_heads/parta2_rpn_head.py
+249
-0
mmdet3d/models/detectors/__init__.py
mmdet3d/models/detectors/__init__.py
+2
-1
mmdet3d/models/detectors/parta2.py
mmdet3d/models/detectors/parta2.py
+117
-0
tests/test_heads.py
tests/test_heads.py
+172
-0
No files found.
configs/kitti/dv_second_secfpn_2x8_cosine_80e_kitti-3d-3class.py
View file @
21a8c818
...
@@ -116,7 +116,7 @@ input_modality = dict(
...
@@ -116,7 +116,7 @@ input_modality = dict(
use_lidar
=
True
,
use_lidar
=
True
,
use_depth
=
False
,
use_depth
=
False
,
use_lidar_intensity
=
True
,
use_lidar_intensity
=
True
,
use_camera
=
Fals
e
,
use_camera
=
Tru
e
,
)
)
db_sampler
=
dict
(
db_sampler
=
dict
(
root_path
=
data_root
,
root_path
=
data_root
,
...
...
configs/kitti/hv_PartA2_secfpn_4x8_cosine_80e_kitti-3d-3class.py
0 → 100644
View file @
21a8c818
# model settings
voxel_size
=
[
0.05
,
0.05
,
0.1
]
point_cloud_range
=
[
0
,
-
40
,
-
3
,
70.4
,
40
,
1
]
# velodyne coordinates, x, y, z
model
=
dict
(
type
=
'PartA2'
,
voxel_layer
=
dict
(
max_num_points
=
5
,
# max_points_per_voxel
point_cloud_range
=
point_cloud_range
,
voxel_size
=
voxel_size
,
max_voxels
=
(
16000
,
40000
)
# (training, testing) max_coxels
),
voxel_encoder
=
dict
(
type
=
'VoxelFeatureExtractorV3'
),
middle_encoder
=
dict
(
type
=
'SparseUNet'
,
in_channels
=
4
,
output_shape
=
[
41
,
1600
,
1408
],
pre_act
=
False
,
),
backbone
=
dict
(
type
=
'SECOND'
,
in_channels
=
256
,
layer_nums
=
[
5
,
5
],
layer_strides
=
[
1
,
2
],
num_filters
=
[
128
,
256
]),
neck
=
dict
(
type
=
'SECONDFPN'
,
in_channels
=
[
128
,
256
],
upsample_strides
=
[
1
,
2
],
num_upsample_filters
=
[
256
,
256
]),
rpn_head
=
dict
(
type
=
'PartA2RPNHead'
,
class_name
=
[
'Pedestrian'
,
'Cyclist'
,
'Car'
],
in_channels
=
512
,
feat_channels
=
512
,
use_direction_classifier
=
True
,
encode_bg_as_zeros
=
True
,
anchor_generator
=
dict
(
type
=
'Anchor3DRangeGenerator'
,
ranges
=
[[
0
,
-
40.0
,
-
0.6
,
70.4
,
40.0
,
-
0.6
],
[
0
,
-
40.0
,
-
0.6
,
70.4
,
40.0
,
-
0.6
],
[
0
,
-
40.0
,
-
1.78
,
70.4
,
40.0
,
-
1.78
]],
strides
=
[
2
],
sizes
=
[[
0.6
,
0.8
,
1.73
],
[
0.6
,
1.76
,
1.73
],
[
1.6
,
3.9
,
1.56
]],
rotations
=
[
0
,
1.57
],
reshape_out
=
False
),
diff_rad_by_sin
=
True
,
assigner_per_size
=
True
,
assign_per_class
=
True
,
bbox_coder
=
dict
(
type
=
'DeltaXYZWLHRBBoxCoder'
),
loss_cls
=
dict
(
type
=
'FocalLoss'
,
use_sigmoid
=
True
,
gamma
=
2.0
,
alpha
=
0.25
,
loss_weight
=
1.0
),
loss_bbox
=
dict
(
type
=
'SmoothL1Loss'
,
beta
=
1.0
/
9.0
,
loss_weight
=
2.0
),
loss_dir
=
dict
(
type
=
'CrossEntropyLoss'
,
use_sigmoid
=
False
,
loss_weight
=
0.2
),
))
# model training and testing settings
train_cfg
=
dict
(
rpn
=
dict
(
assigner
=
[
dict
(
# for Pedestrian
type
=
'MaxIoUAssigner'
,
iou_calculator
=
dict
(
type
=
'BboxOverlapsNearest3D'
),
pos_iou_thr
=
0.5
,
neg_iou_thr
=
0.35
,
min_pos_iou
=
0.35
,
ignore_iof_thr
=-
1
),
dict
(
# for Cyclist
type
=
'MaxIoUAssigner'
,
iou_calculator
=
dict
(
type
=
'BboxOverlapsNearest3D'
),
pos_iou_thr
=
0.5
,
neg_iou_thr
=
0.35
,
min_pos_iou
=
0.35
,
ignore_iof_thr
=-
1
),
dict
(
# for Car
type
=
'MaxIoUAssigner'
,
iou_calculator
=
dict
(
type
=
'BboxOverlapsNearest3D'
),
pos_iou_thr
=
0.6
,
neg_iou_thr
=
0.45
,
min_pos_iou
=
0.45
,
ignore_iof_thr
=-
1
),
],
allowed_border
=
0
,
pos_weight
=-
1
,
debug
=
False
),
rpn_proposal
=
dict
(
nms_pre
=
9000
,
nms_post
=
512
,
nms_thr
=
0.8
,
score_thr
=
0
,
use_rotate_nms
=
False
),
)
test_cfg
=
dict
(
rpn
=
dict
(
nms_pre
=
1024
,
max_per_img
=
100
,
use_rotate_nms
=
True
,
nms_across_levels
=
False
,
nms_thr
=
0.7
,
score_thr
=
0
))
# dataset settings
dataset_type
=
'KittiDataset'
data_root
=
'data/kitti/'
class_names
=
[
'Pedestrian'
,
'Cyclist'
,
'Car'
]
img_norm_cfg
=
dict
(
mean
=
[
123.675
,
116.28
,
103.53
],
std
=
[
58.395
,
57.12
,
57.375
],
to_rgb
=
True
)
input_modality
=
dict
(
use_lidar
=
True
,
use_depth
=
False
,
use_lidar_intensity
=
True
,
use_camera
=
True
)
db_sampler
=
dict
(
root_path
=
data_root
,
info_path
=
data_root
+
'kitti_dbinfos_train.pkl'
,
rate
=
1.0
,
use_road_plane
=
False
,
object_rot_range
=
[
0.0
,
0.0
],
prepare
=
dict
(
filter_by_difficulty
=
[
-
1
],
filter_by_min_points
=
dict
(
Car
=
5
,
Pedestrian
=
10
,
Cyclist
=
10
)),
sample_groups
=
dict
(
Car
=
12
,
Pedestrian
=
6
,
Cyclist
=
6
),
)
train_pipeline
=
[
dict
(
type
=
'ObjectSample'
,
db_sampler
=
db_sampler
),
dict
(
type
=
'ObjectNoise'
,
num_try
=
100
,
loc_noise_std
=
[
0
,
0
,
0
],
global_rot_range
=
[
0.0
,
0.0
],
rot_uniform_noise
=
[
-
0.39269908
,
0.39269908
]),
dict
(
type
=
'RandomFlip3D'
,
flip_ratio
=
0.5
),
dict
(
type
=
'GlobalRotScale'
,
rot_uniform_noise
=
[
-
0.78539816
,
0.78539816
],
scaling_uniform_noise
=
[
0.95
,
1.05
],
trans_normal_noise
=
[
0.2
,
0.2
,
0.2
]),
dict
(
type
=
'PointsRangeFilter'
,
point_cloud_range
=
point_cloud_range
),
dict
(
type
=
'ObjectRangeFilter'
,
point_cloud_range
=
point_cloud_range
),
dict
(
type
=
'PointShuffle'
),
dict
(
type
=
'DefaultFormatBundle3D'
,
class_names
=
class_names
),
dict
(
type
=
'Collect3D'
,
keys
=
[
'points'
,
'gt_bboxes_3d'
,
'gt_labels_3d'
]),
]
test_pipeline
=
[
dict
(
type
=
'PointsRangeFilter'
,
point_cloud_range
=
point_cloud_range
),
dict
(
type
=
'DefaultFormatBundle3D'
,
class_names
=
class_names
,
with_label
=
False
),
dict
(
type
=
'Collect3D'
,
keys
=
[
'points'
,
'gt_bboxes_3d'
]),
]
data
=
dict
(
samples_per_gpu
=
2
,
workers_per_gpu
=
2
,
train
=
dict
(
type
=
dataset_type
,
root_path
=
data_root
,
ann_file
=
data_root
+
'kitti_infos_train.pkl'
,
split
=
'training'
,
training
=
True
,
pipeline
=
train_pipeline
,
modality
=
input_modality
,
class_names
=
class_names
,
with_label
=
True
),
val
=
dict
(
type
=
dataset_type
,
root_path
=
data_root
,
ann_file
=
data_root
+
'kitti_infos_val.pkl'
,
split
=
'training'
,
pipeline
=
test_pipeline
,
modality
=
input_modality
,
class_names
=
class_names
,
with_label
=
True
),
test
=
dict
(
type
=
dataset_type
,
root_path
=
data_root
,
ann_file
=
data_root
+
'kitti_infos_val.pkl'
,
split
=
'testing'
,
pipeline
=
test_pipeline
,
modality
=
input_modality
,
class_names
=
class_names
,
with_label
=
True
))
# optimizer
lr
=
0.003
# max learning rate
optimizer
=
dict
(
type
=
'AdamW'
,
lr
=
lr
,
betas
=
(
0.95
,
0.99
),
# the momentum is change during training
weight_decay
=
0.001
)
optimizer_config
=
dict
(
grad_clip
=
dict
(
max_norm
=
10
,
norm_type
=
2
))
lr_config
=
dict
(
policy
=
'cosine'
,
warmup
=
'linear'
,
warmup_iters
=
1000
,
warmup_ratio
=
1.0
/
10
,
target_lr
=
1e-5
,
as_ratio
=
True
)
momentum_config
=
None
checkpoint_config
=
dict
(
interval
=
1
)
# yapf:disable
log_config
=
dict
(
interval
=
50
,
hooks
=
[
dict
(
type
=
'TextLoggerHook'
),
dict
(
type
=
'TensorboardLoggerHook'
)
])
# yapf:enable
# runtime settings
total_epochs
=
80
dist_params
=
dict
(
backend
=
'nccl'
,
port
=
29502
)
log_level
=
'INFO'
work_dir
=
'./work_dirs/parta2_secfpn_80e'
load_from
=
None
resume_from
=
None
workflow
=
[(
'train'
,
1
)]
mmdet3d/models/anchor_heads/__init__.py
View file @
21a8c818
from
.boxvelo_head
import
Anchor3DVeloHead
from
.boxvelo_head
import
Anchor3DVeloHead
from
.parta2_rpn_head
import
PartA2RPNHead
from
.second_head
import
SECONDHead
from
.second_head
import
SECONDHead
__all__
=
[
'Anchor3DVeloHead'
,
'SECONDHead'
]
__all__
=
[
'Anchor3DVeloHead'
,
'SECONDHead'
,
'PartA2RPNHead'
]
mmdet3d/models/anchor_heads/parta2_rpn_head.py
0 → 100644
View file @
21a8c818
from
__future__
import
division
import
numpy
as
np
import
torch
from
mmdet3d.core
import
box_torch_ops
,
boxes3d_to_bev_torch_lidar
from
mmdet3d.ops.iou3d.iou3d_utils
import
nms_gpu
,
nms_normal_gpu
from
mmdet.models
import
HEADS
from
.second_head
import
SECONDHead
@
HEADS
.
register_module
class
PartA2RPNHead
(
SECONDHead
):
"""rpn head for PartA2
Args:
class_name (list[str]): name of classes (TODO: to be removed)
in_channels (int): Number of channels in the input feature map.
train_cfg (dict): train configs
test_cfg (dict): test configs
feat_channels (int): Number of channels of the feature map.
use_direction_classifier (bool): Whether to add a direction classifier.
encode_bg_as_zeros (bool): Whether to use sigmoid of softmax
(TODO: to be removed)
box_code_size (int): The size of box code.
anchor_generator(dict): Config dict of anchor generator.
assigner_per_size (bool): Whether to do assignment for each separate
anchor size.
assign_per_class (bool): Whether to do assignment for each class.
diff_rad_by_sin (bool): Whether to change the difference into sin
difference for box regression loss.
dir_offset (float | int): The offset of BEV rotation angles
(TODO: may be moved into box coder)
dirlimit_offset (float | int): The limited range of BEV rotation angles
(TODO: may be moved into box coder)
box_coder (dict): Config dict of box coders.
loss_cls (dict): Config of classification loss.
loss_bbox (dict): Config of localization loss.
loss_dir (dict): Config of direction classifier loss.
"""
# npqa:W293
def
__init__
(
self
,
class_name
,
in_channels
,
train_cfg
,
test_cfg
,
feat_channels
=
256
,
use_direction_classifier
=
True
,
encode_bg_as_zeros
=
False
,
box_code_size
=
7
,
anchor_generator
=
dict
(
type
=
'Anchor3DRangeGenerator'
,
range
=
[
0
,
-
39.68
,
-
1.78
,
69.12
,
39.68
,
-
1.78
],
strides
=
[
2
],
sizes
=
[[
1.6
,
3.9
,
1.56
]],
rotations
=
[
0
,
1.57
],
custom_values
=
[],
reshape_out
=
False
),
assigner_per_size
=
False
,
assign_per_class
=
False
,
diff_rad_by_sin
=
True
,
dir_offset
=
0
,
dir_limit_offset
=
1
,
bbox_coder
=
dict
(
type
=
'DeltaXYZWLHRBBoxCoder'
),
loss_cls
=
dict
(
type
=
'CrossEntropyLoss'
,
use_sigmoid
=
True
,
loss_weight
=
1.0
),
loss_bbox
=
dict
(
type
=
'SmoothL1Loss'
,
beta
=
1.0
/
9.0
,
loss_weight
=
2.0
),
loss_dir
=
dict
(
type
=
'CrossEntropyLoss'
,
loss_weight
=
0.2
)):
super
().
__init__
(
class_name
,
in_channels
,
train_cfg
,
test_cfg
,
feat_channels
,
use_direction_classifier
,
encode_bg_as_zeros
,
box_code_size
,
anchor_generator
,
assigner_per_size
,
assign_per_class
,
diff_rad_by_sin
,
dir_offset
,
dir_limit_offset
,
bbox_coder
,
loss_cls
,
loss_bbox
,
loss_dir
)
def
get_bboxes
(
self
,
cls_scores
,
bbox_preds
,
dir_cls_preds
,
input_metas
,
cfg
,
rescale
=
False
):
assert
len
(
cls_scores
)
==
len
(
bbox_preds
)
assert
len
(
cls_scores
)
==
len
(
dir_cls_preds
)
num_levels
=
len
(
cls_scores
)
featmap_sizes
=
[
cls_scores
[
i
].
shape
[
-
2
:]
for
i
in
range
(
num_levels
)]
device
=
cls_scores
[
0
].
device
mlvl_anchors
=
self
.
anchor_generator
.
grid_anchors
(
featmap_sizes
,
device
=
device
)
mlvl_anchors
=
[
anchor
.
reshape
(
-
1
,
self
.
box_code_size
)
for
anchor
in
mlvl_anchors
]
result_list
=
[]
for
img_id
in
range
(
len
(
input_metas
)):
cls_score_list
=
[
cls_scores
[
i
][
img_id
].
detach
()
for
i
in
range
(
num_levels
)
]
bbox_pred_list
=
[
bbox_preds
[
i
][
img_id
].
detach
()
for
i
in
range
(
num_levels
)
]
dir_cls_pred_list
=
[
dir_cls_preds
[
i
][
img_id
].
detach
()
for
i
in
range
(
num_levels
)
]
input_meta
=
input_metas
[
img_id
]
proposals
=
self
.
get_bboxes_single
(
cls_score_list
,
bbox_pred_list
,
dir_cls_pred_list
,
mlvl_anchors
,
input_meta
,
cfg
,
rescale
)
result_list
.
append
(
proposals
)
return
result_list
def
get_bboxes_single
(
self
,
cls_scores
,
bbox_preds
,
dir_cls_preds
,
mlvl_anchors
,
input_meta
,
cfg
,
rescale
=
False
):
assert
len
(
cls_scores
)
==
len
(
bbox_preds
)
==
len
(
mlvl_anchors
)
mlvl_bboxes
=
[]
mlvl_max_scores
=
[]
mlvl_label_pred
=
[]
mlvl_dir_scores
=
[]
mlvl_cls_score
=
[]
for
cls_score
,
bbox_pred
,
dir_cls_pred
,
anchors
in
zip
(
cls_scores
,
bbox_preds
,
dir_cls_preds
,
mlvl_anchors
):
assert
cls_score
.
size
()[
-
2
:]
==
bbox_pred
.
size
()[
-
2
:]
assert
cls_score
.
size
()[
-
2
:]
==
dir_cls_pred
.
size
()[
-
2
:]
dir_cls_pred
=
dir_cls_pred
.
permute
(
1
,
2
,
0
).
reshape
(
-
1
,
2
)
dir_cls_score
=
torch
.
max
(
dir_cls_pred
,
dim
=-
1
)[
1
]
cls_score
=
cls_score
.
permute
(
1
,
2
,
0
).
reshape
(
-
1
,
self
.
num_classes
)
if
self
.
use_sigmoid_cls
:
scores
=
cls_score
.
sigmoid
()
else
:
scores
=
cls_score
.
softmax
(
-
1
)
bbox_pred
=
bbox_pred
.
permute
(
1
,
2
,
0
).
reshape
(
-
1
,
self
.
box_code_size
)
nms_pre
=
cfg
.
get
(
'nms_pre'
,
-
1
)
if
self
.
use_sigmoid_cls
:
max_scores
,
pred_labels
=
scores
.
max
(
dim
=
1
)
else
:
max_scores
,
pred_labels
=
scores
[:,
:
-
1
].
max
(
dim
=
1
)
# get topk
if
nms_pre
>
0
and
scores
.
shape
[
0
]
>
nms_pre
:
topk_scores
,
topk_inds
=
max_scores
.
topk
(
nms_pre
)
anchors
=
anchors
[
topk_inds
,
:]
bbox_pred
=
bbox_pred
[
topk_inds
,
:]
max_scores
=
topk_scores
cls_score
=
cls_score
[
topk_inds
,
:]
dir_cls_score
=
dir_cls_score
[
topk_inds
]
pred_labels
=
pred_labels
[
topk_inds
]
bboxes
=
self
.
bbox_coder
.
decode
(
anchors
,
bbox_pred
)
mlvl_bboxes
.
append
(
bboxes
)
mlvl_max_scores
.
append
(
max_scores
)
mlvl_cls_score
.
append
(
cls_score
)
mlvl_label_pred
.
append
(
pred_labels
)
mlvl_dir_scores
.
append
(
dir_cls_score
)
mlvl_bboxes
=
torch
.
cat
(
mlvl_bboxes
)
mlvl_bboxes_for_nms
=
boxes3d_to_bev_torch_lidar
(
mlvl_bboxes
)
mlvl_max_scores
=
torch
.
cat
(
mlvl_max_scores
)
mlvl_label_pred
=
torch
.
cat
(
mlvl_label_pred
)
mlvl_dir_scores
=
torch
.
cat
(
mlvl_dir_scores
)
mlvl_cls_score
=
torch
.
cat
(
mlvl_cls_score
)
# shape [k, num_class] before sigmoid
score_thr
=
cfg
.
get
(
'score_thr'
,
0
)
result
=
self
.
class_agnostic_nms
(
mlvl_bboxes
,
mlvl_bboxes_for_nms
,
mlvl_max_scores
,
mlvl_label_pred
,
mlvl_cls_score
,
mlvl_dir_scores
,
score_thr
,
cfg
.
nms_post
,
cfg
)
result
.
update
(
dict
(
sample_idx
=
input_meta
[
'sample_idx'
]))
return
result
def
class_agnostic_nms
(
self
,
mlvl_bboxes
,
mlvl_bboxes_for_nms
,
mlvl_max_scores
,
mlvl_label_pred
,
mlvl_cls_score
,
mlvl_dir_scores
,
score_thr
,
max_num
,
cfg
):
bboxes
=
[]
scores
=
[]
labels
=
[]
dir_scores
=
[]
cls_scores
=
[]
score_thr_inds
=
mlvl_max_scores
>
score_thr
_scores
=
mlvl_max_scores
[
score_thr_inds
]
_bboxes_for_nms
=
mlvl_bboxes_for_nms
[
score_thr_inds
,
:]
if
cfg
.
use_rotate_nms
:
nms_func
=
nms_gpu
else
:
nms_func
=
nms_normal_gpu
selected
=
nms_func
(
_bboxes_for_nms
,
_scores
,
cfg
.
nms_thr
)
_mlvl_bboxes
=
mlvl_bboxes
[
score_thr_inds
,
:]
_mlvl_dir_scores
=
mlvl_dir_scores
[
score_thr_inds
]
_mlvl_label_pred
=
mlvl_label_pred
[
score_thr_inds
]
_mlvl_cls_score
=
mlvl_cls_score
[
score_thr_inds
]
if
len
(
selected
)
>
0
:
bboxes
.
append
(
_mlvl_bboxes
[
selected
])
scores
.
append
(
_scores
[
selected
])
labels
.
append
(
_mlvl_label_pred
[
selected
])
cls_scores
.
append
(
_mlvl_cls_score
[
selected
])
dir_scores
.
append
(
_mlvl_dir_scores
[
selected
])
dir_rot
=
box_torch_ops
.
limit_period
(
bboxes
[
-
1
][...,
6
]
-
self
.
dir_offset
,
self
.
dir_limit_offset
,
np
.
pi
)
bboxes
[
-
1
][...,
6
]
=
(
dir_rot
+
self
.
dir_offset
+
np
.
pi
*
dir_scores
[
-
1
].
to
(
bboxes
[
-
1
].
dtype
))
if
bboxes
:
bboxes
=
torch
.
cat
(
bboxes
,
dim
=
0
)
scores
=
torch
.
cat
(
scores
,
dim
=
0
)
cls_scores
=
torch
.
cat
(
cls_scores
,
dim
=
0
)
labels
=
torch
.
cat
(
labels
,
dim
=
0
)
dir_scores
=
torch
.
cat
(
dir_scores
,
dim
=
0
)
if
bboxes
.
shape
[
0
]
>
max_num
:
_
,
inds
=
scores
.
sort
(
descending
=
True
)
inds
=
inds
[:
max_num
]
bboxes
=
bboxes
[
inds
,
:]
labels
=
labels
[
inds
]
scores
=
scores
[
inds
]
cls_scores
=
cls_scores
[
inds
]
dir_scores
=
dir_scores
[
inds
]
return
dict
(
box3d_lidar
=
bboxes
.
cpu
(),
scores
=
scores
.
cpu
(),
label_preds
=
labels
.
cpu
(),
cls_preds
=
cls_scores
.
cpu
(
)
# raw scores with shape [max_num, cls_num]
)
else
:
return
dict
(
box3d_lidar
=
mlvl_bboxes
.
new_zeros
([
0
,
self
.
box_code_size
]).
cpu
(),
scores
=
mlvl_bboxes
.
new_zeros
([
0
]).
cpu
(),
label_preds
=
mlvl_bboxes
.
new_zeros
([
0
]).
cpu
(),
cls_preds
=
mlvl_bboxes
.
new_zeros
([
0
,
mlvl_cls_score
.
shape
[
-
1
]
]).
cpu
())
mmdet3d/models/detectors/__init__.py
View file @
21a8c818
...
@@ -3,10 +3,11 @@ from .mvx_faster_rcnn import (DynamicMVXFasterRCNN, DynamicMVXFasterRCNNV2,
...
@@ -3,10 +3,11 @@ from .mvx_faster_rcnn import (DynamicMVXFasterRCNN, DynamicMVXFasterRCNNV2,
DynamicMVXFasterRCNNV3
)
DynamicMVXFasterRCNNV3
)
from
.mvx_single_stage
import
MVXSingleStageDetector
from
.mvx_single_stage
import
MVXSingleStageDetector
from
.mvx_two_stage
import
MVXTwoStageDetector
from
.mvx_two_stage
import
MVXTwoStageDetector
from
.parta2
import
PartA2
from
.voxelnet
import
DynamicVoxelNet
,
VoxelNet
from
.voxelnet
import
DynamicVoxelNet
,
VoxelNet
__all__
=
[
__all__
=
[
'BaseDetector'
,
'VoxelNet'
,
'DynamicVoxelNet'
,
'MVXSingleStageDetector'
,
'BaseDetector'
,
'VoxelNet'
,
'DynamicVoxelNet'
,
'MVXSingleStageDetector'
,
'MVXTwoStageDetector'
,
'DynamicMVXFasterRCNN'
,
'DynamicMVXFasterRCNNV2'
,
'MVXTwoStageDetector'
,
'DynamicMVXFasterRCNN'
,
'DynamicMVXFasterRCNNV2'
,
'DynamicMVXFasterRCNNV3'
'DynamicMVXFasterRCNNV3'
,
'PartA2'
]
]
mmdet3d/models/detectors/parta2.py
0 → 100644
View file @
21a8c818
import
torch
import
torch.nn.functional
as
F
from
mmdet3d.ops
import
Voxelization
from
mmdet.models
import
DETECTORS
,
TwoStageDetector
from
..
import
builder
@
DETECTORS
.
register_module
class
PartA2
(
TwoStageDetector
):
def
__init__
(
self
,
voxel_layer
,
voxel_encoder
,
middle_encoder
,
backbone
,
neck
=
None
,
rpn_head
=
None
,
roi_head
=
None
,
train_cfg
=
None
,
test_cfg
=
None
,
pretrained
=
None
):
super
(
PartA2
,
self
).
__init__
(
backbone
=
backbone
,
neck
=
neck
,
rpn_head
=
rpn_head
,
roi_head
=
roi_head
,
train_cfg
=
train_cfg
,
test_cfg
=
test_cfg
,
pretrained
=
pretrained
,
)
self
.
voxel_layer
=
Voxelization
(
**
voxel_layer
)
self
.
voxel_encoder
=
builder
.
build_voxel_encoder
(
voxel_encoder
)
self
.
middle_encoder
=
builder
.
build_middle_encoder
(
middle_encoder
)
def
extract_feat
(
self
,
points
,
img_meta
):
voxels
,
num_points
,
coors
=
self
.
voxelize
(
points
)
voxel_dict
=
dict
(
voxels
=
voxels
,
num_points
=
num_points
,
coors
=
coors
)
voxel_features
=
self
.
voxel_encoder
(
voxels
,
num_points
,
coors
)
batch_size
=
coors
[
-
1
,
0
].
item
()
+
1
feats_dict
=
self
.
middle_encoder
(
voxel_features
,
coors
,
batch_size
)
x
=
self
.
backbone
(
feats_dict
[
'spatial_features'
])
if
self
.
with_neck
:
neck_feats
=
self
.
neck
(
x
)
feats_dict
.
update
({
'neck_feats'
:
neck_feats
})
return
feats_dict
,
voxel_dict
@
torch
.
no_grad
()
def
voxelize
(
self
,
points
):
voxels
,
coors
,
num_points
=
[],
[],
[]
for
res
in
points
:
res_voxels
,
res_coors
,
res_num_points
=
self
.
voxel_layer
(
res
)
voxels
.
append
(
res_voxels
)
coors
.
append
(
res_coors
)
num_points
.
append
(
res_num_points
)
voxels
=
torch
.
cat
(
voxels
,
dim
=
0
)
num_points
=
torch
.
cat
(
num_points
,
dim
=
0
)
coors_batch
=
[]
for
i
,
coor
in
enumerate
(
coors
):
coor_pad
=
F
.
pad
(
coor
,
(
1
,
0
),
mode
=
'constant'
,
value
=
i
)
coors_batch
.
append
(
coor_pad
)
coors_batch
=
torch
.
cat
(
coors_batch
,
dim
=
0
)
return
voxels
,
num_points
,
coors_batch
def
forward_train
(
self
,
points
,
img_meta
,
gt_bboxes_3d
,
gt_labels_3d
,
gt_bboxes_ignore
=
None
,
proposals
=
None
):
# TODO: complete it
feats_dict
,
voxels_dict
=
self
.
extract_feat
(
points
,
img_meta
)
losses
=
dict
()
if
self
.
with_rpn
:
rpn_outs
=
self
.
rpn_head
(
feats_dict
[
'neck_feats'
])
rpn_loss_inputs
=
rpn_outs
+
(
gt_bboxes_3d
,
gt_labels_3d
,
img_meta
)
rpn_losses
=
self
.
rpn_head
.
loss
(
*
rpn_loss_inputs
,
gt_bboxes_ignore
=
gt_bboxes_ignore
)
losses
.
update
(
rpn_losses
)
proposal_cfg
=
self
.
train_cfg
.
get
(
'rpn_proposal'
,
self
.
test_cfg
.
rpn
)
proposal_inputs
=
rpn_outs
+
(
img_meta
,
proposal_cfg
)
proposal_list
=
self
.
rpn_head
.
get_bboxes
(
*
proposal_inputs
)
else
:
proposal_list
=
proposals
# noqa: F841
return
losses
def
forward_test
(
self
,
**
kwargs
):
return
self
.
simple_test
(
**
kwargs
)
def
forward
(
self
,
return_loss
=
True
,
**
kwargs
):
if
return_loss
:
return
self
.
forward_train
(
**
kwargs
)
else
:
return
self
.
forward_test
(
**
kwargs
)
def
simple_test
(
self
,
points
,
img_meta
,
gt_bboxes_3d
=
None
,
proposals
=
None
,
rescale
=
False
):
feats_dict
,
voxels_dict
=
self
.
extract_feat
(
points
,
img_meta
)
# TODO: complete it
if
proposals
is
None
:
proposal_list
=
self
.
simple_test_rpn
(
feats_dict
[
'neck_feats'
],
img_meta
,
self
.
test_cfg
.
rpn
)
else
:
proposal_list
=
proposals
return
self
.
roi_head
.
simple_test
(
feats_dict
,
proposal_list
,
img_meta
,
rescale
=
rescale
)
tests/test_heads.py
0 → 100644
View file @
21a8c818
import
copy
from
os.path
import
dirname
,
exists
,
join
import
pytest
import
torch
def
_get_config_directory
():
""" Find the predefined detector config directory """
try
:
# Assume we are running in the source mmdetection repo
repo_dpath
=
dirname
(
dirname
(
__file__
))
except
NameError
:
# For IPython development when this __file__ is not defined
import
mmdet
repo_dpath
=
dirname
(
dirname
(
mmdet
.
__file__
))
config_dpath
=
join
(
repo_dpath
,
'configs'
)
if
not
exists
(
config_dpath
):
raise
Exception
(
'Cannot find config path'
)
return
config_dpath
def
_get_config_module
(
fname
):
"""
Load a configuration as a python module
"""
from
mmcv
import
Config
config_dpath
=
_get_config_directory
()
config_fpath
=
join
(
config_dpath
,
fname
)
config_mod
=
Config
.
fromfile
(
config_fpath
)
return
config_mod
def
_get_head_cfg
(
fname
):
"""
Grab configs necessary to create a bbox_head. These are deep copied to
allow for safe modification of parameters without influencing other tests.
"""
import
mmcv
config
=
_get_config_module
(
fname
)
model
=
copy
.
deepcopy
(
config
.
model
)
train_cfg
=
mmcv
.
Config
(
copy
.
deepcopy
(
config
.
train_cfg
))
test_cfg
=
mmcv
.
Config
(
copy
.
deepcopy
(
config
.
test_cfg
))
bbox_head
=
model
.
bbox_head
bbox_head
.
update
(
train_cfg
=
train_cfg
)
bbox_head
.
update
(
test_cfg
=
test_cfg
)
return
bbox_head
def
_get_rpn_head_cfg
(
fname
):
"""
Grab configs necessary to create a rpn_head. These are deep copied to allow
for safe modification of parameters without influencing other tests.
"""
import
mmcv
config
=
_get_config_module
(
fname
)
model
=
copy
.
deepcopy
(
config
.
model
)
train_cfg
=
mmcv
.
Config
(
copy
.
deepcopy
(
config
.
train_cfg
))
test_cfg
=
mmcv
.
Config
(
copy
.
deepcopy
(
config
.
test_cfg
))
rpn_head
=
model
.
rpn_head
rpn_head
.
update
(
train_cfg
=
train_cfg
.
rpn
)
rpn_head
.
update
(
test_cfg
=
test_cfg
.
rpn
)
return
rpn_head
,
train_cfg
.
rpn_proposal
def
test_second_head_loss
():
if
not
torch
.
cuda
.
is_available
():
pytest
.
skip
(
'test requires GPU and torch+cuda'
)
bbox_head_cfg
=
_get_head_cfg
(
'kitti/dv_second_secfpn_2x8_cosine_80e_kitti-3d-3class.py'
)
from
mmdet3d.models.builder
import
build_head
self
=
build_head
(
bbox_head_cfg
)
self
.
cuda
()
assert
isinstance
(
self
.
conv_cls
,
torch
.
nn
.
modules
.
conv
.
Conv2d
)
assert
self
.
conv_cls
.
in_channels
==
512
assert
self
.
conv_cls
.
out_channels
==
18
assert
self
.
conv_reg
.
out_channels
==
42
assert
self
.
conv_dir_cls
.
out_channels
==
12
# test forward
feats
=
list
()
feats
.
append
(
torch
.
rand
([
2
,
512
,
200
,
176
],
dtype
=
torch
.
float32
).
cuda
())
(
cls_score
,
bbox_pred
,
dir_cls_preds
)
=
self
.
forward
(
feats
)
assert
cls_score
[
0
].
shape
==
torch
.
Size
([
2
,
18
,
200
,
176
])
assert
bbox_pred
[
0
].
shape
==
torch
.
Size
([
2
,
42
,
200
,
176
])
assert
dir_cls_preds
[
0
].
shape
==
torch
.
Size
([
2
,
12
,
200
,
176
])
# test loss
gt_bboxes
=
list
(
torch
.
tensor
(
[[[
6.4118
,
-
3.4305
,
-
1.7291
,
1.7033
,
3.4693
,
1.6197
,
-
0.9091
]],
[[
16.9107
,
9.7925
,
-
1.9201
,
1.6097
,
3.2786
,
1.5307
,
-
2.4056
]]],
dtype
=
torch
.
float32
).
cuda
())
gt_labels
=
list
(
torch
.
tensor
([[
0
],
[
1
]],
dtype
=
torch
.
int64
).
cuda
())
input_metas
=
[{
'sample_idx'
:
1234
},
{
'sample_idx'
:
2345
}]
# fake input_metas
losses
=
self
.
loss
(
cls_score
,
bbox_pred
,
dir_cls_preds
,
gt_bboxes
,
gt_labels
,
input_metas
)
assert
losses
[
'loss_cls_3d'
][
0
]
>
0
assert
losses
[
'loss_bbox_3d'
][
0
]
>
0
assert
losses
[
'loss_dir_3d'
][
0
]
>
0
# test empty ground truth case
gt_bboxes
=
list
(
torch
.
empty
((
2
,
0
,
7
)).
cuda
())
gt_labels
=
list
(
torch
.
empty
((
2
,
0
)).
cuda
())
empty_gt_losses
=
self
.
loss
(
cls_score
,
bbox_pred
,
dir_cls_preds
,
gt_bboxes
,
gt_labels
,
input_metas
)
assert
empty_gt_losses
[
'loss_cls_3d'
][
0
]
>
0
assert
empty_gt_losses
[
'loss_bbox_3d'
][
0
]
==
0
assert
empty_gt_losses
[
'loss_dir_3d'
][
0
]
==
0
def
test_second_head_getboxes
():
if
not
torch
.
cuda
.
is_available
():
pytest
.
skip
(
'test requires GPU and torch+cuda'
)
bbox_head_cfg
=
_get_head_cfg
(
'kitti/dv_second_secfpn_2x8_cosine_80e_kitti-3d-3class.py'
)
from
mmdet3d.models.builder
import
build_head
self
=
build_head
(
bbox_head_cfg
)
self
.
cuda
()
feats
=
list
()
feats
.
append
(
torch
.
rand
([
2
,
512
,
200
,
176
],
dtype
=
torch
.
float32
).
cuda
())
input_metas
=
[{
'sample_idx'
:
1234
},
{
'sample_idx'
:
2345
}]
# fake input_metas
(
cls_score
,
bbox_pred
,
dir_cls_preds
)
=
self
.
forward
(
feats
)
# test get_boxes
cls_score
[
0
]
-=
1.5
# too many positive samples may cause cuda oom
result_list
=
self
.
get_bboxes
(
cls_score
,
bbox_pred
,
dir_cls_preds
,
input_metas
)
assert
(
result_list
[
0
][
'scores'
]
>
0.3
).
all
()
def
test_parta2_rpnhead_getboxes
():
if
not
torch
.
cuda
.
is_available
():
pytest
.
skip
(
'test requires GPU and torch+cuda'
)
rpn_head_cfg
,
proposal_cfg
=
_get_rpn_head_cfg
(
'kitti/hv_PartA2_secfpn_4x8_cosine_80e_kitti-3d-3class.py'
)
from
mmdet3d.models.builder
import
build_head
self
=
build_head
(
rpn_head_cfg
)
self
.
cuda
()
feats
=
list
()
feats
.
append
(
torch
.
rand
([
2
,
512
,
200
,
176
],
dtype
=
torch
.
float32
).
cuda
())
input_metas
=
[{
'sample_idx'
:
1234
},
{
'sample_idx'
:
2345
}]
# fake input_metas
(
cls_score
,
bbox_pred
,
dir_cls_preds
)
=
self
.
forward
(
feats
)
# test get_boxes
cls_score
[
0
]
-=
1.5
# too many positive samples may cause cuda oom
result_list
=
self
.
get_bboxes
(
cls_score
,
bbox_pred
,
dir_cls_preds
,
input_metas
,
proposal_cfg
)
assert
result_list
[
0
][
'scores'
].
shape
==
torch
.
Size
([
512
])
assert
result_list
[
0
][
'label_preds'
].
shape
==
torch
.
Size
([
512
])
assert
result_list
[
0
][
'cls_preds'
].
shape
==
torch
.
Size
([
512
,
3
])
assert
result_list
[
0
][
'box3d_lidar'
].
shape
==
torch
.
Size
([
512
,
7
])
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