|
|
|
import pytest |
|
import torch |
|
from torch.nn.modules.batchnorm import _BatchNorm |
|
|
|
from mmdet.models.necks import (FPG, FPN, FPN_CARAFE, NASFCOS_FPN, NASFPN, |
|
YOLOXPAFPN, ChannelMapper, CTResNetNeck, |
|
DilatedEncoder, DyHead, SSDNeck, YOLOV3Neck) |
|
|
|
|
|
def test_fpn(): |
|
"""Tests fpn.""" |
|
s = 64 |
|
in_channels = [8, 16, 32, 64] |
|
feat_sizes = [s // 2**i for i in range(4)] |
|
out_channels = 8 |
|
|
|
|
|
FPN(in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=0, |
|
end_level=-1, |
|
num_outs=5) |
|
FPN(in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=0, |
|
end_level=3, |
|
num_outs=5) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
FPN(in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
end_level=2, |
|
num_outs=3) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
FPN(in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
num_outs=2) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
FPN(in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
end_level=4, |
|
num_outs=2) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
FPN(in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
end_level=3, |
|
num_outs=1) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
FPN(in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
add_extra_convs='on_xxx', |
|
num_outs=5) |
|
|
|
fpn_model = FPN( |
|
in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
add_extra_convs=True, |
|
num_outs=5) |
|
|
|
|
|
feats = [ |
|
torch.rand(1, in_channels[i], feat_sizes[i], feat_sizes[i]) |
|
for i in range(len(in_channels)) |
|
] |
|
outs = fpn_model(feats) |
|
assert fpn_model.add_extra_convs == 'on_input' |
|
assert len(outs) == fpn_model.num_outs |
|
for i in range(fpn_model.num_outs): |
|
outs[i].shape[1] == out_channels |
|
outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
fpn_model = FPN( |
|
in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
add_extra_convs=False, |
|
num_outs=5) |
|
outs = fpn_model(feats) |
|
assert len(outs) == fpn_model.num_outs |
|
assert not fpn_model.add_extra_convs |
|
for i in range(fpn_model.num_outs): |
|
outs[i].shape[1] == out_channels |
|
outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
fpn_model = FPN( |
|
in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
add_extra_convs=True, |
|
no_norm_on_lateral=False, |
|
norm_cfg=dict(type='BN', requires_grad=True), |
|
num_outs=5) |
|
outs = fpn_model(feats) |
|
assert len(outs) == fpn_model.num_outs |
|
assert fpn_model.add_extra_convs == 'on_input' |
|
for i in range(fpn_model.num_outs): |
|
outs[i].shape[1] == out_channels |
|
outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
bn_exist = False |
|
for m in fpn_model.modules(): |
|
if isinstance(m, _BatchNorm): |
|
bn_exist = True |
|
assert bn_exist |
|
|
|
|
|
fpn_model = FPN( |
|
in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
add_extra_convs=True, |
|
upsample_cfg=dict(mode='bilinear', align_corners=True), |
|
num_outs=5) |
|
fpn_model(feats) |
|
outs = fpn_model(feats) |
|
assert len(outs) == fpn_model.num_outs |
|
assert fpn_model.add_extra_convs == 'on_input' |
|
for i in range(fpn_model.num_outs): |
|
outs[i].shape[1] == out_channels |
|
outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
fpn_model = FPN( |
|
in_channels=in_channels, |
|
out_channels=out_channels, |
|
start_level=1, |
|
add_extra_convs=True, |
|
upsample_cfg=dict(scale_factor=2), |
|
num_outs=5) |
|
outs = fpn_model(feats) |
|
assert len(outs) == fpn_model.num_outs |
|
for i in range(fpn_model.num_outs): |
|
outs[i].shape[1] == out_channels |
|
outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
fpn_model = FPN( |
|
in_channels=in_channels, |
|
out_channels=out_channels, |
|
add_extra_convs='on_input', |
|
start_level=1, |
|
num_outs=5) |
|
assert fpn_model.add_extra_convs == 'on_input' |
|
outs = fpn_model(feats) |
|
assert len(outs) == fpn_model.num_outs |
|
for i in range(fpn_model.num_outs): |
|
outs[i].shape[1] == out_channels |
|
outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
fpn_model = FPN( |
|
in_channels=in_channels, |
|
out_channels=out_channels, |
|
add_extra_convs='on_lateral', |
|
start_level=1, |
|
num_outs=5) |
|
assert fpn_model.add_extra_convs == 'on_lateral' |
|
outs = fpn_model(feats) |
|
assert len(outs) == fpn_model.num_outs |
|
for i in range(fpn_model.num_outs): |
|
outs[i].shape[1] == out_channels |
|
outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
fpn_model = FPN( |
|
in_channels=in_channels, |
|
out_channels=out_channels, |
|
add_extra_convs='on_output', |
|
start_level=1, |
|
num_outs=5) |
|
assert fpn_model.add_extra_convs == 'on_output' |
|
outs = fpn_model(feats) |
|
assert len(outs) == fpn_model.num_outs |
|
for i in range(fpn_model.num_outs): |
|
outs[i].shape[1] == out_channels |
|
outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
def test_channel_mapper(): |
|
"""Tests ChannelMapper.""" |
|
s = 64 |
|
in_channels = [8, 16, 32, 64] |
|
feat_sizes = [s // 2**i for i in range(4)] |
|
out_channels = 8 |
|
kernel_size = 3 |
|
feats = [ |
|
torch.rand(1, in_channels[i], feat_sizes[i], feat_sizes[i]) |
|
for i in range(len(in_channels)) |
|
] |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
channel_mapper = ChannelMapper( |
|
in_channels=10, out_channels=out_channels, kernel_size=kernel_size) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
channel_mapper = ChannelMapper( |
|
in_channels=in_channels[:-1], |
|
out_channels=out_channels, |
|
kernel_size=kernel_size) |
|
channel_mapper(feats) |
|
|
|
channel_mapper = ChannelMapper( |
|
in_channels=in_channels, |
|
out_channels=out_channels, |
|
kernel_size=kernel_size) |
|
|
|
outs = channel_mapper(feats) |
|
assert len(outs) == len(feats) |
|
for i in range(len(feats)): |
|
outs[i].shape[1] == out_channels |
|
outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
def test_dilated_encoder(): |
|
in_channels = 16 |
|
out_channels = 32 |
|
out_shape = 34 |
|
dilated_encoder = DilatedEncoder(in_channels, out_channels, 16, 2, |
|
[2, 4, 6, 8]) |
|
feat = [torch.rand(1, in_channels, 34, 34)] |
|
out_feat = dilated_encoder(feat)[0] |
|
assert out_feat.shape == (1, out_channels, out_shape, out_shape) |
|
|
|
|
|
def test_ct_resnet_neck(): |
|
|
|
with pytest.raises(TypeError): |
|
CTResNetNeck( |
|
in_channel=10, num_deconv_filters=10, num_deconv_kernels=4) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
CTResNetNeck( |
|
in_channel=10, |
|
num_deconv_filters=(10, 10), |
|
num_deconv_kernels=(4, )) |
|
|
|
in_channels = 16 |
|
num_filters = (8, 8) |
|
num_kernels = (4, 4) |
|
feat = torch.rand(1, 16, 4, 4) |
|
ct_resnet_neck = CTResNetNeck( |
|
in_channel=in_channels, |
|
num_deconv_filters=num_filters, |
|
num_deconv_kernels=num_kernels, |
|
use_dcn=False) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
ct_resnet_neck(feat) |
|
|
|
out_feat = ct_resnet_neck([feat])[0] |
|
assert out_feat.shape == (1, num_filters[-1], 16, 16) |
|
|
|
if torch.cuda.is_available(): |
|
|
|
ct_resnet_neck = CTResNetNeck( |
|
in_channel=in_channels, |
|
num_deconv_filters=num_filters, |
|
num_deconv_kernels=num_kernels) |
|
ct_resnet_neck = ct_resnet_neck.cuda() |
|
feat = feat.cuda() |
|
out_feat = ct_resnet_neck([feat])[0] |
|
assert out_feat.shape == (1, num_filters[-1], 16, 16) |
|
|
|
|
|
def test_yolov3_neck(): |
|
|
|
with pytest.raises(AssertionError): |
|
YOLOV3Neck(num_scales=3, in_channels=[16, 8, 4], out_channels=[8, 4]) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
neck = YOLOV3Neck( |
|
num_scales=3, in_channels=[16, 8, 4], out_channels=[8, 4, 2]) |
|
feats = (torch.rand(1, 4, 16, 16), torch.rand(1, 8, 16, 16)) |
|
neck(feats) |
|
|
|
|
|
s = 32 |
|
in_channels = [16, 8, 4] |
|
out_channels = [8, 4, 2] |
|
feat_sizes = [s // 2**i for i in range(len(in_channels) - 1, -1, -1)] |
|
feats = [ |
|
torch.rand(1, in_channels[i], feat_sizes[i], feat_sizes[i]) |
|
for i in range(len(in_channels) - 1, -1, -1) |
|
] |
|
neck = YOLOV3Neck( |
|
num_scales=3, in_channels=in_channels, out_channels=out_channels) |
|
outs = neck(feats) |
|
|
|
assert len(outs) == len(feats) |
|
for i in range(len(outs)): |
|
assert outs[i].shape == \ |
|
(1, out_channels[i], feat_sizes[i], feat_sizes[i]) |
|
|
|
|
|
s = 32 |
|
in_channels = [32, 8, 16] |
|
out_channels = [19, 21, 5] |
|
feat_sizes = [s // 2**i for i in range(len(in_channels) - 1, -1, -1)] |
|
feats = [ |
|
torch.rand(1, in_channels[i], feat_sizes[i], feat_sizes[i]) |
|
for i in range(len(in_channels) - 1, -1, -1) |
|
] |
|
neck = YOLOV3Neck( |
|
num_scales=3, in_channels=in_channels, out_channels=out_channels) |
|
outs = neck(feats) |
|
|
|
assert len(outs) == len(feats) |
|
for i in range(len(outs)): |
|
assert outs[i].shape == \ |
|
(1, out_channels[i], feat_sizes[i], feat_sizes[i]) |
|
|
|
|
|
def test_ssd_neck(): |
|
|
|
with pytest.raises(AssertionError): |
|
SSDNeck( |
|
in_channels=[8, 16], |
|
out_channels=[8, 16, 32], |
|
level_strides=[2], |
|
level_paddings=[2, 1]) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
SSDNeck( |
|
in_channels=[8, 16], |
|
out_channels=[8], |
|
level_strides=[2], |
|
level_paddings=[2]) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
SSDNeck( |
|
in_channels=[8, 16], |
|
out_channels=[4, 16, 64], |
|
level_strides=[2, 2], |
|
level_paddings=[2, 2]) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
SSDNeck( |
|
in_channels=[8, 16], |
|
out_channels=[4, 16, 64], |
|
level_strides=[2], |
|
level_paddings=[2]) |
|
|
|
ssd_neck = SSDNeck( |
|
in_channels=[4], |
|
out_channels=[4, 8, 16], |
|
level_strides=[2, 1], |
|
level_paddings=[1, 0]) |
|
feats = (torch.rand(1, 4, 16, 16), ) |
|
outs = ssd_neck(feats) |
|
assert outs[0].shape == (1, 4, 16, 16) |
|
assert outs[1].shape == (1, 8, 8, 8) |
|
assert outs[2].shape == (1, 16, 6, 6) |
|
|
|
|
|
ssd_neck = SSDNeck( |
|
in_channels=[4, 8], |
|
out_channels=[4, 8, 16], |
|
level_strides=[1], |
|
level_paddings=[1], |
|
l2_norm_scale=None, |
|
use_depthwise=True, |
|
norm_cfg=dict(type='BN'), |
|
act_cfg=dict(type='ReLU6')) |
|
assert not hasattr(ssd_neck, 'l2_norm') |
|
|
|
from mmcv.cnn.bricks import DepthwiseSeparableConvModule |
|
assert isinstance(ssd_neck.extra_layers[0][-1], |
|
DepthwiseSeparableConvModule) |
|
|
|
feats = (torch.rand(1, 4, 8, 8), torch.rand(1, 8, 8, 8)) |
|
outs = ssd_neck(feats) |
|
assert outs[0].shape == (1, 4, 8, 8) |
|
assert outs[1].shape == (1, 8, 8, 8) |
|
assert outs[2].shape == (1, 16, 8, 8) |
|
|
|
|
|
def test_yolox_pafpn(): |
|
s = 64 |
|
in_channels = [8, 16, 32, 64] |
|
feat_sizes = [s // 2**i for i in range(4)] |
|
out_channels = 24 |
|
feats = [ |
|
torch.rand(1, in_channels[i], feat_sizes[i], feat_sizes[i]) |
|
for i in range(len(in_channels)) |
|
] |
|
neck = YOLOXPAFPN(in_channels=in_channels, out_channels=out_channels) |
|
outs = neck(feats) |
|
assert len(outs) == len(feats) |
|
for i in range(len(feats)): |
|
assert outs[i].shape[1] == out_channels |
|
assert outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
neck = YOLOXPAFPN( |
|
in_channels=in_channels, out_channels=out_channels, use_depthwise=True) |
|
|
|
from mmcv.cnn.bricks import DepthwiseSeparableConvModule |
|
assert isinstance(neck.downsamples[0], DepthwiseSeparableConvModule) |
|
|
|
outs = neck(feats) |
|
assert len(outs) == len(feats) |
|
for i in range(len(feats)): |
|
assert outs[i].shape[1] == out_channels |
|
assert outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
|
|
def test_dyhead(): |
|
s = 64 |
|
in_channels = 8 |
|
out_channels = 16 |
|
feat_sizes = [s // 2**i for i in range(4)] |
|
feats = [ |
|
torch.rand(1, in_channels, feat_sizes[i], feat_sizes[i]) |
|
for i in range(len(feat_sizes)) |
|
] |
|
neck = DyHead( |
|
in_channels=in_channels, out_channels=out_channels, num_blocks=3) |
|
outs = neck(feats) |
|
assert len(outs) == len(feats) |
|
for i in range(len(outs)): |
|
assert outs[i].shape[1] == out_channels |
|
assert outs[i].shape[2] == outs[i].shape[3] == s // (2**i) |
|
|
|
feat = torch.rand(1, 8, 4, 4) |
|
|
|
with pytest.raises(AssertionError): |
|
neck(feat) |
|
|
|
|
|
def test_fpg(): |
|
|
|
norm_cfg = dict(type='BN', requires_grad=True) |
|
FPG(in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
inter_channels=8, |
|
num_outs=5, |
|
add_extra_convs=True, |
|
start_level=1, |
|
end_level=-1, |
|
stack_times=9, |
|
paths=['bu'] * 9, |
|
same_down_trans=None, |
|
same_up_trans=dict( |
|
type='conv', |
|
kernel_size=3, |
|
stride=2, |
|
padding=1, |
|
norm_cfg=norm_cfg, |
|
inplace=False, |
|
order=('act', 'conv', 'norm')), |
|
across_lateral_trans=dict( |
|
type='conv', |
|
kernel_size=1, |
|
norm_cfg=norm_cfg, |
|
inplace=False, |
|
order=('act', 'conv', 'norm')), |
|
across_down_trans=dict( |
|
type='interpolation_conv', |
|
mode='nearest', |
|
kernel_size=3, |
|
norm_cfg=norm_cfg, |
|
order=('act', 'conv', 'norm'), |
|
inplace=False), |
|
across_up_trans=None, |
|
across_skip_trans=dict( |
|
type='conv', |
|
kernel_size=1, |
|
norm_cfg=norm_cfg, |
|
inplace=False, |
|
order=('act', 'conv', 'norm')), |
|
output_trans=dict( |
|
type='last_conv', |
|
kernel_size=3, |
|
order=('act', 'conv', 'norm'), |
|
inplace=False), |
|
norm_cfg=norm_cfg, |
|
skip_inds=[(0, 1, 2, 3), (0, 1, 2), (0, 1), (0, ), ()]) |
|
FPG(in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
inter_channels=8, |
|
num_outs=5, |
|
add_extra_convs=True, |
|
start_level=1, |
|
end_level=3, |
|
stack_times=9, |
|
paths=['bu'] * 9, |
|
same_down_trans=None, |
|
same_up_trans=dict( |
|
type='conv', |
|
kernel_size=3, |
|
stride=2, |
|
padding=1, |
|
norm_cfg=norm_cfg, |
|
inplace=False, |
|
order=('act', 'conv', 'norm')), |
|
across_lateral_trans=dict( |
|
type='conv', |
|
kernel_size=1, |
|
norm_cfg=norm_cfg, |
|
inplace=False, |
|
order=('act', 'conv', 'norm')), |
|
across_down_trans=dict( |
|
type='interpolation_conv', |
|
mode='nearest', |
|
kernel_size=3, |
|
norm_cfg=norm_cfg, |
|
order=('act', 'conv', 'norm'), |
|
inplace=False), |
|
across_up_trans=None, |
|
across_skip_trans=dict( |
|
type='conv', |
|
kernel_size=1, |
|
norm_cfg=norm_cfg, |
|
inplace=False, |
|
order=('act', 'conv', 'norm')), |
|
output_trans=dict( |
|
type='last_conv', |
|
kernel_size=3, |
|
order=('act', 'conv', 'norm'), |
|
inplace=False), |
|
norm_cfg=norm_cfg, |
|
skip_inds=[(0, 1, 2, 3), (0, 1, 2), (0, 1), (0, ), ()]) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
FPG(in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
stack_times=9, |
|
paths=['bu'] * 9, |
|
start_level=1, |
|
end_level=4, |
|
num_outs=2, |
|
skip_inds=[(0, 1, 2, 3), (0, 1, 2), (0, 1), (0, ), ()]) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
FPG(in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
stack_times=9, |
|
paths=['bu'] * 9, |
|
start_level=1, |
|
end_level=2, |
|
num_outs=3, |
|
skip_inds=[(0, 1, 2, 3), (0, 1, 2), (0, 1), (0, ), ()]) |
|
|
|
|
|
def test_fpn_carafe(): |
|
|
|
FPN_CARAFE( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
start_level=0, |
|
end_level=3, |
|
num_outs=4) |
|
FPN_CARAFE( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
start_level=0, |
|
end_level=-1, |
|
num_outs=4) |
|
|
|
with pytest.raises(AssertionError): |
|
FPN_CARAFE( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
start_level=1, |
|
end_level=4, |
|
num_outs=2) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
FPN_CARAFE( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
start_level=1, |
|
end_level=2, |
|
num_outs=3) |
|
|
|
|
|
def test_nas_fpn(): |
|
|
|
NASFPN( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
stack_times=9, |
|
start_level=0, |
|
end_level=3, |
|
num_outs=4) |
|
NASFPN( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
stack_times=9, |
|
start_level=0, |
|
end_level=-1, |
|
num_outs=4) |
|
|
|
with pytest.raises(AssertionError): |
|
NASFPN( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
stack_times=9, |
|
start_level=1, |
|
end_level=4, |
|
num_outs=2) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
NASFPN( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
stack_times=9, |
|
start_level=1, |
|
end_level=2, |
|
num_outs=3) |
|
|
|
|
|
def test_nasfcos_fpn(): |
|
|
|
NASFCOS_FPN( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
start_level=0, |
|
end_level=3, |
|
num_outs=4) |
|
NASFCOS_FPN( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
start_level=0, |
|
end_level=-1, |
|
num_outs=4) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
NASFCOS_FPN( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
start_level=1, |
|
end_level=4, |
|
num_outs=2) |
|
|
|
|
|
with pytest.raises(AssertionError): |
|
NASFCOS_FPN( |
|
in_channels=[8, 16, 32, 64], |
|
out_channels=8, |
|
start_level=1, |
|
end_level=2, |
|
num_outs=3) |
|
|