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
dcuai
dlexamples
Commits
142dcf29
Commit
142dcf29
authored
Apr 15, 2022
by
hepj
Browse files
增加conformer代码
parent
7f99c1c3
Changes
317
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
3386 additions
and
0 deletions
+3386
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/fp16/deprecated_fp16_utils.py
...main/mmdetection/mmdet/core/fp16/deprecated_fp16_utils.py
+47
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/mask/__init__.py
...LP/Conformer-main/mmdetection/mmdet/core/mask/__init__.py
+8
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/mask/mask_target.py
...Conformer-main/mmdetection/mmdet/core/mask/mask_target.py
+62
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/mask/structures.py
.../Conformer-main/mmdetection/mmdet/core/mask/structures.py
+828
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/mask/utils.py
...h/NLP/Conformer-main/mmdetection/mmdet/core/mask/utils.py
+63
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/post_processing/__init__.py
...r-main/mmdetection/mmdet/core/post_processing/__init__.py
+8
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/post_processing/bbox_nms.py
...r-main/mmdetection/mmdet/core/post_processing/bbox_nms.py
+157
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/post_processing/merge_augs.py
...main/mmdetection/mmdet/core/post_processing/merge_augs.py
+117
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/utils/__init__.py
...P/Conformer-main/mmdetection/mmdet/core/utils/__init__.py
+7
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/utils/dist_utils.py
...Conformer-main/mmdetection/mmdet/core/utils/dist_utils.py
+69
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/utils/misc.py
...h/NLP/Conformer-main/mmdetection/mmdet/core/utils/misc.py
+61
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/visualization/__init__.py
...mer-main/mmdetection/mmdet/core/visualization/__init__.py
+4
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/visualization/image.py
...former-main/mmdetection/mmdet/core/visualization/image.py
+296
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/__init__.py
...NLP/Conformer-main/mmdetection/mmdet/datasets/__init__.py
+22
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/builder.py
.../NLP/Conformer-main/mmdetection/mmdet/datasets/builder.py
+143
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/cityscapes.py
...P/Conformer-main/mmdetection/mmdet/datasets/cityscapes.py
+334
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/coco.py
...rch/NLP/Conformer-main/mmdetection/mmdet/datasets/coco.py
+544
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/custom.py
...h/NLP/Conformer-main/mmdetection/mmdet/datasets/custom.py
+324
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/dataset_wrappers.py
...ormer-main/mmdetection/mmdet/datasets/dataset_wrappers.py
+282
-0
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/deepfashion.py
.../Conformer-main/mmdetection/mmdet/datasets/deepfashion.py
+10
-0
No files found.
Too many changes to show.
To preserve performance only
317 of 317+
files are displayed.
Plain diff
Email patch
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/fp16/deprecated_fp16_utils.py
0 → 100644
View file @
142dcf29
import
warnings
from
mmcv.runner
import
(
Fp16OptimizerHook
,
auto_fp16
,
force_fp32
,
wrap_fp16_model
)
class
DeprecatedFp16OptimizerHook
(
Fp16OptimizerHook
):
"""A wrapper class for the FP16 optimizer hook. This class wraps
:class:`Fp16OptimizerHook` in `mmcv.runner` and shows a warning that the
:class:`Fp16OptimizerHook` from `mmdet.core` will be deprecated.
Refer to :class:`Fp16OptimizerHook` in `mmcv.runner` for more details.
Args:
loss_scale (float): Scale factor multiplied with loss.
"""
def
__init__
(
*
args
,
**
kwargs
):
super
().
__init__
(
*
args
,
**
kwargs
)
warnings
.
warn
(
'Importing Fp16OptimizerHook from "mmdet.core" will be '
'deprecated in the future. Please import them from "mmcv.runner" '
'instead'
)
def
deprecated_auto_fp16
(
*
args
,
**
kwargs
):
warnings
.
warn
(
'Importing auto_fp16 from "mmdet.core" will be '
'deprecated in the future. Please import them from "mmcv.runner" '
'instead'
)
return
auto_fp16
(
*
args
,
**
kwargs
)
def
deprecated_force_fp32
(
*
args
,
**
kwargs
):
warnings
.
warn
(
'Importing force_fp32 from "mmdet.core" will be '
'deprecated in the future. Please import them from "mmcv.runner" '
'instead'
)
return
force_fp32
(
*
args
,
**
kwargs
)
def
deprecated_wrap_fp16_model
(
*
args
,
**
kwargs
):
warnings
.
warn
(
'Importing wrap_fp16_model from "mmdet.core" will be '
'deprecated in the future. Please import them from "mmcv.runner" '
'instead'
)
wrap_fp16_model
(
*
args
,
**
kwargs
)
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/mask/__init__.py
0 → 100644
View file @
142dcf29
from
.mask_target
import
mask_target
from
.structures
import
BaseInstanceMasks
,
BitmapMasks
,
PolygonMasks
from
.utils
import
encode_mask_results
,
split_combined_polys
__all__
=
[
'split_combined_polys'
,
'mask_target'
,
'BaseInstanceMasks'
,
'BitmapMasks'
,
'PolygonMasks'
,
'encode_mask_results'
]
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/mask/mask_target.py
0 → 100644
View file @
142dcf29
import
numpy
as
np
import
torch
from
torch.nn.modules.utils
import
_pair
def
mask_target
(
pos_proposals_list
,
pos_assigned_gt_inds_list
,
gt_masks_list
,
cfg
):
"""Compute mask target for positive proposals in multiple images.
Args:
pos_proposals_list (list[Tensor]): Positive proposals in multiple
images.
pos_assigned_gt_inds_list (list[Tensor]): Assigned GT indices for each
positive proposals.
gt_masks_list (list[:obj:`BaseInstanceMasks`]): Ground truth masks of
each image.
cfg (dict): Config dict that specifies the mask size.
Returns:
list[Tensor]: Mask target of each image.
"""
cfg_list
=
[
cfg
for
_
in
range
(
len
(
pos_proposals_list
))]
mask_targets
=
map
(
mask_target_single
,
pos_proposals_list
,
pos_assigned_gt_inds_list
,
gt_masks_list
,
cfg_list
)
mask_targets
=
list
(
mask_targets
)
if
len
(
mask_targets
)
>
0
:
mask_targets
=
torch
.
cat
(
mask_targets
)
return
mask_targets
def
mask_target_single
(
pos_proposals
,
pos_assigned_gt_inds
,
gt_masks
,
cfg
):
"""Compute mask target for each positive proposal in the image.
Args:
pos_proposals (Tensor): Positive proposals.
pos_assigned_gt_inds (Tensor): Assigned GT inds of positive proposals.
gt_masks (:obj:`BaseInstanceMasks`): GT masks in the format of Bitmap
or Polygon.
cfg (dict): Config dict that indicate the mask size.
Returns:
Tensor: Mask target of each positive proposals in the image.
"""
device
=
pos_proposals
.
device
mask_size
=
_pair
(
cfg
.
mask_size
)
num_pos
=
pos_proposals
.
size
(
0
)
if
num_pos
>
0
:
proposals_np
=
pos_proposals
.
cpu
().
numpy
()
maxh
,
maxw
=
gt_masks
.
height
,
gt_masks
.
width
proposals_np
[:,
[
0
,
2
]]
=
np
.
clip
(
proposals_np
[:,
[
0
,
2
]],
0
,
maxw
)
proposals_np
[:,
[
1
,
3
]]
=
np
.
clip
(
proposals_np
[:,
[
1
,
3
]],
0
,
maxh
)
pos_assigned_gt_inds
=
pos_assigned_gt_inds
.
cpu
().
numpy
()
mask_targets
=
gt_masks
.
crop_and_resize
(
proposals_np
,
mask_size
,
device
=
device
,
inds
=
pos_assigned_gt_inds
).
to_ndarray
()
mask_targets
=
torch
.
from_numpy
(
mask_targets
).
float
().
to
(
device
)
else
:
mask_targets
=
pos_proposals
.
new_zeros
((
0
,
)
+
mask_size
)
return
mask_targets
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/mask/structures.py
0 → 100644
View file @
142dcf29
from
abc
import
ABCMeta
,
abstractmethod
import
cv2
import
mmcv
import
numpy
as
np
import
pycocotools.mask
as
maskUtils
import
torch
from
mmcv.ops.roi_align
import
roi_align
class
BaseInstanceMasks
(
metaclass
=
ABCMeta
):
"""Base class for instance masks."""
@
abstractmethod
def
rescale
(
self
,
scale
,
interpolation
=
'nearest'
):
"""Rescale masks as large as possible while keeping the aspect ratio.
For details can refer to `mmcv.imrescale`.
Args:
scale (tuple[int]): The maximum size (h, w) of rescaled mask.
interpolation (str): Same as :func:`mmcv.imrescale`.
Returns:
BaseInstanceMasks: The rescaled masks.
"""
pass
@
abstractmethod
def
resize
(
self
,
out_shape
,
interpolation
=
'nearest'
):
"""Resize masks to the given out_shape.
Args:
out_shape: Target (h, w) of resized mask.
interpolation (str): See :func:`mmcv.imresize`.
Returns:
BaseInstanceMasks: The resized masks.
"""
pass
@
abstractmethod
def
flip
(
self
,
flip_direction
=
'horizontal'
):
"""Flip masks alone the given direction.
Args:
flip_direction (str): Either 'horizontal' or 'vertical'.
Returns:
BaseInstanceMasks: The flipped masks.
"""
pass
@
abstractmethod
def
pad
(
self
,
out_shape
,
pad_val
):
"""Pad masks to the given size of (h, w).
Args:
out_shape (tuple[int]): Target (h, w) of padded mask.
pad_val (int): The padded value.
Returns:
BaseInstanceMasks: The padded masks.
"""
pass
@
abstractmethod
def
crop
(
self
,
bbox
):
"""Crop each mask by the given bbox.
Args:
bbox (ndarray): Bbox in format [x1, y1, x2, y2], shape (4, ).
Return:
BaseInstanceMasks: The cropped masks.
"""
pass
@
abstractmethod
def
crop_and_resize
(
self
,
bboxes
,
out_shape
,
inds
,
device
,
interpolation
=
'bilinear'
):
"""Crop and resize masks by the given bboxes.
This function is mainly used in mask targets computation.
It firstly align mask to bboxes by assigned_inds, then crop mask by the
assigned bbox and resize to the size of (mask_h, mask_w)
Args:
bboxes (Tensor): Bboxes in format [x1, y1, x2, y2], shape (N, 4)
out_shape (tuple[int]): Target (h, w) of resized mask
inds (ndarray): Indexes to assign masks to each bbox
device (str): Device of bboxes
interpolation (str): See `mmcv.imresize`
Return:
BaseInstanceMasks: the cropped and resized masks.
"""
pass
@
abstractmethod
def
expand
(
self
,
expanded_h
,
expanded_w
,
top
,
left
):
"""see :class:`Expand`."""
pass
@
property
@
abstractmethod
def
areas
(
self
):
"""ndarray: areas of each instance."""
pass
@
abstractmethod
def
to_ndarray
(
self
):
"""Convert masks to the format of ndarray.
Return:
ndarray: Converted masks in the format of ndarray.
"""
pass
@
abstractmethod
def
to_tensor
(
self
,
dtype
,
device
):
"""Convert masks to the format of Tensor.
Args:
dtype (str): Dtype of converted mask.
device (torch.device): Device of converted masks.
Returns:
Tensor: Converted masks in the format of Tensor.
"""
pass
@
abstractmethod
def
translate
(
self
,
out_shape
,
offset
,
direction
=
'horizontal'
,
fill_val
=
0
,
interpolation
=
'bilinear'
):
"""Translate the masks.
Args:
out_shape (tuple[int]): Shape for output mask, format (h, w).
offset (int | float): The offset for translate.
direction (str): The translate direction, either "horizontal"
or "vertical".
fill_val (int | float): Border value. Default 0.
interpolation (str): Same as :func:`mmcv.imtranslate`.
Returns:
Translated masks.
"""
pass
def
shear
(
self
,
out_shape
,
magnitude
,
direction
=
'horizontal'
,
border_value
=
0
,
interpolation
=
'bilinear'
):
"""Shear the masks.
Args:
out_shape (tuple[int]): Shape for output mask, format (h, w).
magnitude (int | float): The magnitude used for shear.
direction (str): The shear direction, either "horizontal"
or "vertical".
border_value (int | tuple[int]): Value used in case of a
constant border. Default 0.
interpolation (str): Same as in :func:`mmcv.imshear`.
Returns:
ndarray: Sheared masks.
"""
pass
@
abstractmethod
def
rotate
(
self
,
out_shape
,
angle
,
center
=
None
,
scale
=
1.0
,
fill_val
=
0
):
"""Rotate the masks.
Args:
out_shape (tuple[int]): Shape for output mask, format (h, w).
angle (int | float): Rotation angle in degrees. Positive values
mean counter-clockwise rotation.
center (tuple[float], optional): Center point (w, h) of the
rotation in source image. If not specified, the center of
the image will be used.
scale (int | float): Isotropic scale factor.
fill_val (int | float): Border value. Default 0 for masks.
Returns:
Rotated masks.
"""
pass
class
BitmapMasks
(
BaseInstanceMasks
):
"""This class represents masks in the form of bitmaps.
Args:
masks (ndarray): ndarray of masks in shape (N, H, W), where N is
the number of objects.
height (int): height of masks
width (int): width of masks
"""
def
__init__
(
self
,
masks
,
height
,
width
):
self
.
height
=
height
self
.
width
=
width
if
len
(
masks
)
==
0
:
self
.
masks
=
np
.
empty
((
0
,
self
.
height
,
self
.
width
),
dtype
=
np
.
uint8
)
else
:
assert
isinstance
(
masks
,
(
list
,
np
.
ndarray
))
if
isinstance
(
masks
,
list
):
assert
isinstance
(
masks
[
0
],
np
.
ndarray
)
assert
masks
[
0
].
ndim
==
2
# (H, W)
else
:
assert
masks
.
ndim
==
3
# (N, H, W)
self
.
masks
=
np
.
stack
(
masks
).
reshape
(
-
1
,
height
,
width
)
assert
self
.
masks
.
shape
[
1
]
==
self
.
height
assert
self
.
masks
.
shape
[
2
]
==
self
.
width
def
__getitem__
(
self
,
index
):
"""Index the BitmapMask.
Args:
index (int | ndarray): Indices in the format of integer or ndarray.
Returns:
:obj:`BitmapMasks`: Indexed bitmap masks.
"""
masks
=
self
.
masks
[
index
].
reshape
(
-
1
,
self
.
height
,
self
.
width
)
return
BitmapMasks
(
masks
,
self
.
height
,
self
.
width
)
def
__iter__
(
self
):
return
iter
(
self
.
masks
)
def
__repr__
(
self
):
s
=
self
.
__class__
.
__name__
+
'('
s
+=
f
'num_masks=
{
len
(
self
.
masks
)
}
, '
s
+=
f
'height=
{
self
.
height
}
, '
s
+=
f
'width=
{
self
.
width
}
)'
return
s
def
__len__
(
self
):
"""Number of masks."""
return
len
(
self
.
masks
)
def
rescale
(
self
,
scale
,
interpolation
=
'nearest'
):
"""See :func:`BaseInstanceMasks.rescale`."""
if
len
(
self
.
masks
)
==
0
:
new_w
,
new_h
=
mmcv
.
rescale_size
((
self
.
width
,
self
.
height
),
scale
)
rescaled_masks
=
np
.
empty
((
0
,
new_h
,
new_w
),
dtype
=
np
.
uint8
)
else
:
rescaled_masks
=
np
.
stack
([
mmcv
.
imrescale
(
mask
,
scale
,
interpolation
=
interpolation
)
for
mask
in
self
.
masks
])
height
,
width
=
rescaled_masks
.
shape
[
1
:]
return
BitmapMasks
(
rescaled_masks
,
height
,
width
)
def
resize
(
self
,
out_shape
,
interpolation
=
'nearest'
):
"""See :func:`BaseInstanceMasks.resize`."""
if
len
(
self
.
masks
)
==
0
:
resized_masks
=
np
.
empty
((
0
,
*
out_shape
),
dtype
=
np
.
uint8
)
else
:
resized_masks
=
np
.
stack
([
mmcv
.
imresize
(
mask
,
out_shape
[::
-
1
],
interpolation
=
interpolation
)
for
mask
in
self
.
masks
])
return
BitmapMasks
(
resized_masks
,
*
out_shape
)
def
flip
(
self
,
flip_direction
=
'horizontal'
):
"""See :func:`BaseInstanceMasks.flip`."""
assert
flip_direction
in
(
'horizontal'
,
'vertical'
,
'diagonal'
)
if
len
(
self
.
masks
)
==
0
:
flipped_masks
=
self
.
masks
else
:
flipped_masks
=
np
.
stack
([
mmcv
.
imflip
(
mask
,
direction
=
flip_direction
)
for
mask
in
self
.
masks
])
return
BitmapMasks
(
flipped_masks
,
self
.
height
,
self
.
width
)
def
pad
(
self
,
out_shape
,
pad_val
=
0
):
"""See :func:`BaseInstanceMasks.pad`."""
if
len
(
self
.
masks
)
==
0
:
padded_masks
=
np
.
empty
((
0
,
*
out_shape
),
dtype
=
np
.
uint8
)
else
:
padded_masks
=
np
.
stack
([
mmcv
.
impad
(
mask
,
shape
=
out_shape
,
pad_val
=
pad_val
)
for
mask
in
self
.
masks
])
return
BitmapMasks
(
padded_masks
,
*
out_shape
)
def
crop
(
self
,
bbox
):
"""See :func:`BaseInstanceMasks.crop`."""
assert
isinstance
(
bbox
,
np
.
ndarray
)
assert
bbox
.
ndim
==
1
# clip the boundary
bbox
=
bbox
.
copy
()
bbox
[
0
::
2
]
=
np
.
clip
(
bbox
[
0
::
2
],
0
,
self
.
width
)
bbox
[
1
::
2
]
=
np
.
clip
(
bbox
[
1
::
2
],
0
,
self
.
height
)
x1
,
y1
,
x2
,
y2
=
bbox
w
=
np
.
maximum
(
x2
-
x1
,
1
)
h
=
np
.
maximum
(
y2
-
y1
,
1
)
if
len
(
self
.
masks
)
==
0
:
cropped_masks
=
np
.
empty
((
0
,
h
,
w
),
dtype
=
np
.
uint8
)
else
:
cropped_masks
=
self
.
masks
[:,
y1
:
y1
+
h
,
x1
:
x1
+
w
]
return
BitmapMasks
(
cropped_masks
,
h
,
w
)
def
crop_and_resize
(
self
,
bboxes
,
out_shape
,
inds
,
device
=
'cpu'
,
interpolation
=
'bilinear'
):
"""See :func:`BaseInstanceMasks.crop_and_resize`."""
if
len
(
self
.
masks
)
==
0
:
empty_masks
=
np
.
empty
((
0
,
*
out_shape
),
dtype
=
np
.
uint8
)
return
BitmapMasks
(
empty_masks
,
*
out_shape
)
# convert bboxes to tensor
if
isinstance
(
bboxes
,
np
.
ndarray
):
bboxes
=
torch
.
from_numpy
(
bboxes
).
to
(
device
=
device
)
if
isinstance
(
inds
,
np
.
ndarray
):
inds
=
torch
.
from_numpy
(
inds
).
to
(
device
=
device
)
num_bbox
=
bboxes
.
shape
[
0
]
fake_inds
=
torch
.
arange
(
num_bbox
,
device
=
device
).
to
(
dtype
=
bboxes
.
dtype
)[:,
None
]
rois
=
torch
.
cat
([
fake_inds
,
bboxes
],
dim
=
1
)
# Nx5
rois
=
rois
.
to
(
device
=
device
)
if
num_bbox
>
0
:
gt_masks_th
=
torch
.
from_numpy
(
self
.
masks
).
to
(
device
).
index_select
(
0
,
inds
).
to
(
dtype
=
rois
.
dtype
)
targets
=
roi_align
(
gt_masks_th
[:,
None
,
:,
:],
rois
,
out_shape
,
1.0
,
0
,
'avg'
,
True
).
squeeze
(
1
)
resized_masks
=
(
targets
>=
0.5
).
cpu
().
numpy
()
else
:
resized_masks
=
[]
return
BitmapMasks
(
resized_masks
,
*
out_shape
)
def
expand
(
self
,
expanded_h
,
expanded_w
,
top
,
left
):
"""See :func:`BaseInstanceMasks.expand`."""
if
len
(
self
.
masks
)
==
0
:
expanded_mask
=
np
.
empty
((
0
,
expanded_h
,
expanded_w
),
dtype
=
np
.
uint8
)
else
:
expanded_mask
=
np
.
zeros
((
len
(
self
),
expanded_h
,
expanded_w
),
dtype
=
np
.
uint8
)
expanded_mask
[:,
top
:
top
+
self
.
height
,
left
:
left
+
self
.
width
]
=
self
.
masks
return
BitmapMasks
(
expanded_mask
,
expanded_h
,
expanded_w
)
def
translate
(
self
,
out_shape
,
offset
,
direction
=
'horizontal'
,
fill_val
=
0
,
interpolation
=
'bilinear'
):
"""Translate the BitmapMasks.
Args:
out_shape (tuple[int]): Shape for output mask, format (h, w).
offset (int | float): The offset for translate.
direction (str): The translate direction, either "horizontal"
or "vertical".
fill_val (int | float): Border value. Default 0 for masks.
interpolation (str): Same as :func:`mmcv.imtranslate`.
Returns:
BitmapMasks: Translated BitmapMasks.
"""
if
len
(
self
.
masks
)
==
0
:
translated_masks
=
np
.
empty
((
0
,
*
out_shape
),
dtype
=
np
.
uint8
)
else
:
translated_masks
=
mmcv
.
imtranslate
(
self
.
masks
.
transpose
((
1
,
2
,
0
)),
offset
,
direction
,
border_value
=
fill_val
,
interpolation
=
interpolation
)
if
translated_masks
.
ndim
==
2
:
translated_masks
=
translated_masks
[:,
:,
None
]
translated_masks
=
translated_masks
.
transpose
(
(
2
,
0
,
1
)).
astype
(
self
.
masks
.
dtype
)
return
BitmapMasks
(
translated_masks
,
*
out_shape
)
def
shear
(
self
,
out_shape
,
magnitude
,
direction
=
'horizontal'
,
border_value
=
0
,
interpolation
=
'bilinear'
):
"""Shear the BitmapMasks.
Args:
out_shape (tuple[int]): Shape for output mask, format (h, w).
magnitude (int | float): The magnitude used for shear.
direction (str): The shear direction, either "horizontal"
or "vertical".
border_value (int | tuple[int]): Value used in case of a
constant border.
interpolation (str): Same as in :func:`mmcv.imshear`.
Returns:
BitmapMasks: The sheared masks.
"""
if
len
(
self
.
masks
)
==
0
:
sheared_masks
=
np
.
empty
((
0
,
*
out_shape
),
dtype
=
np
.
uint8
)
else
:
sheared_masks
=
mmcv
.
imshear
(
self
.
masks
.
transpose
((
1
,
2
,
0
)),
magnitude
,
direction
,
border_value
=
border_value
,
interpolation
=
interpolation
)
if
sheared_masks
.
ndim
==
2
:
sheared_masks
=
sheared_masks
[:,
:,
None
]
sheared_masks
=
sheared_masks
.
transpose
(
(
2
,
0
,
1
)).
astype
(
self
.
masks
.
dtype
)
return
BitmapMasks
(
sheared_masks
,
*
out_shape
)
def
rotate
(
self
,
out_shape
,
angle
,
center
=
None
,
scale
=
1.0
,
fill_val
=
0
):
"""Rotate the BitmapMasks.
Args:
out_shape (tuple[int]): Shape for output mask, format (h, w).
angle (int | float): Rotation angle in degrees. Positive values
mean counter-clockwise rotation.
center (tuple[float], optional): Center point (w, h) of the
rotation in source image. If not specified, the center of
the image will be used.
scale (int | float): Isotropic scale factor.
fill_val (int | float): Border value. Default 0 for masks.
Returns:
BitmapMasks: Rotated BitmapMasks.
"""
if
len
(
self
.
masks
)
==
0
:
rotated_masks
=
np
.
empty
((
0
,
*
out_shape
),
dtype
=
self
.
masks
.
dtype
)
else
:
rotated_masks
=
mmcv
.
imrotate
(
self
.
masks
.
transpose
((
1
,
2
,
0
)),
angle
,
center
=
center
,
scale
=
scale
,
border_value
=
fill_val
)
if
rotated_masks
.
ndim
==
2
:
# case when only one mask, (h, w)
rotated_masks
=
rotated_masks
[:,
:,
None
]
# (h, w, 1)
rotated_masks
=
rotated_masks
.
transpose
(
(
2
,
0
,
1
)).
astype
(
self
.
masks
.
dtype
)
return
BitmapMasks
(
rotated_masks
,
*
out_shape
)
@
property
def
areas
(
self
):
"""See :py:attr:`BaseInstanceMasks.areas`."""
return
self
.
masks
.
sum
((
1
,
2
))
def
to_ndarray
(
self
):
"""See :func:`BaseInstanceMasks.to_ndarray`."""
return
self
.
masks
def
to_tensor
(
self
,
dtype
,
device
):
"""See :func:`BaseInstanceMasks.to_tensor`."""
return
torch
.
tensor
(
self
.
masks
,
dtype
=
dtype
,
device
=
device
)
class
PolygonMasks
(
BaseInstanceMasks
):
"""This class represents masks in the form of polygons.
Polygons is a list of three levels. The first level of the list
corresponds to objects, the second level to the polys that compose the
object, the third level to the poly coordinates
Args:
masks (list[list[ndarray]]): The first level of the list
corresponds to objects, the second level to the polys that
compose the object, the third level to the poly coordinates
height (int): height of masks
width (int): width of masks
"""
def
__init__
(
self
,
masks
,
height
,
width
):
assert
isinstance
(
masks
,
list
)
if
len
(
masks
)
>
0
:
assert
isinstance
(
masks
[
0
],
list
)
assert
isinstance
(
masks
[
0
][
0
],
np
.
ndarray
)
self
.
height
=
height
self
.
width
=
width
self
.
masks
=
masks
def
__getitem__
(
self
,
index
):
"""Index the polygon masks.
Args:
index (ndarray | List): The indices.
Returns:
:obj:`PolygonMasks`: The indexed polygon masks.
"""
if
isinstance
(
index
,
np
.
ndarray
):
index
=
index
.
tolist
()
if
isinstance
(
index
,
list
):
masks
=
[
self
.
masks
[
i
]
for
i
in
index
]
else
:
try
:
masks
=
self
.
masks
[
index
]
except
Exception
:
raise
ValueError
(
f
'Unsupported input of type
{
type
(
index
)
}
for indexing!'
)
if
len
(
masks
)
and
isinstance
(
masks
[
0
],
np
.
ndarray
):
masks
=
[
masks
]
# ensure a list of three levels
return
PolygonMasks
(
masks
,
self
.
height
,
self
.
width
)
def
__iter__
(
self
):
return
iter
(
self
.
masks
)
def
__repr__
(
self
):
s
=
self
.
__class__
.
__name__
+
'('
s
+=
f
'num_masks=
{
len
(
self
.
masks
)
}
, '
s
+=
f
'height=
{
self
.
height
}
, '
s
+=
f
'width=
{
self
.
width
}
)'
return
s
def
__len__
(
self
):
"""Number of masks."""
return
len
(
self
.
masks
)
def
rescale
(
self
,
scale
,
interpolation
=
None
):
"""see :func:`BaseInstanceMasks.rescale`"""
new_w
,
new_h
=
mmcv
.
rescale_size
((
self
.
width
,
self
.
height
),
scale
)
if
len
(
self
.
masks
)
==
0
:
rescaled_masks
=
PolygonMasks
([],
new_h
,
new_w
)
else
:
rescaled_masks
=
self
.
resize
((
new_h
,
new_w
))
return
rescaled_masks
def
resize
(
self
,
out_shape
,
interpolation
=
None
):
"""see :func:`BaseInstanceMasks.resize`"""
if
len
(
self
.
masks
)
==
0
:
resized_masks
=
PolygonMasks
([],
*
out_shape
)
else
:
h_scale
=
out_shape
[
0
]
/
self
.
height
w_scale
=
out_shape
[
1
]
/
self
.
width
resized_masks
=
[]
for
poly_per_obj
in
self
.
masks
:
resized_poly
=
[]
for
p
in
poly_per_obj
:
p
=
p
.
copy
()
p
[
0
::
2
]
*=
w_scale
p
[
1
::
2
]
*=
h_scale
resized_poly
.
append
(
p
)
resized_masks
.
append
(
resized_poly
)
resized_masks
=
PolygonMasks
(
resized_masks
,
*
out_shape
)
return
resized_masks
def
flip
(
self
,
flip_direction
=
'horizontal'
):
"""see :func:`BaseInstanceMasks.flip`"""
assert
flip_direction
in
(
'horizontal'
,
'vertical'
,
'diagonal'
)
if
len
(
self
.
masks
)
==
0
:
flipped_masks
=
PolygonMasks
([],
self
.
height
,
self
.
width
)
else
:
flipped_masks
=
[]
for
poly_per_obj
in
self
.
masks
:
flipped_poly_per_obj
=
[]
for
p
in
poly_per_obj
:
p
=
p
.
copy
()
if
flip_direction
==
'horizontal'
:
p
[
0
::
2
]
=
self
.
width
-
p
[
0
::
2
]
elif
flip_direction
==
'vertical'
:
p
[
1
::
2
]
=
self
.
height
-
p
[
1
::
2
]
else
:
p
[
0
::
2
]
=
self
.
width
-
p
[
0
::
2
]
p
[
1
::
2
]
=
self
.
height
-
p
[
1
::
2
]
flipped_poly_per_obj
.
append
(
p
)
flipped_masks
.
append
(
flipped_poly_per_obj
)
flipped_masks
=
PolygonMasks
(
flipped_masks
,
self
.
height
,
self
.
width
)
return
flipped_masks
def
crop
(
self
,
bbox
):
"""see :func:`BaseInstanceMasks.crop`"""
assert
isinstance
(
bbox
,
np
.
ndarray
)
assert
bbox
.
ndim
==
1
# clip the boundary
bbox
=
bbox
.
copy
()
bbox
[
0
::
2
]
=
np
.
clip
(
bbox
[
0
::
2
],
0
,
self
.
width
)
bbox
[
1
::
2
]
=
np
.
clip
(
bbox
[
1
::
2
],
0
,
self
.
height
)
x1
,
y1
,
x2
,
y2
=
bbox
w
=
np
.
maximum
(
x2
-
x1
,
1
)
h
=
np
.
maximum
(
y2
-
y1
,
1
)
if
len
(
self
.
masks
)
==
0
:
cropped_masks
=
PolygonMasks
([],
h
,
w
)
else
:
cropped_masks
=
[]
for
poly_per_obj
in
self
.
masks
:
cropped_poly_per_obj
=
[]
for
p
in
poly_per_obj
:
# pycocotools will clip the boundary
p
=
p
.
copy
()
p
[
0
::
2
]
-=
bbox
[
0
]
p
[
1
::
2
]
-=
bbox
[
1
]
cropped_poly_per_obj
.
append
(
p
)
cropped_masks
.
append
(
cropped_poly_per_obj
)
cropped_masks
=
PolygonMasks
(
cropped_masks
,
h
,
w
)
return
cropped_masks
def
pad
(
self
,
out_shape
,
pad_val
=
0
):
"""padding has no effect on polygons`"""
return
PolygonMasks
(
self
.
masks
,
*
out_shape
)
def
expand
(
self
,
*
args
,
**
kwargs
):
"""TODO: Add expand for polygon"""
raise
NotImplementedError
def
crop_and_resize
(
self
,
bboxes
,
out_shape
,
inds
,
device
=
'cpu'
,
interpolation
=
'bilinear'
):
"""see :func:`BaseInstanceMasks.crop_and_resize`"""
out_h
,
out_w
=
out_shape
if
len
(
self
.
masks
)
==
0
:
return
PolygonMasks
([],
out_h
,
out_w
)
resized_masks
=
[]
for
i
in
range
(
len
(
bboxes
)):
mask
=
self
.
masks
[
inds
[
i
]]
bbox
=
bboxes
[
i
,
:]
x1
,
y1
,
x2
,
y2
=
bbox
w
=
np
.
maximum
(
x2
-
x1
,
1
)
h
=
np
.
maximum
(
y2
-
y1
,
1
)
h_scale
=
out_h
/
max
(
h
,
0.1
)
# avoid too large scale
w_scale
=
out_w
/
max
(
w
,
0.1
)
resized_mask
=
[]
for
p
in
mask
:
p
=
p
.
copy
()
# crop
# pycocotools will clip the boundary
p
[
0
::
2
]
-=
bbox
[
0
]
p
[
1
::
2
]
-=
bbox
[
1
]
# resize
p
[
0
::
2
]
*=
w_scale
p
[
1
::
2
]
*=
h_scale
resized_mask
.
append
(
p
)
resized_masks
.
append
(
resized_mask
)
return
PolygonMasks
(
resized_masks
,
*
out_shape
)
def
translate
(
self
,
out_shape
,
offset
,
direction
=
'horizontal'
,
fill_val
=
None
,
interpolation
=
None
):
"""Translate the PolygonMasks."""
assert
fill_val
is
None
or
fill_val
==
0
,
'Here fill_val is not '
\
f
'used, and defaultly should be None or 0. got
{
fill_val
}
.'
if
len
(
self
.
masks
)
==
0
:
translated_masks
=
PolygonMasks
([],
*
out_shape
)
else
:
translated_masks
=
[]
for
poly_per_obj
in
self
.
masks
:
translated_poly_per_obj
=
[]
for
p
in
poly_per_obj
:
p
=
p
.
copy
()
if
direction
==
'horizontal'
:
p
[
0
::
2
]
=
np
.
clip
(
p
[
0
::
2
]
+
offset
,
0
,
out_shape
[
1
])
elif
direction
==
'vertical'
:
p
[
1
::
2
]
=
np
.
clip
(
p
[
1
::
2
]
+
offset
,
0
,
out_shape
[
0
])
translated_poly_per_obj
.
append
(
p
)
translated_masks
.
append
(
translated_poly_per_obj
)
translated_masks
=
PolygonMasks
(
translated_masks
,
*
out_shape
)
return
translated_masks
def
shear
(
self
,
out_shape
,
magnitude
,
direction
=
'horizontal'
,
border_value
=
0
,
interpolation
=
'bilinear'
):
"""See :func:`BaseInstanceMasks.shear`."""
if
len
(
self
.
masks
)
==
0
:
sheared_masks
=
PolygonMasks
([],
*
out_shape
)
else
:
sheared_masks
=
[]
if
direction
==
'horizontal'
:
shear_matrix
=
np
.
stack
([[
1
,
magnitude
],
[
0
,
1
]]).
astype
(
np
.
float32
)
elif
direction
==
'vertical'
:
shear_matrix
=
np
.
stack
([[
1
,
0
],
[
magnitude
,
1
]]).
astype
(
np
.
float32
)
for
poly_per_obj
in
self
.
masks
:
sheared_poly
=
[]
for
p
in
poly_per_obj
:
p
=
np
.
stack
([
p
[
0
::
2
],
p
[
1
::
2
]],
axis
=
0
)
# [2, n]
new_coords
=
np
.
matmul
(
shear_matrix
,
p
)
# [2, n]
new_coords
[
0
,
:]
=
np
.
clip
(
new_coords
[
0
,
:],
0
,
out_shape
[
1
])
new_coords
[
1
,
:]
=
np
.
clip
(
new_coords
[
1
,
:],
0
,
out_shape
[
0
])
sheared_poly
.
append
(
new_coords
.
transpose
((
1
,
0
)).
reshape
(
-
1
))
sheared_masks
.
append
(
sheared_poly
)
sheared_masks
=
PolygonMasks
(
sheared_masks
,
*
out_shape
)
return
sheared_masks
def
rotate
(
self
,
out_shape
,
angle
,
center
=
None
,
scale
=
1.0
,
fill_val
=
0
):
"""See :func:`BaseInstanceMasks.rotate`."""
if
len
(
self
.
masks
)
==
0
:
rotated_masks
=
PolygonMasks
([],
*
out_shape
)
else
:
rotated_masks
=
[]
rotate_matrix
=
cv2
.
getRotationMatrix2D
(
center
,
-
angle
,
scale
)
for
poly_per_obj
in
self
.
masks
:
rotated_poly
=
[]
for
p
in
poly_per_obj
:
p
=
p
.
copy
()
coords
=
np
.
stack
([
p
[
0
::
2
],
p
[
1
::
2
]],
axis
=
1
)
# [n, 2]
# pad 1 to convert from format [x, y] to homogeneous
# coordinates format [x, y, 1]
coords
=
np
.
concatenate
(
(
coords
,
np
.
ones
((
coords
.
shape
[
0
],
1
),
coords
.
dtype
)),
axis
=
1
)
# [n, 3]
rotated_coords
=
np
.
matmul
(
rotate_matrix
[
None
,
:,
:],
coords
[:,
:,
None
])[...,
0
]
# [n, 2, 1] -> [n, 2]
rotated_coords
[:,
0
]
=
np
.
clip
(
rotated_coords
[:,
0
],
0
,
out_shape
[
1
])
rotated_coords
[:,
1
]
=
np
.
clip
(
rotated_coords
[:,
1
],
0
,
out_shape
[
0
])
rotated_poly
.
append
(
rotated_coords
.
reshape
(
-
1
))
rotated_masks
.
append
(
rotated_poly
)
rotated_masks
=
PolygonMasks
(
rotated_masks
,
*
out_shape
)
return
rotated_masks
def
to_bitmap
(
self
):
"""convert polygon masks to bitmap masks."""
bitmap_masks
=
self
.
to_ndarray
()
return
BitmapMasks
(
bitmap_masks
,
self
.
height
,
self
.
width
)
@
property
def
areas
(
self
):
"""Compute areas of masks.
This func is modified from `detectron2
<https://github.com/facebookresearch/detectron2/blob/ffff8acc35ea88ad1cb1806ab0f00b4c1c5dbfd9/detectron2/structures/masks.py#L387>`_.
The function only works with Polygons using the shoelace formula.
Return:
ndarray: areas of each instance
"""
# noqa: W501
area
=
[]
for
polygons_per_obj
in
self
.
masks
:
area_per_obj
=
0
for
p
in
polygons_per_obj
:
area_per_obj
+=
self
.
_polygon_area
(
p
[
0
::
2
],
p
[
1
::
2
])
area
.
append
(
area_per_obj
)
return
np
.
asarray
(
area
)
def
_polygon_area
(
self
,
x
,
y
):
"""Compute the area of a component of a polygon.
Using the shoelace formula:
https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates
Args:
x (ndarray): x coordinates of the component
y (ndarray): y coordinates of the component
Return:
float: the are of the component
"""
# noqa: 501
return
0.5
*
np
.
abs
(
np
.
dot
(
x
,
np
.
roll
(
y
,
1
))
-
np
.
dot
(
y
,
np
.
roll
(
x
,
1
)))
def
to_ndarray
(
self
):
"""Convert masks to the format of ndarray."""
if
len
(
self
.
masks
)
==
0
:
return
np
.
empty
((
0
,
self
.
height
,
self
.
width
),
dtype
=
np
.
uint8
)
bitmap_masks
=
[]
for
poly_per_obj
in
self
.
masks
:
bitmap_masks
.
append
(
polygon_to_bitmap
(
poly_per_obj
,
self
.
height
,
self
.
width
))
return
np
.
stack
(
bitmap_masks
)
def
to_tensor
(
self
,
dtype
,
device
):
"""See :func:`BaseInstanceMasks.to_tensor`."""
if
len
(
self
.
masks
)
==
0
:
return
torch
.
empty
((
0
,
self
.
height
,
self
.
width
),
dtype
=
dtype
,
device
=
device
)
ndarray_masks
=
self
.
to_ndarray
()
return
torch
.
tensor
(
ndarray_masks
,
dtype
=
dtype
,
device
=
device
)
def
polygon_to_bitmap
(
polygons
,
height
,
width
):
"""Convert masks from the form of polygons to bitmaps.
Args:
polygons (list[ndarray]): masks in polygon representation
height (int): mask height
width (int): mask width
Return:
ndarray: the converted masks in bitmap representation
"""
rles
=
maskUtils
.
frPyObjects
(
polygons
,
height
,
width
)
rle
=
maskUtils
.
merge
(
rles
)
bitmap_mask
=
maskUtils
.
decode
(
rle
).
astype
(
np
.
bool
)
return
bitmap_mask
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/mask/utils.py
0 → 100644
View file @
142dcf29
import
mmcv
import
numpy
as
np
import
pycocotools.mask
as
mask_util
def
split_combined_polys
(
polys
,
poly_lens
,
polys_per_mask
):
"""Split the combined 1-D polys into masks.
A mask is represented as a list of polys, and a poly is represented as
a 1-D array. In dataset, all masks are concatenated into a single 1-D
tensor. Here we need to split the tensor into original representations.
Args:
polys (list): a list (length = image num) of 1-D tensors
poly_lens (list): a list (length = image num) of poly length
polys_per_mask (list): a list (length = image num) of poly number
of each mask
Returns:
list: a list (length = image num) of list (length = mask num) of
\
list (length = poly num) of numpy array.
"""
mask_polys_list
=
[]
for
img_id
in
range
(
len
(
polys
)):
polys_single
=
polys
[
img_id
]
polys_lens_single
=
poly_lens
[
img_id
].
tolist
()
polys_per_mask_single
=
polys_per_mask
[
img_id
].
tolist
()
split_polys
=
mmcv
.
slice_list
(
polys_single
,
polys_lens_single
)
mask_polys
=
mmcv
.
slice_list
(
split_polys
,
polys_per_mask_single
)
mask_polys_list
.
append
(
mask_polys
)
return
mask_polys_list
# TODO: move this function to more proper place
def
encode_mask_results
(
mask_results
):
"""Encode bitmap mask to RLE code.
Args:
mask_results (list | tuple[list]): bitmap mask results.
In mask scoring rcnn, mask_results is a tuple of (segm_results,
segm_cls_score).
Returns:
list | tuple: RLE encoded mask.
"""
if
isinstance
(
mask_results
,
tuple
):
# mask scoring
cls_segms
,
cls_mask_scores
=
mask_results
else
:
cls_segms
=
mask_results
num_classes
=
len
(
cls_segms
)
encoded_mask_results
=
[[]
for
_
in
range
(
num_classes
)]
for
i
in
range
(
len
(
cls_segms
)):
for
cls_segm
in
cls_segms
[
i
]:
encoded_mask_results
[
i
].
append
(
mask_util
.
encode
(
np
.
array
(
cls_segm
[:,
:,
np
.
newaxis
],
order
=
'F'
,
dtype
=
'uint8'
))[
0
])
# encoded with RLE
if
isinstance
(
mask_results
,
tuple
):
return
encoded_mask_results
,
cls_mask_scores
else
:
return
encoded_mask_results
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/post_processing/__init__.py
0 → 100644
View file @
142dcf29
from
.bbox_nms
import
fast_nms
,
multiclass_nms
from
.merge_augs
import
(
merge_aug_bboxes
,
merge_aug_masks
,
merge_aug_proposals
,
merge_aug_scores
)
__all__
=
[
'multiclass_nms'
,
'merge_aug_proposals'
,
'merge_aug_bboxes'
,
'merge_aug_scores'
,
'merge_aug_masks'
,
'fast_nms'
]
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/post_processing/bbox_nms.py
0 → 100644
View file @
142dcf29
import
torch
from
mmcv.ops.nms
import
batched_nms
from
mmdet.core.bbox.iou_calculators
import
bbox_overlaps
def
multiclass_nms
(
multi_bboxes
,
multi_scores
,
score_thr
,
nms_cfg
,
max_num
=-
1
,
score_factors
=
None
,
return_inds
=
False
):
"""NMS for multi-class bboxes.
Args:
multi_bboxes (Tensor): shape (n, #class*4) or (n, 4)
multi_scores (Tensor): shape (n, #class), where the last column
contains scores of the background class, but this will be ignored.
score_thr (float): bbox threshold, bboxes with scores lower than it
will not be considered.
nms_thr (float): NMS IoU threshold
max_num (int, optional): if there are more than max_num bboxes after
NMS, only top max_num will be kept. Default to -1.
score_factors (Tensor, optional): The factors multiplied to scores
before applying NMS. Default to None.
return_inds (bool, optional): Whether return the indices of kept
bboxes. Default to False.
Returns:
tuple: (bboxes, labels, indices (optional)), tensors of shape (k, 5),
(k), and (k). Labels are 0-based.
"""
num_classes
=
multi_scores
.
size
(
1
)
-
1
# exclude background category
if
multi_bboxes
.
shape
[
1
]
>
4
:
bboxes
=
multi_bboxes
.
view
(
multi_scores
.
size
(
0
),
-
1
,
4
)
else
:
bboxes
=
multi_bboxes
[:,
None
].
expand
(
multi_scores
.
size
(
0
),
num_classes
,
4
)
scores
=
multi_scores
[:,
:
-
1
]
labels
=
torch
.
arange
(
num_classes
,
dtype
=
torch
.
long
)
labels
=
labels
.
view
(
1
,
-
1
).
expand_as
(
scores
)
bboxes
=
bboxes
.
reshape
(
-
1
,
4
)
scores
=
scores
.
reshape
(
-
1
)
labels
=
labels
.
reshape
(
-
1
)
# remove low scoring boxes
valid_mask
=
scores
>
score_thr
# multiply score_factor after threshold to preserve more bboxes, improve
# mAP by 1% for YOLOv3
if
score_factors
is
not
None
:
# expand the shape to match original shape of score
score_factors
=
score_factors
.
view
(
-
1
,
1
).
expand
(
multi_scores
.
size
(
0
),
num_classes
)
score_factors
=
score_factors
.
reshape
(
-
1
)
scores
=
scores
*
score_factors
inds
=
valid_mask
.
nonzero
(
as_tuple
=
False
).
squeeze
(
1
)
bboxes
,
scores
,
labels
=
bboxes
[
inds
],
scores
[
inds
],
labels
[
inds
]
if
inds
.
numel
()
==
0
:
if
torch
.
onnx
.
is_in_onnx_export
():
raise
RuntimeError
(
'[ONNX Error] Can not record NMS '
'as it has not been executed this time'
)
if
return_inds
:
return
bboxes
,
labels
,
inds
else
:
return
bboxes
,
labels
# TODO: add size check before feed into batched_nms
dets
,
keep
=
batched_nms
(
bboxes
,
scores
,
labels
,
nms_cfg
)
if
max_num
>
0
:
dets
=
dets
[:
max_num
]
keep
=
keep
[:
max_num
]
if
return_inds
:
return
dets
,
labels
[
keep
],
keep
else
:
return
dets
,
labels
[
keep
]
def
fast_nms
(
multi_bboxes
,
multi_scores
,
multi_coeffs
,
score_thr
,
iou_thr
,
top_k
,
max_num
=-
1
):
"""Fast NMS in `YOLACT <https://arxiv.org/abs/1904.02689>`_.
Fast NMS allows already-removed detections to suppress other detections so
that every instance can be decided to be kept or discarded in parallel,
which is not possible in traditional NMS. This relaxation allows us to
implement Fast NMS entirely in standard GPU-accelerated matrix operations.
Args:
multi_bboxes (Tensor): shape (n, #class*4) or (n, 4)
multi_scores (Tensor): shape (n, #class+1), where the last column
contains scores of the background class, but this will be ignored.
multi_coeffs (Tensor): shape (n, #class*coeffs_dim).
score_thr (float): bbox threshold, bboxes with scores lower than it
will not be considered.
iou_thr (float): IoU threshold to be considered as conflicted.
top_k (int): if there are more than top_k bboxes before NMS,
only top top_k will be kept.
max_num (int): if there are more than max_num bboxes after NMS,
only top max_num will be kept. If -1, keep all the bboxes.
Default: -1.
Returns:
tuple: (bboxes, labels, coefficients), tensors of shape (k, 5), (k, 1),
and (k, coeffs_dim). Labels are 0-based.
"""
scores
=
multi_scores
[:,
:
-
1
].
t
()
# [#class, n]
scores
,
idx
=
scores
.
sort
(
1
,
descending
=
True
)
idx
=
idx
[:,
:
top_k
].
contiguous
()
scores
=
scores
[:,
:
top_k
]
# [#class, topk]
num_classes
,
num_dets
=
idx
.
size
()
boxes
=
multi_bboxes
[
idx
.
view
(
-
1
),
:].
view
(
num_classes
,
num_dets
,
4
)
coeffs
=
multi_coeffs
[
idx
.
view
(
-
1
),
:].
view
(
num_classes
,
num_dets
,
-
1
)
iou
=
bbox_overlaps
(
boxes
,
boxes
)
# [#class, topk, topk]
iou
.
triu_
(
diagonal
=
1
)
iou_max
,
_
=
iou
.
max
(
dim
=
1
)
# Now just filter out the ones higher than the threshold
keep
=
iou_max
<=
iou_thr
# Second thresholding introduces 0.2 mAP gain at negligible time cost
keep
*=
scores
>
score_thr
# Assign each kept detection to its corresponding class
classes
=
torch
.
arange
(
num_classes
,
device
=
boxes
.
device
)[:,
None
].
expand_as
(
keep
)
classes
=
classes
[
keep
]
boxes
=
boxes
[
keep
]
coeffs
=
coeffs
[
keep
]
scores
=
scores
[
keep
]
# Only keep the top max_num highest scores across all classes
scores
,
idx
=
scores
.
sort
(
0
,
descending
=
True
)
if
max_num
>
0
:
idx
=
idx
[:
max_num
]
scores
=
scores
[:
max_num
]
classes
=
classes
[
idx
]
boxes
=
boxes
[
idx
]
coeffs
=
coeffs
[
idx
]
cls_dets
=
torch
.
cat
([
boxes
,
scores
[:,
None
]],
dim
=
1
)
return
cls_dets
,
classes
,
coeffs
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/post_processing/merge_augs.py
0 → 100644
View file @
142dcf29
import
numpy
as
np
import
torch
from
mmcv.ops
import
nms
from
..bbox
import
bbox_mapping_back
def
merge_aug_proposals
(
aug_proposals
,
img_metas
,
rpn_test_cfg
):
"""Merge augmented proposals (multiscale, flip, etc.)
Args:
aug_proposals (list[Tensor]): proposals from different testing
schemes, shape (n, 5). Note that they are not rescaled to the
original image size.
img_metas (list[dict]): list of image info dict where each dict has:
'img_shape', 'scale_factor', 'flip', and may also contain
'filename', 'ori_shape', 'pad_shape', and 'img_norm_cfg'.
For details on the values of these keys see
`mmdet/datasets/pipelines/formatting.py:Collect`.
rpn_test_cfg (dict): rpn test config.
Returns:
Tensor: shape (n, 4), proposals corresponding to original image scale.
"""
recovered_proposals
=
[]
for
proposals
,
img_info
in
zip
(
aug_proposals
,
img_metas
):
img_shape
=
img_info
[
'img_shape'
]
scale_factor
=
img_info
[
'scale_factor'
]
flip
=
img_info
[
'flip'
]
flip_direction
=
img_info
[
'flip_direction'
]
_proposals
=
proposals
.
clone
()
_proposals
[:,
:
4
]
=
bbox_mapping_back
(
_proposals
[:,
:
4
],
img_shape
,
scale_factor
,
flip
,
flip_direction
)
recovered_proposals
.
append
(
_proposals
)
aug_proposals
=
torch
.
cat
(
recovered_proposals
,
dim
=
0
)
merged_proposals
,
_
=
nms
(
aug_proposals
[:,
:
4
].
contiguous
(),
aug_proposals
[:,
-
1
].
contiguous
(),
rpn_test_cfg
.
nms_thr
)
scores
=
merged_proposals
[:,
4
]
_
,
order
=
scores
.
sort
(
0
,
descending
=
True
)
num
=
min
(
rpn_test_cfg
.
max_num
,
merged_proposals
.
shape
[
0
])
order
=
order
[:
num
]
merged_proposals
=
merged_proposals
[
order
,
:]
return
merged_proposals
def
merge_aug_bboxes
(
aug_bboxes
,
aug_scores
,
img_metas
,
rcnn_test_cfg
):
"""Merge augmented detection bboxes and scores.
Args:
aug_bboxes (list[Tensor]): shape (n, 4*#class)
aug_scores (list[Tensor] or None): shape (n, #class)
img_shapes (list[Tensor]): shape (3, ).
rcnn_test_cfg (dict): rcnn test config.
Returns:
tuple: (bboxes, scores)
"""
recovered_bboxes
=
[]
for
bboxes
,
img_info
in
zip
(
aug_bboxes
,
img_metas
):
img_shape
=
img_info
[
0
][
'img_shape'
]
scale_factor
=
img_info
[
0
][
'scale_factor'
]
flip
=
img_info
[
0
][
'flip'
]
flip_direction
=
img_info
[
0
][
'flip_direction'
]
bboxes
=
bbox_mapping_back
(
bboxes
,
img_shape
,
scale_factor
,
flip
,
flip_direction
)
recovered_bboxes
.
append
(
bboxes
)
bboxes
=
torch
.
stack
(
recovered_bboxes
).
mean
(
dim
=
0
)
if
aug_scores
is
None
:
return
bboxes
else
:
scores
=
torch
.
stack
(
aug_scores
).
mean
(
dim
=
0
)
return
bboxes
,
scores
def
merge_aug_scores
(
aug_scores
):
"""Merge augmented bbox scores."""
if
isinstance
(
aug_scores
[
0
],
torch
.
Tensor
):
return
torch
.
mean
(
torch
.
stack
(
aug_scores
),
dim
=
0
)
else
:
return
np
.
mean
(
aug_scores
,
axis
=
0
)
def
merge_aug_masks
(
aug_masks
,
img_metas
,
rcnn_test_cfg
,
weights
=
None
):
"""Merge augmented mask prediction.
Args:
aug_masks (list[ndarray]): shape (n, #class, h, w)
img_shapes (list[ndarray]): shape (3, ).
rcnn_test_cfg (dict): rcnn test config.
Returns:
tuple: (bboxes, scores)
"""
recovered_masks
=
[]
for
mask
,
img_info
in
zip
(
aug_masks
,
img_metas
):
flip
=
img_info
[
0
][
'flip'
]
flip_direction
=
img_info
[
0
][
'flip_direction'
]
if
flip
:
if
flip_direction
==
'horizontal'
:
mask
=
mask
[:,
:,
:,
::
-
1
]
elif
flip_direction
==
'vertical'
:
mask
=
mask
[:,
:,
::
-
1
,
:]
else
:
raise
ValueError
(
f
"Invalid flipping direction '
{
flip_direction
}
'"
)
recovered_masks
.
append
(
mask
)
if
weights
is
None
:
merged_masks
=
np
.
mean
(
recovered_masks
,
axis
=
0
)
else
:
merged_masks
=
np
.
average
(
np
.
array
(
recovered_masks
),
axis
=
0
,
weights
=
np
.
array
(
weights
))
return
merged_masks
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/utils/__init__.py
0 → 100644
View file @
142dcf29
from
.dist_utils
import
DistOptimizerHook
,
allreduce_grads
,
reduce_mean
from
.misc
import
mask2ndarray
,
multi_apply
,
unmap
__all__
=
[
'allreduce_grads'
,
'DistOptimizerHook'
,
'reduce_mean'
,
'multi_apply'
,
'unmap'
,
'mask2ndarray'
]
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/utils/dist_utils.py
0 → 100644
View file @
142dcf29
import
warnings
from
collections
import
OrderedDict
import
torch.distributed
as
dist
from
mmcv.runner
import
OptimizerHook
from
torch._utils
import
(
_flatten_dense_tensors
,
_take_tensors
,
_unflatten_dense_tensors
)
def
_allreduce_coalesced
(
tensors
,
world_size
,
bucket_size_mb
=-
1
):
if
bucket_size_mb
>
0
:
bucket_size_bytes
=
bucket_size_mb
*
1024
*
1024
buckets
=
_take_tensors
(
tensors
,
bucket_size_bytes
)
else
:
buckets
=
OrderedDict
()
for
tensor
in
tensors
:
tp
=
tensor
.
type
()
if
tp
not
in
buckets
:
buckets
[
tp
]
=
[]
buckets
[
tp
].
append
(
tensor
)
buckets
=
buckets
.
values
()
for
bucket
in
buckets
:
flat_tensors
=
_flatten_dense_tensors
(
bucket
)
dist
.
all_reduce
(
flat_tensors
)
flat_tensors
.
div_
(
world_size
)
for
tensor
,
synced
in
zip
(
bucket
,
_unflatten_dense_tensors
(
flat_tensors
,
bucket
)):
tensor
.
copy_
(
synced
)
def
allreduce_grads
(
params
,
coalesce
=
True
,
bucket_size_mb
=-
1
):
"""Allreduce gradients.
Args:
params (list[torch.Parameters]): List of parameters of a model
coalesce (bool, optional): Whether allreduce parameters as a whole.
Defaults to True.
bucket_size_mb (int, optional): Size of bucket, the unit is MB.
Defaults to -1.
"""
grads
=
[
param
.
grad
.
data
for
param
in
params
if
param
.
requires_grad
and
param
.
grad
is
not
None
]
world_size
=
dist
.
get_world_size
()
if
coalesce
:
_allreduce_coalesced
(
grads
,
world_size
,
bucket_size_mb
)
else
:
for
tensor
in
grads
:
dist
.
all_reduce
(
tensor
.
div_
(
world_size
))
class
DistOptimizerHook
(
OptimizerHook
):
"""Deprecated optimizer hook for distributed training."""
def
__init__
(
self
,
*
args
,
**
kwargs
):
warnings
.
warn
(
'"DistOptimizerHook" is deprecated, please switch to'
'"mmcv.runner.OptimizerHook".'
)
super
().
__init__
(
*
args
,
**
kwargs
)
def
reduce_mean
(
tensor
):
""""Obtain the mean of tensor on different GPUs."""
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
)
return
tensor
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/utils/misc.py
0 → 100644
View file @
142dcf29
from
functools
import
partial
import
numpy
as
np
import
torch
from
six.moves
import
map
,
zip
from
..mask.structures
import
BitmapMasks
,
PolygonMasks
def
multi_apply
(
func
,
*
args
,
**
kwargs
):
"""Apply function to a list of arguments.
Note:
This function applies the ``func`` to multiple inputs and
map the multiple outputs of the ``func`` into different
list. Each list contains the same type of outputs corresponding
to different inputs.
Args:
func (Function): A function that will be applied to a list of
arguments
Returns:
tuple(list): A tuple containing multiple list, each list contains
\
a kind of returned results by the function
"""
pfunc
=
partial
(
func
,
**
kwargs
)
if
kwargs
else
func
map_results
=
map
(
pfunc
,
*
args
)
return
tuple
(
map
(
list
,
zip
(
*
map_results
)))
def
unmap
(
data
,
count
,
inds
,
fill
=
0
):
"""Unmap a subset of item (data) back to the original set of items (of size
count)"""
if
data
.
dim
()
==
1
:
ret
=
data
.
new_full
((
count
,
),
fill
)
ret
[
inds
.
type
(
torch
.
bool
)]
=
data
else
:
new_size
=
(
count
,
)
+
data
.
size
()[
1
:]
ret
=
data
.
new_full
(
new_size
,
fill
)
ret
[
inds
.
type
(
torch
.
bool
),
:]
=
data
return
ret
def
mask2ndarray
(
mask
):
"""Convert Mask to ndarray..
Args:
mask (:obj:`BitmapMasks` or :obj:`PolygonMasks` or
torch.Tensor or np.ndarray): The mask to be converted.
Returns:
np.ndarray: Ndarray mask of shape (n, h, w) that has been converted
"""
if
isinstance
(
mask
,
(
BitmapMasks
,
PolygonMasks
)):
mask
=
mask
.
to_ndarray
()
elif
isinstance
(
mask
,
torch
.
Tensor
):
mask
=
mask
.
detach
().
cpu
().
numpy
()
elif
not
isinstance
(
mask
,
np
.
ndarray
):
raise
TypeError
(
f
'Unsupported
{
type
(
mask
)
}
data type'
)
return
mask
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/visualization/__init__.py
0 → 100644
View file @
142dcf29
from
.image
import
(
color_val_matplotlib
,
imshow_det_bboxes
,
imshow_gt_det_bboxes
)
__all__
=
[
'imshow_det_bboxes'
,
'imshow_gt_det_bboxes'
,
'color_val_matplotlib'
]
PyTorch/NLP/Conformer-main/mmdetection/mmdet/core/visualization/image.py
0 → 100644
View file @
142dcf29
import
os.path
as
osp
import
warnings
import
matplotlib.pyplot
as
plt
import
mmcv
import
numpy
as
np
import
pycocotools.mask
as
mask_util
from
matplotlib.collections
import
PatchCollection
from
matplotlib.patches
import
Polygon
from
..utils
import
mask2ndarray
def
color_val_matplotlib
(
color
):
"""Convert various input in BGR order to normalized RGB matplotlib color
tuples,
Args:
color (:obj:`Color`/str/tuple/int/ndarray): Color inputs
Returns:
tuple[float]: A tuple of 3 normalized floats indicating RGB channels.
"""
color
=
mmcv
.
color_val
(
color
)
color
=
[
color
/
255
for
color
in
color
[::
-
1
]]
return
tuple
(
color
)
def
imshow_det_bboxes
(
img
,
bboxes
,
labels
,
segms
=
None
,
class_names
=
None
,
score_thr
=
0
,
bbox_color
=
'green'
,
text_color
=
'green'
,
mask_color
=
None
,
thickness
=
2
,
font_scale
=
0.5
,
font_size
=
13
,
win_name
=
''
,
fig_size
=
(
15
,
10
),
show
=
True
,
wait_time
=
0
,
out_file
=
None
):
"""Draw bboxes and class labels (with scores) on an image.
Args:
img (str or ndarray): The image to be displayed.
bboxes (ndarray): Bounding boxes (with scores), shaped (n, 4) or
(n, 5).
labels (ndarray): Labels of bboxes.
segms (ndarray or None): Masks, shaped (n,h,w) or None
class_names (list[str]): Names of each classes.
score_thr (float): Minimum score of bboxes to be shown. Default: 0
bbox_color (str or tuple(int) or :obj:`Color`):Color of bbox lines.
The tuple of color should be in BGR order. Default: 'green'
text_color (str or tuple(int) or :obj:`Color`):Color of texts.
The tuple of color should be in BGR order. Default: 'green'
mask_color (str or tuple(int) or :obj:`Color`, optional):
Color of masks. The tuple of color should be in BGR order.
Default: None
thickness (int): Thickness of lines. Default: 2
font_scale (float): Font scales of texts. Default: 0.5
font_size (int): Font size of texts. Default: 13
show (bool): Whether to show the image. Default: True
win_name (str): The window name. Default: ''
fig_size (tuple): Figure size of the pyplot figure. Default: (15, 10)
wait_time (float): Value of waitKey param. Default: 0.
out_file (str, optional): The filename to write the image.
Default: None
Returns:
ndarray: The image with bboxes drawn on it.
"""
warnings
.
warn
(
'"font_scale" will be deprecated in v2.9.0,'
'Please use "font_size"'
)
assert
bboxes
.
ndim
==
2
,
\
f
' bboxes ndim should be 2, but its ndim is
{
bboxes
.
ndim
}
.'
assert
labels
.
ndim
==
1
,
\
f
' labels ndim should be 1, but its ndim is
{
labels
.
ndim
}
.'
assert
bboxes
.
shape
[
0
]
==
labels
.
shape
[
0
],
\
'bboxes.shape[0] and labels.shape[0] should have the same length.'
assert
bboxes
.
shape
[
1
]
==
4
or
bboxes
.
shape
[
1
]
==
5
,
\
f
' bboxes.shape[1] should be 4 or 5, but its
{
bboxes
.
shape
[
1
]
}
.'
img
=
mmcv
.
imread
(
img
).
copy
()
if
score_thr
>
0
:
assert
bboxes
.
shape
[
1
]
==
5
scores
=
bboxes
[:,
-
1
]
inds
=
scores
>
score_thr
bboxes
=
bboxes
[
inds
,
:]
labels
=
labels
[
inds
]
if
segms
is
not
None
:
segms
=
segms
[
inds
,
...]
mask_colors
=
[]
if
labels
.
shape
[
0
]
>
0
:
if
mask_color
is
None
:
# random color
np
.
random
.
seed
(
42
)
mask_colors
=
[
np
.
random
.
randint
(
0
,
256
,
(
1
,
3
),
dtype
=
np
.
uint8
)
for
_
in
range
(
max
(
labels
)
+
1
)
]
else
:
# specify color
mask_colors
=
[
np
.
array
(
mmcv
.
color_val
(
mask_color
)[::
-
1
],
dtype
=
np
.
uint8
)
]
*
(
max
(
labels
)
+
1
)
bbox_color
=
color_val_matplotlib
(
bbox_color
)
text_color
=
color_val_matplotlib
(
text_color
)
img
=
mmcv
.
bgr2rgb
(
img
)
img
=
np
.
ascontiguousarray
(
img
)
plt
.
figure
(
win_name
,
figsize
=
fig_size
)
plt
.
title
(
win_name
)
plt
.
axis
(
'off'
)
ax
=
plt
.
gca
()
polygons
=
[]
color
=
[]
for
i
,
(
bbox
,
label
)
in
enumerate
(
zip
(
bboxes
,
labels
)):
bbox_int
=
bbox
.
astype
(
np
.
int32
)
poly
=
[[
bbox_int
[
0
],
bbox_int
[
1
]],
[
bbox_int
[
0
],
bbox_int
[
3
]],
[
bbox_int
[
2
],
bbox_int
[
3
]],
[
bbox_int
[
2
],
bbox_int
[
1
]]]
np_poly
=
np
.
array
(
poly
).
reshape
((
4
,
2
))
polygons
.
append
(
Polygon
(
np_poly
))
color
.
append
(
bbox_color
)
label_text
=
class_names
[
label
]
if
class_names
is
not
None
else
f
'class
{
label
}
'
if
len
(
bbox
)
>
4
:
label_text
+=
f
'|
{
bbox
[
-
1
]:.
02
f
}
'
ax
.
text
(
bbox_int
[
0
],
bbox_int
[
1
],
f
'
{
label_text
}
'
,
bbox
=
{
'facecolor'
:
'black'
,
'alpha'
:
0.8
,
'pad'
:
0.7
,
'edgecolor'
:
'none'
},
color
=
text_color
,
fontsize
=
font_size
,
verticalalignment
=
'top'
,
horizontalalignment
=
'left'
)
if
segms
is
not
None
:
color_mask
=
mask_colors
[
labels
[
i
]]
mask
=
segms
[
i
].
astype
(
bool
)
img
[
mask
]
=
img
[
mask
]
*
0.5
+
color_mask
*
0.5
plt
.
imshow
(
img
)
p
=
PatchCollection
(
polygons
,
facecolor
=
'none'
,
edgecolors
=
color
,
linewidths
=
thickness
)
ax
.
add_collection
(
p
)
if
out_file
is
not
None
:
dir_name
=
osp
.
abspath
(
osp
.
dirname
(
out_file
))
mmcv
.
mkdir_or_exist
(
dir_name
)
plt
.
savefig
(
out_file
)
if
not
show
:
plt
.
close
()
if
show
:
if
wait_time
==
0
:
plt
.
show
()
else
:
plt
.
show
(
block
=
False
)
plt
.
pause
(
wait_time
)
plt
.
close
()
return
mmcv
.
rgb2bgr
(
img
)
def
imshow_gt_det_bboxes
(
img
,
annotation
,
result
,
class_names
=
None
,
score_thr
=
0
,
gt_bbox_color
=
(
255
,
102
,
61
),
gt_text_color
=
(
255
,
102
,
61
),
gt_mask_color
=
(
255
,
102
,
61
),
det_bbox_color
=
(
72
,
101
,
241
),
det_text_color
=
(
72
,
101
,
241
),
det_mask_color
=
(
72
,
101
,
241
),
thickness
=
2
,
font_size
=
13
,
win_name
=
''
,
fig_size
=
(
15
,
10
),
show
=
True
,
wait_time
=
0
,
out_file
=
None
):
"""General visualization GT and result function.
Args:
img (str or ndarray): The image to be displayed.)
annotation (dict): Ground truth annotations where contain keys of
'gt_bboxes' and 'gt_labels' or 'gt_masks'
result (tuple[list] or list): The detection result, can be either
(bbox, segm) or just bbox.
class_names (list[str]): Names of each classes.
score_thr (float): Minimum score of bboxes to be shown. Default: 0
gt_bbox_color (str or tuple(int) or :obj:`Color`):Color of bbox lines.
The tuple of color should be in BGR order. Default: (255, 102, 61)
gt_text_color (str or tuple(int) or :obj:`Color`):Color of texts.
The tuple of color should be in BGR order. Default: (255, 102, 61)
gt_mask_color (str or tuple(int) or :obj:`Color`, optional):
Color of masks. The tuple of color should be in BGR order.
Default: (255, 102, 61)
det_bbox_color (str or tuple(int) or :obj:`Color`):Color of bbox lines.
The tuple of color should be in BGR order. Default: (72, 101, 241)
det_text_color (str or tuple(int) or :obj:`Color`):Color of texts.
The tuple of color should be in BGR order. Default: (72, 101, 241)
det_mask_color (str or tuple(int) or :obj:`Color`, optional):
Color of masks. The tuple of color should be in BGR order.
Default: (72, 101, 241)
thickness (int): Thickness of lines. Default: 2
font_size (int): Font size of texts. Default: 13
win_name (str): The window name. Default: ''
fig_size (tuple): Figure size of the pyplot figure. Default: (15, 10)
show (bool): Whether to show the image. Default: True
wait_time (float): Value of waitKey param. Default: 0.
out_file (str, optional): The filename to write the image.
Default: None
Returns:
ndarray: The image with bboxes or masks drawn on it.
"""
assert
'gt_bboxes'
in
annotation
assert
'gt_labels'
in
annotation
assert
isinstance
(
result
,
(
tuple
,
list
)),
f
'Expected tuple or list, but get
{
type
(
result
)
}
'
gt_masks
=
annotation
.
get
(
'gt_masks'
,
None
)
if
gt_masks
is
not
None
:
gt_masks
=
mask2ndarray
(
gt_masks
)
img
=
mmcv
.
imread
(
img
)
img
=
imshow_det_bboxes
(
img
,
annotation
[
'gt_bboxes'
],
annotation
[
'gt_labels'
],
gt_masks
,
class_names
=
class_names
,
bbox_color
=
gt_bbox_color
,
text_color
=
gt_text_color
,
mask_color
=
gt_mask_color
,
thickness
=
thickness
,
font_size
=
font_size
,
win_name
=
win_name
,
fig_size
=
fig_size
,
show
=
False
)
if
isinstance
(
result
,
tuple
):
bbox_result
,
segm_result
=
result
if
isinstance
(
segm_result
,
tuple
):
segm_result
=
segm_result
[
0
]
# ms rcnn
else
:
bbox_result
,
segm_result
=
result
,
None
bboxes
=
np
.
vstack
(
bbox_result
)
labels
=
[
np
.
full
(
bbox
.
shape
[
0
],
i
,
dtype
=
np
.
int32
)
for
i
,
bbox
in
enumerate
(
bbox_result
)
]
labels
=
np
.
concatenate
(
labels
)
segms
=
None
if
segm_result
is
not
None
and
len
(
labels
)
>
0
:
# non empty
segms
=
mmcv
.
concat_list
(
segm_result
)
segms
=
mask_util
.
decode
(
segms
)
segms
=
segms
.
transpose
(
2
,
0
,
1
)
img
=
imshow_det_bboxes
(
img
,
bboxes
,
labels
,
segms
=
segms
,
class_names
=
class_names
,
score_thr
=
score_thr
,
bbox_color
=
det_bbox_color
,
text_color
=
det_text_color
,
mask_color
=
det_mask_color
,
thickness
=
thickness
,
font_size
=
font_size
,
win_name
=
win_name
,
fig_size
=
fig_size
,
show
=
show
,
wait_time
=
wait_time
,
out_file
=
out_file
)
return
img
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/__init__.py
0 → 100644
View file @
142dcf29
from
.builder
import
DATASETS
,
PIPELINES
,
build_dataloader
,
build_dataset
from
.cityscapes
import
CityscapesDataset
from
.coco
import
CocoDataset
from
.custom
import
CustomDataset
from
.dataset_wrappers
import
(
ClassBalancedDataset
,
ConcatDataset
,
RepeatDataset
)
from
.deepfashion
import
DeepFashionDataset
from
.lvis
import
LVISDataset
,
LVISV1Dataset
,
LVISV05Dataset
from
.samplers
import
DistributedGroupSampler
,
DistributedSampler
,
GroupSampler
from
.utils
import
get_loading_pipeline
,
replace_ImageToTensor
from
.voc
import
VOCDataset
from
.wider_face
import
WIDERFaceDataset
from
.xml_style
import
XMLDataset
__all__
=
[
'CustomDataset'
,
'XMLDataset'
,
'CocoDataset'
,
'DeepFashionDataset'
,
'VOCDataset'
,
'CityscapesDataset'
,
'LVISDataset'
,
'LVISV05Dataset'
,
'LVISV1Dataset'
,
'GroupSampler'
,
'DistributedGroupSampler'
,
'DistributedSampler'
,
'build_dataloader'
,
'ConcatDataset'
,
'RepeatDataset'
,
'ClassBalancedDataset'
,
'WIDERFaceDataset'
,
'DATASETS'
,
'PIPELINES'
,
'build_dataset'
,
'replace_ImageToTensor'
,
'get_loading_pipeline'
]
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/builder.py
0 → 100644
View file @
142dcf29
import
copy
import
platform
import
random
from
functools
import
partial
import
numpy
as
np
from
mmcv.parallel
import
collate
from
mmcv.runner
import
get_dist_info
from
mmcv.utils
import
Registry
,
build_from_cfg
from
torch.utils.data
import
DataLoader
from
.samplers
import
DistributedGroupSampler
,
DistributedSampler
,
GroupSampler
if
platform
.
system
()
!=
'Windows'
:
# https://github.com/pytorch/pytorch/issues/973
import
resource
rlimit
=
resource
.
getrlimit
(
resource
.
RLIMIT_NOFILE
)
hard_limit
=
rlimit
[
1
]
soft_limit
=
min
(
4096
,
hard_limit
)
resource
.
setrlimit
(
resource
.
RLIMIT_NOFILE
,
(
soft_limit
,
hard_limit
))
DATASETS
=
Registry
(
'dataset'
)
PIPELINES
=
Registry
(
'pipeline'
)
def
_concat_dataset
(
cfg
,
default_args
=
None
):
from
.dataset_wrappers
import
ConcatDataset
ann_files
=
cfg
[
'ann_file'
]
img_prefixes
=
cfg
.
get
(
'img_prefix'
,
None
)
seg_prefixes
=
cfg
.
get
(
'seg_prefix'
,
None
)
proposal_files
=
cfg
.
get
(
'proposal_file'
,
None
)
separate_eval
=
cfg
.
get
(
'separate_eval'
,
True
)
datasets
=
[]
num_dset
=
len
(
ann_files
)
for
i
in
range
(
num_dset
):
data_cfg
=
copy
.
deepcopy
(
cfg
)
# pop 'separate_eval' since it is not a valid key for common datasets.
if
'separate_eval'
in
data_cfg
:
data_cfg
.
pop
(
'separate_eval'
)
data_cfg
[
'ann_file'
]
=
ann_files
[
i
]
if
isinstance
(
img_prefixes
,
(
list
,
tuple
)):
data_cfg
[
'img_prefix'
]
=
img_prefixes
[
i
]
if
isinstance
(
seg_prefixes
,
(
list
,
tuple
)):
data_cfg
[
'seg_prefix'
]
=
seg_prefixes
[
i
]
if
isinstance
(
proposal_files
,
(
list
,
tuple
)):
data_cfg
[
'proposal_file'
]
=
proposal_files
[
i
]
datasets
.
append
(
build_dataset
(
data_cfg
,
default_args
))
return
ConcatDataset
(
datasets
,
separate_eval
)
def
build_dataset
(
cfg
,
default_args
=
None
):
from
.dataset_wrappers
import
(
ConcatDataset
,
RepeatDataset
,
ClassBalancedDataset
)
if
isinstance
(
cfg
,
(
list
,
tuple
)):
dataset
=
ConcatDataset
([
build_dataset
(
c
,
default_args
)
for
c
in
cfg
])
elif
cfg
[
'type'
]
==
'ConcatDataset'
:
dataset
=
ConcatDataset
(
[
build_dataset
(
c
,
default_args
)
for
c
in
cfg
[
'datasets'
]],
cfg
.
get
(
'separate_eval'
,
True
))
elif
cfg
[
'type'
]
==
'RepeatDataset'
:
dataset
=
RepeatDataset
(
build_dataset
(
cfg
[
'dataset'
],
default_args
),
cfg
[
'times'
])
elif
cfg
[
'type'
]
==
'ClassBalancedDataset'
:
dataset
=
ClassBalancedDataset
(
build_dataset
(
cfg
[
'dataset'
],
default_args
),
cfg
[
'oversample_thr'
])
elif
isinstance
(
cfg
.
get
(
'ann_file'
),
(
list
,
tuple
)):
dataset
=
_concat_dataset
(
cfg
,
default_args
)
else
:
dataset
=
build_from_cfg
(
cfg
,
DATASETS
,
default_args
)
return
dataset
def
build_dataloader
(
dataset
,
samples_per_gpu
,
workers_per_gpu
,
num_gpus
=
1
,
dist
=
True
,
shuffle
=
True
,
seed
=
None
,
**
kwargs
):
"""Build PyTorch DataLoader.
In distributed training, each GPU/process has a dataloader.
In non-distributed training, there is only one dataloader for all GPUs.
Args:
dataset (Dataset): A PyTorch dataset.
samples_per_gpu (int): Number of training samples on each GPU, i.e.,
batch size of each GPU.
workers_per_gpu (int): How many subprocesses to use for data loading
for each GPU.
num_gpus (int): Number of GPUs. Only used in non-distributed training.
dist (bool): Distributed training/test or not. Default: True.
shuffle (bool): Whether to shuffle the data at every epoch.
Default: True.
kwargs: any keyword argument to be used to initialize DataLoader
Returns:
DataLoader: A PyTorch dataloader.
"""
rank
,
world_size
=
get_dist_info
()
if
dist
:
# DistributedGroupSampler will definitely shuffle the data to satisfy
# that images on each GPU are in the same group
if
shuffle
:
sampler
=
DistributedGroupSampler
(
dataset
,
samples_per_gpu
,
world_size
,
rank
)
else
:
sampler
=
DistributedSampler
(
dataset
,
world_size
,
rank
,
shuffle
=
False
)
batch_size
=
samples_per_gpu
num_workers
=
workers_per_gpu
else
:
sampler
=
GroupSampler
(
dataset
,
samples_per_gpu
)
if
shuffle
else
None
batch_size
=
num_gpus
*
samples_per_gpu
num_workers
=
num_gpus
*
workers_per_gpu
init_fn
=
partial
(
worker_init_fn
,
num_workers
=
num_workers
,
rank
=
rank
,
seed
=
seed
)
if
seed
is
not
None
else
None
data_loader
=
DataLoader
(
dataset
,
batch_size
=
batch_size
,
sampler
=
sampler
,
num_workers
=
num_workers
,
collate_fn
=
partial
(
collate
,
samples_per_gpu
=
samples_per_gpu
),
pin_memory
=
False
,
worker_init_fn
=
init_fn
,
**
kwargs
)
return
data_loader
def
worker_init_fn
(
worker_id
,
num_workers
,
rank
,
seed
):
# The seed of each worker equals to
# num_worker * rank + worker_id + user_seed
worker_seed
=
num_workers
*
rank
+
worker_id
+
seed
np
.
random
.
seed
(
worker_seed
)
random
.
seed
(
worker_seed
)
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/cityscapes.py
0 → 100644
View file @
142dcf29
# Modified from https://github.com/facebookresearch/detectron2/blob/master/detectron2/data/datasets/cityscapes.py # noqa
# and https://github.com/mcordts/cityscapesScripts/blob/master/cityscapesscripts/evaluation/evalInstanceLevelSemanticLabeling.py # noqa
import
glob
import
os
import
os.path
as
osp
import
tempfile
from
collections
import
OrderedDict
import
mmcv
import
numpy
as
np
import
pycocotools.mask
as
maskUtils
from
mmcv.utils
import
print_log
from
.builder
import
DATASETS
from
.coco
import
CocoDataset
@
DATASETS
.
register_module
()
class
CityscapesDataset
(
CocoDataset
):
CLASSES
=
(
'person'
,
'rider'
,
'car'
,
'truck'
,
'bus'
,
'train'
,
'motorcycle'
,
'bicycle'
)
def
_filter_imgs
(
self
,
min_size
=
32
):
"""Filter images too small or without ground truths."""
valid_inds
=
[]
# obtain images that contain annotation
ids_with_ann
=
set
(
_
[
'image_id'
]
for
_
in
self
.
coco
.
anns
.
values
())
# obtain images that contain annotations of the required categories
ids_in_cat
=
set
()
for
i
,
class_id
in
enumerate
(
self
.
cat_ids
):
ids_in_cat
|=
set
(
self
.
coco
.
cat_img_map
[
class_id
])
# merge the image id sets of the two conditions and use the merged set
# to filter out images if self.filter_empty_gt=True
ids_in_cat
&=
ids_with_ann
valid_img_ids
=
[]
for
i
,
img_info
in
enumerate
(
self
.
data_infos
):
img_id
=
img_info
[
'id'
]
ann_ids
=
self
.
coco
.
getAnnIds
(
imgIds
=
[
img_id
])
ann_info
=
self
.
coco
.
loadAnns
(
ann_ids
)
all_iscrowd
=
all
([
_
[
'iscrowd'
]
for
_
in
ann_info
])
if
self
.
filter_empty_gt
and
(
self
.
img_ids
[
i
]
not
in
ids_in_cat
or
all_iscrowd
):
continue
if
min
(
img_info
[
'width'
],
img_info
[
'height'
])
>=
min_size
:
valid_inds
.
append
(
i
)
valid_img_ids
.
append
(
img_id
)
self
.
img_ids
=
valid_img_ids
return
valid_inds
def
_parse_ann_info
(
self
,
img_info
,
ann_info
):
"""Parse bbox and mask annotation.
Args:
img_info (dict): Image info of an image.
ann_info (list[dict]): Annotation info of an image.
Returns:
dict: A dict containing the following keys: bboxes,
\
bboxes_ignore, labels, masks, seg_map.
\
"masks" are already decoded into binary masks.
"""
gt_bboxes
=
[]
gt_labels
=
[]
gt_bboxes_ignore
=
[]
gt_masks_ann
=
[]
for
i
,
ann
in
enumerate
(
ann_info
):
if
ann
.
get
(
'ignore'
,
False
):
continue
x1
,
y1
,
w
,
h
=
ann
[
'bbox'
]
if
ann
[
'area'
]
<=
0
or
w
<
1
or
h
<
1
:
continue
if
ann
[
'category_id'
]
not
in
self
.
cat_ids
:
continue
bbox
=
[
x1
,
y1
,
x1
+
w
,
y1
+
h
]
if
ann
.
get
(
'iscrowd'
,
False
):
gt_bboxes_ignore
.
append
(
bbox
)
else
:
gt_bboxes
.
append
(
bbox
)
gt_labels
.
append
(
self
.
cat2label
[
ann
[
'category_id'
]])
gt_masks_ann
.
append
(
ann
[
'segmentation'
])
if
gt_bboxes
:
gt_bboxes
=
np
.
array
(
gt_bboxes
,
dtype
=
np
.
float32
)
gt_labels
=
np
.
array
(
gt_labels
,
dtype
=
np
.
int64
)
else
:
gt_bboxes
=
np
.
zeros
((
0
,
4
),
dtype
=
np
.
float32
)
gt_labels
=
np
.
array
([],
dtype
=
np
.
int64
)
if
gt_bboxes_ignore
:
gt_bboxes_ignore
=
np
.
array
(
gt_bboxes_ignore
,
dtype
=
np
.
float32
)
else
:
gt_bboxes_ignore
=
np
.
zeros
((
0
,
4
),
dtype
=
np
.
float32
)
ann
=
dict
(
bboxes
=
gt_bboxes
,
labels
=
gt_labels
,
bboxes_ignore
=
gt_bboxes_ignore
,
masks
=
gt_masks_ann
,
seg_map
=
img_info
[
'segm_file'
])
return
ann
def
results2txt
(
self
,
results
,
outfile_prefix
):
"""Dump the detection results to a txt file.
Args:
results (list[list | tuple]): Testing results of the
dataset.
outfile_prefix (str): The filename prefix of the json files.
If the prefix is "somepath/xxx",
the txt files will be named "somepath/xxx.txt".
Returns:
list[str]: Result txt files which contains corresponding
\
instance segmentation images.
"""
try
:
import
cityscapesscripts.helpers.labels
as
CSLabels
except
ImportError
:
raise
ImportError
(
'Please run "pip install citscapesscripts" to '
'install cityscapesscripts first.'
)
result_files
=
[]
os
.
makedirs
(
outfile_prefix
,
exist_ok
=
True
)
prog_bar
=
mmcv
.
ProgressBar
(
len
(
self
))
for
idx
in
range
(
len
(
self
)):
result
=
results
[
idx
]
filename
=
self
.
data_infos
[
idx
][
'filename'
]
basename
=
osp
.
splitext
(
osp
.
basename
(
filename
))[
0
]
pred_txt
=
osp
.
join
(
outfile_prefix
,
basename
+
'_pred.txt'
)
bbox_result
,
segm_result
=
result
bboxes
=
np
.
vstack
(
bbox_result
)
# segm results
if
isinstance
(
segm_result
,
tuple
):
# Some detectors use different scores for bbox and mask,
# like Mask Scoring R-CNN. Score of segm will be used instead
# of bbox score.
segms
=
mmcv
.
concat_list
(
segm_result
[
0
])
mask_score
=
segm_result
[
1
]
else
:
# use bbox score for mask score
segms
=
mmcv
.
concat_list
(
segm_result
)
mask_score
=
[
bbox
[
-
1
]
for
bbox
in
bboxes
]
labels
=
[
np
.
full
(
bbox
.
shape
[
0
],
i
,
dtype
=
np
.
int32
)
for
i
,
bbox
in
enumerate
(
bbox_result
)
]
labels
=
np
.
concatenate
(
labels
)
assert
len
(
bboxes
)
==
len
(
segms
)
==
len
(
labels
)
num_instances
=
len
(
bboxes
)
prog_bar
.
update
()
with
open
(
pred_txt
,
'w'
)
as
fout
:
for
i
in
range
(
num_instances
):
pred_class
=
labels
[
i
]
classes
=
self
.
CLASSES
[
pred_class
]
class_id
=
CSLabels
.
name2label
[
classes
].
id
score
=
mask_score
[
i
]
mask
=
maskUtils
.
decode
(
segms
[
i
]).
astype
(
np
.
uint8
)
png_filename
=
osp
.
join
(
outfile_prefix
,
basename
+
f
'_
{
i
}
_
{
classes
}
.png'
)
mmcv
.
imwrite
(
mask
,
png_filename
)
fout
.
write
(
f
'
{
osp
.
basename
(
png_filename
)
}
{
class_id
}
'
f
'
{
score
}
\n
'
)
result_files
.
append
(
pred_txt
)
return
result_files
def
format_results
(
self
,
results
,
txtfile_prefix
=
None
):
"""Format the results to txt (standard format for Cityscapes
evaluation).
Args:
results (list): Testing results of the dataset.
txtfile_prefix (str | None): The prefix of txt 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. Default: None.
Returns:
tuple: (result_files, tmp_dir), result_files is a dict containing
\
the json filepaths, tmp_dir is the temporal directory created
\
for saving txt/png files when txtfile_prefix is not specified.
"""
assert
isinstance
(
results
,
list
),
'results must be a list'
assert
len
(
results
)
==
len
(
self
),
(
'The length of results is not equal to the dataset len: {} != {}'
.
format
(
len
(
results
),
len
(
self
)))
assert
isinstance
(
results
,
list
),
'results must be a list'
assert
len
(
results
)
==
len
(
self
),
(
'The length of results is not equal to the dataset len: {} != {}'
.
format
(
len
(
results
),
len
(
self
)))
if
txtfile_prefix
is
None
:
tmp_dir
=
tempfile
.
TemporaryDirectory
()
txtfile_prefix
=
osp
.
join
(
tmp_dir
.
name
,
'results'
)
else
:
tmp_dir
=
None
result_files
=
self
.
results2txt
(
results
,
txtfile_prefix
)
return
result_files
,
tmp_dir
def
evaluate
(
self
,
results
,
metric
=
'bbox'
,
logger
=
None
,
outfile_prefix
=
None
,
classwise
=
False
,
proposal_nums
=
(
100
,
300
,
1000
),
iou_thrs
=
np
.
arange
(
0.5
,
0.96
,
0.05
)):
"""Evaluation in Cityscapes/COCO protocol.
Args:
results (list[list | tuple]): Testing results of the dataset.
metric (str | list[str]): Metrics to be evaluated. Options are
'bbox', 'segm', 'proposal', 'proposal_fast'.
logger (logging.Logger | str | None): Logger used for printing
related information during evaluation. Default: None.
outfile_prefix (str | None): The prefix of output file. It includes
the file path and the prefix of filename, e.g., "a/b/prefix".
If results are evaluated with COCO protocol, it would be the
prefix of output json file. For example, the metric is 'bbox'
and 'segm', then json files would be "a/b/prefix.bbox.json" and
"a/b/prefix.segm.json".
If results are evaluated with cityscapes protocol, it would be
the prefix of output txt/png files. The output files would be
png images under folder "a/b/prefix/xxx/" and the file name of
images would be written into a txt file
"a/b/prefix/xxx_pred.txt", where "xxx" is the video name of
cityscapes. If not specified, a temp file will be created.
Default: None.
classwise (bool): Whether to evaluating the AP for each class.
proposal_nums (Sequence[int]): Proposal number used for evaluating
recalls, such as recall@100, recall@1000.
Default: (100, 300, 1000).
iou_thrs (Sequence[float]): IoU threshold used for evaluating
recalls. If set to a list, the average recall of all IoUs will
also be computed. Default: 0.5.
Returns:
dict[str, float]: COCO style evaluation metric or cityscapes mAP
\
and AP@50.
"""
eval_results
=
dict
()
metrics
=
metric
.
copy
()
if
isinstance
(
metric
,
list
)
else
[
metric
]
if
'cityscapes'
in
metrics
:
eval_results
.
update
(
self
.
_evaluate_cityscapes
(
results
,
outfile_prefix
,
logger
))
metrics
.
remove
(
'cityscapes'
)
# left metrics are all coco metric
if
len
(
metrics
)
>
0
:
# create CocoDataset with CityscapesDataset annotation
self_coco
=
CocoDataset
(
self
.
ann_file
,
self
.
pipeline
.
transforms
,
None
,
self
.
data_root
,
self
.
img_prefix
,
self
.
seg_prefix
,
self
.
proposal_file
,
self
.
test_mode
,
self
.
filter_empty_gt
)
# TODO: remove this in the future
# reload annotations of correct class
self_coco
.
CLASSES
=
self
.
CLASSES
self_coco
.
data_infos
=
self_coco
.
load_annotations
(
self
.
ann_file
)
eval_results
.
update
(
self_coco
.
evaluate
(
results
,
metrics
,
logger
,
outfile_prefix
,
classwise
,
proposal_nums
,
iou_thrs
))
return
eval_results
def
_evaluate_cityscapes
(
self
,
results
,
txtfile_prefix
,
logger
):
"""Evaluation in Cityscapes protocol.
Args:
results (list): Testing results of the dataset.
txtfile_prefix (str | None): The prefix of output txt file
logger (logging.Logger | str | None): Logger used for printing
related information during evaluation. Default: None.
Returns:
dict[str: float]: Cityscapes evaluation results, contains 'mAP'
\
and 'AP@50'.
"""
try
:
import
cityscapesscripts.evaluation.evalInstanceLevelSemanticLabeling
as
CSEval
# noqa
except
ImportError
:
raise
ImportError
(
'Please run "pip install citscapesscripts" to '
'install cityscapesscripts first.'
)
msg
=
'Evaluating in Cityscapes style'
if
logger
is
None
:
msg
=
'
\n
'
+
msg
print_log
(
msg
,
logger
=
logger
)
result_files
,
tmp_dir
=
self
.
format_results
(
results
,
txtfile_prefix
)
if
tmp_dir
is
None
:
result_dir
=
osp
.
join
(
txtfile_prefix
,
'results'
)
else
:
result_dir
=
osp
.
join
(
tmp_dir
.
name
,
'results'
)
eval_results
=
OrderedDict
()
print_log
(
f
'Evaluating results under
{
result_dir
}
...'
,
logger
=
logger
)
# set global states in cityscapes evaluation API
CSEval
.
args
.
cityscapesPath
=
os
.
path
.
join
(
self
.
img_prefix
,
'../..'
)
CSEval
.
args
.
predictionPath
=
os
.
path
.
abspath
(
result_dir
)
CSEval
.
args
.
predictionWalk
=
None
CSEval
.
args
.
JSONOutput
=
False
CSEval
.
args
.
colorized
=
False
CSEval
.
args
.
gtInstancesFile
=
os
.
path
.
join
(
result_dir
,
'gtInstances.json'
)
CSEval
.
args
.
groundTruthSearch
=
os
.
path
.
join
(
self
.
img_prefix
.
replace
(
'leftImg8bit'
,
'gtFine'
),
'*/*_gtFine_instanceIds.png'
)
groundTruthImgList
=
glob
.
glob
(
CSEval
.
args
.
groundTruthSearch
)
assert
len
(
groundTruthImgList
),
'Cannot find ground truth images'
\
f
' in
{
CSEval
.
args
.
groundTruthSearch
}
.'
predictionImgList
=
[]
for
gt
in
groundTruthImgList
:
predictionImgList
.
append
(
CSEval
.
getPrediction
(
gt
,
CSEval
.
args
))
CSEval_results
=
CSEval
.
evaluateImgLists
(
predictionImgList
,
groundTruthImgList
,
CSEval
.
args
)[
'averages'
]
eval_results
[
'mAP'
]
=
CSEval_results
[
'allAp'
]
eval_results
[
'AP@50'
]
=
CSEval_results
[
'allAp50%'
]
if
tmp_dir
is
not
None
:
tmp_dir
.
cleanup
()
return
eval_results
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/coco.py
0 → 100644
View file @
142dcf29
import
itertools
import
logging
import
os.path
as
osp
import
tempfile
from
collections
import
OrderedDict
import
mmcv
import
numpy
as
np
from
mmcv.utils
import
print_log
from
pycocotools.coco
import
COCO
from
pycocotools.cocoeval
import
COCOeval
from
terminaltables
import
AsciiTable
from
mmdet.core
import
eval_recalls
from
.builder
import
DATASETS
from
.custom
import
CustomDataset
try
:
import
pycocotools
if
not
hasattr
(
pycocotools
,
'__sphinx_mock__'
):
# for doc generation
assert
pycocotools
.
__version__
>=
'12.0.2'
except
AssertionError
:
raise
AssertionError
(
'Incompatible version of pycocotools is installed. '
'Run pip uninstall pycocotools first. Then run pip '
'install mmpycocotools to install open-mmlab forked '
'pycocotools.'
)
@
DATASETS
.
register_module
()
class
CocoDataset
(
CustomDataset
):
CLASSES
=
(
'person'
,
'bicycle'
,
'car'
,
'motorcycle'
,
'airplane'
,
'bus'
,
'train'
,
'truck'
,
'boat'
,
'traffic light'
,
'fire hydrant'
,
'stop sign'
,
'parking meter'
,
'bench'
,
'bird'
,
'cat'
,
'dog'
,
'horse'
,
'sheep'
,
'cow'
,
'elephant'
,
'bear'
,
'zebra'
,
'giraffe'
,
'backpack'
,
'umbrella'
,
'handbag'
,
'tie'
,
'suitcase'
,
'frisbee'
,
'skis'
,
'snowboard'
,
'sports ball'
,
'kite'
,
'baseball bat'
,
'baseball glove'
,
'skateboard'
,
'surfboard'
,
'tennis racket'
,
'bottle'
,
'wine glass'
,
'cup'
,
'fork'
,
'knife'
,
'spoon'
,
'bowl'
,
'banana'
,
'apple'
,
'sandwich'
,
'orange'
,
'broccoli'
,
'carrot'
,
'hot dog'
,
'pizza'
,
'donut'
,
'cake'
,
'chair'
,
'couch'
,
'potted plant'
,
'bed'
,
'dining table'
,
'toilet'
,
'tv'
,
'laptop'
,
'mouse'
,
'remote'
,
'keyboard'
,
'cell phone'
,
'microwave'
,
'oven'
,
'toaster'
,
'sink'
,
'refrigerator'
,
'book'
,
'clock'
,
'vase'
,
'scissors'
,
'teddy bear'
,
'hair drier'
,
'toothbrush'
)
def
load_annotations
(
self
,
ann_file
):
"""Load annotation from COCO style annotation file.
Args:
ann_file (str): Path of annotation file.
Returns:
list[dict]: Annotation info from COCO api.
"""
self
.
coco
=
COCO
(
ann_file
)
self
.
cat_ids
=
self
.
coco
.
get_cat_ids
(
cat_names
=
self
.
CLASSES
)
self
.
cat2label
=
{
cat_id
:
i
for
i
,
cat_id
in
enumerate
(
self
.
cat_ids
)}
self
.
img_ids
=
self
.
coco
.
get_img_ids
()
data_infos
=
[]
for
i
in
self
.
img_ids
:
info
=
self
.
coco
.
load_imgs
([
i
])[
0
]
info
[
'filename'
]
=
info
[
'file_name'
]
data_infos
.
append
(
info
)
return
data_infos
def
get_ann_info
(
self
,
idx
):
"""Get COCO annotation by index.
Args:
idx (int): Index of data.
Returns:
dict: Annotation info of specified index.
"""
img_id
=
self
.
data_infos
[
idx
][
'id'
]
ann_ids
=
self
.
coco
.
get_ann_ids
(
img_ids
=
[
img_id
])
ann_info
=
self
.
coco
.
load_anns
(
ann_ids
)
return
self
.
_parse_ann_info
(
self
.
data_infos
[
idx
],
ann_info
)
def
get_cat_ids
(
self
,
idx
):
"""Get COCO category ids by index.
Args:
idx (int): Index of data.
Returns:
list[int]: All categories in the image of specified index.
"""
img_id
=
self
.
data_infos
[
idx
][
'id'
]
ann_ids
=
self
.
coco
.
get_ann_ids
(
img_ids
=
[
img_id
])
ann_info
=
self
.
coco
.
load_anns
(
ann_ids
)
return
[
ann
[
'category_id'
]
for
ann
in
ann_info
]
def
_filter_imgs
(
self
,
min_size
=
32
):
"""Filter images too small or without ground truths."""
valid_inds
=
[]
# obtain images that contain annotation
ids_with_ann
=
set
(
_
[
'image_id'
]
for
_
in
self
.
coco
.
anns
.
values
())
# obtain images that contain annotations of the required categories
ids_in_cat
=
set
()
for
i
,
class_id
in
enumerate
(
self
.
cat_ids
):
ids_in_cat
|=
set
(
self
.
coco
.
cat_img_map
[
class_id
])
# merge the image id sets of the two conditions and use the merged set
# to filter out images if self.filter_empty_gt=True
ids_in_cat
&=
ids_with_ann
valid_img_ids
=
[]
for
i
,
img_info
in
enumerate
(
self
.
data_infos
):
img_id
=
self
.
img_ids
[
i
]
if
self
.
filter_empty_gt
and
img_id
not
in
ids_in_cat
:
continue
if
min
(
img_info
[
'width'
],
img_info
[
'height'
])
>=
min_size
:
valid_inds
.
append
(
i
)
valid_img_ids
.
append
(
img_id
)
self
.
img_ids
=
valid_img_ids
return
valid_inds
def
_parse_ann_info
(
self
,
img_info
,
ann_info
):
"""Parse bbox and mask annotation.
Args:
ann_info (list[dict]): Annotation info of an image.
with_mask (bool): Whether to parse mask annotations.
Returns:
dict: A dict containing the following keys: bboxes, bboxes_ignore,
\
labels, masks, seg_map. "masks" are raw annotations and not
\
decoded into binary masks.
"""
gt_bboxes
=
[]
gt_labels
=
[]
gt_bboxes_ignore
=
[]
gt_masks_ann
=
[]
for
i
,
ann
in
enumerate
(
ann_info
):
if
ann
.
get
(
'ignore'
,
False
):
continue
x1
,
y1
,
w
,
h
=
ann
[
'bbox'
]
inter_w
=
max
(
0
,
min
(
x1
+
w
,
img_info
[
'width'
])
-
max
(
x1
,
0
))
inter_h
=
max
(
0
,
min
(
y1
+
h
,
img_info
[
'height'
])
-
max
(
y1
,
0
))
if
inter_w
*
inter_h
==
0
:
continue
if
ann
[
'area'
]
<=
0
or
w
<
1
or
h
<
1
:
continue
if
ann
[
'category_id'
]
not
in
self
.
cat_ids
:
continue
bbox
=
[
x1
,
y1
,
x1
+
w
,
y1
+
h
]
if
ann
.
get
(
'iscrowd'
,
False
):
gt_bboxes_ignore
.
append
(
bbox
)
else
:
gt_bboxes
.
append
(
bbox
)
gt_labels
.
append
(
self
.
cat2label
[
ann
[
'category_id'
]])
gt_masks_ann
.
append
(
ann
.
get
(
'segmentation'
,
None
))
if
gt_bboxes
:
gt_bboxes
=
np
.
array
(
gt_bboxes
,
dtype
=
np
.
float32
)
gt_labels
=
np
.
array
(
gt_labels
,
dtype
=
np
.
int64
)
else
:
gt_bboxes
=
np
.
zeros
((
0
,
4
),
dtype
=
np
.
float32
)
gt_labels
=
np
.
array
([],
dtype
=
np
.
int64
)
if
gt_bboxes_ignore
:
gt_bboxes_ignore
=
np
.
array
(
gt_bboxes_ignore
,
dtype
=
np
.
float32
)
else
:
gt_bboxes_ignore
=
np
.
zeros
((
0
,
4
),
dtype
=
np
.
float32
)
seg_map
=
img_info
[
'filename'
].
replace
(
'jpg'
,
'png'
)
ann
=
dict
(
bboxes
=
gt_bboxes
,
labels
=
gt_labels
,
bboxes_ignore
=
gt_bboxes_ignore
,
masks
=
gt_masks_ann
,
seg_map
=
seg_map
)
return
ann
def
xyxy2xywh
(
self
,
bbox
):
"""Convert ``xyxy`` style bounding boxes to ``xywh`` style for COCO
evaluation.
Args:
bbox (numpy.ndarray): The bounding boxes, shape (4, ), in
``xyxy`` order.
Returns:
list[float]: The converted bounding boxes, in ``xywh`` order.
"""
_bbox
=
bbox
.
tolist
()
return
[
_bbox
[
0
],
_bbox
[
1
],
_bbox
[
2
]
-
_bbox
[
0
],
_bbox
[
3
]
-
_bbox
[
1
],
]
def
_proposal2json
(
self
,
results
):
"""Convert proposal results to COCO json style."""
json_results
=
[]
for
idx
in
range
(
len
(
self
)):
img_id
=
self
.
img_ids
[
idx
]
bboxes
=
results
[
idx
]
for
i
in
range
(
bboxes
.
shape
[
0
]):
data
=
dict
()
data
[
'image_id'
]
=
img_id
data
[
'bbox'
]
=
self
.
xyxy2xywh
(
bboxes
[
i
])
data
[
'score'
]
=
float
(
bboxes
[
i
][
4
])
data
[
'category_id'
]
=
1
json_results
.
append
(
data
)
return
json_results
def
_det2json
(
self
,
results
):
"""Convert detection results to COCO json style."""
json_results
=
[]
for
idx
in
range
(
len
(
self
)):
img_id
=
self
.
img_ids
[
idx
]
result
=
results
[
idx
]
for
label
in
range
(
len
(
result
)):
bboxes
=
result
[
label
]
for
i
in
range
(
bboxes
.
shape
[
0
]):
data
=
dict
()
data
[
'image_id'
]
=
img_id
data
[
'bbox'
]
=
self
.
xyxy2xywh
(
bboxes
[
i
])
data
[
'score'
]
=
float
(
bboxes
[
i
][
4
])
data
[
'category_id'
]
=
self
.
cat_ids
[
label
]
json_results
.
append
(
data
)
return
json_results
def
_segm2json
(
self
,
results
):
"""Convert instance segmentation results to COCO json style."""
bbox_json_results
=
[]
segm_json_results
=
[]
for
idx
in
range
(
len
(
self
)):
img_id
=
self
.
img_ids
[
idx
]
det
,
seg
=
results
[
idx
]
for
label
in
range
(
len
(
det
)):
# bbox results
bboxes
=
det
[
label
]
for
i
in
range
(
bboxes
.
shape
[
0
]):
data
=
dict
()
data
[
'image_id'
]
=
img_id
data
[
'bbox'
]
=
self
.
xyxy2xywh
(
bboxes
[
i
])
data
[
'score'
]
=
float
(
bboxes
[
i
][
4
])
data
[
'category_id'
]
=
self
.
cat_ids
[
label
]
bbox_json_results
.
append
(
data
)
# segm results
# some detectors use different scores for bbox and mask
if
isinstance
(
seg
,
tuple
):
segms
=
seg
[
0
][
label
]
mask_score
=
seg
[
1
][
label
]
else
:
segms
=
seg
[
label
]
mask_score
=
[
bbox
[
4
]
for
bbox
in
bboxes
]
for
i
in
range
(
bboxes
.
shape
[
0
]):
data
=
dict
()
data
[
'image_id'
]
=
img_id
data
[
'bbox'
]
=
self
.
xyxy2xywh
(
bboxes
[
i
])
data
[
'score'
]
=
float
(
mask_score
[
i
])
data
[
'category_id'
]
=
self
.
cat_ids
[
label
]
if
isinstance
(
segms
[
i
][
'counts'
],
bytes
):
segms
[
i
][
'counts'
]
=
segms
[
i
][
'counts'
].
decode
()
data
[
'segmentation'
]
=
segms
[
i
]
segm_json_results
.
append
(
data
)
return
bbox_json_results
,
segm_json_results
def
results2json
(
self
,
results
,
outfile_prefix
):
"""Dump the detection results to a COCO style json file.
There are 3 types of results: proposals, bbox predictions, mask
predictions, and they have different data types. This method will
automatically recognize the type, and dump them to json files.
Args:
results (list[list | tuple | ndarray]): Testing results of the
dataset.
outfile_prefix (str): The filename prefix of the json files. If the
prefix is "somepath/xxx", the json files will be named
"somepath/xxx.bbox.json", "somepath/xxx.segm.json",
"somepath/xxx.proposal.json".
Returns:
dict[str: str]: Possible keys are "bbox", "segm", "proposal", and
\
values are corresponding filenames.
"""
result_files
=
dict
()
if
isinstance
(
results
[
0
],
list
):
json_results
=
self
.
_det2json
(
results
)
result_files
[
'bbox'
]
=
f
'
{
outfile_prefix
}
.bbox.json'
result_files
[
'proposal'
]
=
f
'
{
outfile_prefix
}
.bbox.json'
mmcv
.
dump
(
json_results
,
result_files
[
'bbox'
])
elif
isinstance
(
results
[
0
],
tuple
):
json_results
=
self
.
_segm2json
(
results
)
result_files
[
'bbox'
]
=
f
'
{
outfile_prefix
}
.bbox.json'
result_files
[
'proposal'
]
=
f
'
{
outfile_prefix
}
.bbox.json'
result_files
[
'segm'
]
=
f
'
{
outfile_prefix
}
.segm.json'
mmcv
.
dump
(
json_results
[
0
],
result_files
[
'bbox'
])
mmcv
.
dump
(
json_results
[
1
],
result_files
[
'segm'
])
elif
isinstance
(
results
[
0
],
np
.
ndarray
):
json_results
=
self
.
_proposal2json
(
results
)
result_files
[
'proposal'
]
=
f
'
{
outfile_prefix
}
.proposal.json'
mmcv
.
dump
(
json_results
,
result_files
[
'proposal'
])
else
:
raise
TypeError
(
'invalid type of results'
)
return
result_files
def
fast_eval_recall
(
self
,
results
,
proposal_nums
,
iou_thrs
,
logger
=
None
):
gt_bboxes
=
[]
for
i
in
range
(
len
(
self
.
img_ids
)):
ann_ids
=
self
.
coco
.
get_ann_ids
(
img_ids
=
self
.
img_ids
[
i
])
ann_info
=
self
.
coco
.
load_anns
(
ann_ids
)
if
len
(
ann_info
)
==
0
:
gt_bboxes
.
append
(
np
.
zeros
((
0
,
4
)))
continue
bboxes
=
[]
for
ann
in
ann_info
:
if
ann
.
get
(
'ignore'
,
False
)
or
ann
[
'iscrowd'
]:
continue
x1
,
y1
,
w
,
h
=
ann
[
'bbox'
]
bboxes
.
append
([
x1
,
y1
,
x1
+
w
,
y1
+
h
])
bboxes
=
np
.
array
(
bboxes
,
dtype
=
np
.
float32
)
if
bboxes
.
shape
[
0
]
==
0
:
bboxes
=
np
.
zeros
((
0
,
4
))
gt_bboxes
.
append
(
bboxes
)
recalls
=
eval_recalls
(
gt_bboxes
,
results
,
proposal_nums
,
iou_thrs
,
logger
=
logger
)
ar
=
recalls
.
mean
(
axis
=
1
)
return
ar
def
format_results
(
self
,
results
,
jsonfile_prefix
=
None
,
**
kwargs
):
"""Format the results to json (standard format for COCO evaluation).
Args:
results (list[tuple | numpy.ndarray]): Testing results of the
dataset.
jsonfile_prefix (str | None): The prefix of json 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. Default: None.
Returns:
tuple: (result_files, tmp_dir), result_files is a dict containing
\
the json filepaths, tmp_dir is the temporal directory created
\
for saving json files when jsonfile_prefix is not specified.
"""
assert
isinstance
(
results
,
list
),
'results must be a list'
assert
len
(
results
)
==
len
(
self
),
(
'The length of results is not equal to the dataset len: {} != {}'
.
format
(
len
(
results
),
len
(
self
)))
if
jsonfile_prefix
is
None
:
tmp_dir
=
tempfile
.
TemporaryDirectory
()
jsonfile_prefix
=
osp
.
join
(
tmp_dir
.
name
,
'results'
)
else
:
tmp_dir
=
None
result_files
=
self
.
results2json
(
results
,
jsonfile_prefix
)
return
result_files
,
tmp_dir
def
evaluate
(
self
,
results
,
metric
=
'bbox'
,
logger
=
None
,
jsonfile_prefix
=
None
,
classwise
=
False
,
proposal_nums
=
(
100
,
300
,
1000
),
iou_thrs
=
None
,
metric_items
=
None
):
"""Evaluation in COCO protocol.
Args:
results (list[list | tuple]): Testing results of the dataset.
metric (str | list[str]): Metrics to be evaluated. Options are
'bbox', 'segm', 'proposal', 'proposal_fast'.
logger (logging.Logger | str | None): Logger used for printing
related information during evaluation. Default: None.
jsonfile_prefix (str | None): The prefix of json 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. Default: None.
classwise (bool): Whether to evaluating the AP for each class.
proposal_nums (Sequence[int]): Proposal number used for evaluating
recalls, such as recall@100, recall@1000.
Default: (100, 300, 1000).
iou_thrs (Sequence[float], optional): IoU threshold used for
evaluating recalls/mAPs. If set to a list, the average of all
IoUs will also be computed. If not specified, [0.50, 0.55,
0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95] will be used.
Default: None.
metric_items (list[str] | str, optional): Metric items that will
be returned. If not specified, ``['AR@100', 'AR@300',
'AR@1000', 'AR_s@1000', 'AR_m@1000', 'AR_l@1000' ]`` will be
used when ``metric=='proposal'``, ``['mAP', 'mAP_50', 'mAP_75',
'mAP_s', 'mAP_m', 'mAP_l']`` will be used when
``metric=='bbox' or metric=='segm'``.
Returns:
dict[str, float]: COCO style evaluation metric.
"""
metrics
=
metric
if
isinstance
(
metric
,
list
)
else
[
metric
]
allowed_metrics
=
[
'bbox'
,
'segm'
,
'proposal'
,
'proposal_fast'
]
for
metric
in
metrics
:
if
metric
not
in
allowed_metrics
:
raise
KeyError
(
f
'metric
{
metric
}
is not supported'
)
if
iou_thrs
is
None
:
iou_thrs
=
np
.
linspace
(
.
5
,
0.95
,
int
(
np
.
round
((
0.95
-
.
5
)
/
.
05
))
+
1
,
endpoint
=
True
)
if
metric_items
is
not
None
:
if
not
isinstance
(
metric_items
,
list
):
metric_items
=
[
metric_items
]
result_files
,
tmp_dir
=
self
.
format_results
(
results
,
jsonfile_prefix
)
eval_results
=
OrderedDict
()
cocoGt
=
self
.
coco
for
metric
in
metrics
:
msg
=
f
'Evaluating
{
metric
}
...'
if
logger
is
None
:
msg
=
'
\n
'
+
msg
print_log
(
msg
,
logger
=
logger
)
if
metric
==
'proposal_fast'
:
ar
=
self
.
fast_eval_recall
(
results
,
proposal_nums
,
iou_thrs
,
logger
=
'silent'
)
log_msg
=
[]
for
i
,
num
in
enumerate
(
proposal_nums
):
eval_results
[
f
'AR@
{
num
}
'
]
=
ar
[
i
]
log_msg
.
append
(
f
'
\n
AR@
{
num
}
\t
{
ar
[
i
]:.
4
f
}
'
)
log_msg
=
''
.
join
(
log_msg
)
print_log
(
log_msg
,
logger
=
logger
)
continue
if
metric
not
in
result_files
:
raise
KeyError
(
f
'
{
metric
}
is not in results'
)
try
:
cocoDt
=
cocoGt
.
loadRes
(
result_files
[
metric
])
except
IndexError
:
print_log
(
'The testing results of the whole dataset is empty.'
,
logger
=
logger
,
level
=
logging
.
ERROR
)
break
iou_type
=
'bbox'
if
metric
==
'proposal'
else
metric
cocoEval
=
COCOeval
(
cocoGt
,
cocoDt
,
iou_type
)
cocoEval
.
params
.
catIds
=
self
.
cat_ids
cocoEval
.
params
.
imgIds
=
self
.
img_ids
cocoEval
.
params
.
maxDets
=
list
(
proposal_nums
)
cocoEval
.
params
.
iouThrs
=
iou_thrs
# mapping of cocoEval.stats
coco_metric_names
=
{
'mAP'
:
0
,
'mAP_50'
:
1
,
'mAP_75'
:
2
,
'mAP_s'
:
3
,
'mAP_m'
:
4
,
'mAP_l'
:
5
,
'AR@100'
:
6
,
'AR@300'
:
7
,
'AR@1000'
:
8
,
'AR_s@1000'
:
9
,
'AR_m@1000'
:
10
,
'AR_l@1000'
:
11
}
if
metric_items
is
not
None
:
for
metric_item
in
metric_items
:
if
metric_item
not
in
coco_metric_names
:
raise
KeyError
(
f
'metric item
{
metric_item
}
is not supported'
)
if
metric
==
'proposal'
:
cocoEval
.
params
.
useCats
=
0
cocoEval
.
evaluate
()
cocoEval
.
accumulate
()
cocoEval
.
summarize
()
if
metric_items
is
None
:
metric_items
=
[
'AR@100'
,
'AR@300'
,
'AR@1000'
,
'AR_s@1000'
,
'AR_m@1000'
,
'AR_l@1000'
]
for
item
in
metric_items
:
val
=
float
(
f
'
{
cocoEval
.
stats
[
coco_metric_names
[
item
]]:.
3
f
}
'
)
eval_results
[
item
]
=
val
else
:
cocoEval
.
evaluate
()
cocoEval
.
accumulate
()
cocoEval
.
summarize
()
if
classwise
:
# Compute per-category AP
# Compute per-category AP
# from https://github.com/facebookresearch/detectron2/
precisions
=
cocoEval
.
eval
[
'precision'
]
# precision: (iou, recall, cls, area range, max dets)
assert
len
(
self
.
cat_ids
)
==
precisions
.
shape
[
2
]
results_per_category
=
[]
for
idx
,
catId
in
enumerate
(
self
.
cat_ids
):
# area range index 0: all area ranges
# max dets index -1: typically 100 per image
nm
=
self
.
coco
.
loadCats
(
catId
)[
0
]
precision
=
precisions
[:,
:,
idx
,
0
,
-
1
]
precision
=
precision
[
precision
>
-
1
]
if
precision
.
size
:
ap
=
np
.
mean
(
precision
)
else
:
ap
=
float
(
'nan'
)
results_per_category
.
append
(
(
f
'
{
nm
[
"name"
]
}
'
,
f
'
{
float
(
ap
):
0.3
f
}
'
))
num_columns
=
min
(
6
,
len
(
results_per_category
)
*
2
)
results_flatten
=
list
(
itertools
.
chain
(
*
results_per_category
))
headers
=
[
'category'
,
'AP'
]
*
(
num_columns
//
2
)
results_2d
=
itertools
.
zip_longest
(
*
[
results_flatten
[
i
::
num_columns
]
for
i
in
range
(
num_columns
)
])
table_data
=
[
headers
]
table_data
+=
[
result
for
result
in
results_2d
]
table
=
AsciiTable
(
table_data
)
print_log
(
'
\n
'
+
table
.
table
,
logger
=
logger
)
if
metric_items
is
None
:
metric_items
=
[
'mAP'
,
'mAP_50'
,
'mAP_75'
,
'mAP_s'
,
'mAP_m'
,
'mAP_l'
]
for
metric_item
in
metric_items
:
key
=
f
'
{
metric
}
_
{
metric_item
}
'
val
=
float
(
f
'
{
cocoEval
.
stats
[
coco_metric_names
[
metric_item
]]:.
3
f
}
'
)
eval_results
[
key
]
=
val
ap
=
cocoEval
.
stats
[:
6
]
eval_results
[
f
'
{
metric
}
_mAP_copypaste'
]
=
(
f
'
{
ap
[
0
]:.
3
f
}
{
ap
[
1
]:.
3
f
}
{
ap
[
2
]:.
3
f
}
{
ap
[
3
]:.
3
f
}
'
f
'
{
ap
[
4
]:.
3
f
}
{
ap
[
5
]:.
3
f
}
'
)
if
tmp_dir
is
not
None
:
tmp_dir
.
cleanup
()
return
eval_results
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/custom.py
0 → 100644
View file @
142dcf29
import
os.path
as
osp
import
warnings
from
collections
import
OrderedDict
import
mmcv
import
numpy
as
np
from
mmcv.utils
import
print_log
from
torch.utils.data
import
Dataset
from
mmdet.core
import
eval_map
,
eval_recalls
from
.builder
import
DATASETS
from
.pipelines
import
Compose
@
DATASETS
.
register_module
()
class
CustomDataset
(
Dataset
):
"""Custom dataset for detection.
The annotation format is shown as follows. The `ann` field is optional for
testing.
.. code-block:: none
[
{
'filename': 'a.jpg',
'width': 1280,
'height': 720,
'ann': {
'bboxes': <np.ndarray> (n, 4) in (x1, y1, x2, y2) order.
'labels': <np.ndarray> (n, ),
'bboxes_ignore': <np.ndarray> (k, 4), (optional field)
'labels_ignore': <np.ndarray> (k, 4) (optional field)
}
},
...
]
Args:
ann_file (str): Annotation file path.
pipeline (list[dict]): Processing pipeline.
classes (str | Sequence[str], optional): Specify classes to load.
If is None, ``cls.CLASSES`` will be used. Default: None.
data_root (str, optional): Data root for ``ann_file``,
``img_prefix``, ``seg_prefix``, ``proposal_file`` if specified.
test_mode (bool, optional): If set True, annotation will not be loaded.
filter_empty_gt (bool, optional): If set true, images without bounding
boxes of the dataset's classes will be filtered out. This option
only works when `test_mode=False`, i.e., we never filter images
during tests.
"""
CLASSES
=
None
def
__init__
(
self
,
ann_file
,
pipeline
,
classes
=
None
,
data_root
=
None
,
img_prefix
=
''
,
seg_prefix
=
None
,
proposal_file
=
None
,
test_mode
=
False
,
filter_empty_gt
=
True
):
self
.
ann_file
=
ann_file
self
.
data_root
=
data_root
self
.
img_prefix
=
img_prefix
self
.
seg_prefix
=
seg_prefix
self
.
proposal_file
=
proposal_file
self
.
test_mode
=
test_mode
self
.
filter_empty_gt
=
filter_empty_gt
self
.
CLASSES
=
self
.
get_classes
(
classes
)
# join paths if data_root is specified
if
self
.
data_root
is
not
None
:
if
not
osp
.
isabs
(
self
.
ann_file
):
self
.
ann_file
=
osp
.
join
(
self
.
data_root
,
self
.
ann_file
)
if
not
(
self
.
img_prefix
is
None
or
osp
.
isabs
(
self
.
img_prefix
)):
self
.
img_prefix
=
osp
.
join
(
self
.
data_root
,
self
.
img_prefix
)
if
not
(
self
.
seg_prefix
is
None
or
osp
.
isabs
(
self
.
seg_prefix
)):
self
.
seg_prefix
=
osp
.
join
(
self
.
data_root
,
self
.
seg_prefix
)
if
not
(
self
.
proposal_file
is
None
or
osp
.
isabs
(
self
.
proposal_file
)):
self
.
proposal_file
=
osp
.
join
(
self
.
data_root
,
self
.
proposal_file
)
# load annotations (and proposals)
self
.
data_infos
=
self
.
load_annotations
(
self
.
ann_file
)
if
self
.
proposal_file
is
not
None
:
self
.
proposals
=
self
.
load_proposals
(
self
.
proposal_file
)
else
:
self
.
proposals
=
None
# filter images too small and containing no annotations
if
not
test_mode
:
valid_inds
=
self
.
_filter_imgs
()
self
.
data_infos
=
[
self
.
data_infos
[
i
]
for
i
in
valid_inds
]
if
self
.
proposals
is
not
None
:
self
.
proposals
=
[
self
.
proposals
[
i
]
for
i
in
valid_inds
]
# set group flag for the sampler
self
.
_set_group_flag
()
# processing pipeline
self
.
pipeline
=
Compose
(
pipeline
)
def
__len__
(
self
):
"""Total number of samples of data."""
return
len
(
self
.
data_infos
)
def
load_annotations
(
self
,
ann_file
):
"""Load annotation from annotation file."""
return
mmcv
.
load
(
ann_file
)
def
load_proposals
(
self
,
proposal_file
):
"""Load proposal from proposal file."""
return
mmcv
.
load
(
proposal_file
)
def
get_ann_info
(
self
,
idx
):
"""Get annotation by index.
Args:
idx (int): Index of data.
Returns:
dict: Annotation info of specified index.
"""
return
self
.
data_infos
[
idx
][
'ann'
]
def
get_cat_ids
(
self
,
idx
):
"""Get category ids by index.
Args:
idx (int): Index of data.
Returns:
list[int]: All categories in the image of specified index.
"""
return
self
.
data_infos
[
idx
][
'ann'
][
'labels'
].
astype
(
np
.
int
).
tolist
()
def
pre_pipeline
(
self
,
results
):
"""Prepare results dict for pipeline."""
results
[
'img_prefix'
]
=
self
.
img_prefix
results
[
'seg_prefix'
]
=
self
.
seg_prefix
results
[
'proposal_file'
]
=
self
.
proposal_file
results
[
'bbox_fields'
]
=
[]
results
[
'mask_fields'
]
=
[]
results
[
'seg_fields'
]
=
[]
def
_filter_imgs
(
self
,
min_size
=
32
):
"""Filter images too small."""
if
self
.
filter_empty_gt
:
warnings
.
warn
(
'CustomDataset does not support filtering empty gt images.'
)
valid_inds
=
[]
for
i
,
img_info
in
enumerate
(
self
.
data_infos
):
if
min
(
img_info
[
'width'
],
img_info
[
'height'
])
>=
min_size
:
valid_inds
.
append
(
i
)
return
valid_inds
def
_set_group_flag
(
self
):
"""Set flag according to image aspect ratio.
Images with aspect ratio greater than 1 will be set as group 1,
otherwise group 0.
"""
self
.
flag
=
np
.
zeros
(
len
(
self
),
dtype
=
np
.
uint8
)
for
i
in
range
(
len
(
self
)):
img_info
=
self
.
data_infos
[
i
]
if
img_info
[
'width'
]
/
img_info
[
'height'
]
>
1
:
self
.
flag
[
i
]
=
1
def
_rand_another
(
self
,
idx
):
"""Get another random index from the same group as the given index."""
pool
=
np
.
where
(
self
.
flag
==
self
.
flag
[
idx
])[
0
]
return
np
.
random
.
choice
(
pool
)
def
__getitem__
(
self
,
idx
):
"""Get training/test data after pipeline.
Args:
idx (int): Index of data.
Returns:
dict: Training/test data (with annotation if `test_mode` is set
\
True).
"""
if
self
.
test_mode
:
return
self
.
prepare_test_img
(
idx
)
while
True
:
data
=
self
.
prepare_train_img
(
idx
)
if
data
is
None
:
idx
=
self
.
_rand_another
(
idx
)
continue
return
data
def
prepare_train_img
(
self
,
idx
):
"""Get training data and annotations after pipeline.
Args:
idx (int): Index of data.
Returns:
dict: Training data and annotation after pipeline with new keys
\
introduced by pipeline.
"""
img_info
=
self
.
data_infos
[
idx
]
ann_info
=
self
.
get_ann_info
(
idx
)
results
=
dict
(
img_info
=
img_info
,
ann_info
=
ann_info
)
if
self
.
proposals
is
not
None
:
results
[
'proposals'
]
=
self
.
proposals
[
idx
]
self
.
pre_pipeline
(
results
)
return
self
.
pipeline
(
results
)
def
prepare_test_img
(
self
,
idx
):
"""Get testing data after pipeline.
Args:
idx (int): Index of data.
Returns:
dict: Testing data after pipeline with new keys intorduced by
\
piepline.
"""
img_info
=
self
.
data_infos
[
idx
]
results
=
dict
(
img_info
=
img_info
)
if
self
.
proposals
is
not
None
:
results
[
'proposals'
]
=
self
.
proposals
[
idx
]
self
.
pre_pipeline
(
results
)
return
self
.
pipeline
(
results
)
@
classmethod
def
get_classes
(
cls
,
classes
=
None
):
"""Get class names of current dataset.
Args:
classes (Sequence[str] | str | None): If classes is None, use
default CLASSES defined by builtin dataset. If classes is a
string, take it as a file name. The file contains the name of
classes where each line contains one class name. If classes is
a tuple or list, override the CLASSES defined by the dataset.
Returns:
tuple[str] or list[str]: Names of categories of the dataset.
"""
if
classes
is
None
:
return
cls
.
CLASSES
if
isinstance
(
classes
,
str
):
# take it as a file path
class_names
=
mmcv
.
list_from_file
(
classes
)
elif
isinstance
(
classes
,
(
tuple
,
list
)):
class_names
=
classes
else
:
raise
ValueError
(
f
'Unsupported type
{
type
(
classes
)
}
of classes.'
)
return
class_names
def
format_results
(
self
,
results
,
**
kwargs
):
"""Place holder to format result to dataset specific output."""
pass
def
evaluate
(
self
,
results
,
metric
=
'mAP'
,
logger
=
None
,
proposal_nums
=
(
100
,
300
,
1000
),
iou_thr
=
0.5
,
scale_ranges
=
None
):
"""Evaluate the dataset.
Args:
results (list): Testing results of the dataset.
metric (str | list[str]): Metrics to be evaluated.
logger (logging.Logger | None | str): Logger used for printing
related information during evaluation. Default: None.
proposal_nums (Sequence[int]): Proposal number used for evaluating
recalls, such as recall@100, recall@1000.
Default: (100, 300, 1000).
iou_thr (float | list[float]): IoU threshold. Default: 0.5.
scale_ranges (list[tuple] | None): Scale ranges for evaluating mAP.
Default: None.
"""
if
not
isinstance
(
metric
,
str
):
assert
len
(
metric
)
==
1
metric
=
metric
[
0
]
allowed_metrics
=
[
'mAP'
,
'recall'
]
if
metric
not
in
allowed_metrics
:
raise
KeyError
(
f
'metric
{
metric
}
is not supported'
)
annotations
=
[
self
.
get_ann_info
(
i
)
for
i
in
range
(
len
(
self
))]
eval_results
=
OrderedDict
()
iou_thrs
=
[
iou_thr
]
if
isinstance
(
iou_thr
,
float
)
else
iou_thr
if
metric
==
'mAP'
:
assert
isinstance
(
iou_thrs
,
list
)
mean_aps
=
[]
for
iou_thr
in
iou_thrs
:
print_log
(
f
'
\n
{
"-"
*
15
}
iou_thr:
{
iou_thr
}{
"-"
*
15
}
'
)
mean_ap
,
_
=
eval_map
(
results
,
annotations
,
scale_ranges
=
scale_ranges
,
iou_thr
=
iou_thr
,
dataset
=
self
.
CLASSES
,
logger
=
logger
)
mean_aps
.
append
(
mean_ap
)
eval_results
[
f
'AP
{
int
(
iou_thr
*
100
):
02
d
}
'
]
=
round
(
mean_ap
,
3
)
eval_results
[
'mAP'
]
=
sum
(
mean_aps
)
/
len
(
mean_aps
)
elif
metric
==
'recall'
:
gt_bboxes
=
[
ann
[
'bboxes'
]
for
ann
in
annotations
]
recalls
=
eval_recalls
(
gt_bboxes
,
results
,
proposal_nums
,
iou_thr
,
logger
=
logger
)
for
i
,
num
in
enumerate
(
proposal_nums
):
for
j
,
iou
in
enumerate
(
iou_thr
):
eval_results
[
f
'recall@
{
num
}
@
{
iou
}
'
]
=
recalls
[
i
,
j
]
if
recalls
.
shape
[
1
]
>
1
:
ar
=
recalls
.
mean
(
axis
=
1
)
for
i
,
num
in
enumerate
(
proposal_nums
):
eval_results
[
f
'AR@
{
num
}
'
]
=
ar
[
i
]
return
eval_results
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/dataset_wrappers.py
0 → 100644
View file @
142dcf29
import
bisect
import
math
from
collections
import
defaultdict
import
numpy
as
np
from
mmcv.utils
import
print_log
from
torch.utils.data.dataset
import
ConcatDataset
as
_ConcatDataset
from
.builder
import
DATASETS
from
.coco
import
CocoDataset
@
DATASETS
.
register_module
()
class
ConcatDataset
(
_ConcatDataset
):
"""A wrapper of concatenated dataset.
Same as :obj:`torch.utils.data.dataset.ConcatDataset`, but
concat the group flag for image aspect ratio.
Args:
datasets (list[:obj:`Dataset`]): A list of datasets.
separate_eval (bool): Whether to evaluate the results
separately if it is used as validation dataset.
Defaults to True.
"""
def
__init__
(
self
,
datasets
,
separate_eval
=
True
):
super
(
ConcatDataset
,
self
).
__init__
(
datasets
)
self
.
CLASSES
=
datasets
[
0
].
CLASSES
self
.
separate_eval
=
separate_eval
if
not
separate_eval
:
if
any
([
isinstance
(
ds
,
CocoDataset
)
for
ds
in
datasets
]):
raise
NotImplementedError
(
'Evaluating concatenated CocoDataset as a whole is not'
' supported! Please set "separate_eval=True"'
)
elif
len
(
set
([
type
(
ds
)
for
ds
in
datasets
]))
!=
1
:
raise
NotImplementedError
(
'All the datasets should have same types'
)
if
hasattr
(
datasets
[
0
],
'flag'
):
flags
=
[]
for
i
in
range
(
0
,
len
(
datasets
)):
flags
.
append
(
datasets
[
i
].
flag
)
self
.
flag
=
np
.
concatenate
(
flags
)
def
get_cat_ids
(
self
,
idx
):
"""Get category ids of concatenated dataset by index.
Args:
idx (int): Index of data.
Returns:
list[int]: All categories in the image of specified index.
"""
if
idx
<
0
:
if
-
idx
>
len
(
self
):
raise
ValueError
(
'absolute value of index should not exceed dataset length'
)
idx
=
len
(
self
)
+
idx
dataset_idx
=
bisect
.
bisect_right
(
self
.
cumulative_sizes
,
idx
)
if
dataset_idx
==
0
:
sample_idx
=
idx
else
:
sample_idx
=
idx
-
self
.
cumulative_sizes
[
dataset_idx
-
1
]
return
self
.
datasets
[
dataset_idx
].
get_cat_ids
(
sample_idx
)
def
evaluate
(
self
,
results
,
logger
=
None
,
**
kwargs
):
"""Evaluate the results.
Args:
results (list[list | tuple]): Testing results of the dataset.
logger (logging.Logger | str | None): Logger used for printing
related information during evaluation. Default: None.
Returns:
dict[str: float]: AP results of the total dataset or each separate
dataset if `self.separate_eval=True`.
"""
assert
len
(
results
)
==
self
.
cumulative_sizes
[
-
1
],
\
(
'Dataset and results have different sizes: '
f
'
{
self
.
cumulative_sizes
[
-
1
]
}
v.s.
{
len
(
results
)
}
'
)
# Check whether all the datasets support evaluation
for
dataset
in
self
.
datasets
:
assert
hasattr
(
dataset
,
'evaluate'
),
\
f
'
{
type
(
dataset
)
}
does not implement evaluate function'
if
self
.
separate_eval
:
dataset_idx
=
-
1
total_eval_results
=
dict
()
for
size
,
dataset
in
zip
(
self
.
cumulative_sizes
,
self
.
datasets
):
start_idx
=
0
if
dataset_idx
==
-
1
else
\
self
.
cumulative_sizes
[
dataset_idx
]
end_idx
=
self
.
cumulative_sizes
[
dataset_idx
+
1
]
results_per_dataset
=
results
[
start_idx
:
end_idx
]
print_log
(
f
'
\n
Evaluateing
{
dataset
.
ann_file
}
with '
f
'
{
len
(
results_per_dataset
)
}
images now'
,
logger
=
logger
)
eval_results_per_dataset
=
dataset
.
evaluate
(
results_per_dataset
,
logger
=
logger
,
**
kwargs
)
dataset_idx
+=
1
for
k
,
v
in
eval_results_per_dataset
.
items
():
total_eval_results
.
update
({
f
'
{
dataset_idx
}
_
{
k
}
'
:
v
})
return
total_eval_results
elif
any
([
isinstance
(
ds
,
CocoDataset
)
for
ds
in
self
.
datasets
]):
raise
NotImplementedError
(
'Evaluating concatenated CocoDataset as a whole is not'
' supported! Please set "separate_eval=True"'
)
elif
len
(
set
([
type
(
ds
)
for
ds
in
self
.
datasets
]))
!=
1
:
raise
NotImplementedError
(
'All the datasets should have same types'
)
else
:
original_data_infos
=
self
.
datasets
[
0
].
data_infos
self
.
datasets
[
0
].
data_infos
=
sum
(
[
dataset
.
data_infos
for
dataset
in
self
.
datasets
],
[])
eval_results
=
self
.
datasets
[
0
].
evaluate
(
results
,
logger
=
logger
,
**
kwargs
)
self
.
datasets
[
0
].
data_infos
=
original_data_infos
return
eval_results
@
DATASETS
.
register_module
()
class
RepeatDataset
(
object
):
"""A wrapper of repeated dataset.
The length of repeated dataset will be `times` larger than the original
dataset. This is useful when the data loading time is long but the dataset
is small. Using RepeatDataset can reduce the data loading time between
epochs.
Args:
dataset (:obj:`Dataset`): The dataset to be repeated.
times (int): Repeat times.
"""
def
__init__
(
self
,
dataset
,
times
):
self
.
dataset
=
dataset
self
.
times
=
times
self
.
CLASSES
=
dataset
.
CLASSES
if
hasattr
(
self
.
dataset
,
'flag'
):
self
.
flag
=
np
.
tile
(
self
.
dataset
.
flag
,
times
)
self
.
_ori_len
=
len
(
self
.
dataset
)
def
__getitem__
(
self
,
idx
):
return
self
.
dataset
[
idx
%
self
.
_ori_len
]
def
get_cat_ids
(
self
,
idx
):
"""Get category ids of repeat dataset by index.
Args:
idx (int): Index of data.
Returns:
list[int]: All categories in the image of specified index.
"""
return
self
.
dataset
.
get_cat_ids
(
idx
%
self
.
_ori_len
)
def
__len__
(
self
):
"""Length after repetition."""
return
self
.
times
*
self
.
_ori_len
# Modified from https://github.com/facebookresearch/detectron2/blob/41d475b75a230221e21d9cac5d69655e3415e3a4/detectron2/data/samplers/distributed_sampler.py#L57 # noqa
@
DATASETS
.
register_module
()
class
ClassBalancedDataset
(
object
):
"""A wrapper of repeated dataset with repeat factor.
Suitable for training on class imbalanced datasets like LVIS. Following
the sampling strategy in the `paper <https://arxiv.org/abs/1908.03195>`_,
in each epoch, an image may appear multiple times based on its
"repeat factor".
The repeat factor for an image is a function of the frequency the rarest
category labeled in that image. The "frequency of category c" in [0, 1]
is defined by the fraction of images in the training set (without repeats)
in which category c appears.
The dataset needs to instantiate :func:`self.get_cat_ids` to support
ClassBalancedDataset.
The repeat factor is computed as followed.
1. For each category c, compute the fraction # of images
that contain it: :math:`f(c)`
2. For each category c, compute the category-level repeat factor:
:math:`r(c) = max(1, sqrt(t/f(c)))`
3. For each image I, compute the image-level repeat factor:
:math:`r(I) = max_{c in I} r(c)`
Args:
dataset (:obj:`CustomDataset`): The dataset to be repeated.
oversample_thr (float): frequency threshold below which data is
repeated. For categories with ``f_c >= oversample_thr``, there is
no oversampling. For categories with ``f_c < oversample_thr``, the
degree of oversampling following the square-root inverse frequency
heuristic above.
filter_empty_gt (bool, optional): If set true, images without bounding
boxes will not be oversampled. Otherwise, they will be categorized
as the pure background class and involved into the oversampling.
Default: True.
"""
def
__init__
(
self
,
dataset
,
oversample_thr
,
filter_empty_gt
=
True
):
self
.
dataset
=
dataset
self
.
oversample_thr
=
oversample_thr
self
.
filter_empty_gt
=
filter_empty_gt
self
.
CLASSES
=
dataset
.
CLASSES
repeat_factors
=
self
.
_get_repeat_factors
(
dataset
,
oversample_thr
)
repeat_indices
=
[]
for
dataset_idx
,
repeat_factor
in
enumerate
(
repeat_factors
):
repeat_indices
.
extend
([
dataset_idx
]
*
math
.
ceil
(
repeat_factor
))
self
.
repeat_indices
=
repeat_indices
flags
=
[]
if
hasattr
(
self
.
dataset
,
'flag'
):
for
flag
,
repeat_factor
in
zip
(
self
.
dataset
.
flag
,
repeat_factors
):
flags
.
extend
([
flag
]
*
int
(
math
.
ceil
(
repeat_factor
)))
assert
len
(
flags
)
==
len
(
repeat_indices
)
self
.
flag
=
np
.
asarray
(
flags
,
dtype
=
np
.
uint8
)
def
_get_repeat_factors
(
self
,
dataset
,
repeat_thr
):
"""Get repeat factor for each images in the dataset.
Args:
dataset (:obj:`CustomDataset`): The dataset
repeat_thr (float): The threshold of frequency. If an image
contains the categories whose frequency below the threshold,
it would be repeated.
Returns:
list[float]: The repeat factors for each images in the dataset.
"""
# 1. For each category c, compute the fraction # of images
# that contain it: f(c)
category_freq
=
defaultdict
(
int
)
num_images
=
len
(
dataset
)
for
idx
in
range
(
num_images
):
cat_ids
=
set
(
self
.
dataset
.
get_cat_ids
(
idx
))
if
len
(
cat_ids
)
==
0
and
not
self
.
filter_empty_gt
:
cat_ids
=
set
([
len
(
self
.
CLASSES
)])
for
cat_id
in
cat_ids
:
category_freq
[
cat_id
]
+=
1
for
k
,
v
in
category_freq
.
items
():
category_freq
[
k
]
=
v
/
num_images
# 2. For each category c, compute the category-level repeat factor:
# r(c) = max(1, sqrt(t/f(c)))
category_repeat
=
{
cat_id
:
max
(
1.0
,
math
.
sqrt
(
repeat_thr
/
cat_freq
))
for
cat_id
,
cat_freq
in
category_freq
.
items
()
}
# 3. For each image I, compute the image-level repeat factor:
# r(I) = max_{c in I} r(c)
repeat_factors
=
[]
for
idx
in
range
(
num_images
):
cat_ids
=
set
(
self
.
dataset
.
get_cat_ids
(
idx
))
if
len
(
cat_ids
)
==
0
and
not
self
.
filter_empty_gt
:
cat_ids
=
set
([
len
(
self
.
CLASSES
)])
repeat_factor
=
1
if
len
(
cat_ids
)
>
0
:
repeat_factor
=
max
(
{
category_repeat
[
cat_id
]
for
cat_id
in
cat_ids
})
repeat_factors
.
append
(
repeat_factor
)
return
repeat_factors
def
__getitem__
(
self
,
idx
):
ori_index
=
self
.
repeat_indices
[
idx
]
return
self
.
dataset
[
ori_index
]
def
__len__
(
self
):
"""Length after repetition."""
return
len
(
self
.
repeat_indices
)
PyTorch/NLP/Conformer-main/mmdetection/mmdet/datasets/deepfashion.py
0 → 100644
View file @
142dcf29
from
.builder
import
DATASETS
from
.coco
import
CocoDataset
@
DATASETS
.
register_module
()
class
DeepFashionDataset
(
CocoDataset
):
CLASSES
=
(
'top'
,
'skirt'
,
'leggings'
,
'dress'
,
'outer'
,
'pants'
,
'bag'
,
'neckwear'
,
'headwear'
,
'eyeglass'
,
'belt'
,
'footwear'
,
'hair'
,
'skin'
,
'face'
)
Prev
1
…
6
7
8
9
10
11
12
13
14
…
16
Next
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