# 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