# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
import pytest
import torch
from mmpose.models.necks import PoseWarperNeck
def test_posewarper_neck():
"""Test PoseWarperNeck."""
with pytest.raises(AssertionError):
# test value of trans_conv_kernel
_ = PoseWarperNeck(
out_channels=3,
in_channels=512,
inner_channels=128,
trans_conv_kernel=2)
with pytest.raises(TypeError):
# test type of res_blocks_cfg
_ = PoseWarperNeck(
out_channels=3,
in_channels=512,
inner_channels=128,
res_blocks_cfg=2)
with pytest.raises(AssertionError):
# test value of dilations
neck = PoseWarperNeck(
out_channels=3, in_channels=512, inner_channels=128, dilations=[])
in_channels = 48
out_channels = 17
inner_channels = 128
neck = PoseWarperNeck(
in_channels=in_channels,
out_channels=out_channels,
inner_channels=inner_channels)
with pytest.raises(TypeError):
# the forward require two arguments: inputs and frame_weight
_ = neck(1)
with pytest.raises(AssertionError):
# the inputs to PoseWarperNeck must be list or tuple
_ = neck(1, [0.1])
# test the case when num_frames * batch_size if larger than
# the default value of 'im2col_step' but can not be divided
# by it in mmcv.ops.deform_conv
b_0 = 8 # batch_size
b_1 = 16
h_0 = 4 # image height
h_1 = 2
num_frame_0 = 2
num_frame_1 = 5
# test input format
# B, C, H, W
x0_shape = (b_0, in_channels, h_0, h_0)
x1_shape = (b_1, in_channels, h_1, h_1)
# test concat_tensors case
# at the same time, features output from backbone like ResNet is Tensors
x0_shape = (b_0 * num_frame_0, in_channels, h_0, h_0)
x0 = _demo_inputs(x0_shape, length=1)
frame_weight_0 = np.random.uniform(0, 1, num_frame_0)
# test forward
y = neck(x0, frame_weight_0)
assert y.shape == torch.Size([b_0, out_channels, h_0, h_0])
# test concat_tensors case
# this time, features output from backbone like HRNet
# is list of Tensors rather than Tensors
x0_shape = (b_0 * num_frame_0, in_channels, h_0, h_0)
x0 = _demo_inputs(x0_shape, length=2)
x0 = [x0]
frame_weight_0 = np.random.uniform(0, 1, num_frame_0)
# test forward
y = neck(x0, frame_weight_0)
assert y.shape == torch.Size([b_0, out_channels, h_0, h_0])
# test not concat_tensors case
# at the same time, features output from backbone like ResNet is Tensors
x1_shape = (b_1, in_channels, h_1, h_1)
x1 = _demo_inputs(x1_shape, length=num_frame_1)
frame_weight_1 = np.random.uniform(0, 1, num_frame_1)
# test forward
y = neck(x1, frame_weight_1)
assert y.shape == torch.Size([b_1, out_channels, h_1, h_1])
# test not concat_tensors case
# this time, features output from backbone like HRNet
# is list of Tensors rather than Tensors
x1_shape = (b_1, in_channels, h_1, h_1)
x1 = _demo_inputs(x1_shape, length=2)
x1 = [x1 for _ in range(num_frame_1)]
frame_weight_1 = np.random.uniform(0, 1, num_frame_1)
# test forward
y = neck(x1, frame_weight_1)
assert y.shape == torch.Size([b_1, out_channels, h_1, h_1])
# test special case that when in concat_tensors case,
# batch_size * num_frames is larger than the default value
# 'im2col_step' in mmcv.ops.deform_conv, but can not be divided by it
# see https://github.com/open-mmlab/mmcv/issues/1440
x1_shape = (b_1 * num_frame_1, in_channels, h_1, h_1)
x1 = _demo_inputs(x1_shape, length=2)
x1 = [x1]
frame_weight_0 = np.random.uniform(0, 1, num_frame_1)
y = neck(x1, frame_weight_1)
assert y.shape == torch.Size([b_1, out_channels, h_1, h_1])
# test the inappropriate value of `im2col_step`
neck = PoseWarperNeck(
in_channels=in_channels,
out_channels=out_channels,
inner_channels=inner_channels,
im2col_step=32)
with pytest.raises(AssertionError):
_ = neck(x1, frame_weight_1)
def _demo_inputs(input_shape=(80, 48, 4, 4), length=1):
"""Create a superset of inputs needed to run backbone.
Args:
input_shape (tuple): input batch dimensions.
Default: (1, 3, 64, 64).
length (int): the length of output list
nested (bool): whether the output Tensor is double-nested list.
"""
imgs = [
torch.FloatTensor(np.random.random(input_shape)) for _ in range(length)
]
return imgs