Commit 0fd8347d authored by unknown's avatar unknown
Browse files

添加mmclassification-0.24.1代码,删除mmclassification-speed-benchmark

parent cc567e9e
# Copyright (c) OpenMMLab. All rights reserved.
import copy
import os.path as osp
import random
......@@ -62,6 +63,11 @@ def test_resize():
transform = dict(type='Resize', size=224, interpolation='2333')
build_from_cfg(transform, PIPELINES)
# test assertion when resize_short is invalid
with pytest.raises(AssertionError):
transform = dict(type='Resize', size=224, adaptive_side='False')
build_from_cfg(transform, PIPELINES)
# test repr
transform = dict(type='Resize', size=224)
resize_module = build_from_cfg(transform, PIPELINES)
......@@ -70,7 +76,7 @@ def test_resize():
# read test image
results = dict()
img = mmcv.imread(
osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color')
osp.join(osp.dirname(__file__), '../../data/color.jpg'), 'color')
original_img = copy.deepcopy(img)
results['img'] = img
results['img2'] = copy.deepcopy(img)
......@@ -163,6 +169,102 @@ def test_resize():
assert results['img_shape'] == (224, 224, 3)
assert np.allclose(results['img'], resized_img, atol=30)
# test resize when size is tuple, the second value is -1
# and adaptive_side='long'
transform = dict(
type='Resize',
size=(224, -1),
adaptive_side='long',
interpolation='bilinear')
resize_module = build_from_cfg(transform, PIPELINES)
results = reset_results(results, original_img)
results = resize_module(results)
assert np.equal(results['img'], results['img2']).all()
assert results['img_shape'] == (168, 224, 3)
# test resize when size is tuple, the second value is -1
# and adaptive_side='long', h > w
transform1 = dict(type='Resize', size=(300, 200), interpolation='bilinear')
resize_module1 = build_from_cfg(transform1, PIPELINES)
transform2 = dict(
type='Resize',
size=(224, -1),
adaptive_side='long',
interpolation='bilinear')
resize_module2 = build_from_cfg(transform2, PIPELINES)
results = reset_results(results, original_img)
results = resize_module1(results)
results = resize_module2(results)
assert np.equal(results['img'], results['img2']).all()
assert results['img_shape'] == (224, 149, 3)
# test resize when size is tuple, the second value is -1
# and adaptive_side='short', h > w
transform1 = dict(type='Resize', size=(300, 200), interpolation='bilinear')
resize_module1 = build_from_cfg(transform1, PIPELINES)
transform2 = dict(
type='Resize',
size=(224, -1),
adaptive_side='short',
interpolation='bilinear')
resize_module2 = build_from_cfg(transform2, PIPELINES)
results = reset_results(results, original_img)
results = resize_module1(results)
results = resize_module2(results)
assert np.equal(results['img'], results['img2']).all()
assert results['img_shape'] == (336, 224, 3)
# test interpolation method checking
with pytest.raises(AssertionError):
transform = dict(
type='Resize', size=(300, 200), backend='cv2', interpolation='box')
resize_module = build_from_cfg(transform, PIPELINES)
with pytest.raises(AssertionError):
transform = dict(
type='Resize',
size=(300, 200),
backend='pillow',
interpolation='area')
resize_module = build_from_cfg(transform, PIPELINES)
def test_pad():
results = dict()
img = mmcv.imread(
osp.join(osp.dirname(__file__), '../../data/color.jpg'), 'color')
results['img'] = img
results['img2'] = copy.deepcopy(img)
results['img_shape'] = img.shape
results['ori_shape'] = img.shape
results['img_fields'] = ['img', 'img2']
# test assertion if shape is None
with pytest.raises(AssertionError):
transform = dict(type='Pad', size=None)
pad_module = build_from_cfg(transform, PIPELINES)
pad_result = pad_module(copy.deepcopy(results))
assert np.equal(pad_result['img'], pad_result['img2']).all()
assert pad_result['img_shape'] == (400, 400, 3)
# test if pad is valid
transform = dict(type='Pad', size=(400, 400))
pad_module = build_from_cfg(transform, PIPELINES)
pad_result = pad_module(copy.deepcopy(results))
assert isinstance(repr(pad_module), str)
assert np.equal(pad_result['img'], pad_result['img2']).all()
assert pad_result['img_shape'] == (400, 400, 3)
assert np.allclose(pad_result['img'][-100:, :, :], 0)
# test if pad_to_square is valid
transform = dict(type='Pad', pad_to_square=True)
pad_module = build_from_cfg(transform, PIPELINES)
pad_result = pad_module(copy.deepcopy(results))
assert isinstance(repr(pad_module), str)
assert np.equal(pad_result['img'], pad_result['img2']).all()
assert pad_result['img_shape'] == (400, 400, 3)
assert np.allclose(pad_result['img'][-100:, :, :], 0)
def test_center_crop():
# test assertion if size is smaller than 0
......@@ -220,7 +322,7 @@ def test_center_crop():
# read test image
results = dict()
img = mmcv.imread(
osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color')
osp.join(osp.dirname(__file__), '../../data/color.jpg'), 'color')
original_img = copy.deepcopy(img)
results['img'] = img
results['img2'] = copy.deepcopy(img)
......@@ -343,7 +445,7 @@ def test_normalize():
# read data
results = dict()
img = mmcv.imread(
osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color')
osp.join(osp.dirname(__file__), '../../data/color.jpg'), 'color')
original_img = copy.deepcopy(img)
results['img'] = img
results['img2'] = copy.deepcopy(img)
......@@ -371,9 +473,9 @@ def test_normalize():
def test_randomcrop():
ori_img = mmcv.imread(
osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color')
osp.join(osp.dirname(__file__), '../../data/color.jpg'), 'color')
ori_img_pil = Image.open(
osp.join(osp.dirname(__file__), '../data/color.jpg'))
osp.join(osp.dirname(__file__), '../../data/color.jpg'))
seed = random.randint(0, 100)
# test crop size is int
......@@ -517,9 +619,9 @@ def test_randomcrop():
def test_randomresizedcrop():
ori_img = mmcv.imread(
osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color')
osp.join(osp.dirname(__file__), '../../data/color.jpg'), 'color')
ori_img_pil = Image.open(
osp.join(osp.dirname(__file__), '../data/color.jpg'))
osp.join(osp.dirname(__file__), '../../data/color.jpg'))
seed = random.randint(0, 100)
......@@ -900,7 +1002,7 @@ def test_randomflip():
# read test image
results = dict()
img = mmcv.imread(
osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color')
osp.join(osp.dirname(__file__), '../../data/color.jpg'), 'color')
original_img = copy.deepcopy(img)
results['img'] = img
results['img2'] = copy.deepcopy(img)
......@@ -928,7 +1030,7 @@ def test_randomflip():
results = flip_module(results)
assert np.equal(results['img'], results['img2']).all()
# compare hotizontal flip with torchvision
# compare horizontal flip with torchvision
transform = dict(type='RandomFlip', flip_prob=1, direction='horizontal')
flip_module = build_from_cfg(transform, PIPELINES)
results = reset_results(results, original_img)
......@@ -1077,7 +1179,7 @@ def test_color_jitter():
# read test image
results = dict()
img = mmcv.imread(
osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color')
osp.join(osp.dirname(__file__), '../../data/color.jpg'), 'color')
original_img = copy.deepcopy(img)
results['img'] = img
results['img2'] = copy.deepcopy(img)
......@@ -1123,7 +1225,7 @@ def test_lighting():
# read test image
results = dict()
img = mmcv.imread(
osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color')
osp.join(osp.dirname(__file__), '../../data/color.jpg'), 'color')
original_img = copy.deepcopy(img)
results['img'] = img
results['img2'] = copy.deepcopy(img)
......@@ -1165,15 +1267,26 @@ def test_lighting():
def test_albu_transform():
results = dict(
img_prefix=osp.join(osp.dirname(__file__), '../data'),
img_info=dict(filename='color.jpg'))
img_prefix=osp.join(osp.dirname(__file__), '../../data'),
img_info=dict(filename='color.jpg'),
gt_label=np.array(1))
# Define simple pipeline
load = dict(type='LoadImageFromFile')
load = build_from_cfg(load, PIPELINES)
albu_transform = dict(
type='Albu', transforms=[dict(type='ChannelShuffle', p=1)])
type='Albu',
transforms=[
dict(type='ChannelShuffle', p=1),
dict(
type='ShiftScaleRotate',
shift_limit=0.0625,
scale_limit=0.0,
rotate_limit=0,
interpolation=1,
p=1)
])
albu_transform = build_from_cfg(albu_transform, PIPELINES)
normalize = dict(type='Normalize', mean=[0] * 3, std=[0] * 3, to_rgb=True)
......@@ -1185,3 +1298,4 @@ def test_albu_transform():
results = normalize(results)
assert results['img'].dtype == np.float32
assert results['gt_label'].shape == np.array(1).shape
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
from mmcv import Config
from mmdet.apis import inference_detector
from mmdet.models import build_detector
from mmcls.models import (MobileNetV2, MobileNetV3, RegNet, ResNeSt, ResNet,
ResNeXt, SEResNet, SEResNeXt, SwinTransformer,
TIMMBackbone)
from mmcls.models.backbones.timm_backbone import timm
backbone_configs = dict(
mobilenetv2=dict(
backbone=dict(
type='mmcls.MobileNetV2',
widen_factor=1.0,
norm_cfg=dict(type='GN', num_groups=2, requires_grad=True),
out_indices=(4, 7)),
out_channels=[96, 1280]),
mobilenetv3=dict(
backbone=dict(
type='mmcls.MobileNetV3',
norm_cfg=dict(type='GN', num_groups=2, requires_grad=True),
out_indices=range(7, 12)),
out_channels=[48, 48, 96, 96, 96]),
regnet=dict(
backbone=dict(type='mmcls.RegNet', arch='regnetx_400mf'),
out_channels=384),
resnext=dict(
backbone=dict(
type='mmcls.ResNeXt', depth=50, groups=32, width_per_group=4),
out_channels=2048),
resnet=dict(
backbone=dict(type='mmcls.ResNet', depth=50), out_channels=2048),
seresnet=dict(
backbone=dict(type='mmcls.SEResNet', depth=50), out_channels=2048),
seresnext=dict(
backbone=dict(
type='mmcls.SEResNeXt', depth=50, groups=32, width_per_group=4),
out_channels=2048),
resnest=dict(
backbone=dict(
type='mmcls.ResNeSt',
depth=50,
radix=2,
reduction_factor=4,
out_indices=(0, 1, 2, 3)),
out_channels=[256, 512, 1024, 2048]),
swin=dict(
backbone=dict(
type='mmcls.SwinTransformer',
arch='small',
drop_path_rate=0.2,
img_size=800,
out_indices=(2, 3)),
out_channels=[384, 768]),
timm_efficientnet=dict(
backbone=dict(
type='mmcls.TIMMBackbone',
model_name='efficientnet_b1',
features_only=True,
pretrained=False,
out_indices=(1, 2, 3, 4)),
out_channels=[24, 40, 112, 320]),
timm_resnet=dict(
backbone=dict(
type='mmcls.TIMMBackbone',
model_name='resnet50',
features_only=True,
pretrained=False,
out_indices=(1, 2, 3, 4)),
out_channels=[256, 512, 1024, 2048]))
module_mapping = {
'mobilenetv2': MobileNetV2,
'mobilenetv3': MobileNetV3,
'regnet': RegNet,
'resnext': ResNeXt,
'resnet': ResNet,
'seresnext': SEResNeXt,
'seresnet': SEResNet,
'resnest': ResNeSt,
'swin': SwinTransformer,
'timm_efficientnet': TIMMBackbone,
'timm_resnet': TIMMBackbone
}
def test_mmdet_inference():
config_path = './tests/data/retinanet.py'
rng = np.random.RandomState(0)
img1 = rng.rand(100, 100, 3)
for module_name, backbone_config in backbone_configs.items():
module = module_mapping[module_name]
if module is TIMMBackbone and timm is None:
print(f'skip {module_name} because timm is not available')
continue
print(f'test {module_name}')
config = Config.fromfile(config_path)
config.model.backbone = backbone_config['backbone']
out_channels = backbone_config['out_channels']
if isinstance(out_channels, int):
config.model.neck = None
config.model.bbox_head.in_channels = out_channels
anchor_generator = config.model.bbox_head.anchor_generator
anchor_generator.strides = anchor_generator.strides[:1]
else:
config.model.neck.in_channels = out_channels
model = build_detector(config.model)
assert isinstance(model.backbone, module)
model.cfg = config
model.eval()
result = inference_detector(model, img1)
assert len(result) == config.num_classes
# Copyright (c) OpenMMLab. All rights reserved.
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))
# test asymmetric_loss with softmax for single label task
cls_score = torch.Tensor([[5, -5, 0], [5, -5, 0]])
label = torch.Tensor([0, 1])
weight = torch.tensor([0.5, 0.5])
loss_cfg = dict(
type='AsymmetricLoss',
gamma_pos=0.0,
gamma_neg=0.0,
clip=None,
reduction='mean',
loss_weight=1.0,
use_sigmoid=False,
eps=1e-8)
loss = build_loss(loss_cfg)
# test asymmetric_loss for single label task without weight
assert torch.allclose(loss(cls_score, label), torch.tensor(2.5045))
# test asymmetric_loss for single label task with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(2.5045 * 0.5))
# test soft asymmetric_loss with softmax
cls_score = torch.Tensor([[5, -5, 0], [5, -5, 0]])
label = torch.Tensor([[1, 0, 0], [0, 1, 0]])
weight = torch.tensor([0.5, 0.5])
loss_cfg = dict(
type='AsymmetricLoss',
gamma_pos=0.0,
gamma_neg=0.0,
clip=None,
reduction='mean',
loss_weight=1.0,
use_sigmoid=False,
eps=1e-8)
loss = build_loss(loss_cfg)
# test soft asymmetric_loss with softmax without weight
assert torch.allclose(loss(cls_score, label), torch.tensor(2.5045))
# test soft asymmetric_loss with softmax with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(2.5045 * 0.5))
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([[-1000, 1000], [100, -100]])
label = torch.Tensor([0, 1]).long()
class_weight = [0.3, 0.7] # class 0 : 0.3, class 1 : 0.7
weight = torch.tensor([0.6, 0.4])
# test ce_loss without class weight
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(1100.))
# test ce_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(640.))
# test ce_loss with class weight
loss_cfg = dict(
type='CrossEntropyLoss',
reduction='mean',
loss_weight=1.0,
class_weight=class_weight)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(370.))
# test ce_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(208.))
# test bce_loss
cls_score = torch.Tensor([[-200, 100], [500, -1000], [300, -300]])
label = torch.Tensor([[1, 0], [0, 1], [1, 0]])
weight = torch.Tensor([0.6, 0.4, 0.5])
class_weight = [0.1, 0.9] # class 0: 0.1, class 1: 0.9
pos_weight = [0.1, 0.2]
# test bce_loss without class weight
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(300.))
# test ce_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(130.))
# test bce_loss with class weight
loss_cfg = dict(
type='CrossEntropyLoss',
use_sigmoid=True,
reduction='mean',
loss_weight=1.0,
class_weight=class_weight)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(176.667))
# test bce_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(74.333))
# test bce loss with pos_weight
loss_cfg = dict(
type='CrossEntropyLoss',
use_sigmoid=True,
reduction='mean',
loss_weight=1.0,
pos_weight=pos_weight)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(136.6667))
# test soft_ce_loss
cls_score = torch.Tensor([[-1000, 1000], [100, -100]])
label = torch.Tensor([[1.0, 0.0], [0.0, 1.0]])
class_weight = [0.3, 0.7] # class 0 : 0.3, class 1 : 0.7
weight = torch.tensor([0.6, 0.4])
# test soft_ce_loss without class weight
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(1100.))
# test soft_ce_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(640.))
# test soft_ce_loss with class weight
loss_cfg = dict(
type='CrossEntropyLoss',
use_soft=True,
reduction='mean',
loss_weight=1.0,
class_weight=class_weight)
loss = build_loss(loss_cfg)
assert torch.allclose(loss(cls_score, label), torch.tensor(370.))
# test soft_ce_loss with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(208.))
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))
# test focal loss for single label task
cls_score = torch.Tensor([[5, -5, 0], [5, -5, 0]])
label = torch.Tensor([0, 1])
weight = torch.tensor([0.5, 0.5])
assert torch.allclose(loss(cls_score, label), torch.tensor(0.86664125))
# test focal_loss single label with weight
assert torch.allclose(
loss(cls_score, label, weight=weight), torch.tensor(0.86664125 / 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)
# migrate from mmdetection with modifications
def test_seesaw_loss():
# only softmax version of Seesaw Loss is implemented
with pytest.raises(AssertionError):
loss_cfg = dict(type='SeesawLoss', use_sigmoid=True, loss_weight=1.0)
build_loss(loss_cfg)
# test that cls_score.size(-1) == num_classes
loss_cls_cfg = dict(
type='SeesawLoss', p=0.0, q=0.0, loss_weight=1.0, num_classes=2)
loss_cls = build_loss(loss_cls_cfg)
# the length of fake_pred should be num_classe = 4
with pytest.raises(AssertionError):
fake_pred = torch.Tensor([[-100, 100, -100]])
fake_label = torch.Tensor([1]).long()
loss_cls(fake_pred, fake_label)
# the length of fake_pred should be num_classes + 2 = 4
with pytest.raises(AssertionError):
fake_pred = torch.Tensor([[-100, 100, -100, 100]])
fake_label = torch.Tensor([1]).long()
loss_cls(fake_pred, fake_label)
# test the calculation without p and q
loss_cls_cfg = dict(
type='SeesawLoss', p=0.0, q=0.0, loss_weight=1.0, num_classes=2)
loss_cls = build_loss(loss_cls_cfg)
fake_pred = torch.Tensor([[-100, 100]])
fake_label = torch.Tensor([1]).long()
loss = loss_cls(fake_pred, fake_label)
assert torch.allclose(loss, torch.tensor(0.))
# test the calculation with p and without q
loss_cls_cfg = dict(
type='SeesawLoss', p=1.0, q=0.0, loss_weight=1.0, num_classes=2)
loss_cls = build_loss(loss_cls_cfg)
fake_pred = torch.Tensor([[-100, 100]])
fake_label = torch.Tensor([0]).long()
loss_cls.cum_samples[0] = torch.exp(torch.Tensor([20]))
loss = loss_cls(fake_pred, fake_label)
assert torch.allclose(loss, torch.tensor(180.))
# test the calculation with q and without p
loss_cls_cfg = dict(
type='SeesawLoss', p=0.0, q=1.0, loss_weight=1.0, num_classes=2)
loss_cls = build_loss(loss_cls_cfg)
fake_pred = torch.Tensor([[-100, 100]])
fake_label = torch.Tensor([0]).long()
loss = loss_cls(fake_pred, fake_label)
assert torch.allclose(loss, torch.tensor(200.) + torch.tensor(100.).log())
# Copyright (c) OpenMMLab. All rights reserved.
from functools import partial
import pytest
import torch
from mmcls.core import average_performance, mAP
from mmcls.models.losses.accuracy import Accuracy, accuracy_numpy
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)
def test_accuracy():
pred_tensor = torch.tensor([[0.1, 0.2, 0.4], [0.2, 0.5, 0.3],
[0.4, 0.3, 0.1], [0.8, 0.9, 0.0]])
target_tensor = torch.tensor([2, 0, 0, 0])
pred_array = pred_tensor.numpy()
target_array = target_tensor.numpy()
acc_top1 = 50.
acc_top2 = 75.
compute_acc = Accuracy(topk=1)
assert compute_acc(pred_tensor, target_tensor) == acc_top1
assert compute_acc(pred_array, target_array) == acc_top1
compute_acc = Accuracy(topk=(1, ))
assert compute_acc(pred_tensor, target_tensor)[0] == acc_top1
assert compute_acc(pred_array, target_array)[0] == acc_top1
compute_acc = Accuracy(topk=(1, 2))
assert compute_acc(pred_tensor, target_array)[0] == acc_top1
assert compute_acc(pred_tensor, target_tensor)[1] == acc_top2
assert compute_acc(pred_array, target_array)[0] == acc_top1
assert compute_acc(pred_array, target_array)[1] == acc_top2
with pytest.raises(AssertionError):
compute_acc(pred_tensor, 'other_type')
# test accuracy_numpy
compute_acc = partial(accuracy_numpy, topk=(1, 2))
assert compute_acc(pred_array, target_array)[0] == acc_top1
assert compute_acc(pred_array, target_array)[1] == acc_top2
# Copyright (c) OpenMMLab. All rights reserved.
import pytest
import torch
from mmcls.models.losses.utils import convert_to_one_hot
def ori_convert_to_one_hot(targets: torch.Tensor, classes) -> torch.Tensor:
assert (torch.max(targets).item() <
classes), 'Class Index must be less than number of classes'
one_hot_targets = torch.zeros((targets.shape[0], classes),
dtype=torch.long,
device=targets.device)
one_hot_targets.scatter_(1, targets.long(), 1)
return one_hot_targets
def test_convert_to_one_hot():
# label should smaller than classes
targets = torch.tensor([1, 2, 3, 8, 5])
classes = 5
with pytest.raises(AssertionError):
_ = convert_to_one_hot(targets, classes)
# test with original impl
classes = 10
targets = torch.randint(high=classes, size=(10, 1))
ori_one_hot_targets = torch.zeros((targets.shape[0], classes),
dtype=torch.long,
device=targets.device)
ori_one_hot_targets.scatter_(1, targets.long(), 1)
one_hot_targets = convert_to_one_hot(targets, classes)
assert torch.equal(ori_one_hot_targets, one_hot_targets)
# test cuda version
@pytest.mark.skipif(
not torch.cuda.is_available(), reason='requires CUDA support')
def test_convert_to_one_hot_cuda():
# test with original impl
classes = 10
targets = torch.randint(high=classes, size=(10, 1)).cuda()
ori_one_hot_targets = torch.zeros((targets.shape[0], classes),
dtype=torch.long,
device=targets.device)
ori_one_hot_targets.scatter_(1, targets.long(), 1)
one_hot_targets = convert_to_one_hot(targets, classes)
assert torch.equal(ori_one_hot_targets, one_hot_targets)
assert ori_one_hot_targets.device == one_hot_targets.device
# Copyright (c) OpenMMLab. All rights reserved.
from copy import deepcopy
import pytest
import torch
from torch.nn.modules import GroupNorm
from torch.nn.modules.batchnorm import _BatchNorm
from mmcls.models.backbones import Conformer
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_conformer_backbone():
cfg_ori = dict(
arch='T',
drop_path_rate=0.1,
)
with pytest.raises(AssertionError):
# test invalid arch
cfg = deepcopy(cfg_ori)
cfg['arch'] = 'unknown'
Conformer(**cfg)
with pytest.raises(AssertionError):
# test arch without essential keys
cfg = deepcopy(cfg_ori)
cfg['arch'] = {'embed_dims': 24, 'channel_ratio': 6, 'num_heads': 9}
Conformer(**cfg)
# Test Conformer small model with patch size of 16
model = Conformer(**cfg_ori)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), True)
imgs = torch.randn(3, 3, 224, 224)
conv_feature, transformer_feature = model(imgs)[-1]
assert conv_feature.shape == (3, 64 * 1 * 4
) # base_channels * channel_ratio * 4
assert transformer_feature.shape == (3, 384)
# Test Conformer with irregular input size.
model = Conformer(**cfg_ori)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), True)
imgs = torch.randn(3, 3, 241, 241)
conv_feature, transformer_feature = model(imgs)[-1]
assert conv_feature.shape == (3, 64 * 1 * 4
) # base_channels * channel_ratio * 4
assert transformer_feature.shape == (3, 384)
imgs = torch.randn(3, 3, 321, 221)
conv_feature, transformer_feature = model(imgs)[-1]
assert conv_feature.shape == (3, 64 * 1 * 4
) # base_channels * channel_ratio * 4
assert transformer_feature.shape == (3, 384)
# Test custom arch Conformer without output cls token
cfg = deepcopy(cfg_ori)
cfg['arch'] = {
'embed_dims': 128,
'depths': 15,
'num_heads': 16,
'channel_ratio': 3,
}
cfg['with_cls_token'] = False
cfg['base_channels'] = 32
model = Conformer(**cfg)
conv_feature, transformer_feature = model(imgs)[-1]
assert conv_feature.shape == (3, 32 * 3 * 4)
assert transformer_feature.shape == (3, 128)
# Test Conformer with multi out indices
cfg = deepcopy(cfg_ori)
cfg['out_indices'] = [4, 8, 12]
model = Conformer(**cfg)
outs = model(imgs)
assert len(outs) == 3
# stage 1
conv_feature, transformer_feature = outs[0]
assert conv_feature.shape == (3, 64 * 1)
assert transformer_feature.shape == (3, 384)
# stage 2
conv_feature, transformer_feature = outs[1]
assert conv_feature.shape == (3, 64 * 1 * 2)
assert transformer_feature.shape == (3, 384)
# stage 3
conv_feature, transformer_feature = outs[2]
assert conv_feature.shape == (3, 64 * 1 * 4)
assert transformer_feature.shape == (3, 384)
# Copyright (c) OpenMMLab. All rights reserved.
import pytest
import torch
from mmcls.models.backbones import ConvMixer
def test_assertion():
with pytest.raises(AssertionError):
ConvMixer(arch='unknown')
with pytest.raises(AssertionError):
# ConvMixer arch dict should include essential_keys,
ConvMixer(arch=dict(channels=[2, 3, 4, 5]))
with pytest.raises(AssertionError):
# ConvMixer out_indices should be valid depth.
ConvMixer(out_indices=-100)
def test_convmixer():
# Test forward
model = ConvMixer(arch='768/32')
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 1
assert feat[0].shape == torch.Size([1, 768, 32, 32])
# Test forward with multiple outputs
model = ConvMixer(arch='768/32', out_indices=range(32))
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 32
for f in feat:
assert f.shape == torch.Size([1, 768, 32, 32])
# Test with custom arch
model = ConvMixer(
arch={
'embed_dims': 99,
'depth': 5,
'patch_size': 5,
'kernel_size': 9
},
out_indices=range(5))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 5
for f in feat:
assert f.shape == torch.Size([1, 99, 44, 44])
# Test with even kernel size arch
model = ConvMixer(arch={
'embed_dims': 99,
'depth': 5,
'patch_size': 5,
'kernel_size': 8
})
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 1
assert feat[0].shape == torch.Size([1, 99, 44, 44])
# Test frozen_stages
model = ConvMixer(arch='768/32', frozen_stages=10)
model.init_weights()
model.train()
for i in range(10):
assert not model.stages[i].training
for i in range(10, 32):
assert model.stages[i].training
# Copyright (c) OpenMMLab. All rights reserved.
import pytest
import torch
from mmcls.models.backbones import ConvNeXt
def test_assertion():
with pytest.raises(AssertionError):
ConvNeXt(arch='unknown')
with pytest.raises(AssertionError):
# ConvNeXt arch dict should include 'embed_dims',
ConvNeXt(arch=dict(channels=[2, 3, 4, 5]))
with pytest.raises(AssertionError):
# ConvNeXt arch dict should include 'embed_dims',
ConvNeXt(arch=dict(depths=[2, 3, 4], channels=[2, 3, 4, 5]))
def test_convnext():
# Test forward
model = ConvNeXt(arch='tiny', out_indices=-1)
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 1
assert feat[0].shape == torch.Size([1, 768])
# Test forward with multiple outputs
model = ConvNeXt(arch='small', out_indices=(0, 1, 2, 3))
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size([1, 96])
assert feat[1].shape == torch.Size([1, 192])
assert feat[2].shape == torch.Size([1, 384])
assert feat[3].shape == torch.Size([1, 768])
# Test with custom arch
model = ConvNeXt(
arch={
'depths': [2, 3, 4, 5, 6],
'channels': [16, 32, 64, 128, 256]
},
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 == torch.Size([1, 16])
assert feat[1].shape == torch.Size([1, 32])
assert feat[2].shape == torch.Size([1, 64])
assert feat[3].shape == torch.Size([1, 128])
assert feat[4].shape == torch.Size([1, 256])
# Test without gap before final norm
model = ConvNeXt(
arch='small', out_indices=(0, 1, 2, 3), gap_before_final_norm=False)
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size([1, 96, 56, 56])
assert feat[1].shape == torch.Size([1, 192, 28, 28])
assert feat[2].shape == torch.Size([1, 384, 14, 14])
assert feat[3].shape == torch.Size([1, 768, 7, 7])
# Test frozen_stages
model = ConvNeXt(arch='small', out_indices=(0, 1, 2, 3), frozen_stages=2)
model.init_weights()
model.train()
for i in range(2):
assert not model.downsample_layers[i].training
assert not model.stages[i].training
for i in range(2, 4):
assert model.downsample_layers[i].training
assert model.stages[i].training
# Copyright (c) OpenMMLab. All rights reserved.
from copy import deepcopy
from functools import partial
from unittest import TestCase
import torch
from mmcv.cnn import ConvModule
from mmcv.utils.parrots_wrapper import _BatchNorm
from mmcls.models.backbones import CSPDarkNet, CSPResNet, CSPResNeXt
from mmcls.models.backbones.cspnet import (CSPNet, DarknetBottleneck,
ResNetBottleneck, ResNeXtBottleneck)
class TestCSPNet(TestCase):
def setUp(self):
self.arch = dict(
block_fn=(DarknetBottleneck, ResNetBottleneck, ResNeXtBottleneck),
in_channels=(32, 64, 128),
out_channels=(64, 128, 256),
num_blocks=(1, 2, 8),
expand_ratio=(2, 1, 1),
bottle_ratio=(3, 1, 1),
has_downsampler=True,
down_growth=True,
block_args=({}, {}, dict(base_channels=32)))
self.stem_fn = partial(torch.nn.Conv2d, out_channels=32, kernel_size=3)
def test_structure(self):
# Test with attribute arch_setting.
model = CSPNet(arch=self.arch, stem_fn=self.stem_fn, out_indices=[-1])
self.assertEqual(len(model.stages), 3)
self.assertEqual(type(model.stages[0].blocks[0]), DarknetBottleneck)
self.assertEqual(type(model.stages[1].blocks[0]), ResNetBottleneck)
self.assertEqual(type(model.stages[2].blocks[0]), ResNeXtBottleneck)
class TestCSPDarkNet(TestCase):
def setUp(self):
self.class_name = CSPDarkNet
self.cfg = dict(depth=53)
self.out_channels = [64, 128, 256, 512, 1024]
self.all_out_indices = [0, 1, 2, 3, 4]
self.frozen_stages = 2
self.stem_down = (1, 1)
self.num_stages = 5
def test_structure(self):
# Test invalid default depths
with self.assertRaisesRegex(AssertionError, 'depth must be one of'):
cfg = deepcopy(self.cfg)
cfg['depth'] = 'unknown'
self.class_name(**cfg)
# Test out_indices
cfg = deepcopy(self.cfg)
cfg['out_indices'] = {1: 1}
with self.assertRaisesRegex(AssertionError, "get <class 'dict'>"):
self.class_name(**cfg)
cfg['out_indices'] = [0, 13]
with self.assertRaisesRegex(AssertionError, 'Invalid out_indices 13'):
self.class_name(**cfg)
# Test model structure
cfg = deepcopy(self.cfg)
model = self.class_name(**cfg)
self.assertEqual(len(model.stages), self.num_stages)
def test_forward(self):
imgs = torch.randn(3, 3, 224, 224)
# test without output_cls_token
cfg = deepcopy(self.cfg)
model = self.class_name(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 1)
self.assertEqual(outs[-1].size(), (3, self.out_channels[-1], 7, 7))
# Test forward with multi out indices
cfg = deepcopy(self.cfg)
cfg['out_indices'] = self.all_out_indices
model = self.class_name(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), len(self.all_out_indices))
w, h = 224 / self.stem_down[0], 224 / self.stem_down[1]
for i, out in enumerate(outs):
self.assertEqual(
out.size(),
(3, self.out_channels[i], w // 2**(i + 1), h // 2**(i + 1)))
# Test frozen stages
cfg = deepcopy(self.cfg)
cfg['frozen_stages'] = self.frozen_stages
model = self.class_name(**cfg)
model.init_weights()
model.train()
assert model.stem.training is False
for param in model.stem.parameters():
assert param.requires_grad is False
for i in range(self.frozen_stages + 1):
stage = model.stages[i]
for mod in stage.modules():
if isinstance(mod, _BatchNorm):
assert mod.training is False, i
for param in stage.parameters():
assert param.requires_grad is False
class TestCSPResNet(TestCSPDarkNet):
def setUp(self):
self.class_name = CSPResNet
self.cfg = dict(depth=50)
self.out_channels = [128, 256, 512, 1024]
self.all_out_indices = [0, 1, 2, 3]
self.frozen_stages = 2
self.stem_down = (2, 2)
self.num_stages = 4
def test_deep_stem(self, ):
cfg = deepcopy(self.cfg)
cfg['deep_stem'] = True
model = self.class_name(**cfg)
self.assertEqual(len(model.stem), 3)
for i in range(3):
self.assertEqual(type(model.stem[i]), ConvModule)
class TestCSPResNeXt(TestCSPDarkNet):
def setUp(self):
self.class_name = CSPResNeXt
self.cfg = dict(depth=50)
self.out_channels = [256, 512, 1024, 2048]
self.all_out_indices = [0, 1, 2, 3]
self.frozen_stages = 2
self.stem_down = (2, 2)
self.num_stages = 4
if __name__ == '__main__':
import unittest
unittest.main()
# Copyright (c) OpenMMLab. All rights reserved.
import math
import os
import tempfile
from copy import deepcopy
from unittest import TestCase
import torch
from mmcv.runner import load_checkpoint, save_checkpoint
from mmcls.models.backbones import DistilledVisionTransformer
from .utils import timm_resize_pos_embed
class TestDeiT(TestCase):
def setUp(self):
self.cfg = dict(
arch='deit-base', img_size=224, patch_size=16, drop_rate=0.1)
def test_init_weights(self):
# test weight init cfg
cfg = deepcopy(self.cfg)
cfg['init_cfg'] = [
dict(
type='Kaiming',
layer='Conv2d',
mode='fan_in',
nonlinearity='linear')
]
model = DistilledVisionTransformer(**cfg)
ori_weight = model.patch_embed.projection.weight.clone().detach()
# The pos_embed is all zero before initialize
self.assertTrue(torch.allclose(model.dist_token, torch.tensor(0.)))
model.init_weights()
initialized_weight = model.patch_embed.projection.weight
self.assertFalse(torch.allclose(ori_weight, initialized_weight))
self.assertFalse(torch.allclose(model.dist_token, torch.tensor(0.)))
# test load checkpoint
pretrain_pos_embed = model.pos_embed.clone().detach()
tmpdir = tempfile.gettempdir()
checkpoint = os.path.join(tmpdir, 'test.pth')
save_checkpoint(model, checkpoint)
cfg = deepcopy(self.cfg)
model = DistilledVisionTransformer(**cfg)
load_checkpoint(model, checkpoint, strict=True)
self.assertTrue(torch.allclose(model.pos_embed, pretrain_pos_embed))
# test load checkpoint with different img_size
cfg = deepcopy(self.cfg)
cfg['img_size'] = 384
model = DistilledVisionTransformer(**cfg)
load_checkpoint(model, checkpoint, strict=True)
resized_pos_embed = timm_resize_pos_embed(
pretrain_pos_embed, model.pos_embed, num_tokens=2)
self.assertTrue(torch.allclose(model.pos_embed, resized_pos_embed))
os.remove(checkpoint)
def test_forward(self):
imgs = torch.randn(3, 3, 224, 224)
# test with_cls_token=False
cfg = deepcopy(self.cfg)
cfg['with_cls_token'] = False
cfg['output_cls_token'] = True
with self.assertRaisesRegex(AssertionError, 'but got False'):
DistilledVisionTransformer(**cfg)
cfg = deepcopy(self.cfg)
cfg['with_cls_token'] = False
cfg['output_cls_token'] = False
model = DistilledVisionTransformer(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 1)
patch_token = outs[-1]
self.assertEqual(patch_token.shape, (3, 768, 14, 14))
# test with output_cls_token
cfg = deepcopy(self.cfg)
model = DistilledVisionTransformer(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 1)
patch_token, cls_token, dist_token = outs[-1]
self.assertEqual(patch_token.shape, (3, 768, 14, 14))
self.assertEqual(cls_token.shape, (3, 768))
self.assertEqual(dist_token.shape, (3, 768))
# test without output_cls_token
cfg = deepcopy(self.cfg)
cfg['output_cls_token'] = False
model = DistilledVisionTransformer(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 1)
patch_token = outs[-1]
self.assertEqual(patch_token.shape, (3, 768, 14, 14))
# Test forward with multi out indices
cfg = deepcopy(self.cfg)
cfg['out_indices'] = [-3, -2, -1]
model = DistilledVisionTransformer(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 3)
for out in outs:
patch_token, cls_token, dist_token = out
self.assertEqual(patch_token.shape, (3, 768, 14, 14))
self.assertEqual(cls_token.shape, (3, 768))
self.assertEqual(dist_token.shape, (3, 768))
# Test forward with dynamic input size
imgs1 = torch.randn(3, 3, 224, 224)
imgs2 = torch.randn(3, 3, 256, 256)
imgs3 = torch.randn(3, 3, 256, 309)
cfg = deepcopy(self.cfg)
model = DistilledVisionTransformer(**cfg)
for imgs in [imgs1, imgs2, imgs3]:
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 1)
patch_token, cls_token, dist_token = outs[-1]
expect_feat_shape = (math.ceil(imgs.shape[2] / 16),
math.ceil(imgs.shape[3] / 16))
self.assertEqual(patch_token.shape, (3, 768, *expect_feat_shape))
self.assertEqual(cls_token.shape, (3, 768))
self.assertEqual(dist_token.shape, (3, 768))
# Copyright (c) OpenMMLab. All rights reserved.
import pytest
import torch
from mmcls.models.backbones import DenseNet
def test_assertion():
with pytest.raises(AssertionError):
DenseNet(arch='unknown')
with pytest.raises(AssertionError):
# DenseNet arch dict should include essential_keys,
DenseNet(arch=dict(channels=[2, 3, 4, 5]))
with pytest.raises(AssertionError):
# DenseNet out_indices should be valid depth.
DenseNet(out_indices=-100)
def test_DenseNet():
# Test forward
model = DenseNet(arch='121')
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 1
assert feat[0].shape == torch.Size([1, 1024, 7, 7])
# Test memory efficient option
model = DenseNet(arch='121', memory_efficient=True)
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 1
assert feat[0].shape == torch.Size([1, 1024, 7, 7])
# Test drop rate
model = DenseNet(arch='121', drop_rate=0.05)
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 1
assert feat[0].shape == torch.Size([1, 1024, 7, 7])
# Test forward with multiple outputs
model = DenseNet(arch='121', out_indices=(0, 1, 2, 3))
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 4
assert feat[0].shape == torch.Size([1, 128, 28, 28])
assert feat[1].shape == torch.Size([1, 256, 14, 14])
assert feat[2].shape == torch.Size([1, 512, 7, 7])
assert feat[3].shape == torch.Size([1, 1024, 7, 7])
# Test with custom arch
model = DenseNet(
arch={
'growth_rate': 20,
'depths': [4, 8, 12, 16, 20],
'init_channels': 40,
},
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 == torch.Size([1, 60, 28, 28])
assert feat[1].shape == torch.Size([1, 110, 14, 14])
assert feat[2].shape == torch.Size([1, 175, 7, 7])
assert feat[3].shape == torch.Size([1, 247, 3, 3])
assert feat[4].shape == torch.Size([1, 647, 3, 3])
# Test frozen_stages
model = DenseNet(arch='121', out_indices=(0, 1, 2, 3), frozen_stages=2)
model.init_weights()
model.train()
for i in range(2):
assert not model.stages[i].training
assert not model.transitions[i].training
for i in range(2, 4):
assert model.stages[i].training
assert model.transitions[i].training
# Copyright (c) OpenMMLab. All rights reserved.
from copy import deepcopy
from unittest import TestCase
import torch
from mmcv.cnn import ConvModule
from torch import nn
from mmcls.models.backbones import EfficientFormer
from mmcls.models.backbones.efficientformer import (AttentionWithBias, Flat,
Meta3D, Meta4D)
from mmcls.models.backbones.poolformer import Pooling
class TestEfficientFormer(TestCase):
def setUp(self):
self.cfg = dict(arch='l1', drop_path_rate=0.1)
self.arch = EfficientFormer.arch_settings['l1']
self.custom_arch = {
'layers': [1, 1, 1, 4],
'embed_dims': [48, 96, 224, 448],
'downsamples': [False, True, True, True],
'vit_num': 2,
}
self.custom_cfg = dict(arch=self.custom_arch)
def test_arch(self):
# Test invalid default arch
with self.assertRaisesRegex(AssertionError, 'Unavailable arch'):
cfg = deepcopy(self.cfg)
cfg['arch'] = 'unknown'
EfficientFormer(**cfg)
# Test invalid custom arch
with self.assertRaisesRegex(AssertionError, 'must have'):
cfg = deepcopy(self.custom_cfg)
cfg['arch'].pop('layers')
EfficientFormer(**cfg)
# Test vit_num < 0
with self.assertRaisesRegex(AssertionError, "'vit_num' must"):
cfg = deepcopy(self.custom_cfg)
cfg['arch']['vit_num'] = -1
EfficientFormer(**cfg)
# Test vit_num > last stage layers
with self.assertRaisesRegex(AssertionError, "'vit_num' must"):
cfg = deepcopy(self.custom_cfg)
cfg['arch']['vit_num'] = 10
EfficientFormer(**cfg)
# Test out_ind
with self.assertRaisesRegex(AssertionError, '"out_indices" must'):
cfg = deepcopy(self.custom_cfg)
cfg['out_indices'] = dict
EfficientFormer(**cfg)
# Test custom arch
cfg = deepcopy(self.custom_cfg)
model = EfficientFormer(**cfg)
self.assertEqual(len(model.patch_embed), 2)
layers = self.custom_arch['layers']
downsamples = self.custom_arch['downsamples']
vit_num = self.custom_arch['vit_num']
for i, stage in enumerate(model.network):
if downsamples[i]:
self.assertIsInstance(stage[0], ConvModule)
self.assertEqual(stage[0].conv.stride, (2, 2))
self.assertTrue(hasattr(stage[0].conv, 'bias'))
self.assertTrue(isinstance(stage[0].bn, nn.BatchNorm2d))
if i < len(model.network) - 1:
self.assertIsInstance(stage[-1], Meta4D)
self.assertIsInstance(stage[-1].token_mixer, Pooling)
self.assertEqual(len(stage) - downsamples[i], layers[i])
elif vit_num > 0:
self.assertIsInstance(stage[-1], Meta3D)
self.assertIsInstance(stage[-1].token_mixer, AttentionWithBias)
self.assertEqual(len(stage) - downsamples[i] - 1, layers[i])
flat_layer_idx = len(stage) - vit_num - downsamples[i]
self.assertIsInstance(stage[flat_layer_idx], Flat)
count = 0
for layer in stage:
if isinstance(layer, Meta3D):
count += 1
self.assertEqual(count, vit_num)
def test_init_weights(self):
# test weight init cfg
cfg = deepcopy(self.cfg)
cfg['init_cfg'] = [
dict(
type='Kaiming',
layer='Conv2d',
mode='fan_in',
nonlinearity='linear'),
dict(type='Constant', layer=['LayerScale'], val=1e-4)
]
model = EfficientFormer(**cfg)
ori_weight = model.patch_embed[0].conv.weight.clone().detach()
ori_ls_weight = model.network[0][-1].ls1.weight.clone().detach()
model.init_weights()
initialized_weight = model.patch_embed[0].conv.weight
initialized_ls_weight = model.network[0][-1].ls1.weight
self.assertFalse(torch.allclose(ori_weight, initialized_weight))
self.assertFalse(torch.allclose(ori_ls_weight, initialized_ls_weight))
def test_forward(self):
imgs = torch.randn(1, 3, 224, 224)
# test last stage output
cfg = deepcopy(self.cfg)
model = EfficientFormer(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 1)
feat = outs[-1]
self.assertEqual(feat.shape, (1, 448, 49))
assert hasattr(model, 'norm3')
assert isinstance(getattr(model, 'norm3'), nn.LayerNorm)
# test multiple output indices
cfg = deepcopy(self.cfg)
cfg['out_indices'] = (0, 1, 2, 3)
cfg['reshape_last_feat'] = True
model = EfficientFormer(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 4)
# Test out features shape
for dim, stride, out in zip(self.arch['embed_dims'], [1, 2, 4, 8],
outs):
self.assertEqual(out.shape, (1, dim, 56 // stride, 56 // stride))
# Test norm layer
for i in range(4):
assert hasattr(model, f'norm{i}')
stage_norm = getattr(model, f'norm{i}')
assert isinstance(stage_norm, nn.GroupNorm)
assert stage_norm.num_groups == 1
# Test vit_num == 0
cfg = deepcopy(self.custom_cfg)
cfg['arch']['vit_num'] = 0
cfg['out_indices'] = (0, 1, 2, 3)
model = EfficientFormer(**cfg)
for i in range(4):
assert hasattr(model, f'norm{i}')
stage_norm = getattr(model, f'norm{i}')
assert isinstance(stage_norm, nn.GroupNorm)
assert stage_norm.num_groups == 1
def test_structure(self):
# test drop_path_rate decay
cfg = deepcopy(self.cfg)
cfg['drop_path_rate'] = 0.2
model = EfficientFormer(**cfg)
layers = self.arch['layers']
for i, block in enumerate(model.network):
expect_prob = 0.2 / (sum(layers) - 1) * i
if hasattr(block, 'drop_path'):
if expect_prob == 0:
self.assertIsInstance(block.drop_path, torch.nn.Identity)
else:
self.assertAlmostEqual(block.drop_path.drop_prob,
expect_prob)
# test with first stage frozen.
cfg = deepcopy(self.cfg)
frozen_stages = 1
cfg['frozen_stages'] = frozen_stages
cfg['out_indices'] = (0, 1, 2, 3)
model = EfficientFormer(**cfg)
model.init_weights()
model.train()
# the patch_embed and first stage should not require grad.
self.assertFalse(model.patch_embed.training)
for param in model.patch_embed.parameters():
self.assertFalse(param.requires_grad)
for i in range(frozen_stages):
module = model.network[i]
for param in module.parameters():
self.assertFalse(param.requires_grad)
for param in model.norm0.parameters():
self.assertFalse(param.requires_grad)
# the second stage should require grad.
for i in range(frozen_stages + 1, 4):
module = model.network[i]
for param in module.parameters():
self.assertTrue(param.requires_grad)
if hasattr(model, f'norm{i}'):
norm = getattr(model, f'norm{i}')
for param in norm.parameters():
self.assertTrue(param.requires_grad)
# Copyright (c) OpenMMLab. All rights reserved.
import pytest
import torch
from torch.nn.modules import GroupNorm
from torch.nn.modules.batchnorm import _BatchNorm
from mmcls.models.backbones import EfficientNet
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_efficientnet_backbone():
archs = ['b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b7', 'b8', 'es', 'em', 'el']
with pytest.raises(TypeError):
# pretrained must be a string path
model = EfficientNet()
model.init_weights(pretrained=0)
with pytest.raises(AssertionError):
# arch must in arc_settings
EfficientNet(arch='others')
for arch in archs:
with pytest.raises(ValueError):
# frozen_stages must less than 7
EfficientNet(arch=arch, frozen_stages=12)
# Test EfficientNet
model = EfficientNet()
model.init_weights()
model.train()
# Test EfficientNet with first stage frozen
frozen_stages = 7
model = EfficientNet(arch='b0', frozen_stages=frozen_stages)
model.init_weights()
model.train()
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 EfficientNet with norm eval
model = EfficientNet(norm_eval=True)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), False)
# Test EfficientNet forward with 'b0' arch
out_channels = [32, 16, 24, 40, 112, 320, 1280]
model = EfficientNet(arch='b0', out_indices=(0, 1, 2, 3, 4, 5, 6))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 7
assert feat[0].shape == torch.Size([1, out_channels[0], 112, 112])
assert feat[1].shape == torch.Size([1, out_channels[1], 112, 112])
assert feat[2].shape == torch.Size([1, out_channels[2], 56, 56])
assert feat[3].shape == torch.Size([1, out_channels[3], 28, 28])
assert feat[4].shape == torch.Size([1, out_channels[4], 14, 14])
assert feat[5].shape == torch.Size([1, out_channels[5], 7, 7])
assert feat[6].shape == torch.Size([1, out_channels[6], 7, 7])
# Test EfficientNet forward with 'b0' arch and GroupNorm
out_channels = [32, 16, 24, 40, 112, 320, 1280]
model = EfficientNet(
arch='b0',
out_indices=(0, 1, 2, 3, 4, 5, 6),
norm_cfg=dict(type='GN', num_groups=2, requires_grad=True))
for m in model.modules():
if is_norm(m):
assert isinstance(m, GroupNorm)
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 7
assert feat[0].shape == torch.Size([1, out_channels[0], 112, 112])
assert feat[1].shape == torch.Size([1, out_channels[1], 112, 112])
assert feat[2].shape == torch.Size([1, out_channels[2], 56, 56])
assert feat[3].shape == torch.Size([1, out_channels[3], 28, 28])
assert feat[4].shape == torch.Size([1, out_channels[4], 14, 14])
assert feat[5].shape == torch.Size([1, out_channels[5], 7, 7])
assert feat[6].shape == torch.Size([1, out_channels[6], 7, 7])
# Test EfficientNet forward with 'es' arch
out_channels = [32, 24, 32, 48, 144, 192, 1280]
model = EfficientNet(arch='es', out_indices=(0, 1, 2, 3, 4, 5, 6))
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 7
assert feat[0].shape == torch.Size([1, out_channels[0], 112, 112])
assert feat[1].shape == torch.Size([1, out_channels[1], 112, 112])
assert feat[2].shape == torch.Size([1, out_channels[2], 56, 56])
assert feat[3].shape == torch.Size([1, out_channels[3], 28, 28])
assert feat[4].shape == torch.Size([1, out_channels[4], 14, 14])
assert feat[5].shape == torch.Size([1, out_channels[5], 7, 7])
assert feat[6].shape == torch.Size([1, out_channels[6], 7, 7])
# Test EfficientNet forward with 'es' arch and GroupNorm
out_channels = [32, 24, 32, 48, 144, 192, 1280]
model = EfficientNet(
arch='es',
out_indices=(0, 1, 2, 3, 4, 5, 6),
norm_cfg=dict(type='GN', num_groups=2, requires_grad=True))
for m in model.modules():
if is_norm(m):
assert isinstance(m, GroupNorm)
model.init_weights()
model.train()
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert len(feat) == 7
assert feat[0].shape == torch.Size([1, out_channels[0], 112, 112])
assert feat[1].shape == torch.Size([1, out_channels[1], 112, 112])
assert feat[2].shape == torch.Size([1, out_channels[2], 56, 56])
assert feat[3].shape == torch.Size([1, out_channels[3], 28, 28])
assert feat[4].shape == torch.Size([1, out_channels[4], 14, 14])
assert feat[5].shape == torch.Size([1, out_channels[5], 7, 7])
assert feat[6].shape == torch.Size([1, out_channels[6], 7, 7])
# Copyright (c) OpenMMLab. All rights reserved.
import math
from copy import deepcopy
from itertools import chain
from unittest import TestCase
import pytest
import torch
from mmcv.utils import digit_version
from mmcv.utils.parrots_wrapper import _BatchNorm
from torch import nn
from mmcls.models.backbones import HorNet
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
@pytest.mark.skipif(
digit_version(torch.__version__) < digit_version('1.7.0'),
reason='torch.fft is not available before 1.7.0')
class TestHorNet(TestCase):
def setUp(self):
self.cfg = dict(
arch='t', drop_path_rate=0.1, gap_before_final_norm=False)
def test_arch(self):
# Test invalid default arch
with self.assertRaisesRegex(AssertionError, 'not in default archs'):
cfg = deepcopy(self.cfg)
cfg['arch'] = 'unknown'
HorNet(**cfg)
# Test invalid custom arch
with self.assertRaisesRegex(AssertionError, 'Custom arch needs'):
cfg = deepcopy(self.cfg)
cfg['arch'] = {
'depths': [1, 1, 1, 1],
'orders': [1, 1, 1, 1],
}
HorNet(**cfg)
# Test custom arch
cfg = deepcopy(self.cfg)
base_dim = 64
depths = [2, 3, 18, 2]
embed_dims = [base_dim, base_dim * 2, base_dim * 4, base_dim * 8]
cfg['arch'] = {
'base_dim':
base_dim,
'depths':
depths,
'orders': [2, 3, 4, 5],
'dw_cfg': [
dict(type='DW', kernel_size=7),
dict(type='DW', kernel_size=7),
dict(type='GF', h=14, w=8),
dict(type='GF', h=7, w=4)
],
}
model = HorNet(**cfg)
for i in range(len(depths)):
stage = model.stages[i]
self.assertEqual(stage[-1].out_channels, embed_dims[i])
self.assertEqual(len(stage), depths[i])
def test_init_weights(self):
# test weight init cfg
cfg = deepcopy(self.cfg)
cfg['init_cfg'] = [
dict(
type='Kaiming',
layer='Conv2d',
mode='fan_in',
nonlinearity='linear')
]
model = HorNet(**cfg)
ori_weight = model.downsample_layers[0][0].weight.clone().detach()
model.init_weights()
initialized_weight = model.downsample_layers[0][0].weight
self.assertFalse(torch.allclose(ori_weight, initialized_weight))
def test_forward(self):
imgs = torch.randn(3, 3, 224, 224)
cfg = deepcopy(self.cfg)
model = HorNet(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 1)
feat = outs[-1]
self.assertEqual(feat.shape, (3, 512, 7, 7))
# test multiple output indices
cfg = deepcopy(self.cfg)
cfg['out_indices'] = (0, 1, 2, 3)
model = HorNet(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 4)
for emb_size, stride, out in zip([64, 128, 256, 512], [1, 2, 4, 8],
outs):
self.assertEqual(out.shape,
(3, emb_size, 56 // stride, 56 // stride))
# test with dynamic input shape
imgs1 = torch.randn(3, 3, 224, 224)
imgs2 = torch.randn(3, 3, 256, 256)
imgs3 = torch.randn(3, 3, 256, 309)
cfg = deepcopy(self.cfg)
model = HorNet(**cfg)
for imgs in [imgs1, imgs2, imgs3]:
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 1)
feat = outs[-1]
expect_feat_shape = (math.floor(imgs.shape[2] / 32),
math.floor(imgs.shape[3] / 32))
self.assertEqual(feat.shape, (3, 512, *expect_feat_shape))
def test_structure(self):
# test drop_path_rate decay
cfg = deepcopy(self.cfg)
cfg['drop_path_rate'] = 0.2
model = HorNet(**cfg)
depths = model.arch_settings['depths']
stages = model.stages
blocks = chain(*[stage for stage in stages])
total_depth = sum(depths)
dpr = [
x.item()
for x in torch.linspace(0, cfg['drop_path_rate'], total_depth)
]
for i, (block, expect_prob) in enumerate(zip(blocks, dpr)):
if expect_prob == 0:
assert isinstance(block.drop_path, nn.Identity)
else:
self.assertAlmostEqual(block.drop_path.drop_prob, expect_prob)
# test VAN with first stage frozen.
cfg = deepcopy(self.cfg)
frozen_stages = 0
cfg['frozen_stages'] = frozen_stages
cfg['out_indices'] = (0, 1, 2, 3)
model = HorNet(**cfg)
model.init_weights()
model.train()
# the patch_embed and first stage should not require grad.
for i in range(frozen_stages + 1):
down = model.downsample_layers[i]
for param in down.parameters():
self.assertFalse(param.requires_grad)
blocks = model.stages[i]
for param in blocks.parameters():
self.assertFalse(param.requires_grad)
# the second stage should require grad.
for i in range(frozen_stages + 1, 4):
down = model.downsample_layers[i]
for param in down.parameters():
self.assertTrue(param.requires_grad)
blocks = model.stages[i]
for param in blocks.parameters():
self.assertTrue(param.requires_grad)
# Copyright (c) OpenMMLab. All rights reserved.
import pytest
import torch
from torch.nn.modules import GroupNorm
from torch.nn.modules.batchnorm import _BatchNorm
from mmcls.models.backbones import HRNet
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
@pytest.mark.parametrize('base_channels', [18, 30, 32, 40, 44, 48, 64])
def test_hrnet_arch_zoo(base_channels):
cfg_ori = dict(arch=f'w{base_channels}')
# Test HRNet model with input size of 224
model = HRNet(**cfg_ori)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), True)
imgs = torch.randn(3, 3, 224, 224)
outs = model(imgs)
out_channels = base_channels
out_size = 56
assert isinstance(outs, tuple)
for out in outs:
assert out.shape == (3, out_channels, out_size, out_size)
out_channels = out_channels * 2
out_size = out_size // 2
def test_hrnet_custom_arch():
cfg_ori = dict(
extra=dict(
stage1=dict(
num_modules=1,
num_branches=1,
block='BOTTLENECK',
num_blocks=(4, ),
num_channels=(64, )),
stage2=dict(
num_modules=1,
num_branches=2,
block='BASIC',
num_blocks=(4, 4),
num_channels=(32, 64)),
stage3=dict(
num_modules=4,
num_branches=3,
block='BOTTLENECK',
num_blocks=(4, 4, 2),
num_channels=(32, 64, 128)),
stage4=dict(
num_modules=3,
num_branches=4,
block='BASIC',
num_blocks=(4, 3, 4, 4),
num_channels=(32, 64, 152, 256)),
), )
# Test HRNet model with input size of 224
model = HRNet(**cfg_ori)
model.init_weights()
model.train()
assert check_norm_state(model.modules(), True)
imgs = torch.randn(3, 3, 224, 224)
outs = model(imgs)
out_channels = (32, 64, 152, 256)
out_size = 56
assert isinstance(outs, tuple)
for out, out_channel in zip(outs, out_channels):
assert out.shape == (3, out_channel, out_size, out_size)
out_size = out_size // 2
# Copyright (c) OpenMMLab. All rights reserved.
from copy import deepcopy
from unittest import TestCase
import torch
from torch.nn.modules import GroupNorm
from torch.nn.modules.batchnorm import _BatchNorm
from mmcls.models.backbones import MlpMixer
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
class TestMLPMixer(TestCase):
def setUp(self):
self.cfg = dict(
arch='b',
img_size=224,
patch_size=16,
drop_rate=0.1,
init_cfg=[
dict(
type='Kaiming',
layer='Conv2d',
mode='fan_in',
nonlinearity='linear')
])
def test_arch(self):
# Test invalid default arch
with self.assertRaisesRegex(AssertionError, 'not in default archs'):
cfg = deepcopy(self.cfg)
cfg['arch'] = 'unknown'
MlpMixer(**cfg)
# Test invalid custom arch
with self.assertRaisesRegex(AssertionError, 'Custom arch needs'):
cfg = deepcopy(self.cfg)
cfg['arch'] = {
'embed_dims': 24,
'num_layers': 16,
'tokens_mlp_dims': 4096
}
MlpMixer(**cfg)
# Test custom arch
cfg = deepcopy(self.cfg)
cfg['arch'] = {
'embed_dims': 128,
'num_layers': 6,
'tokens_mlp_dims': 256,
'channels_mlp_dims': 1024
}
model = MlpMixer(**cfg)
self.assertEqual(model.embed_dims, 128)
self.assertEqual(model.num_layers, 6)
for layer in model.layers:
self.assertEqual(layer.token_mix.feedforward_channels, 256)
self.assertEqual(layer.channel_mix.feedforward_channels, 1024)
def test_init_weights(self):
# test weight init cfg
cfg = deepcopy(self.cfg)
cfg['init_cfg'] = [
dict(
type='Kaiming',
layer='Conv2d',
mode='fan_in',
nonlinearity='linear')
]
model = MlpMixer(**cfg)
ori_weight = model.patch_embed.projection.weight.clone().detach()
model.init_weights()
initialized_weight = model.patch_embed.projection.weight
self.assertFalse(torch.allclose(ori_weight, initialized_weight))
def test_forward(self):
imgs = torch.randn(3, 3, 224, 224)
# test forward with single out indices
cfg = deepcopy(self.cfg)
model = MlpMixer(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 1)
feat = outs[-1]
self.assertEqual(feat.shape, (3, 768, 196))
# test forward with multi out indices
cfg = deepcopy(self.cfg)
cfg['out_indices'] = [-3, -2, -1]
model = MlpMixer(**cfg)
outs = model(imgs)
self.assertIsInstance(outs, tuple)
self.assertEqual(len(outs), 3)
for feat in outs:
self.assertEqual(feat.shape, (3, 768, 196))
# test with invalid input shape
imgs2 = torch.randn(3, 3, 256, 256)
cfg = deepcopy(self.cfg)
model = MlpMixer(**cfg)
with self.assertRaisesRegex(AssertionError, 'dynamic input shape.'):
model(imgs2)
# Copyright (c) OpenMMLab. All rights reserved.
import pytest
import torch
from torch.nn.modules import GroupNorm
......@@ -154,7 +155,8 @@ def test_mobilenetv2_backbone():
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == torch.Size((1, 2560, 7, 7))
assert len(feat) == 1
assert feat[0].shape == torch.Size((1, 2560, 7, 7))
# Test MobileNetV2 forward with out_indices=None
model = MobileNetV2(widen_factor=1.0)
......@@ -163,7 +165,8 @@ def test_mobilenetv2_backbone():
imgs = torch.randn(1, 3, 224, 224)
feat = model(imgs)
assert feat.shape == torch.Size((1, 1280, 7, 7))
assert len(feat) == 1
assert feat[0].shape == torch.Size((1, 1280, 7, 7))
# Test MobileNetV2 forward with dict(type='ReLU')
model = MobileNetV2(
......
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