Commit 85529f35 authored by unknown's avatar unknown
Browse files

添加openmmlab测试用例

parent b21b0c01
import pytest
import torch
from mmcls.models.backbones import RegNet
regnet_test_data = [
('regnetx_400mf',
dict(w0=24, wa=24.48, wm=2.54, group_w=16, depth=22,
bot_mul=1.0), [32, 64, 160, 384]),
('regnetx_800mf',
dict(w0=56, wa=35.73, wm=2.28, group_w=16, depth=16,
bot_mul=1.0), [64, 128, 288, 672]),
('regnetx_1.6gf',
dict(w0=80, wa=34.01, wm=2.25, group_w=24, depth=18,
bot_mul=1.0), [72, 168, 408, 912]),
('regnetx_3.2gf',
dict(w0=88, wa=26.31, wm=2.25, group_w=48, depth=25,
bot_mul=1.0), [96, 192, 432, 1008]),
('regnetx_4.0gf',
dict(w0=96, wa=38.65, wm=2.43, group_w=40, depth=23,
bot_mul=1.0), [80, 240, 560, 1360]),
('regnetx_6.4gf',
dict(w0=184, wa=60.83, wm=2.07, group_w=56, depth=17,
bot_mul=1.0), [168, 392, 784, 1624]),
('regnetx_8.0gf',
dict(w0=80, wa=49.56, wm=2.88, group_w=120, depth=23,
bot_mul=1.0), [80, 240, 720, 1920]),
('regnetx_12gf',
dict(w0=168, wa=73.36, wm=2.37, group_w=112, depth=19,
bot_mul=1.0), [224, 448, 896, 2240]),
]
@pytest.mark.parametrize('arch_name,arch,out_channels', regnet_test_data)
def test_regnet_backbone(arch_name, arch, out_channels):
with pytest.raises(AssertionError):
# ResNeXt depth should be in [50, 101, 152]
RegNet(arch_name + '233')
# output the last feature map
model = RegNet(arch_name)
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert isinstance(feat, torch.Tensor)
assert feat.shape == (1, out_channels[-1], 7, 7)
# output feature map of all stages
model = RegNet(arch_name, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == (1, out_channels[0], 56, 56)
assert feat[1].shape == (1, out_channels[1], 28, 28)
assert feat[2].shape == (1, out_channels[2], 14, 14)
assert feat[3].shape == (1, out_channels[3], 7, 7)
@pytest.mark.parametrize('arch_name,arch,out_channels', regnet_test_data)
def test_custom_arch(arch_name, arch, out_channels):
# output the last feature map
model = RegNet(arch)
model.init_weights()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert isinstance(feat, torch.Tensor)
assert feat.shape == (1, out_channels[-1], 7, 7)
# output feature map of all stages
model = RegNet(arch, out_indices=(0, 1, 2, 3))
model.init_weights()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == (1, out_channels[0], 56, 56)
assert feat[1].shape == (1, out_channels[1], 28, 28)
assert feat[2].shape == (1, out_channels[2], 14, 14)
assert feat[3].shape == (1, out_channels[3], 7, 7)
def test_exception():
# arch must be a str or dict
with pytest.raises(TypeError):
_ = RegNet(50)
import pytest
import torch
from mmcls.models.backbones import ResNeSt
from mmcls.models.backbones.resnest import Bottleneck as BottleneckS
def test_bottleneck():
with pytest.raises(AssertionError):
# Style must be in ['pytorch', 'caffe']
BottleneckS(64, 64, radix=2, reduction_factor=4, style='tensorflow')
# Test ResNeSt Bottleneck structure
block = BottleneckS(
64, 256, radix=2, reduction_factor=4, stride=2, style='pytorch')
assert block.avd_layer.stride == 2
assert block.conv2.channels == 64
# Test ResNeSt Bottleneck forward
block = BottleneckS(64, 64, radix=2, reduction_factor=4)
x = torch.randn(2, 64, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size([2, 64, 56, 56])
def test_resnest():
with pytest.raises(KeyError):
# ResNeSt depth should be in [50, 101, 152, 200]
ResNeSt(depth=18)
# Test ResNeSt with radix 2, reduction_factor 4
model = ResNeSt(
depth=50, radix=2, reduction_factor=4, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
imgs = torch.randn(2, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size([2, 256, 56, 56])
assert feat[1].shape == torch.Size([2, 512, 28, 28])
assert feat[2].shape == torch.Size([2, 1024, 14, 14])
assert feat[3].shape == torch.Size([2, 2048, 7, 7])
import pytest
import torch
import torch.nn as nn
from mmcv.cnn import ConvModule
from mmcv.utils.parrots_wrapper import _BatchNorm
from mmcls.models.backbones import ResNet, ResNetV1d
from mmcls.models.backbones.resnet import (BasicBlock, Bottleneck, ResLayer,
get_expansion)
def is_block(modules):
"""Check if is ResNet building block."""
if isinstance(modules, (BasicBlock, Bottleneck)):
return True
return False
def all_zeros(modules):
"""Check if the weight(and bias) is all zero."""
weight_zero = torch.equal(modules.weight.data,
torch.zeros_like(modules.weight.data))
if hasattr(modules, 'bias'):
bias_zero = torch.equal(modules.bias.data,
torch.zeros_like(modules.bias.data))
else:
bias_zero = True
return weight_zero and bias_zero
def check_norm_state(modules, train_state):
"""Check if norm layer is in correct train state."""
for mod in modules:
if isinstance(mod, _BatchNorm):
if mod.training != train_state:
return False
return True
def test_get_expansion():
assert get_expansion(Bottleneck, 2) == 2
assert get_expansion(BasicBlock) == 1
assert get_expansion(Bottleneck) == 4
class MyResBlock(nn.Module):
expansion = 8
assert get_expansion(MyResBlock) == 8
# expansion must be an integer or None
with pytest.raises(TypeError):
get_expansion(Bottleneck, '0')
# expansion is not specified and cannot be inferred
with pytest.raises(TypeError):
class SomeModule(nn.Module):
pass
get_expansion(SomeModule)
def test_basic_block():
# expansion must be 1
with pytest.raises(AssertionError):
BasicBlock(64, 64, expansion=2)
# BasicBlock with stride 1, out_channels == in_channels
block = BasicBlock(64, 64)
assert block.in_channels == 64
assert block.mid_channels == 64
assert block.out_channels == 64
assert block.conv1.in_channels == 64
assert block.conv1.out_channels == 64
assert block.conv1.kernel_size == (3, 3)
assert block.conv1.stride == (1, 1)
assert block.conv2.in_channels == 64
assert block.conv2.out_channels == 64
assert block.conv2.kernel_size == (3, 3)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
# BasicBlock with stride 1 and downsample
downsample = nn.Sequential(
nn.Conv2d(64, 128, kernel_size=1, bias=False), nn.BatchNorm2d(128))
block = BasicBlock(64, 128, downsample=downsample)
assert block.in_channels == 64
assert block.mid_channels == 128
assert block.out_channels == 128
assert block.conv1.in_channels == 64
assert block.conv1.out_channels == 128
assert block.conv1.kernel_size == (3, 3)
assert block.conv1.stride == (1, 1)
assert block.conv2.in_channels == 128
assert block.conv2.out_channels == 128
assert block.conv2.kernel_size == (3, 3)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size([1, 128, 56, 56])
# BasicBlock with stride 2 and downsample
downsample = nn.Sequential(
nn.Conv2d(64, 128, kernel_size=1, stride=2, bias=False),
nn.BatchNorm2d(128))
block = BasicBlock(64, 128, stride=2, downsample=downsample)
assert block.in_channels == 64
assert block.mid_channels == 128
assert block.out_channels == 128
assert block.conv1.in_channels == 64
assert block.conv1.out_channels == 128
assert block.conv1.kernel_size == (3, 3)
assert block.conv1.stride == (2, 2)
assert block.conv2.in_channels == 128
assert block.conv2.out_channels == 128
assert block.conv2.kernel_size == (3, 3)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size([1, 128, 28, 28])
# forward with checkpointing
block = BasicBlock(64, 64, with_cp=True)
assert block.with_cp
x = torch.randn(1, 64, 56, 56, requires_grad=True)
x_out = block(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
def test_bottleneck():
# style must be in ['pytorch', 'caffe']
with pytest.raises(AssertionError):
Bottleneck(64, 64, style='tensorflow')
# expansion must be divisible by out_channels
with pytest.raises(AssertionError):
Bottleneck(64, 64, expansion=3)
# Test Bottleneck style
block = Bottleneck(64, 64, stride=2, style='pytorch')
assert block.conv1.stride == (1, 1)
assert block.conv2.stride == (2, 2)
block = Bottleneck(64, 64, stride=2, style='caffe')
assert block.conv1.stride == (2, 2)
assert block.conv2.stride == (1, 1)
# Bottleneck with stride 1
block = Bottleneck(64, 64, style='pytorch')
assert block.in_channels == 64
assert block.mid_channels == 16
assert block.out_channels == 64
assert block.conv1.in_channels == 64
assert block.conv1.out_channels == 16
assert block.conv1.kernel_size == (1, 1)
assert block.conv2.in_channels == 16
assert block.conv2.out_channels == 16
assert block.conv2.kernel_size == (3, 3)
assert block.conv3.in_channels == 16
assert block.conv3.out_channels == 64
assert block.conv3.kernel_size == (1, 1)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == (1, 64, 56, 56)
# Bottleneck with stride 1 and downsample
downsample = nn.Sequential(
nn.Conv2d(64, 128, kernel_size=1), nn.BatchNorm2d(128))
block = Bottleneck(64, 128, style='pytorch', downsample=downsample)
assert block.in_channels == 64
assert block.mid_channels == 32
assert block.out_channels == 128
assert block.conv1.in_channels == 64
assert block.conv1.out_channels == 32
assert block.conv1.kernel_size == (1, 1)
assert block.conv2.in_channels == 32
assert block.conv2.out_channels == 32
assert block.conv2.kernel_size == (3, 3)
assert block.conv3.in_channels == 32
assert block.conv3.out_channels == 128
assert block.conv3.kernel_size == (1, 1)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == (1, 128, 56, 56)
# Bottleneck with stride 2 and downsample
downsample = nn.Sequential(
nn.Conv2d(64, 128, kernel_size=1, stride=2), nn.BatchNorm2d(128))
block = Bottleneck(
64, 128, stride=2, style='pytorch', downsample=downsample)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == (1, 128, 28, 28)
# Bottleneck with expansion 2
block = Bottleneck(64, 64, style='pytorch', expansion=2)
assert block.in_channels == 64
assert block.mid_channels == 32
assert block.out_channels == 64
assert block.conv1.in_channels == 64
assert block.conv1.out_channels == 32
assert block.conv1.kernel_size == (1, 1)
assert block.conv2.in_channels == 32
assert block.conv2.out_channels == 32
assert block.conv2.kernel_size == (3, 3)
assert block.conv3.in_channels == 32
assert block.conv3.out_channels == 64
assert block.conv3.kernel_size == (1, 1)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == (1, 64, 56, 56)
# Test Bottleneck with checkpointing
block = Bottleneck(64, 64, with_cp=True)
block.train()
assert block.with_cp
x = torch.randn(1, 64, 56, 56, requires_grad=True)
x_out = block(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
def test_basicblock_reslayer():
# 3 BasicBlock w/o downsample
layer = ResLayer(BasicBlock, 3, 32, 32)
assert len(layer) == 3
for i in range(3):
assert layer[i].in_channels == 32
assert layer[i].out_channels == 32
assert layer[i].downsample is None
x = torch.randn(1, 32, 56, 56)
x_out = layer(x)
assert x_out.shape == (1, 32, 56, 56)
# 3 BasicBlock w/ stride 1 and downsample
layer = ResLayer(BasicBlock, 3, 32, 64)
assert len(layer) == 3
assert layer[0].in_channels == 32
assert layer[0].out_channels == 64
assert layer[0].downsample is not None and len(layer[0].downsample) == 2
assert isinstance(layer[0].downsample[0], nn.Conv2d)
assert layer[0].downsample[0].stride == (1, 1)
for i in range(1, 3):
assert layer[i].in_channels == 64
assert layer[i].out_channels == 64
assert layer[i].downsample is None
x = torch.randn(1, 32, 56, 56)
x_out = layer(x)
assert x_out.shape == (1, 64, 56, 56)
# 3 BasicBlock w/ stride 2 and downsample
layer = ResLayer(BasicBlock, 3, 32, 64, stride=2)
assert len(layer) == 3
assert layer[0].in_channels == 32
assert layer[0].out_channels == 64
assert layer[0].stride == 2
assert layer[0].downsample is not None and len(layer[0].downsample) == 2
assert isinstance(layer[0].downsample[0], nn.Conv2d)
assert layer[0].downsample[0].stride == (2, 2)
for i in range(1, 3):
assert layer[i].in_channels == 64
assert layer[i].out_channels == 64
assert layer[i].stride == 1
assert layer[i].downsample is None
x = torch.randn(1, 32, 56, 56)
x_out = layer(x)
assert x_out.shape == (1, 64, 28, 28)
# 3 BasicBlock w/ stride 2 and downsample with avg pool
layer = ResLayer(BasicBlock, 3, 32, 64, stride=2, avg_down=True)
assert len(layer) == 3
assert layer[0].in_channels == 32
assert layer[0].out_channels == 64
assert layer[0].stride == 2
assert layer[0].downsample is not None and len(layer[0].downsample) == 3
assert isinstance(layer[0].downsample[0], nn.AvgPool2d)
assert layer[0].downsample[0].stride == 2
for i in range(1, 3):
assert layer[i].in_channels == 64
assert layer[i].out_channels == 64
assert layer[i].stride == 1
assert layer[i].downsample is None
x = torch.randn(1, 32, 56, 56)
x_out = layer(x)
assert x_out.shape == (1, 64, 28, 28)
def test_bottleneck_reslayer():
# 3 Bottleneck w/o downsample
layer = ResLayer(Bottleneck, 3, 32, 32)
assert len(layer) == 3
for i in range(3):
assert layer[i].in_channels == 32
assert layer[i].out_channels == 32
assert layer[i].downsample is None
x = torch.randn(1, 32, 56, 56)
x_out = layer(x)
assert x_out.shape == (1, 32, 56, 56)
# 3 Bottleneck w/ stride 1 and downsample
layer = ResLayer(Bottleneck, 3, 32, 64)
assert len(layer) == 3
assert layer[0].in_channels == 32
assert layer[0].out_channels == 64
assert layer[0].stride == 1
assert layer[0].conv1.out_channels == 16
assert layer[0].downsample is not None and len(layer[0].downsample) == 2
assert isinstance(layer[0].downsample[0], nn.Conv2d)
assert layer[0].downsample[0].stride == (1, 1)
for i in range(1, 3):
assert layer[i].in_channels == 64
assert layer[i].out_channels == 64
assert layer[i].conv1.out_channels == 16
assert layer[i].stride == 1
assert layer[i].downsample is None
x = torch.randn(1, 32, 56, 56)
x_out = layer(x)
assert x_out.shape == (1, 64, 56, 56)
# 3 Bottleneck w/ stride 2 and downsample
layer = ResLayer(Bottleneck, 3, 32, 64, stride=2)
assert len(layer) == 3
assert layer[0].in_channels == 32
assert layer[0].out_channels == 64
assert layer[0].stride == 2
assert layer[0].conv1.out_channels == 16
assert layer[0].downsample is not None and len(layer[0].downsample) == 2
assert isinstance(layer[0].downsample[0], nn.Conv2d)
assert layer[0].downsample[0].stride == (2, 2)
for i in range(1, 3):
assert layer[i].in_channels == 64
assert layer[i].out_channels == 64
assert layer[i].conv1.out_channels == 16
assert layer[i].stride == 1
assert layer[i].downsample is None
x = torch.randn(1, 32, 56, 56)
x_out = layer(x)
assert x_out.shape == (1, 64, 28, 28)
# 3 Bottleneck w/ stride 2 and downsample with avg pool
layer = ResLayer(Bottleneck, 3, 32, 64, stride=2, avg_down=True)
assert len(layer) == 3
assert layer[0].in_channels == 32
assert layer[0].out_channels == 64
assert layer[0].stride == 2
assert layer[0].conv1.out_channels == 16
assert layer[0].downsample is not None and len(layer[0].downsample) == 3
assert isinstance(layer[0].downsample[0], nn.AvgPool2d)
assert layer[0].downsample[0].stride == 2
for i in range(1, 3):
assert layer[i].in_channels == 64
assert layer[i].out_channels == 64
assert layer[i].conv1.out_channels == 16
assert layer[i].stride == 1
assert layer[i].downsample is None
x = torch.randn(1, 32, 56, 56)
x_out = layer(x)
assert x_out.shape == (1, 64, 28, 28)
# 3 Bottleneck with custom expansion
layer = ResLayer(Bottleneck, 3, 32, 32, expansion=2)
assert len(layer) == 3
for i in range(3):
assert layer[i].in_channels == 32
assert layer[i].out_channels == 32
assert layer[i].stride == 1
assert layer[i].conv1.out_channels == 16
assert layer[i].downsample is None
x = torch.randn(1, 32, 56, 56)
x_out = layer(x)
assert x_out.shape == (1, 32, 56, 56)
def test_resnet():
"""Test resnet backbone."""
with pytest.raises(KeyError):
# ResNet depth should be in [18, 34, 50, 101, 152]
ResNet(20)
with pytest.raises(AssertionError):
# In ResNet: 1 <= num_stages <= 4
ResNet(50, num_stages=0)
with pytest.raises(AssertionError):
# In ResNet: 1 <= num_stages <= 4
ResNet(50, num_stages=5)
with pytest.raises(AssertionError):
# len(strides) == len(dilations) == num_stages
ResNet(50, strides=(1, ), dilations=(1, 1), num_stages=3)
with pytest.raises(TypeError):
# pretrained must be a string path
model = ResNet(50)
model.init_weights(pretrained=0)
with pytest.raises(AssertionError):
# Style must be in ['pytorch', 'caffe']
ResNet(50, style='tensorflow')
# Test ResNet50 norm_eval=True
model = ResNet(50, norm_eval=True)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), False)
# Test ResNet50 with torchvision pretrained weight
model = ResNet(
depth=50,
norm_eval=True,
init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'))
model.init_weights()
model.train()
assert check_norm_state(model.modules(), False)
# Test ResNet50 with first stage frozen
frozen_stages = 1
model = ResNet(50, frozen_stages=frozen_stages)
model.init_weights()
model.train()
assert model.norm1.training is False
for layer in [model.conv1, model.norm1]:
for param in layer.parameters():
assert param.requires_grad is False
for i in range(1, frozen_stages + 1):
layer = getattr(model, f'layer{i}')
for mod in layer.modules():
if isinstance(mod, _BatchNorm):
assert mod.training is False
for param in layer.parameters():
assert param.requires_grad is False
# Test ResNet18 forward
model = ResNet(18, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == (1, 64, 56, 56)
assert feat[1].shape == (1, 128, 28, 28)
assert feat[2].shape == (1, 256, 14, 14)
assert feat[3].shape == (1, 512, 7, 7)
# Test ResNet50 with BatchNorm forward
model = ResNet(50, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == (1, 256, 56, 56)
assert feat[1].shape == (1, 512, 28, 28)
assert feat[2].shape == (1, 1024, 14, 14)
assert feat[3].shape == (1, 2048, 7, 7)
# Test ResNet50 with layers 1, 2, 3 out forward
model = ResNet(50, out_indices=(0, 1, 2))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 3
assert feat[0].shape == (1, 256, 56, 56)
assert feat[1].shape == (1, 512, 28, 28)
assert feat[2].shape == (1, 1024, 14, 14)
# Test ResNet50 with layers 3 (top feature maps) out forward
model = ResNet(50, out_indices=(3, ))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == (1, 2048, 7, 7)
# Test ResNet50 with checkpoint forward
model = ResNet(50, out_indices=(0, 1, 2, 3), with_cp=True)
for m in model.modules():
if is_block(m):
assert m.with_cp
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == (1, 256, 56, 56)
assert feat[1].shape == (1, 512, 28, 28)
assert feat[2].shape == (1, 1024, 14, 14)
assert feat[3].shape == (1, 2048, 7, 7)
# zero initialization of residual blocks
model = ResNet(50, out_indices=(0, 1, 2, 3), zero_init_residual=True)
model.init_weights()
for m in model.modules():
if isinstance(m, Bottleneck):
assert all_zeros(m.norm3)
elif isinstance(m, BasicBlock):
assert all_zeros(m.norm2)
# non-zero initialization of residual blocks
model = ResNet(50, out_indices=(0, 1, 2, 3), zero_init_residual=False)
model.init_weights()
for m in model.modules():
if isinstance(m, Bottleneck):
assert not all_zeros(m.norm3)
elif isinstance(m, BasicBlock):
assert not all_zeros(m.norm2)
def test_resnet_v1d():
model = ResNetV1d(depth=50, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
assert len(model.stem) == 3
for i in range(3):
assert isinstance(model.stem[i], ConvModule)
imgs = torch.randn(1, 3, 224, 224)
feat = model.stem(imgs)
assert feat.shape == (1, 64, 112, 112)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == (1, 256, 56, 56)
assert feat[1].shape == (1, 512, 28, 28)
assert feat[2].shape == (1, 1024, 14, 14)
assert feat[3].shape == (1, 2048, 7, 7)
# Test ResNet50V1d with first stage frozen
frozen_stages = 1
model = ResNetV1d(depth=50, frozen_stages=frozen_stages)
assert len(model.stem) == 3
for i in range(3):
assert isinstance(model.stem[i], ConvModule)
model.init_weights()
model.train()
check_norm_state(model.stem, False)
for param in model.stem.parameters():
assert param.requires_grad is False
for i in range(1, frozen_stages + 1):
layer = getattr(model, f'layer{i}')
for mod in layer.modules():
if isinstance(mod, _BatchNorm):
assert mod.training is False
for param in layer.parameters():
assert param.requires_grad is False
def test_resnet_half_channel():
model = ResNet(50, base_channels=32, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == (1, 128, 56, 56)
assert feat[1].shape == (1, 256, 28, 28)
assert feat[2].shape == (1, 512, 14, 14)
assert feat[3].shape == (1, 1024, 7, 7)
import pytest
import torch
from mmcv.utils.parrots_wrapper import _BatchNorm
from mmcls.models.backbones import ResNet_CIFAR
def check_norm_state(modules, train_state):
"""Check if norm layer is in correct train state."""
for mod in modules:
if isinstance(mod, _BatchNorm):
if mod.training != train_state:
return False
return True
def test_resnet_cifar():
# deep_stem must be False
with pytest.raises(AssertionError):
ResNet_CIFAR(depth=18, deep_stem=True)
# test the feature map size when depth is 18
model = ResNet_CIFAR(depth=18, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 32, 32)
feat = model.conv1(imgs)
assert feat.shape == (1, 64, 32, 32)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == (1, 64, 32, 32)
assert feat[1].shape == (1, 128, 16, 16)
assert feat[2].shape == (1, 256, 8, 8)
assert feat[3].shape == (1, 512, 4, 4)
# test the feature map size when depth is 50
model = ResNet_CIFAR(depth=50, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 32, 32)
feat = model.conv1(imgs)
assert feat.shape == (1, 64, 32, 32)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == (1, 256, 32, 32)
assert feat[1].shape == (1, 512, 16, 16)
assert feat[2].shape == (1, 1024, 8, 8)
assert feat[3].shape == (1, 2048, 4, 4)
# Test ResNet_CIFAR with first stage frozen
frozen_stages = 1
model = ResNet_CIFAR(depth=50, frozen_stages=frozen_stages)
model.init_weights()
model.train()
check_norm_state([model.norm1], False)
for param in model.conv1.parameters():
assert param.requires_grad is False
for i in range(1, frozen_stages + 1):
layer = getattr(model, f'layer{i}')
for mod in layer.modules():
if isinstance(mod, _BatchNorm):
assert mod.training is False
for param in layer.parameters():
assert param.requires_grad is False
import pytest
import torch
from mmcls.models.backbones import ResNeXt
from mmcls.models.backbones.resnext import Bottleneck as BottleneckX
def test_bottleneck():
with pytest.raises(AssertionError):
# Style must be in ['pytorch', 'caffe']
BottleneckX(64, 64, groups=32, width_per_group=4, style='tensorflow')
# Test ResNeXt Bottleneck structure
block = BottleneckX(
64, 256, groups=32, width_per_group=4, stride=2, style='pytorch')
assert block.conv2.stride == (2, 2)
assert block.conv2.groups == 32
assert block.conv2.out_channels == 128
# Test ResNeXt Bottleneck forward
block = BottleneckX(64, 64, base_channels=16, groups=32, width_per_group=4)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
def test_resnext():
with pytest.raises(KeyError):
# ResNeXt depth should be in [50, 101, 152]
ResNeXt(depth=18)
# Test ResNeXt with group 32, width_per_group 4
model = ResNeXt(
depth=50, groups=32, width_per_group=4, out_indices=(0, 1, 2, 3))
for m in model.modules():
if isinstance(m, BottleneckX):
assert m.conv2.groups == 32
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size([1, 256, 56, 56])
assert feat[1].shape == torch.Size([1, 512, 28, 28])
assert feat[2].shape == torch.Size([1, 1024, 14, 14])
assert feat[3].shape == torch.Size([1, 2048, 7, 7])
# Test ResNeXt with group 32, width_per_group 4 and layers 3 out forward
model = ResNeXt(depth=50, groups=32, width_per_group=4, out_indices=(3, ))
for m in model.modules():
if isinstance(m, BottleneckX):
assert m.conv2.groups == 32
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == torch.Size([1, 2048, 7, 7])
import pytest
import torch
from torch.nn.modules import AvgPool2d
from torch.nn.modules.batchnorm import _BatchNorm
from mmcls.models.backbones import SEResNet
from mmcls.models.backbones.resnet import ResLayer
from mmcls.models.backbones.seresnet import SEBottleneck, SELayer
def all_zeros(modules):
"""Check if the weight(and bias) is all zero."""
weight_zero = torch.equal(modules.weight.data,
torch.zeros_like(modules.weight.data))
if hasattr(modules, 'bias'):
bias_zero = torch.equal(modules.bias.data,
torch.zeros_like(modules.bias.data))
else:
bias_zero = True
return weight_zero and bias_zero
def check_norm_state(modules, train_state):
"""Check if norm layer is in correct train state."""
for mod in modules:
if isinstance(mod, _BatchNorm):
if mod.training != train_state:
return False
return True
def test_selayer():
# Test selayer forward
layer = SELayer(64)
x = torch.randn(1, 64, 56, 56)
x_out = layer(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
# Test selayer forward with different ratio
layer = SELayer(64, ratio=8)
x = torch.randn(1, 64, 56, 56)
x_out = layer(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
def test_bottleneck():
with pytest.raises(AssertionError):
# Style must be in ['pytorch', 'caffe']
SEBottleneck(64, 64, style='tensorflow')
# Test SEBottleneck with checkpoint forward
block = SEBottleneck(64, 64, with_cp=True)
assert block.with_cp
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
# Test Bottleneck style
block = SEBottleneck(64, 256, stride=2, style='pytorch')
assert block.conv1.stride == (1, 1)
assert block.conv2.stride == (2, 2)
block = SEBottleneck(64, 256, stride=2, style='caffe')
assert block.conv1.stride == (2, 2)
assert block.conv2.stride == (1, 1)
# Test Bottleneck forward
block = SEBottleneck(64, 64)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
def test_res_layer():
# Test ResLayer of 3 Bottleneck w\o downsample
layer = ResLayer(SEBottleneck, 3, 64, 64, se_ratio=16)
assert len(layer) == 3
assert layer[0].conv1.in_channels == 64
assert layer[0].conv1.out_channels == 16
for i in range(1, len(layer)):
assert layer[i].conv1.in_channels == 64
assert layer[i].conv1.out_channels == 16
for i in range(len(layer)):
assert layer[i].downsample is None
x = torch.randn(1, 64, 56, 56)
x_out = layer(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
# Test ResLayer of 3 SEBottleneck with downsample
layer = ResLayer(SEBottleneck, 3, 64, 256, se_ratio=16)
assert layer[0].downsample[0].out_channels == 256
for i in range(1, len(layer)):
assert layer[i].downsample is None
x = torch.randn(1, 64, 56, 56)
x_out = layer(x)
assert x_out.shape == torch.Size([1, 256, 56, 56])
# Test ResLayer of 3 SEBottleneck with stride=2
layer = ResLayer(SEBottleneck, 3, 64, 256, stride=2, se_ratio=8)
assert layer[0].downsample[0].out_channels == 256
assert layer[0].downsample[0].stride == (2, 2)
for i in range(1, len(layer)):
assert layer[i].downsample is None
x = torch.randn(1, 64, 56, 56)
x_out = layer(x)
assert x_out.shape == torch.Size([1, 256, 28, 28])
# Test ResLayer of 3 SEBottleneck with stride=2 and average downsample
layer = ResLayer(
SEBottleneck, 3, 64, 256, stride=2, avg_down=True, se_ratio=8)
assert isinstance(layer[0].downsample[0], AvgPool2d)
assert layer[0].downsample[1].out_channels == 256
assert layer[0].downsample[1].stride == (1, 1)
for i in range(1, len(layer)):
assert layer[i].downsample is None
x = torch.randn(1, 64, 56, 56)
x_out = layer(x)
assert x_out.shape == torch.Size([1, 256, 28, 28])
def test_seresnet():
"""Test resnet backbone."""
with pytest.raises(KeyError):
# SEResNet depth should be in [50, 101, 152]
SEResNet(20)
with pytest.raises(AssertionError):
# In SEResNet: 1 <= num_stages <= 4
SEResNet(50, num_stages=0)
with pytest.raises(AssertionError):
# In SEResNet: 1 <= num_stages <= 4
SEResNet(50, num_stages=5)
with pytest.raises(AssertionError):
# len(strides) == len(dilations) == num_stages
SEResNet(50, strides=(1, ), dilations=(1, 1), num_stages=3)
with pytest.raises(TypeError):
# pretrained must be a string path
model = SEResNet(50)
model.init_weights(pretrained=0)
with pytest.raises(AssertionError):
# Style must be in ['pytorch', 'caffe']
SEResNet(50, style='tensorflow')
# Test SEResNet50 norm_eval=True
model = SEResNet(50, norm_eval=True)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), False)
# Test SEResNet50 with torchvision pretrained weight
model = SEResNet(
depth=50,
norm_eval=True,
init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'))
model.init_weights()
model.train()
assert check_norm_state(model.modules(), False)
# Test SEResNet50 with first stage frozen
frozen_stages = 1
model = SEResNet(50, frozen_stages=frozen_stages)
model.init_weights()
model.train()
assert model.norm1.training is False
for layer in [model.conv1, model.norm1]:
for param in layer.parameters():
assert param.requires_grad is False
for i in range(1, frozen_stages + 1):
layer = getattr(model, f'layer{i}')
for mod in layer.modules():
if isinstance(mod, _BatchNorm):
assert mod.training is False
for param in layer.parameters():
assert param.requires_grad is False
# Test SEResNet50 with BatchNorm forward
model = SEResNet(50, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size([1, 256, 56, 56])
assert feat[1].shape == torch.Size([1, 512, 28, 28])
assert feat[2].shape == torch.Size([1, 1024, 14, 14])
assert feat[3].shape == torch.Size([1, 2048, 7, 7])
# Test SEResNet50 with layers 1, 2, 3 out forward
model = SEResNet(50, out_indices=(0, 1, 2))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 3
assert feat[0].shape == torch.Size([1, 256, 56, 56])
assert feat[1].shape == torch.Size([1, 512, 28, 28])
assert feat[2].shape == torch.Size([1, 1024, 14, 14])
# Test SEResNet50 with layers 3 (top feature maps) out forward
model = SEResNet(50, out_indices=(3, ))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == torch.Size([1, 2048, 7, 7])
# Test SEResNet50 with checkpoint forward
model = SEResNet(50, out_indices=(0, 1, 2, 3), with_cp=True)
for m in model.modules():
if isinstance(m, SEBottleneck):
assert m.with_cp
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size([1, 256, 56, 56])
assert feat[1].shape == torch.Size([1, 512, 28, 28])
assert feat[2].shape == torch.Size([1, 1024, 14, 14])
assert feat[3].shape == torch.Size([1, 2048, 7, 7])
# Test SEResNet50 zero initialization of residual
model = SEResNet(50, out_indices=(0, 1, 2, 3), zero_init_residual=True)
model.init_weights()
for m in model.modules():
if isinstance(m, SEBottleneck):
assert all_zeros(m.norm3)
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size([1, 256, 56, 56])
assert feat[1].shape == torch.Size([1, 512, 28, 28])
assert feat[2].shape == torch.Size([1, 1024, 14, 14])
assert feat[3].shape == torch.Size([1, 2048, 7, 7])
import pytest
import torch
from mmcls.models.backbones import SEResNeXt
from mmcls.models.backbones.seresnext import SEBottleneck as SEBottleneckX
def test_bottleneck():
with pytest.raises(AssertionError):
# Style must be in ['pytorch', 'caffe']
SEBottleneckX(64, 64, groups=32, width_per_group=4, style='tensorflow')
# Test SEResNeXt Bottleneck structure
block = SEBottleneckX(
64, 256, groups=32, width_per_group=4, stride=2, style='pytorch')
assert block.width_per_group == 4
assert block.conv2.stride == (2, 2)
assert block.conv2.groups == 32
assert block.conv2.out_channels == 128
assert block.conv2.out_channels == block.mid_channels
# Test SEResNeXt Bottleneck structure (groups=1)
block = SEBottleneckX(
64, 256, groups=1, width_per_group=4, stride=2, style='pytorch')
assert block.conv2.stride == (2, 2)
assert block.conv2.groups == 1
assert block.conv2.out_channels == 64
assert block.mid_channels == 64
assert block.conv2.out_channels == block.mid_channels
# Test SEResNeXt Bottleneck forward
block = SEBottleneckX(
64, 64, base_channels=16, groups=32, width_per_group=4)
x = torch.randn(1, 64, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size([1, 64, 56, 56])
def test_seresnext():
with pytest.raises(KeyError):
# SEResNeXt depth should be in [50, 101, 152]
SEResNeXt(depth=18)
# Test SEResNeXt with group 32, width_per_group 4
model = SEResNeXt(
depth=50, groups=32, width_per_group=4, out_indices=(0, 1, 2, 3))
for m in model.modules():
if isinstance(m, SEBottleneckX):
assert m.conv2.groups == 32
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size([1, 256, 56, 56])
assert feat[1].shape == torch.Size([1, 512, 28, 28])
assert feat[2].shape == torch.Size([1, 1024, 14, 14])
assert feat[3].shape == torch.Size([1, 2048, 7, 7])
# Test SEResNeXt with group 32, width_per_group 4 and layers 3 out forward
model = SEResNeXt(
depth=50, groups=32, width_per_group=4, out_indices=(3, ))
for m in model.modules():
if isinstance(m, SEBottleneckX):
assert m.conv2.groups == 32
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == torch.Size([1, 2048, 7, 7])
import pytest
import torch
from torch.nn.modules import GroupNorm
from torch.nn.modules.batchnorm import _BatchNorm
from mmcls.models.backbones import ShuffleNetV1
from mmcls.models.backbones.shufflenet_v1 import ShuffleUnit
def is_block(modules):
"""Check if is ResNet building block."""
if isinstance(modules, (ShuffleUnit, )):
return True
return False
def is_norm(modules):
"""Check if is one of the norms."""
if isinstance(modules, (GroupNorm, _BatchNorm)):
return True
return False
def check_norm_state(modules, train_state):
"""Check if norm layer is in correct train state."""
for mod in modules:
if isinstance(mod, _BatchNorm):
if mod.training != train_state:
return False
return True
def test_shufflenetv1_shuffleuint():
with pytest.raises(ValueError):
# combine must be in ['add', 'concat']
ShuffleUnit(24, 16, groups=3, first_block=True, combine='test')
with pytest.raises(AssertionError):
# in_channels must be equal tp = outplanes when combine='add'
ShuffleUnit(64, 24, groups=4, first_block=True, combine='add')
# Test ShuffleUnit with combine='add'
block = ShuffleUnit(24, 24, groups=3, first_block=True, combine='add')
x = torch.randn(1, 24, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size((1, 24, 56, 56))
# Test ShuffleUnit with combine='concat'
block = ShuffleUnit(24, 240, groups=3, first_block=True, combine='concat')
x = torch.randn(1, 24, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size((1, 240, 28, 28))
# Test ShuffleUnit with checkpoint forward
block = ShuffleUnit(
24, 24, groups=3, first_block=True, combine='add', with_cp=True)
assert block.with_cp
x = torch.randn(1, 24, 56, 56)
x.requires_grad = True
x_out = block(x)
assert x_out.shape == torch.Size((1, 24, 56, 56))
def test_shufflenetv1_backbone():
with pytest.raises(ValueError):
# frozen_stages must be in range(-1, 4)
ShuffleNetV1(frozen_stages=10)
with pytest.raises(ValueError):
# the item in out_indices must be in range(0, 4)
ShuffleNetV1(out_indices=[5])
with pytest.raises(ValueError):
# groups must be in [1, 2, 3, 4, 8]
ShuffleNetV1(groups=10)
with pytest.raises(TypeError):
# pretrained must be str or None
model = ShuffleNetV1()
model.init_weights(pretrained=1)
# Test ShuffleNetV1 norm state
model = ShuffleNetV1()
model.init_weights()
model.train()
assert check_norm_state(model.modules(), True)
# Test ShuffleNetV1 with first stage frozen
frozen_stages = 1
model = ShuffleNetV1(frozen_stages=frozen_stages, out_indices=(0, 1, 2))
model.init_weights()
model.train()
for param in model.conv1.parameters():
assert param.requires_grad is False
for i in range(frozen_stages):
layer = model.layers[i]
for mod in layer.modules():
if isinstance(mod, _BatchNorm):
assert mod.training is False
for param in layer.parameters():
assert param.requires_grad is False
# Test ShuffleNetV1 forward with groups=1
model = ShuffleNetV1(groups=1, out_indices=(0, 1, 2))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 3
assert feat[0].shape == torch.Size((1, 144, 28, 28))
assert feat[1].shape == torch.Size((1, 288, 14, 14))
assert feat[2].shape == torch.Size((1, 576, 7, 7))
# Test ShuffleNetV1 forward with groups=2
model = ShuffleNetV1(groups=2, out_indices=(0, 1, 2))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 3
assert feat[0].shape == torch.Size((1, 200, 28, 28))
assert feat[1].shape == torch.Size((1, 400, 14, 14))
assert feat[2].shape == torch.Size((1, 800, 7, 7))
# Test ShuffleNetV1 forward with groups=3
model = ShuffleNetV1(groups=3, out_indices=(0, 1, 2))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 3
assert feat[0].shape == torch.Size((1, 240, 28, 28))
assert feat[1].shape == torch.Size((1, 480, 14, 14))
assert feat[2].shape == torch.Size((1, 960, 7, 7))
# Test ShuffleNetV1 forward with groups=4
model = ShuffleNetV1(groups=4, out_indices=(0, 1, 2))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 3
assert feat[0].shape == torch.Size((1, 272, 28, 28))
assert feat[1].shape == torch.Size((1, 544, 14, 14))
assert feat[2].shape == torch.Size((1, 1088, 7, 7))
# Test ShuffleNetV1 forward with groups=8
model = ShuffleNetV1(groups=8, out_indices=(0, 1, 2))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 3
assert feat[0].shape == torch.Size((1, 384, 28, 28))
assert feat[1].shape == torch.Size((1, 768, 14, 14))
assert feat[2].shape == torch.Size((1, 1536, 7, 7))
# Test ShuffleNetV1 forward with GroupNorm forward
model = ShuffleNetV1(
groups=3,
norm_cfg=dict(type='GN', num_groups=2, requires_grad=True),
out_indices=(0, 1, 2))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, GroupNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 3
assert feat[0].shape == torch.Size((1, 240, 28, 28))
assert feat[1].shape == torch.Size((1, 480, 14, 14))
assert feat[2].shape == torch.Size((1, 960, 7, 7))
# Test ShuffleNetV1 forward with layers 1, 2 forward
model = ShuffleNetV1(groups=3, out_indices=(1, 2))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 2
assert feat[0].shape == torch.Size((1, 480, 14, 14))
assert feat[1].shape == torch.Size((1, 960, 7, 7))
# Test ShuffleNetV1 forward with layers 2 forward
model = ShuffleNetV1(groups=3, out_indices=(2, ))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert isinstance(feat, torch.Tensor)
assert feat.shape == torch.Size((1, 960, 7, 7))
# Test ShuffleNetV1 forward with checkpoint forward
model = ShuffleNetV1(groups=3, with_cp=True)
for m in model.modules():
if is_block(m):
assert m.with_cp
# Test ShuffleNetV1 with norm_eval
model = ShuffleNetV1(norm_eval=True)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), False)
import pytest
import torch
from torch.nn.modules import GroupNorm
from torch.nn.modules.batchnorm import _BatchNorm
from mmcls.models.backbones import ShuffleNetV2
from mmcls.models.backbones.shufflenet_v2 import InvertedResidual
def is_block(modules):
"""Check if is ResNet building block."""
if isinstance(modules, (InvertedResidual, )):
return True
return False
def is_norm(modules):
"""Check if is one of the norms."""
if isinstance(modules, (GroupNorm, _BatchNorm)):
return True
return False
def check_norm_state(modules, train_state):
"""Check if norm layer is in correct train state."""
for mod in modules:
if isinstance(mod, _BatchNorm):
if mod.training != train_state:
return False
return True
def test_shufflenetv2_invertedresidual():
with pytest.raises(AssertionError):
# when stride==1, in_channels should be equal to out_channels // 2 * 2
InvertedResidual(24, 32, stride=1)
with pytest.raises(AssertionError):
# when in_channels != out_channels // 2 * 2, stride should not be
# equal to 1.
InvertedResidual(24, 32, stride=1)
# Test InvertedResidual forward
block = InvertedResidual(24, 48, stride=2)
x = torch.randn(1, 24, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size((1, 48, 28, 28))
# Test InvertedResidual with checkpoint forward
block = InvertedResidual(48, 48, stride=1, with_cp=True)
assert block.with_cp
x = torch.randn(1, 48, 56, 56)
x.requires_grad = True
x_out = block(x)
assert x_out.shape == torch.Size((1, 48, 56, 56))
def test_shufflenetv2_backbone():
with pytest.raises(ValueError):
# groups must be in 0.5, 1.0, 1.5, 2.0]
ShuffleNetV2(widen_factor=3.0)
with pytest.raises(ValueError):
# frozen_stages must be in [0, 1, 2, 3]
ShuffleNetV2(widen_factor=1.0, frozen_stages=4)
with pytest.raises(ValueError):
# out_indices must be in [0, 1, 2, 3]
ShuffleNetV2(widen_factor=1.0, out_indices=(4, ))
with pytest.raises(TypeError):
# pretrained must be str or None
model = ShuffleNetV2()
model.init_weights(pretrained=1)
# Test ShuffleNetV2 norm state
model = ShuffleNetV2()
model.init_weights()
model.train()
assert check_norm_state(model.modules(), True)
# Test ShuffleNetV2 with first stage frozen
frozen_stages = 1
model = ShuffleNetV2(frozen_stages=frozen_stages)
model.init_weights()
model.train()
for param in model.conv1.parameters():
assert param.requires_grad is False
for i in range(0, frozen_stages):
layer = model.layers[i]
for mod in layer.modules():
if isinstance(mod, _BatchNorm):
assert mod.training is False
for param in layer.parameters():
assert param.requires_grad is False
# Test ShuffleNetV2 with norm_eval
model = ShuffleNetV2(norm_eval=True)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), False)
# Test ShuffleNetV2 forward with widen_factor=0.5
model = ShuffleNetV2(widen_factor=0.5, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size((1, 48, 28, 28))
assert feat[1].shape == torch.Size((1, 96, 14, 14))
assert feat[2].shape == torch.Size((1, 192, 7, 7))
# Test ShuffleNetV2 forward with widen_factor=1.0
model = ShuffleNetV2(widen_factor=1.0, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size((1, 116, 28, 28))
assert feat[1].shape == torch.Size((1, 232, 14, 14))
assert feat[2].shape == torch.Size((1, 464, 7, 7))
# Test ShuffleNetV2 forward with widen_factor=1.5
model = ShuffleNetV2(widen_factor=1.5, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size((1, 176, 28, 28))
assert feat[1].shape == torch.Size((1, 352, 14, 14))
assert feat[2].shape == torch.Size((1, 704, 7, 7))
# Test ShuffleNetV2 forward with widen_factor=2.0
model = ShuffleNetV2(widen_factor=2.0, out_indices=(0, 1, 2, 3))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size((1, 244, 28, 28))
assert feat[1].shape == torch.Size((1, 488, 14, 14))
assert feat[2].shape == torch.Size((1, 976, 7, 7))
# Test ShuffleNetV2 forward with layers 3 forward
model = ShuffleNetV2(widen_factor=1.0, out_indices=(2, ))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert isinstance(feat, torch.Tensor)
assert feat.shape == torch.Size((1, 464, 7, 7))
# Test ShuffleNetV2 forward with layers 1 2 forward
model = ShuffleNetV2(widen_factor=1.0, out_indices=(1, 2))
model.init_weights()
model.train()
for m in model.modules():
if is_norm(m):
assert isinstance(m, _BatchNorm)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 2
assert feat[0].shape == torch.Size((1, 232, 14, 14))
assert feat[1].shape == torch.Size((1, 464, 7, 7))
# Test ShuffleNetV2 forward with checkpoint forward
model = ShuffleNetV2(widen_factor=1.0, with_cp=True)
for m in model.modules():
if is_block(m):
assert m.with_cp
import pytest
import torch
from torch.nn.modules import GroupNorm
from torch.nn.modules.batchnorm import _BatchNorm
from mmcls.models.utils import (Augments, InvertedResidual, SELayer,
channel_shuffle, make_divisible)
def is_norm(modules):
"""Check if is one of the norms."""
if isinstance(modules, (GroupNorm, _BatchNorm)):
return True
return False
def test_make_divisible():
# test min_value is None
result = make_divisible(34, 8, None)
assert result == 32
# test when new_value > min_ratio * value
result = make_divisible(10, 8, min_ratio=0.9)
assert result == 16
# test min_value = 0.8
result = make_divisible(33, 8, min_ratio=0.8)
assert result == 32
def test_channel_shuffle():
x = torch.randn(1, 24, 56, 56)
with pytest.raises(AssertionError):
# num_channels should be divisible by groups
channel_shuffle(x, 7)
groups = 3
batch_size, num_channels, height, width = x.size()
channels_per_group = num_channels // groups
out = channel_shuffle(x, groups)
# test the output value when groups = 3
for b in range(batch_size):
for c in range(num_channels):
c_out = c % channels_per_group * groups + c // channels_per_group
for i in range(height):
for j in range(width):
assert x[b, c, i, j] == out[b, c_out, i, j]
def test_inverted_residual():
with pytest.raises(AssertionError):
# stride must be in [1, 2]
InvertedResidual(16, 16, 32, stride=3)
with pytest.raises(AssertionError):
# se_cfg must be None or dict
InvertedResidual(16, 16, 32, se_cfg=list())
with pytest.raises(AssertionError):
# in_channeld and out_channels must be the same if
# with_expand_conv is False
InvertedResidual(16, 16, 32, with_expand_conv=False)
# Test InvertedResidual forward, stride=1
block = InvertedResidual(16, 16, 32, stride=1)
x = torch.randn(1, 16, 56, 56)
x_out = block(x)
assert getattr(block, 'se', None) is None
assert block.with_res_shortcut
assert x_out.shape == torch.Size((1, 16, 56, 56))
# Test InvertedResidual forward, stride=2
block = InvertedResidual(16, 16, 32, stride=2)
x = torch.randn(1, 16, 56, 56)
x_out = block(x)
assert not block.with_res_shortcut
assert x_out.shape == torch.Size((1, 16, 28, 28))
# Test InvertedResidual forward with se layer
se_cfg = dict(channels=32)
block = InvertedResidual(16, 16, 32, stride=1, se_cfg=se_cfg)
x = torch.randn(1, 16, 56, 56)
x_out = block(x)
assert isinstance(block.se, SELayer)
assert x_out.shape == torch.Size((1, 16, 56, 56))
# Test InvertedResidual forward, with_expand_conv=False
block = InvertedResidual(32, 16, 32, with_expand_conv=False)
x = torch.randn(1, 32, 56, 56)
x_out = block(x)
assert getattr(block, 'expand_conv', None) is None
assert x_out.shape == torch.Size((1, 16, 56, 56))
# Test InvertedResidual forward with GroupNorm
block = InvertedResidual(
16, 16, 32, norm_cfg=dict(type='GN', num_groups=2))
x = torch.randn(1, 16, 56, 56)
x_out = block(x)
for m in block.modules():
if is_norm(m):
assert isinstance(m, GroupNorm)
assert x_out.shape == torch.Size((1, 16, 56, 56))
# Test InvertedResidual forward with HSigmoid
block = InvertedResidual(16, 16, 32, act_cfg=dict(type='HSigmoid'))
x = torch.randn(1, 16, 56, 56)
x_out = block(x)
assert x_out.shape == torch.Size((1, 16, 56, 56))
# Test InvertedResidual forward with checkpoint
block = InvertedResidual(16, 16, 32, with_cp=True)
x = torch.randn(1, 16, 56, 56)
x_out = block(x)
assert block.with_cp
assert x_out.shape == torch.Size((1, 16, 56, 56))
def test_augments():
imgs = torch.randn(4, 3, 32, 32)
labels = torch.randint(0, 10, (4, ))
# Test cutmix
augments_cfg = dict(type='BatchCutMix', alpha=1., num_classes=10, prob=1.)
augs = Augments(augments_cfg)
mixed_imgs, mixed_labels = augs(imgs, labels)
assert mixed_imgs.shape == torch.Size((4, 3, 32, 32))
assert mixed_labels.shape == torch.Size((4, 10))
# Test mixup
augments_cfg = dict(type='BatchMixup', alpha=1., num_classes=10, prob=1.)
augs = Augments(augments_cfg)
mixed_imgs, mixed_labels = augs(imgs, labels)
assert mixed_imgs.shape == torch.Size((4, 3, 32, 32))
assert mixed_labels.shape == torch.Size((4, 10))
# Test cutmixup
augments_cfg = [
dict(type='BatchCutMix', alpha=1., num_classes=10, prob=0.5),
dict(type='BatchMixup', alpha=1., num_classes=10, prob=0.3)
]
augs = Augments(augments_cfg)
mixed_imgs, mixed_labels = augs(imgs, labels)
assert mixed_imgs.shape == torch.Size((4, 3, 32, 32))
assert mixed_labels.shape == torch.Size((4, 10))
augments_cfg = [
dict(type='BatchCutMix', alpha=1., num_classes=10, prob=0.5),
dict(type='BatchMixup', alpha=1., num_classes=10, prob=0.5)
]
augs = Augments(augments_cfg)
mixed_imgs, mixed_labels = augs(imgs, labels)
assert mixed_imgs.shape == torch.Size((4, 3, 32, 32))
assert mixed_labels.shape == torch.Size((4, 10))
augments_cfg = [
dict(type='BatchCutMix', alpha=1., num_classes=10, prob=0.5),
dict(type='BatchMixup', alpha=1., num_classes=10, prob=0.3),
dict(type='Identity', num_classes=10, prob=0.2)
]
augs = Augments(augments_cfg)
mixed_imgs, mixed_labels = augs(imgs, labels)
assert mixed_imgs.shape == torch.Size((4, 3, 32, 32))
assert mixed_labels.shape == torch.Size((4, 10))
import pytest
import torch
from mmcv.utils.parrots_wrapper import _BatchNorm
from mmcls.models.backbones import VGG
def check_norm_state(modules, train_state):
"""Check if norm layer is in correct train state."""
for mod in modules:
if isinstance(mod, _BatchNorm):
if mod.training != train_state:
return False
return True
def test_vgg():
"""Test VGG backbone."""
with pytest.raises(KeyError):
# VGG depth should be in [11, 13, 16, 19]
VGG(18)
with pytest.raises(AssertionError):
# In VGG: 1 <= num_stages <= 5
VGG(11, num_stages=0)
with pytest.raises(AssertionError):
# In VGG: 1 <= num_stages <= 5
VGG(11, num_stages=6)
with pytest.raises(AssertionError):
# len(dilations) == num_stages
VGG(11, dilations=(1, 1), num_stages=3)
with pytest.raises(TypeError):
# pretrained must be a string path
model = VGG(11)
model.init_weights(pretrained=0)
# Test VGG11 norm_eval=True
model = VGG(11, norm_eval=True)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), False)
# Test VGG11 forward without classifiers
model = VGG(11, out_indices=(0, 1, 2, 3, 4))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 5
assert feat[0].shape == (1, 64, 112, 112)
assert feat[1].shape == (1, 128, 56, 56)
assert feat[2].shape == (1, 256, 28, 28)
assert feat[3].shape == (1, 512, 14, 14)
assert feat[4].shape == (1, 512, 7, 7)
# Test VGG11 forward with classifiers
model = VGG(11, num_classes=10, out_indices=(0, 1, 2, 3, 4, 5))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 6
assert feat[0].shape == (1, 64, 112, 112)
assert feat[1].shape == (1, 128, 56, 56)
assert feat[2].shape == (1, 256, 28, 28)
assert feat[3].shape == (1, 512, 14, 14)
assert feat[4].shape == (1, 512, 7, 7)
assert feat[5].shape == (1, 10)
# Test VGG11BN forward
model = VGG(11, norm_cfg=dict(type='BN'), out_indices=(0, 1, 2, 3, 4))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 5
assert feat[0].shape == (1, 64, 112, 112)
assert feat[1].shape == (1, 128, 56, 56)
assert feat[2].shape == (1, 256, 28, 28)
assert feat[3].shape == (1, 512, 14, 14)
assert feat[4].shape == (1, 512, 7, 7)
# Test VGG11BN forward with classifiers
model = VGG(
11,
num_classes=10,
norm_cfg=dict(type='BN'),
out_indices=(0, 1, 2, 3, 4, 5))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 6
assert feat[0].shape == (1, 64, 112, 112)
assert feat[1].shape == (1, 128, 56, 56)
assert feat[2].shape == (1, 256, 28, 28)
assert feat[3].shape == (1, 512, 14, 14)
assert feat[4].shape == (1, 512, 7, 7)
assert feat[5].shape == (1, 10)
# Test VGG13 with layers 1, 2, 3 out forward
model = VGG(13, out_indices=(0, 1, 2))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 3
assert feat[0].shape == (1, 64, 112, 112)
assert feat[1].shape == (1, 128, 56, 56)
assert feat[2].shape == (1, 256, 28, 28)
# Test VGG16 with top feature maps out forward
model = VGG(16)
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == (1, 512, 7, 7)
# Test VGG19 with classification score out forward
model = VGG(19, num_classes=10)
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == (1, 10)
import pytest
import torch
from torch.nn.modules import GroupNorm
from torch.nn.modules.batchnorm import _BatchNorm
from mmcls.models.backbones import VGG, VisionTransformer
def is_norm(modules):
"""Check if is one of the norms."""
if isinstance(modules, (GroupNorm, _BatchNorm)):
return True
return False
def check_norm_state(modules, train_state):
"""Check if norm layer is in correct train state."""
for mod in modules:
if isinstance(mod, _BatchNorm):
if mod.training != train_state:
return False
return True
def test_vit_backbone():
with pytest.raises(TypeError):
# pretrained must be a string path
model = VisionTransformer()
model.init_weights(pretrained=0)
# Test ViT base model with input size of 224
# and patch size of 16
model = VisionTransformer()
model.init_weights()
model.train()
assert check_norm_state(model.modules(), True)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == torch.Size((1, 768))
def test_vit_hybrid_backbone():
# Test VGG11+ViT-B/16 hybrid model
backbone = VGG(11, norm_eval=True)
backbone.init_weights()
model = VisionTransformer(hybrid_backbone=backbone)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), True)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == torch.Size((1, 768))
import torch
from mmcls.models.classifiers import ImageClassifier
def test_image_classifier():
# Test mixup in ImageClassifier
model_cfg = dict(
backbone=dict(
type='ResNet_CIFAR',
depth=50,
num_stages=4,
out_indices=(3, ),
style='pytorch'),
neck=dict(type='GlobalAveragePooling'),
head=dict(
type='MultiLabelLinearClsHead',
num_classes=10,
in_channels=2048,
loss=dict(type='CrossEntropyLoss', loss_weight=1.0,
use_soft=True)),
train_cfg=dict(
augments=dict(
type='BatchMixup', alpha=1., num_classes=10, prob=1.)))
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
imgs = torch.randn(16, 3, 32, 32)
label = torch.randint(0, 10, (16, ))
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
# Considering BC-breaking
model_cfg['train_cfg'] = dict(mixup=dict(alpha=1.0, num_classes=10))
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
imgs = torch.randn(16, 3, 32, 32)
label = torch.randint(0, 10, (16, ))
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
def test_image_classifier_with_cutmix():
# Test cutmix in ImageClassifier
model_cfg = dict(
backbone=dict(
type='ResNet_CIFAR',
depth=50,
num_stages=4,
out_indices=(3, ),
style='pytorch'),
neck=dict(type='GlobalAveragePooling'),
head=dict(
type='MultiLabelLinearClsHead',
num_classes=10,
in_channels=2048,
loss=dict(type='CrossEntropyLoss', loss_weight=1.0,
use_soft=True)),
train_cfg=dict(
augments=dict(
type='BatchCutMix', alpha=1., num_classes=10, prob=1.)))
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
imgs = torch.randn(16, 3, 32, 32)
label = torch.randint(0, 10, (16, ))
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
# Considering BC-breaking
model_cfg['train_cfg'] = dict(
cutmix=dict(alpha=1.0, num_classes=10, cutmix_prob=1.0))
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
imgs = torch.randn(16, 3, 32, 32)
label = torch.randint(0, 10, (16, ))
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
def test_image_classifier_with_augments():
imgs = torch.randn(16, 3, 32, 32)
label = torch.randint(0, 10, (16, ))
# Test cutmix and mixup in ImageClassifier
model_cfg = dict(
backbone=dict(
type='ResNet_CIFAR',
depth=50,
num_stages=4,
out_indices=(3, ),
style='pytorch'),
neck=dict(type='GlobalAveragePooling'),
head=dict(
type='MultiLabelLinearClsHead',
num_classes=10,
in_channels=2048,
loss=dict(type='CrossEntropyLoss', loss_weight=1.0,
use_soft=True)),
train_cfg=dict(augments=[
dict(type='BatchCutMix', alpha=1., num_classes=10, prob=0.5),
dict(type='BatchMixup', alpha=1., num_classes=10, prob=0.3),
dict(type='Identity', num_classes=10, prob=0.2)
]))
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
# Test cutmix with cutmix_minmax in ImageClassifier
model_cfg['train_cfg'] = dict(
augments=dict(
type='BatchCutMix',
alpha=1.,
num_classes=10,
prob=1.,
cutmix_minmax=[0.2, 0.8]))
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
# Test not using cutmix and mixup in ImageClassifier
model_cfg = dict(
backbone=dict(
type='ResNet_CIFAR',
depth=50,
num_stages=4,
out_indices=(3, ),
style='pytorch'),
neck=dict(type='GlobalAveragePooling'),
head=dict(
type='LinearClsHead',
num_classes=10,
in_channels=2048,
loss=dict(type='CrossEntropyLoss', loss_weight=1.0)))
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
imgs = torch.randn(16, 3, 32, 32)
label = torch.randint(0, 10, (16, ))
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
# Test not using cutmix and mixup in ImageClassifier
model_cfg['train_cfg'] = dict(augments=None)
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
def test_image_classifier_with_label_smooth_loss():
# Test mixup in ImageClassifier
model_cfg = dict(
backbone=dict(
type='ResNet_CIFAR',
depth=50,
num_stages=4,
out_indices=(3, ),
style='pytorch'),
neck=dict(type='GlobalAveragePooling'),
head=dict(
type='MultiLabelLinearClsHead',
num_classes=10,
in_channels=2048,
loss=dict(type='LabelSmoothLoss', label_smooth_val=0.1)),
train_cfg=dict(
augments=dict(
type='BatchMixup', alpha=1., num_classes=10, prob=1.)))
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
imgs = torch.randn(16, 3, 32, 32)
label = torch.randint(0, 10, (16, ))
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
def test_image_classifier_vit():
model_cfg = dict(
backbone=dict(
type='VisionTransformer',
num_layers=12,
embed_dim=768,
num_heads=12,
img_size=224,
patch_size=16,
in_channels=3,
feedforward_channels=3072,
drop_rate=0.1,
attn_drop_rate=0.),
neck=None,
head=dict(
type='VisionTransformerClsHead',
num_classes=1000,
in_channels=768,
hidden_dim=3072,
loss=dict(type='CrossEntropyLoss', loss_weight=1.0, use_soft=True),
topk=(1, 5),
),
train_cfg=dict(
augments=dict(
type='BatchMixup', alpha=0.2, num_classes=1000, prob=1.)))
img_classifier = ImageClassifier(**model_cfg)
img_classifier.init_weights()
imgs = torch.randn(2, 3, 224, 224)
label = torch.randint(0, 1000, (2, ))
losses = img_classifier.forward_train(imgs, label)
assert losses['loss'].item() > 0
import bisect
import math
import random
import string
import tempfile
from collections import defaultdict
from unittest.mock import MagicMock, patch
import numpy as np
import pytest
import torch
from mmcls.datasets import (DATASETS, BaseDataset, ClassBalancedDataset,
ConcatDataset, MultiLabelDataset, RepeatDataset)
from mmcls.datasets.utils import check_integrity, rm_suffix
@pytest.mark.parametrize(
'dataset_name',
['MNIST', 'FashionMNIST', 'CIFAR10', 'CIFAR100', 'ImageNet', 'VOC'])
def test_datasets_override_default(dataset_name):
dataset_class = DATASETS.get(dataset_name)
dataset_class.load_annotations = MagicMock()
original_classes = dataset_class.CLASSES
# Test VOC year
if dataset_name == 'VOC':
dataset = dataset_class(
data_prefix='VOC2007',
pipeline=[],
classes=('bus', 'car'),
test_mode=True)
assert dataset.year == 2007
with pytest.raises(ValueError):
dataset = dataset_class(
data_prefix='VOC',
pipeline=[],
classes=('bus', 'car'),
test_mode=True)
# Test setting classes as a tuple
dataset = dataset_class(
data_prefix='VOC2007' if dataset_name == 'VOC' else '',
pipeline=[],
classes=('bus', 'car'),
test_mode=True)
assert dataset.CLASSES != original_classes
assert dataset.CLASSES == ('bus', 'car')
# Test setting classes as a list
dataset = dataset_class(
data_prefix='VOC2007' if dataset_name == 'VOC' else '',
pipeline=[],
classes=['bus', 'car'],
test_mode=True)
assert dataset.CLASSES != original_classes
assert dataset.CLASSES == ['bus', 'car']
# Test setting classes through a file
tmp_file = tempfile.NamedTemporaryFile()
with open(tmp_file.name, 'w') as f:
f.write('bus\ncar\n')
dataset = dataset_class(
data_prefix='VOC2007' if dataset_name == 'VOC' else '',
pipeline=[],
classes=tmp_file.name,
test_mode=True)
tmp_file.close()
assert dataset.CLASSES != original_classes
assert dataset.CLASSES == ['bus', 'car']
# Test overriding not a subset
dataset = dataset_class(
data_prefix='VOC2007' if dataset_name == 'VOC' else '',
pipeline=[],
classes=['foo'],
test_mode=True)
assert dataset.CLASSES != original_classes
assert dataset.CLASSES == ['foo']
# Test default behavior
dataset = dataset_class(
data_prefix='VOC2007' if dataset_name == 'VOC' else '', pipeline=[])
if dataset_name == 'VOC':
assert dataset.data_prefix == 'VOC2007'
else:
assert dataset.data_prefix == ''
assert not dataset.test_mode
assert dataset.ann_file is None
assert dataset.CLASSES == original_classes
@patch.multiple(MultiLabelDataset, __abstractmethods__=set())
@patch.multiple(BaseDataset, __abstractmethods__=set())
def test_dataset_evaluation():
# test multi-class single-label evaluation
dataset = BaseDataset(data_prefix='', pipeline=[], test_mode=True)
dataset.data_infos = [
dict(gt_label=0),
dict(gt_label=0),
dict(gt_label=1),
dict(gt_label=2),
dict(gt_label=1),
dict(gt_label=0)
]
fake_results = np.array([[0.7, 0, 0.3], [0.5, 0.2, 0.3], [0.4, 0.5, 0.1],
[0, 0, 1], [0, 0, 1], [0, 0, 1]])
eval_results = dataset.evaluate(
fake_results,
metric=['precision', 'recall', 'f1_score', 'support', 'accuracy'],
metric_options={'topk': 1})
assert eval_results['precision'] == pytest.approx(
(1 + 1 + 1 / 3) / 3 * 100.0)
assert eval_results['recall'] == pytest.approx(
(2 / 3 + 1 / 2 + 1) / 3 * 100.0)
assert eval_results['f1_score'] == pytest.approx(
(4 / 5 + 2 / 3 + 1 / 2) / 3 * 100.0)
assert eval_results['support'] == 6
assert eval_results['accuracy'] == pytest.approx(4 / 6 * 100)
# test input as tensor
fake_results_tensor = torch.from_numpy(fake_results)
eval_results_ = dataset.evaluate(
fake_results_tensor,
metric=['precision', 'recall', 'f1_score', 'support', 'accuracy'],
metric_options={'topk': 1})
assert eval_results_ == eval_results
# test thr
eval_results = dataset.evaluate(
fake_results,
metric=['precision', 'recall', 'f1_score', 'accuracy'],
metric_options={
'thrs': 0.6,
'topk': 1
})
assert eval_results['precision'] == pytest.approx(
(1 + 0 + 1 / 3) / 3 * 100.0)
assert eval_results['recall'] == pytest.approx((1 / 3 + 0 + 1) / 3 * 100.0)
assert eval_results['f1_score'] == pytest.approx(
(1 / 2 + 0 + 1 / 2) / 3 * 100.0)
assert eval_results['accuracy'] == pytest.approx(2 / 6 * 100)
# thrs must be a float, tuple or None
with pytest.raises(TypeError):
eval_results = dataset.evaluate(
fake_results,
metric=['precision', 'recall', 'f1_score', 'accuracy'],
metric_options={
'thrs': 'thr',
'topk': 1
})
# test topk and thr as tuple
eval_results = dataset.evaluate(
fake_results,
metric=['precision', 'recall', 'f1_score', 'accuracy'],
metric_options={
'thrs': (0.5, 0.6),
'topk': (1, 2)
})
assert {
'precision_thr_0.50', 'precision_thr_0.60', 'recall_thr_0.50',
'recall_thr_0.60', 'f1_score_thr_0.50', 'f1_score_thr_0.60',
'accuracy_top-1_thr_0.50', 'accuracy_top-1_thr_0.60',
'accuracy_top-2_thr_0.50', 'accuracy_top-2_thr_0.60'
} == eval_results.keys()
assert type(eval_results['precision_thr_0.50']) == float
assert type(eval_results['recall_thr_0.50']) == float
assert type(eval_results['f1_score_thr_0.50']) == float
assert type(eval_results['accuracy_top-1_thr_0.50']) == float
eval_results = dataset.evaluate(
fake_results,
metric='accuracy',
metric_options={
'thrs': 0.5,
'topk': (1, 2)
})
assert {'accuracy_top-1', 'accuracy_top-2'} == eval_results.keys()
assert type(eval_results['accuracy_top-1']) == float
eval_results = dataset.evaluate(
fake_results,
metric='accuracy',
metric_options={
'thrs': (0.5, 0.6),
'topk': 1
})
assert {'accuracy_thr_0.50', 'accuracy_thr_0.60'} == eval_results.keys()
assert type(eval_results['accuracy_thr_0.50']) == float
# test evaluation results for classes
eval_results = dataset.evaluate(
fake_results,
metric=['precision', 'recall', 'f1_score', 'support'],
metric_options={'average_mode': 'none'})
assert eval_results['precision'].shape == (3, )
assert eval_results['recall'].shape == (3, )
assert eval_results['f1_score'].shape == (3, )
assert eval_results['support'].shape == (3, )
# the average_mode method must be valid
with pytest.raises(ValueError):
eval_results = dataset.evaluate(
fake_results,
metric='precision',
metric_options={'average_mode': 'micro'})
with pytest.raises(ValueError):
eval_results = dataset.evaluate(
fake_results,
metric='recall',
metric_options={'average_mode': 'micro'})
with pytest.raises(ValueError):
eval_results = dataset.evaluate(
fake_results,
metric='f1_score',
metric_options={'average_mode': 'micro'})
with pytest.raises(ValueError):
eval_results = dataset.evaluate(
fake_results,
metric='support',
metric_options={'average_mode': 'micro'})
# the metric must be valid for the dataset
with pytest.raises(ValueError):
eval_results = dataset.evaluate(fake_results, metric='map')
# test multi-label evalutation
dataset = MultiLabelDataset(data_prefix='', pipeline=[], test_mode=True)
dataset.data_infos = [
dict(gt_label=[1, 1, 0, -1]),
dict(gt_label=[1, 1, 0, -1]),
dict(gt_label=[0, -1, 1, -1]),
dict(gt_label=[0, 1, 0, -1]),
dict(gt_label=[0, 1, 0, -1]),
]
fake_results = np.array([[0.9, 0.8, 0.3, 0.2], [0.1, 0.2, 0.2, 0.1],
[0.7, 0.5, 0.9, 0.3], [0.8, 0.1, 0.1, 0.2],
[0.8, 0.1, 0.1, 0.2]])
# the metric must be valid
with pytest.raises(ValueError):
metric = 'coverage'
dataset.evaluate(fake_results, metric=metric)
# only one metric
metric = 'mAP'
eval_results = dataset.evaluate(fake_results, metric=metric)
assert 'mAP' in eval_results.keys()
assert 'CP' not in eval_results.keys()
# multiple metrics
metric = ['mAP', 'CR', 'OF1']
eval_results = dataset.evaluate(fake_results, metric=metric)
assert 'mAP' in eval_results.keys()
assert 'CR' in eval_results.keys()
assert 'OF1' in eval_results.keys()
assert 'CF1' not in eval_results.keys()
@patch.multiple(BaseDataset, __abstractmethods__=set())
def test_dataset_wrapper():
BaseDataset.CLASSES = ('foo', 'bar')
BaseDataset.__getitem__ = MagicMock(side_effect=lambda idx: idx)
dataset_a = BaseDataset(data_prefix='', pipeline=[], test_mode=True)
len_a = 10
cat_ids_list_a = [
np.random.randint(0, 80, num).tolist()
for num in np.random.randint(1, 20, len_a)
]
dataset_a.data_infos = MagicMock()
dataset_a.data_infos.__len__.return_value = len_a
dataset_a.get_cat_ids = MagicMock(
side_effect=lambda idx: cat_ids_list_a[idx])
dataset_b = BaseDataset(data_prefix='', pipeline=[], test_mode=True)
len_b = 20
cat_ids_list_b = [
np.random.randint(0, 80, num).tolist()
for num in np.random.randint(1, 20, len_b)
]
dataset_b.data_infos = MagicMock()
dataset_b.data_infos.__len__.return_value = len_b
dataset_b.get_cat_ids = MagicMock(
side_effect=lambda idx: cat_ids_list_b[idx])
concat_dataset = ConcatDataset([dataset_a, dataset_b])
assert concat_dataset[5] == 5
assert concat_dataset[25] == 15
assert concat_dataset.get_cat_ids(5) == cat_ids_list_a[5]
assert concat_dataset.get_cat_ids(25) == cat_ids_list_b[15]
assert len(concat_dataset) == len(dataset_a) + len(dataset_b)
assert concat_dataset.CLASSES == BaseDataset.CLASSES
repeat_dataset = RepeatDataset(dataset_a, 10)
assert repeat_dataset[5] == 5
assert repeat_dataset[15] == 5
assert repeat_dataset[27] == 7
assert repeat_dataset.get_cat_ids(5) == cat_ids_list_a[5]
assert repeat_dataset.get_cat_ids(15) == cat_ids_list_a[5]
assert repeat_dataset.get_cat_ids(27) == cat_ids_list_a[7]
assert len(repeat_dataset) == 10 * len(dataset_a)
assert repeat_dataset.CLASSES == BaseDataset.CLASSES
category_freq = defaultdict(int)
for cat_ids in cat_ids_list_a:
cat_ids = set(cat_ids)
for cat_id in cat_ids:
category_freq[cat_id] += 1
for k, v in category_freq.items():
category_freq[k] = v / len(cat_ids_list_a)
mean_freq = np.mean(list(category_freq.values()))
repeat_thr = mean_freq
category_repeat = {
cat_id: max(1.0, math.sqrt(repeat_thr / cat_freq))
for cat_id, cat_freq in category_freq.items()
}
repeat_factors = []
for cat_ids in cat_ids_list_a:
cat_ids = set(cat_ids)
repeat_factor = max({category_repeat[cat_id] for cat_id in cat_ids})
repeat_factors.append(math.ceil(repeat_factor))
repeat_factors_cumsum = np.cumsum(repeat_factors)
repeat_factor_dataset = ClassBalancedDataset(dataset_a, repeat_thr)
assert repeat_factor_dataset.CLASSES == BaseDataset.CLASSES
assert len(repeat_factor_dataset) == repeat_factors_cumsum[-1]
for idx in np.random.randint(0, len(repeat_factor_dataset), 3):
assert repeat_factor_dataset[idx] == bisect.bisect_right(
repeat_factors_cumsum, idx)
def test_dataset_utils():
# test rm_suffix
assert rm_suffix('a.jpg') == 'a'
assert rm_suffix('a.bak.jpg') == 'a.bak'
assert rm_suffix('a.bak.jpg', suffix='.jpg') == 'a.bak'
assert rm_suffix('a.bak.jpg', suffix='.bak.jpg') == 'a'
# test check_integrity
rand_file = ''.join(random.sample(string.ascii_letters, 10))
assert not check_integrity(rand_file, md5=None)
assert not check_integrity(rand_file, md5=2333)
tmp_file = tempfile.NamedTemporaryFile()
assert check_integrity(tmp_file.name, md5=None)
assert not check_integrity(tmp_file.name, md5=2333)
import logging
import tempfile
import warnings
from unittest.mock import MagicMock, patch
import mmcv.runner
import pytest
import torch
import torch.nn as nn
from mmcv.runner import obj_from_dict
from torch.utils.data import DataLoader, Dataset
from mmcls.apis import single_gpu_test
# TODO import eval hooks from mmcv and delete them from mmcls
try:
from mmcv.runner.hooks import EvalHook, DistEvalHook
use_mmcv_hook = True
except ImportError:
warnings.warn('DeprecationWarning: EvalHook and DistEvalHook from mmcls '
'will be deprecated.'
'Please install mmcv through master branch.')
from mmcls.core import EvalHook, DistEvalHook
use_mmcv_hook = False
class ExampleDataset(Dataset):
def __getitem__(self, idx):
results = dict(img=torch.tensor([1]), img_metas=dict())
return results
def __len__(self):
return 1
class ExampleModel(nn.Module):
def __init__(self):
super(ExampleModel, self).__init__()
self.test_cfg = None
self.conv = nn.Conv2d(3, 3, 3)
def forward(self, img, img_metas, test_mode=False, **kwargs):
return img
def train_step(self, data_batch, optimizer):
loss = self.forward(**data_batch)
return dict(loss=loss)
def test_iter_eval_hook():
with pytest.raises(TypeError):
test_dataset = ExampleModel()
data_loader = [
DataLoader(
test_dataset,
batch_size=1,
sampler=None,
num_worker=0,
shuffle=False)
]
EvalHook(data_loader, by_epoch=False)
test_dataset = ExampleDataset()
test_dataset.evaluate = MagicMock(return_value=dict(test='success'))
loader = DataLoader(test_dataset, batch_size=1)
model = ExampleModel()
data_loader = DataLoader(
test_dataset, batch_size=1, sampler=None, num_workers=0, shuffle=False)
optim_cfg = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005)
optimizer = obj_from_dict(optim_cfg, torch.optim,
dict(params=model.parameters()))
# test EvalHook
with tempfile.TemporaryDirectory() as tmpdir:
eval_hook = EvalHook(data_loader, by_epoch=False)
runner = mmcv.runner.IterBasedRunner(
model=model,
optimizer=optimizer,
work_dir=tmpdir,
logger=logging.getLogger(),
max_iters=1)
runner.register_hook(eval_hook)
runner.run([loader], [('train', 1)], 1)
test_dataset.evaluate.assert_called_with([torch.tensor([1])],
logger=runner.logger)
def test_epoch_eval_hook():
with pytest.raises(TypeError):
test_dataset = ExampleModel()
data_loader = [
DataLoader(
test_dataset,
batch_size=1,
sampler=None,
num_worker=0,
shuffle=False)
]
EvalHook(data_loader, by_epoch=True)
test_dataset = ExampleDataset()
test_dataset.evaluate = MagicMock(return_value=dict(test='success'))
loader = DataLoader(test_dataset, batch_size=1)
model = ExampleModel()
data_loader = DataLoader(
test_dataset, batch_size=1, sampler=None, num_workers=0, shuffle=False)
optim_cfg = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005)
optimizer = obj_from_dict(optim_cfg, torch.optim,
dict(params=model.parameters()))
# test EvalHook with interval
with tempfile.TemporaryDirectory() as tmpdir:
eval_hook = EvalHook(data_loader, by_epoch=True, interval=2)
runner = mmcv.runner.EpochBasedRunner(
model=model,
optimizer=optimizer,
work_dir=tmpdir,
logger=logging.getLogger(),
max_epochs=2)
runner.register_hook(eval_hook)
runner.run([loader], [('train', 1)])
test_dataset.evaluate.assert_called_once_with([torch.tensor([1])],
logger=runner.logger)
def multi_gpu_test(model, data_loader, tmpdir=None, gpu_collect=False):
results = single_gpu_test(model, data_loader)
return results
@patch('mmcls.apis.multi_gpu_test', multi_gpu_test)
def test_dist_eval_hook():
with pytest.raises(TypeError):
test_dataset = ExampleModel()
data_loader = [
DataLoader(
test_dataset,
batch_size=1,
sampler=None,
num_worker=0,
shuffle=False)
]
DistEvalHook(data_loader, by_epoch=False)
test_dataset = ExampleDataset()
test_dataset.evaluate = MagicMock(return_value=dict(test='success'))
loader = DataLoader(test_dataset, batch_size=1)
model = ExampleModel()
data_loader = DataLoader(
test_dataset, batch_size=1, sampler=None, num_workers=0, shuffle=False)
optim_cfg = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005)
optimizer = obj_from_dict(optim_cfg, torch.optim,
dict(params=model.parameters()))
# test DistEvalHook
with tempfile.TemporaryDirectory() as tmpdir:
if use_mmcv_hook:
p = patch('mmcv.engine.multi_gpu_test', multi_gpu_test)
p.start()
eval_hook = DistEvalHook(data_loader, by_epoch=False)
runner = mmcv.runner.IterBasedRunner(
model=model,
optimizer=optimizer,
work_dir=tmpdir,
logger=logging.getLogger(),
max_iters=1)
runner.register_hook(eval_hook)
runner.run([loader], [('train', 1)])
test_dataset.evaluate.assert_called_with([torch.tensor([1])],
logger=runner.logger)
if use_mmcv_hook:
p.stop()
@patch('mmcls.apis.multi_gpu_test', multi_gpu_test)
def test_dist_eval_hook_epoch():
with pytest.raises(TypeError):
test_dataset = ExampleModel()
data_loader = [
DataLoader(
test_dataset,
batch_size=1,
sampler=None,
num_worker=0,
shuffle=False)
]
DistEvalHook(data_loader)
test_dataset = ExampleDataset()
test_dataset.evaluate = MagicMock(return_value=dict(test='success'))
loader = DataLoader(test_dataset, batch_size=1)
model = ExampleModel()
data_loader = DataLoader(
test_dataset, batch_size=1, sampler=None, num_workers=0, shuffle=False)
optim_cfg = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005)
optimizer = obj_from_dict(optim_cfg, torch.optim,
dict(params=model.parameters()))
# test DistEvalHook
with tempfile.TemporaryDirectory() as tmpdir:
if use_mmcv_hook:
p = patch('mmcv.engine.multi_gpu_test', multi_gpu_test)
p.start()
eval_hook = DistEvalHook(data_loader, by_epoch=True, interval=2)
runner = mmcv.runner.EpochBasedRunner(
model=model,
optimizer=optimizer,
work_dir=tmpdir,
logger=logging.getLogger(),
max_epochs=2)
runner.register_hook(eval_hook)
runner.run([loader], [('train', 1)])
test_dataset.evaluate.assert_called_with([torch.tensor([1])],
logger=runner.logger)
if use_mmcv_hook:
p.stop()
import torch
from mmcls.models.heads import (ClsHead, LinearClsHead, MultiLabelClsHead,
MultiLabelLinearClsHead)
def test_cls_head():
# test ClsHead with cal_acc=False
head = ClsHead()
fake_cls_score = torch.rand(4, 3)
fake_gt_label = torch.randint(0, 2, (4, ))
losses = head.loss(fake_cls_score, fake_gt_label)
assert losses['loss'].item() > 0
# test ClsHead with cal_acc=True
head = ClsHead(cal_acc=True)
fake_cls_score = torch.rand(4, 3)
fake_gt_label = torch.randint(0, 2, (4, ))
losses = head.loss(fake_cls_score, fake_gt_label)
assert losses['loss'].item() > 0
# test LinearClsHead
head = LinearClsHead(10, 100)
fake_cls_score = torch.rand(4, 10)
fake_gt_label = torch.randint(0, 10, (4, ))
losses = head.loss(fake_cls_score, fake_gt_label)
assert losses['loss'].item() > 0
def test_multilabel_head():
head = MultiLabelClsHead()
fake_cls_score = torch.rand(4, 3)
fake_gt_label = torch.randint(0, 2, (4, 3))
losses = head.loss(fake_cls_score, fake_gt_label)
assert losses['loss'].item() > 0
def test_multilabel_linear_head():
head = MultiLabelLinearClsHead(3, 5)
fake_cls_score = torch.rand(4, 3)
fake_gt_label = torch.randint(0, 2, (4, 3))
head.init_weights()
losses = head.loss(fake_cls_score, fake_gt_label)
assert losses['loss'].item() > 0
import pytest
import torch
from mmcls.models import build_loss
def test_asymmetric_loss():
# test asymmetric_loss
cls_score = torch.Tensor([[5, -5, 0], [5, -5, 0]])
label = torch.Tensor([[1, 0, 1], [0, 1, 0]])
weight = torch.tensor([0.5, 0.5])
loss_cfg = dict(
type='AsymmetricLoss',
gamma_pos=1.0,
gamma_neg=4.0,
clip=0.05,
reduction='mean',
loss_weight=1.0)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(3.80845 / 3))
# test asymmetric_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(3.80845 / 6))
# test asymmetric_loss without clip
loss_cfg = dict(
type='AsymmetricLoss',
gamma_pos=1.0,
gamma_neg=4.0,
clip=None,
reduction='mean',
loss_weight=1.0)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(5.1186 / 3))
def test_cross_entropy_loss():
with pytest.raises(AssertionError):
# use_sigmoid and use_soft could not be set simultaneously
loss_cfg = dict(
type='CrossEntropyLoss', use_sigmoid=True, use_soft=True)
loss = build_loss(loss_cfg)
# test ce_loss
cls_score = torch.Tensor([[100, -100]])
label = torch.Tensor([1]).long()
weight = torch.tensor(0.5)
loss_cfg = dict(type='CrossEntropyLoss', reduction='mean', loss_weight=1.0)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(200.))
# test ce_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(100.))
# test bce_loss
cls_score = torch.Tensor([[100, -100], [100, -100]])
label = torch.Tensor([[1, 0], [0, 1]])
weight = torch.Tensor([0.5, 0.5])
loss_cfg = dict(
type='CrossEntropyLoss',
use_sigmoid=True,
reduction='mean',
loss_weight=1.0)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(50.))
# test ce_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(25.))
# test soft_ce_loss
cls_score = torch.Tensor([[100, -100]])
label = torch.Tensor([[1, 0], [0, 1]])
weight = torch.tensor(0.5)
loss_cfg = dict(
type='CrossEntropyLoss',
use_soft=True,
reduction='mean',
loss_weight=1.0)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(100.))
# test soft_ce_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(50.))
def test_focal_loss():
# test focal_loss
cls_score = torch.Tensor([[5, -5, 0], [5, -5, 0]])
label = torch.Tensor([[1, 0, 1], [0, 1, 0]])
weight = torch.tensor([0.5, 0.5])
loss_cfg = dict(
type='FocalLoss',
gamma=2.0,
alpha=0.25,
reduction='mean',
loss_weight=1.0)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(0.8522))
# test focal_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(0.8522 / 2))
def test_label_smooth_loss():
# test label_smooth_val assertion
with pytest.raises(AssertionError):
loss_cfg = dict(type='LabelSmoothLoss', label_smooth_val=1.0)
build_loss(loss_cfg)
with pytest.raises(AssertionError):
loss_cfg = dict(type='LabelSmoothLoss', label_smooth_val='str')
build_loss(loss_cfg)
# test reduction assertion
with pytest.raises(AssertionError):
loss_cfg = dict(
type='LabelSmoothLoss', label_smooth_val=0.1, reduction='unknown')
build_loss(loss_cfg)
# test mode assertion
with pytest.raises(AssertionError):
loss_cfg = dict(
type='LabelSmoothLoss', label_smooth_val=0.1, mode='unknown')
build_loss(loss_cfg)
# test original mode label smooth loss
cls_score = torch.tensor([[1., -1.]])
label = torch.tensor([0])
loss_cfg = dict(
type='LabelSmoothLoss',
label_smooth_val=0.1,
mode='original',
reduction='mean',
loss_weight=1.0)
loss = build_loss(loss_cfg)
correct = 0.2269 # from timm
assert loss(cls_score, label) - correct <= 0.0001
# test classy_vision mode label smooth loss
loss_cfg = dict(
type='LabelSmoothLoss',
label_smooth_val=0.1,
mode='classy_vision',
reduction='mean',
loss_weight=1.0)
loss = build_loss(loss_cfg)
correct = 0.2178 # from ClassyVision
assert loss(cls_score, label) - correct <= 0.0001
# test multi_label mode label smooth loss
cls_score = torch.tensor([[1., -1., 1]])
label = torch.tensor([[1, 0, 1]])
loss_cfg = dict(
type='LabelSmoothLoss',
label_smooth_val=0.1,
mode='multi_label',
reduction='mean',
loss_weight=1.0)
loss = build_loss(loss_cfg)
smooth_label = torch.tensor([[0.9, 0.1, 0.9]])
correct = torch.binary_cross_entropy_with_logits(cls_score,
smooth_label).mean()
assert torch.allclose(loss(cls_score, label), correct)
# test label linear combination smooth loss
cls_score = torch.tensor([[1., -1., 0.]])
label1 = torch.tensor([[1., 0., 0.]])
label2 = torch.tensor([[0., 0., 1.]])
label_mix = label1 * 0.6 + label2 * 0.4
loss_cfg = dict(
type='LabelSmoothLoss',
label_smooth_val=0.1,
mode='original',
reduction='mean',
num_classes=3,
loss_weight=1.0)
loss = build_loss(loss_cfg)
smooth_label1 = loss.original_smooth_label(label1)
smooth_label2 = loss.original_smooth_label(label2)
label_smooth_mix = smooth_label1 * 0.6 + smooth_label2 * 0.4
correct = (-torch.log_softmax(cls_score, -1) * label_smooth_mix).sum()
assert loss(cls_score, label_mix) - correct <= 0.0001
# test label smooth loss with weight
cls_score = torch.tensor([[1., -1.], [1., -1.]])
label = torch.tensor([0, 1])
weight = torch.tensor([0.5, 0.5])
loss_cfg = dict(
type='LabelSmoothLoss',
reduction='mean',
label_smooth_val=0.1,
loss_weight=1.0)
loss = build_loss(loss_cfg)
assert torch.allclose(
loss(cls_score, label, weight=weight),
loss(cls_score, label) / 2)
import pytest
import torch
from mmcls.core import average_performance, mAP
def test_mAP():
target = torch.Tensor([[1, 1, 0, -1], [1, 1, 0, -1], [0, -1, 1, -1],
[0, 1, 0, -1]])
pred = torch.Tensor([[0.9, 0.8, 0.3, 0.2], [0.1, 0.2, 0.2, 0.1],
[0.7, 0.5, 0.9, 0.3], [0.8, 0.1, 0.1, 0.2]])
# target and pred should both be np.ndarray or torch.Tensor
with pytest.raises(TypeError):
target_list = target.tolist()
_ = mAP(pred, target_list)
# target and pred should be in the same shape
with pytest.raises(AssertionError):
target_shorter = target[:-1]
_ = mAP(pred, target_shorter)
assert mAP(pred, target) == pytest.approx(68.75, rel=1e-2)
target_no_difficult = torch.Tensor([[1, 1, 0, 0], [0, 1, 0, 0],
[0, 0, 1, 0], [1, 0, 0, 0]])
assert mAP(pred, target_no_difficult) == pytest.approx(70.83, rel=1e-2)
def test_average_performance():
target = torch.Tensor([[1, 1, 0, -1], [1, 1, 0, -1], [0, -1, 1, -1],
[0, 1, 0, -1], [0, 1, 0, -1]])
pred = torch.Tensor([[0.9, 0.8, 0.3, 0.2], [0.1, 0.2, 0.2, 0.1],
[0.7, 0.5, 0.9, 0.3], [0.8, 0.1, 0.1, 0.2],
[0.8, 0.1, 0.1, 0.2]])
# target and pred should both be np.ndarray or torch.Tensor
with pytest.raises(TypeError):
target_list = target.tolist()
_ = average_performance(pred, target_list)
# target and pred should be in the same shape
with pytest.raises(AssertionError):
target_shorter = target[:-1]
_ = average_performance(pred, target_shorter)
assert average_performance(pred, target) == average_performance(
pred, target, thr=0.5)
assert average_performance(pred, target, thr=0.5, k=2) \
== average_performance(pred, target, thr=0.5)
assert average_performance(
pred, target, thr=0.3) == pytest.approx(
(31.25, 43.75, 36.46, 33.33, 42.86, 37.50), rel=1e-2)
assert average_performance(
pred, target, k=2) == pytest.approx(
(43.75, 50.00, 46.67, 40.00, 57.14, 47.06), rel=1e-2)
import pytest
import torch
from mmcls.models.necks import GlobalAveragePooling
def test_gap_neck():
# test 1d gap_neck
neck = GlobalAveragePooling(dim=1)
# batch_size, num_features, feature_size
fake_input = torch.rand(1, 16, 24)
output = neck(fake_input)
# batch_size, num_features
assert output.shape == (1, 16)
# test 1d gap_neck
neck = GlobalAveragePooling(dim=2)
# batch_size, num_features, feature_size(2)
fake_input = torch.rand(1, 16, 24, 24)
output = neck(fake_input)
# batch_size, num_features
assert output.shape == (1, 16)
# test 1d gap_neck
neck = GlobalAveragePooling(dim=3)
# batch_size, num_features, feature_size(3)
fake_input = torch.rand(1, 16, 24, 24, 5)
output = neck(fake_input)
# batch_size, num_features
assert output.shape == (1, 16)
with pytest.raises(AssertionError):
# dim must in [1, 2, 3]
GlobalAveragePooling(dim='other')
import copy
import random
import mmcv
import numpy as np
import pytest
from mmcv.utils import build_from_cfg
from mmcls.datasets.builder import PIPELINES
def construct_toy_data():
img = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
dtype=np.uint8)
img = np.stack([img, img, img], axis=-1)
results = dict()
# image
results['ori_img'] = img
results['img'] = img
results['img2'] = copy.deepcopy(img)
results['img_shape'] = img.shape
results['ori_shape'] = img.shape
results['img_fields'] = ['img', 'img2']
return results
def construct_toy_data_photometric():
img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]],
dtype=np.uint8)
img = np.stack([img, img, img], axis=-1)
results = dict()
# image
results['ori_img'] = img
results['img'] = img
results['img2'] = copy.deepcopy(img)
results['img_shape'] = img.shape
results['ori_shape'] = img.shape
results['img_fields'] = ['img', 'img2']
return results
def test_rand_augment():
policies = [
dict(
type='Translate',
magnitude_key='magnitude',
magnitude_range=(0, 1),
pad_val=128,
prob=1.,
direction='horizontal'),
dict(type='Invert', prob=1.),
dict(
type='Rotate',
magnitude_key='angle',
magnitude_range=(0, 30),
prob=0.)
]
# test assertion for num_policies
with pytest.raises(AssertionError):
transform = dict(
type='RandAugment',
policies=policies,
num_policies=1.5,
magnitude_level=12)
build_from_cfg(transform, PIPELINES)
with pytest.raises(AssertionError):
transform = dict(
type='RandAugment',
policies=policies,
num_policies=-1,
magnitude_level=12)
build_from_cfg(transform, PIPELINES)
# test assertion for magnitude_level
with pytest.raises(AssertionError):
transform = dict(
type='RandAugment',
policies=policies,
num_policies=1,
magnitude_level=None)
build_from_cfg(transform, PIPELINES)
with pytest.raises(AssertionError):
transform = dict(
type='RandAugment',
policies=policies,
num_policies=1,
magnitude_level=-1)
build_from_cfg(transform, PIPELINES)
# test assertion for magnitude_std
with pytest.raises(AssertionError):
transform = dict(
type='RandAugment',
policies=policies,
num_policies=1,
magnitude_level=12,
magnitude_std=None)
build_from_cfg(transform, PIPELINES)
with pytest.raises(AssertionError):
transform = dict(
type='RandAugment',
policies=policies,
num_policies=1,
magnitude_level=12,
magnitude_std='unknown')
build_from_cfg(transform, PIPELINES)
# test assertion for total_level
with pytest.raises(AssertionError):
transform = dict(
type='RandAugment',
policies=policies,
num_policies=1,
magnitude_level=12,
total_level=None)
build_from_cfg(transform, PIPELINES)
with pytest.raises(AssertionError):
transform = dict(
type='RandAugment',
policies=policies,
num_policies=1,
magnitude_level=12,
total_level=-30)
build_from_cfg(transform, PIPELINES)
# test assertion for policies
with pytest.raises(AssertionError):
transform = dict(
type='RandAugment',
policies=[],
num_policies=2,
magnitude_level=12)
build_from_cfg(transform, PIPELINES)
with pytest.raises(AssertionError):
invalid_policies = copy.deepcopy(policies)
invalid_policies.append(('Wrong_policy'))
transform = dict(
type='RandAugment',
policies=invalid_policies,
num_policies=2,
magnitude_level=12)
build_from_cfg(transform, PIPELINES)
with pytest.raises(AssertionError):
invalid_policies = copy.deepcopy(policies)
invalid_policies[2].pop('type')
transform = dict(
type='RandAugment',
policies=invalid_policies,
num_policies=2,
magnitude_level=12)
build_from_cfg(transform, PIPELINES)
with pytest.raises(AssertionError):
invalid_policies = copy.deepcopy(policies)
invalid_policies[2].pop('magnitude_range')
transform = dict(
type='RandAugment',
policies=invalid_policies,
num_policies=2,
magnitude_level=12)
build_from_cfg(transform, PIPELINES)
# test case where num_policies = 1
random.seed(1)
np.random.seed(0)
results = construct_toy_data()
transform = dict(
type='RandAugment',
policies=policies,
num_policies=1,
magnitude_level=12)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
# apply translate
img_augmented = np.array(
[[128, 128, 1, 2], [128, 128, 5, 6], [128, 128, 9, 10]],
dtype=np.uint8)
img_augmented = np.stack([img_augmented, img_augmented, img_augmented],
axis=-1)
assert (results['img'] == img_augmented).all()
results = construct_toy_data()
transform = dict(
type='RandAugment',
policies=policies,
num_policies=1,
magnitude_level=12)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
# apply rotation with prob=0.
assert (results['img'] == results['ori_img']).all()
# test case where magnitude_range is reversed
random.seed(1)
np.random.seed(0)
results = construct_toy_data()
reversed_policies = [
dict(
type='Translate',
magnitude_key='magnitude',
magnitude_range=(1, 0),
pad_val=128,
prob=1.,
direction='horizontal'),
dict(type='Invert', prob=1.),
dict(
type='Rotate',
magnitude_key='angle',
magnitude_range=(30, 0),
prob=0.)
]
transform = dict(
type='RandAugment',
policies=reversed_policies,
num_policies=1,
magnitude_level=30)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case where num_policies = 2
random.seed(0)
np.random.seed(0)
results = construct_toy_data()
transform = dict(
type='RandAugment',
policies=policies,
num_policies=2,
magnitude_level=12)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
# apply rotate and rotate with prob=0
assert (results['img'] == results['ori_img']).all()
results = construct_toy_data()
transform = dict(
type='RandAugment',
policies=policies,
num_policies=2,
magnitude_level=12)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
# apply invert and translate
img_augmented = np.array(
[[252, 251, 128, 128], [248, 247, 128, 128], [244, 243, 128, 128]],
dtype=np.uint8)
img_augmented = np.stack([img_augmented, img_augmented, img_augmented],
axis=-1)
assert (results['img'] == img_augmented).all()
results = construct_toy_data()
transform = dict(
type='RandAugment',
policies=policies,
num_policies=2,
magnitude_level=0)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
# apply invert and invert
assert (results['img'] == results['ori_img']).all()
# test case where magnitude_level = 0
results = construct_toy_data()
transform = dict(
type='RandAugment',
policies=policies,
num_policies=2,
magnitude_level=0)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
# apply rotate and translate
assert (results['img'] == results['ori_img']).all()
# test case where magnitude_std = "inf"
random.seed(3)
np.random.seed(3)
results = construct_toy_data()
transform = dict(
type='RandAugment',
policies=policies,
num_policies=2,
magnitude_level=12,
magnitude_std='inf')
pipeline = build_from_cfg(transform, PIPELINES)
# apply invert and translate (magnitude=0.148)
results = pipeline(results)
img_augmented = np.array(
[[127, 254, 253, 252], [127, 250, 249, 248], [127, 246, 245, 244]],
dtype=np.uint8)
img_augmented = np.stack([img_augmented, img_augmented, img_augmented],
axis=-1)
np.testing.assert_array_equal(results['img'], img_augmented)
# test case where magnitude_std = 0.5
random.seed(3)
np.random.seed(3)
results = construct_toy_data()
transform = dict(
type='RandAugment',
policies=policies,
num_policies=2,
magnitude_level=12,
magnitude_std=0.5)
pipeline = build_from_cfg(transform, PIPELINES)
# apply invert and translate (magnitude=0.384)
results = pipeline(results)
img_augmented = np.array(
[[127, 127, 254, 253], [127, 127, 250, 249], [127, 127, 246, 245]],
dtype=np.uint8)
img_augmented = np.stack([img_augmented, img_augmented, img_augmented],
axis=-1)
np.testing.assert_array_equal(results['img'], img_augmented)
# test case where magnitude_std is negtive
random.seed(3)
np.random.seed(0)
results = construct_toy_data()
transform = dict(
type='RandAugment',
policies=policies,
num_policies=2,
magnitude_level=12,
magnitude_std=-1)
pipeline = build_from_cfg(transform, PIPELINES)
# apply translate (magnitude=0.4) and invert
results = pipeline(results)
img_augmented = np.array(
[[127, 127, 254, 253], [127, 127, 250, 249], [127, 127, 246, 245]],
dtype=np.uint8)
img_augmented = np.stack([img_augmented, img_augmented, img_augmented],
axis=-1)
np.testing.assert_array_equal(results['img'], img_augmented)
def test_shear():
# test assertion for invalid type of magnitude
with pytest.raises(AssertionError):
transform = dict(type='Shear', magnitude=None)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid pad_val
with pytest.raises(AssertionError):
transform = dict(type='Shear', magnitude=0.5, pad_val=(0, 0))
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='Shear', magnitude=0.5, prob=100)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid direction
with pytest.raises(AssertionError):
transform = dict(type='Shear', magnitude=0.5, direction='diagonal')
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of random_negative_prob
with pytest.raises(AssertionError):
transform = dict(type='Shear', magnitude=0.5, random_negative_prob=100)
build_from_cfg(transform, PIPELINES)
# test case when magnitude = 0, therefore no shear
results = construct_toy_data()
transform = dict(type='Shear', magnitude=0., prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob = 0, therefore no shear
results = construct_toy_data()
transform = dict(type='Shear', magnitude=0.5, prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test shear horizontally, magnitude=1
results = construct_toy_data()
transform = dict(
type='Shear', magnitude=1, pad_val=0, prob=1., random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
sheared_img = np.array([[1, 2, 3, 4], [0, 5, 6, 7], [0, 0, 9, 10]],
dtype=np.uint8)
sheared_img = np.stack([sheared_img, sheared_img, sheared_img], axis=-1)
assert (results['img'] == sheared_img).all()
assert (results['img'] == results['img2']).all()
# test shear vertically, magnitude=-1
results = construct_toy_data()
transform = dict(
type='Shear',
magnitude=-1,
pad_val=0,
prob=1.,
direction='vertical',
random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
sheared_img = np.array([[1, 6, 11, 0], [5, 10, 0, 0], [9, 0, 0, 0]],
dtype=np.uint8)
sheared_img = np.stack([sheared_img, sheared_img, sheared_img], axis=-1)
assert (results['img'] == sheared_img).all()
# test shear vertically, magnitude=1, random_negative_prob=1
results = construct_toy_data()
transform = dict(
type='Shear',
magnitude=1,
pad_val=0,
prob=1.,
direction='vertical',
random_negative_prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
sheared_img = np.array([[1, 6, 11, 0], [5, 10, 0, 0], [9, 0, 0, 0]],
dtype=np.uint8)
sheared_img = np.stack([sheared_img, sheared_img, sheared_img], axis=-1)
assert (results['img'] == sheared_img).all()
# test auto aug with shear
results = construct_toy_data()
policies = [[transform]]
autoaug = dict(type='AutoAugment', policies=policies)
pipeline = build_from_cfg(autoaug, PIPELINES)
results = pipeline(results)
assert (results['img'] == sheared_img).all()
def test_translate():
# test assertion for invalid type of magnitude
with pytest.raises(AssertionError):
transform = dict(type='Translate', magnitude=None)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid pad_val
with pytest.raises(AssertionError):
transform = dict(type='Translate', magnitude=0.5, pad_val=(0, 0))
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='Translate', magnitude=0.5, prob=100)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid direction
with pytest.raises(AssertionError):
transform = dict(type='Translate', magnitude=0.5, direction='diagonal')
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of random_negative_prob
with pytest.raises(AssertionError):
transform = dict(
type='Translate', magnitude=0.5, random_negative_prob=100)
build_from_cfg(transform, PIPELINES)
# test case when magnitude=0, therefore no translate
results = construct_toy_data()
transform = dict(type='Translate', magnitude=0., prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=0, therefore no translate
results = construct_toy_data()
transform = dict(type='Translate', magnitude=1., prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test translate horizontally, magnitude=0.5
results = construct_toy_data()
transform = dict(
type='Translate',
magnitude=0.5,
pad_val=0,
prob=1.,
random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
translated_img = np.array([[0, 0, 1, 2], [0, 0, 5, 6], [0, 0, 9, 10]],
dtype=np.uint8)
translated_img = np.stack([translated_img, translated_img, translated_img],
axis=-1)
assert (results['img'] == translated_img).all()
assert (results['img'] == results['img2']).all()
# test translate vertically, magnitude=-0.5
results = construct_toy_data()
transform = dict(
type='Translate',
magnitude=-0.5,
pad_val=0,
prob=1.,
direction='vertical',
random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
translated_img = np.array([[9, 10, 11, 12], [0, 0, 0, 0], [0, 0, 0, 0]],
dtype=np.uint8)
translated_img = np.stack([translated_img, translated_img, translated_img],
axis=-1)
assert (results['img'] == translated_img).all()
# test translate vertically, magnitude=0.5, random_negative_prob=1
results = construct_toy_data()
transform = dict(
type='Translate',
magnitude=0.5,
pad_val=0,
prob=1.,
direction='vertical',
random_negative_prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
translated_img = np.array([[9, 10, 11, 12], [0, 0, 0, 0], [0, 0, 0, 0]],
dtype=np.uint8)
translated_img = np.stack([translated_img, translated_img, translated_img],
axis=-1)
assert (results['img'] == translated_img).all()
def test_rotate():
# test assertion for invalid type of angle
with pytest.raises(AssertionError):
transform = dict(type='Rotate', angle=None)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid type of center
with pytest.raises(AssertionError):
transform = dict(type='Rotate', angle=90., center=0)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid lenth of center
with pytest.raises(AssertionError):
transform = dict(type='Rotate', angle=90., center=(0, ))
build_from_cfg(transform, PIPELINES)
# test assertion for invalid scale
with pytest.raises(AssertionError):
transform = dict(type='Rotate', angle=90., scale=None)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid pad_val
with pytest.raises(AssertionError):
transform = dict(type='Rotate', angle=90., pad_val=(0, 0))
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='Rotate', angle=90., prob=100)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of random_negative_prob
with pytest.raises(AssertionError):
transform = dict(type='Rotate', angle=0.5, random_negative_prob=100)
build_from_cfg(transform, PIPELINES)
# test case when angle=0, therefore no rotation
results = construct_toy_data()
transform = dict(type='Rotate', angle=0., prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when angle=360, therefore no rotation
results = construct_toy_data()
transform = dict(type='Rotate', angle=360., prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=0, therefore no rotation
results = construct_toy_data()
transform = dict(type='Rotate', angle=90., prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test rotate clockwise, angle=30.
results = construct_toy_data()
transform = dict(
type='Rotate', angle=30., pad_val=0, prob=1., random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
rotated_img = np.array([[5, 2, 2, 0], [9, 6, 7, 4], [0, 11, 11, 8]],
dtype=np.uint8)
rotated_img = np.stack([rotated_img, rotated_img, rotated_img], axis=-1)
assert (results['img'] == rotated_img).all()
assert (results['img'] == results['img2']).all()
# test rotate clockwise, angle=90, center=(1,1)
results = construct_toy_data()
transform = dict(
type='Rotate',
angle=90.,
center=(1, 1),
prob=1.,
random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
rotated_img = np.array([[9, 5, 1, 128], [10, 6, 2, 128], [11, 7, 3, 128]],
dtype=np.uint8)
rotated_img = np.stack([rotated_img, rotated_img, rotated_img], axis=-1)
assert (results['img'] == rotated_img).all()
assert (results['img'] == results['img2']).all()
# test rotate counter-clockwise, angle=90.
results = construct_toy_data()
transform = dict(
type='Rotate', angle=-90., pad_val=0, prob=1., random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
rotated_img = np.array([[4, 8, 12, 0], [3, 7, 11, 0], [2, 6, 10, 0]],
dtype=np.uint8)
rotated_img = np.stack([rotated_img, rotated_img, rotated_img], axis=-1)
assert (results['img'] == rotated_img).all()
assert (results['img'] == results['img2']).all()
# test rotate counter-clockwise, angle=90, random_negative_prob=1
results = construct_toy_data()
transform = dict(
type='Rotate', angle=-90., pad_val=0, prob=1., random_negative_prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
rotated_img = np.array([[0, 10, 6, 2], [0, 11, 7, 3], [0, 12, 8, 4]],
dtype=np.uint8)
rotated_img = np.stack([rotated_img, rotated_img, rotated_img], axis=-1)
assert (results['img'] == rotated_img).all()
assert (results['img'] == results['img2']).all()
def test_auto_contrast():
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='AutoContrast', prob=100)
build_from_cfg(transform, PIPELINES)
# test case when prob=0, therefore no auto_contrast
results = construct_toy_data()
transform = dict(type='AutoContrast', prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=1
results = construct_toy_data()
transform = dict(type='AutoContrast', prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
auto_contrasted_img = np.array(
[[0, 23, 46, 69], [92, 115, 139, 162], [185, 208, 231, 255]],
dtype=np.uint8)
auto_contrasted_img = np.stack(
[auto_contrasted_img, auto_contrasted_img, auto_contrasted_img],
axis=-1)
assert (results['img'] == auto_contrasted_img).all()
assert (results['img'] == results['img2']).all()
def test_invert():
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='Invert', prob=100)
build_from_cfg(transform, PIPELINES)
# test case when prob=0, therefore no invert
results = construct_toy_data()
transform = dict(type='Invert', prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=1
results = construct_toy_data()
transform = dict(type='Invert', prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
inverted_img = np.array(
[[254, 253, 252, 251], [250, 249, 248, 247], [246, 245, 244, 243]],
dtype=np.uint8)
inverted_img = np.stack([inverted_img, inverted_img, inverted_img],
axis=-1)
assert (results['img'] == inverted_img).all()
assert (results['img'] == results['img2']).all()
def test_equalize(nb_rand_test=100):
def _imequalize(img):
# equalize the image using PIL.ImageOps.equalize
from PIL import ImageOps, Image
img = Image.fromarray(img)
equalized_img = np.asarray(ImageOps.equalize(img))
return equalized_img
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='Equalize', prob=100)
build_from_cfg(transform, PIPELINES)
# test case when prob=0, therefore no equalize
results = construct_toy_data()
transform = dict(type='Equalize', prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=1 with randomly sampled image.
results = construct_toy_data()
transform = dict(type='Equalize', prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
for _ in range(nb_rand_test):
img = np.clip(np.random.normal(0, 1, (1000, 1200, 3)) * 260, 0,
255).astype(np.uint8)
results['img'] = img
results = pipeline(copy.deepcopy(results))
assert (results['img'] == _imequalize(img)).all()
def test_solarize():
# test assertion for invalid type of thr
with pytest.raises(AssertionError):
transform = dict(type='Solarize', thr=(1, 2))
build_from_cfg(transform, PIPELINES)
# test case when prob=0, therefore no solarize
results = construct_toy_data_photometric()
transform = dict(type='Solarize', thr=128, prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when thr=256, therefore no solarize
results = construct_toy_data_photometric()
transform = dict(type='Solarize', thr=256, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when thr=128
results = construct_toy_data_photometric()
transform = dict(type='Solarize', thr=128, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_solarized = np.array([[0, 127, 0], [1, 127, 1], [2, 126, 2]],
dtype=np.uint8)
img_solarized = np.stack([img_solarized, img_solarized, img_solarized],
axis=-1)
assert (results['img'] == img_solarized).all()
assert (results['img'] == results['img2']).all()
# test case when thr=100
results = construct_toy_data_photometric()
transform = dict(type='Solarize', thr=100, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_solarized = np.array([[0, 127, 0], [1, 128, 1], [2, 126, 2]],
dtype=np.uint8)
img_solarized = np.stack([img_solarized, img_solarized, img_solarized],
axis=-1)
assert (results['img'] == img_solarized).all()
assert (results['img'] == results['img2']).all()
def test_solarize_add():
# test assertion for invalid type of magnitude
with pytest.raises(AssertionError):
transform = dict(type='SolarizeAdd', magnitude=(1, 2))
build_from_cfg(transform, PIPELINES)
# test assertion for invalid type of thr
with pytest.raises(AssertionError):
transform = dict(type='SolarizeAdd', magnitude=100, thr=(1, 2))
build_from_cfg(transform, PIPELINES)
# test case when prob=0, therefore no solarize
results = construct_toy_data_photometric()
transform = dict(type='SolarizeAdd', magnitude=100, thr=128, prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when thr=0, therefore no solarize
results = construct_toy_data_photometric()
transform = dict(type='SolarizeAdd', magnitude=100, thr=0, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when thr=128, magnitude=100
results = construct_toy_data_photometric()
transform = dict(type='SolarizeAdd', magnitude=100, thr=128, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_solarized = np.array(
[[100, 128, 255], [101, 227, 254], [102, 129, 253]], dtype=np.uint8)
img_solarized = np.stack([img_solarized, img_solarized, img_solarized],
axis=-1)
assert (results['img'] == img_solarized).all()
assert (results['img'] == results['img2']).all()
# test case when thr=100, magnitude=50
results = construct_toy_data_photometric()
transform = dict(type='SolarizeAdd', magnitude=50, thr=100, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_solarized = np.array([[50, 128, 255], [51, 127, 254], [52, 129, 253]],
dtype=np.uint8)
img_solarized = np.stack([img_solarized, img_solarized, img_solarized],
axis=-1)
assert (results['img'] == img_solarized).all()
assert (results['img'] == results['img2']).all()
def test_posterize():
# test assertion for invalid value of bits
with pytest.raises(AssertionError):
transform = dict(type='Posterize', bits=10)
build_from_cfg(transform, PIPELINES)
# test case when prob=0, therefore no posterize
results = construct_toy_data_photometric()
transform = dict(type='Posterize', bits=4, prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when bits=8, therefore no solarize
results = construct_toy_data_photometric()
transform = dict(type='Posterize', bits=8, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when bits=1
results = construct_toy_data_photometric()
transform = dict(type='Posterize', bits=1, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_posterized = np.array([[0, 128, 128], [0, 0, 128], [0, 128, 128]],
dtype=np.uint8)
img_posterized = np.stack([img_posterized, img_posterized, img_posterized],
axis=-1)
assert (results['img'] == img_posterized).all()
assert (results['img'] == results['img2']).all()
# test case when bits=3
results = construct_toy_data_photometric()
transform = dict(type='Posterize', bits=3, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_posterized = np.array([[0, 128, 224], [0, 96, 224], [0, 128, 224]],
dtype=np.uint8)
img_posterized = np.stack([img_posterized, img_posterized, img_posterized],
axis=-1)
assert (results['img'] == img_posterized).all()
assert (results['img'] == results['img2']).all()
def test_contrast(nb_rand_test=100):
def _adjust_contrast(img, factor):
from PIL.ImageEnhance import Contrast
from PIL import Image
# Image.fromarray defaultly supports RGB, not BGR.
# convert from BGR to RGB
img = Image.fromarray(img[..., ::-1], mode='RGB')
contrasted_img = Contrast(img).enhance(factor)
# convert from RGB to BGR
return np.asarray(contrasted_img)[..., ::-1]
# test assertion for invalid type of magnitude
with pytest.raises(AssertionError):
transform = dict(type='Contrast', magnitude=None)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='Contrast', magnitude=0.5, prob=100)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of random_negative_prob
with pytest.raises(AssertionError):
transform = dict(
type='Contrast', magnitude=0.5, random_negative_prob=100)
build_from_cfg(transform, PIPELINES)
# test case when magnitude=0, therefore no adjusting contrast
results = construct_toy_data_photometric()
transform = dict(type='Contrast', magnitude=0., prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=0, therefore no adjusting contrast
results = construct_toy_data_photometric()
transform = dict(type='Contrast', magnitude=1., prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=1 with randomly sampled image.
results = construct_toy_data()
for _ in range(nb_rand_test):
magnitude = np.random.uniform() * np.random.choice([-1, 1])
transform = dict(
type='Contrast',
magnitude=magnitude,
prob=1.,
random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
img = np.clip(np.random.uniform(0, 1, (1200, 1000, 3)) * 260, 0,
255).astype(np.uint8)
results['img'] = img
results = pipeline(copy.deepcopy(results))
# Note the gap (less_equal 1) between PIL.ImageEnhance.Contrast
# and mmcv.adjust_contrast comes from the gap that converts from
# a color image to gray image using mmcv or PIL.
np.testing.assert_allclose(
results['img'],
_adjust_contrast(img, 1 + magnitude),
rtol=0,
atol=1)
def test_color_transform():
# test assertion for invalid type of magnitude
with pytest.raises(AssertionError):
transform = dict(type='ColorTransform', magnitude=None)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='ColorTransform', magnitude=0.5, prob=100)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of random_negative_prob
with pytest.raises(AssertionError):
transform = dict(
type='ColorTransform', magnitude=0.5, random_negative_prob=100)
build_from_cfg(transform, PIPELINES)
# test case when magnitude=0, therefore no color transform
results = construct_toy_data_photometric()
transform = dict(type='ColorTransform', magnitude=0., prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=0, therefore no color transform
results = construct_toy_data_photometric()
transform = dict(type='ColorTransform', magnitude=1., prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when magnitude=-1, therefore got gray img
results = construct_toy_data_photometric()
transform = dict(
type='ColorTransform', magnitude=-1., prob=1., random_negative_prob=0)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_gray = mmcv.bgr2gray(results['ori_img'])
img_gray = np.stack([img_gray, img_gray, img_gray], axis=-1)
assert (results['img'] == img_gray).all()
# test case when magnitude=0.5
results = construct_toy_data_photometric()
transform = dict(
type='ColorTransform', magnitude=.5, prob=1., random_negative_prob=0)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_r = np.round(
np.clip((results['ori_img'] * 0.5 + img_gray * 0.5), 0,
255)).astype(results['ori_img'].dtype)
assert (results['img'] == img_r).all()
assert (results['img'] == results['img2']).all()
# test case when magnitude=0.3, random_negative_prob=1
results = construct_toy_data_photometric()
transform = dict(
type='ColorTransform', magnitude=.3, prob=1., random_negative_prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_r = np.round(
np.clip((results['ori_img'] * 0.7 + img_gray * 0.3), 0,
255)).astype(results['ori_img'].dtype)
assert (results['img'] == img_r).all()
assert (results['img'] == results['img2']).all()
def test_brightness(nb_rand_test=100):
def _adjust_brightness(img, factor):
# adjust the brightness of image using
# PIL.ImageEnhance.Brightness
from PIL.ImageEnhance import Brightness
from PIL import Image
img = Image.fromarray(img)
brightened_img = Brightness(img).enhance(factor)
return np.asarray(brightened_img)
# test assertion for invalid type of magnitude
with pytest.raises(AssertionError):
transform = dict(type='Brightness', magnitude=None)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='Brightness', magnitude=0.5, prob=100)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of random_negative_prob
with pytest.raises(AssertionError):
transform = dict(
type='Brightness', magnitude=0.5, random_negative_prob=100)
build_from_cfg(transform, PIPELINES)
# test case when magnitude=0, therefore no adjusting brightness
results = construct_toy_data_photometric()
transform = dict(type='Brightness', magnitude=0., prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=0, therefore no adjusting brightness
results = construct_toy_data_photometric()
transform = dict(type='Brightness', magnitude=1., prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=1 with randomly sampled image.
results = construct_toy_data()
for _ in range(nb_rand_test):
magnitude = np.random.uniform() * np.random.choice([-1, 1])
transform = dict(
type='Brightness',
magnitude=magnitude,
prob=1.,
random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
img = np.clip(np.random.uniform(0, 1, (1200, 1000, 3)) * 260, 0,
255).astype(np.uint8)
results['img'] = img
results = pipeline(copy.deepcopy(results))
np.testing.assert_allclose(
results['img'],
_adjust_brightness(img, 1 + magnitude),
rtol=0,
atol=1)
def test_sharpness(nb_rand_test=100):
def _adjust_sharpness(img, factor):
# adjust the sharpness of image using
# PIL.ImageEnhance.Sharpness
from PIL.ImageEnhance import Sharpness
from PIL import Image
img = Image.fromarray(img)
sharpened_img = Sharpness(img).enhance(factor)
return np.asarray(sharpened_img)
# test assertion for invalid type of magnitude
with pytest.raises(AssertionError):
transform = dict(type='Sharpness', magnitude=None)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='Sharpness', magnitude=0.5, prob=100)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of random_negative_prob
with pytest.raises(AssertionError):
transform = dict(
type='Sharpness', magnitude=0.5, random_negative_prob=100)
build_from_cfg(transform, PIPELINES)
# test case when magnitude=0, therefore no adjusting sharpness
results = construct_toy_data_photometric()
transform = dict(type='Sharpness', magnitude=0., prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=0, therefore no adjusting sharpness
results = construct_toy_data_photometric()
transform = dict(type='Sharpness', magnitude=1., prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when prob=1 with randomly sampled image.
results = construct_toy_data()
for _ in range(nb_rand_test):
magnitude = np.random.uniform() * np.random.choice([-1, 1])
transform = dict(
type='Sharpness',
magnitude=magnitude,
prob=1.,
random_negative_prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
img = np.clip(np.random.uniform(0, 1, (1200, 1000, 3)) * 260, 0,
255).astype(np.uint8)
results['img'] = img
results = pipeline(copy.deepcopy(results))
np.testing.assert_allclose(
results['img'][1:-1, 1:-1],
_adjust_sharpness(img, 1 + magnitude)[1:-1, 1:-1],
rtol=0,
atol=1)
def test_cutout():
# test assertion for invalid type of shape
with pytest.raises(TypeError):
transform = dict(type='Cutout', shape=None)
build_from_cfg(transform, PIPELINES)
# test assertion for invalid value of prob
with pytest.raises(AssertionError):
transform = dict(type='Cutout', shape=1, prob=100)
build_from_cfg(transform, PIPELINES)
# test case when prob=0, therefore no cutout
results = construct_toy_data()
transform = dict(type='Cutout', shape=2, prob=0.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when shape=0, therefore no cutout
results = construct_toy_data()
transform = dict(type='Cutout', shape=0, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == results['ori_img']).all()
# test case when shape=6, therefore the whole img has been cut
results = construct_toy_data()
transform = dict(type='Cutout', shape=6, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
assert (results['img'] == np.ones_like(results['ori_img']) * 128).all()
# test case when shape is int
np.random.seed(0)
results = construct_toy_data()
transform = dict(type='Cutout', shape=1, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_cutout = np.array([[1, 2, 3, 4], [5, 128, 7, 8], [9, 10, 11, 12]],
dtype=np.uint8)
img_cutout = np.stack([img_cutout, img_cutout, img_cutout], axis=-1)
assert (results['img'] == img_cutout).all()
# test case when shape is tuple
np.random.seed(0)
results = construct_toy_data()
transform = dict(type='Cutout', shape=(1, 2), pad_val=0, prob=1.)
pipeline = build_from_cfg(transform, PIPELINES)
results = pipeline(results)
img_cutout = np.array([[1, 2, 3, 4], [5, 0, 0, 8], [9, 10, 11, 12]],
dtype=np.uint8)
img_cutout = np.stack([img_cutout, img_cutout, img_cutout], axis=-1)
assert (results['img'] == img_cutout).all()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment