전공 공부/파이썬 기초

TypeError: new() received an invalid combination of arguments

상솜공방 2023. 9. 20. 11:48
TypeError: new() received an invalid combination of arguments - got (float, int, int, int), but expected one of:
 * (*, torch.device device)
 * (torch.Storage storage)
 * (Tensor other)
 * (tuple of ints size, *, torch.device device)
 * (object data, *, torch.device device)

현재 이미지 인페인팅과 관련된 논문의 코드를 뜯어보며 공부중인데, DeconvResnetBlock을 생성하는 부분에서 위와 같은 오류가 발생했다.

(git link: https://github.com/xcyan/neurips18_hierchical_image_manipulation)

 

DeconvResnetBlock을 생성하는 전체 클래스 코드는 다음과 같다.

class DeconvResnetBlock(nn.Module):
    def __init__(self, in_planes, out_planes, num_layers=1, stride=1, kernel_size=3, norm_fn=None, activation_fn=None):
        super(DeconvResnetBlock, self).__init__()

        #두 함수가 정의되지 않으면 오류 발생
        assert norm_fn
        assert activation_fn
        
        ###############################
        ## Build shortcut connection ##
        ###############################
        if out_planes == in_planes and stride == 1:
            self.shortcut = None
        else:
            self.shortcut = []
            if in_planes != out_planes:
                self.shortcut += [nn.Conv2d(in_planes, out_planes, kernel_size=1),
                                  norm_fn(out_planes)]
            if stride > 1:
                self.shortcut += [nn.Upsample(scale_factor=stride, mode='bilinear')]
            
            self.shortcut = nn.Sequential(*self.shortcut)
            
        ###########################
        ## Build Deep connection ##
        ###########################
        self.deep = []
        if kernel_size % 2 == 1:
            self.build_conv2d_block(in_planes, out_planes, num_layers, stride,
                                    kernel_size, norm_fn, activation_fn)
        else:
            self.build_tconv2d_block(in_planes, out_planes, num_layers, stride,
                                     kernel_size, norm_fn, activation_fn)
        
        self.deep = nn.Sequential(*self.deep)

    def build_conv2d_block(self, in_planes, out_planes, num_layers, stride, kernel_size, norm_fn, activation_fn):
        if stride > 1:
            self.deep.append(nn.Upsample(scale_factor=stride, mode='bilinear'))
        padding = int((kernel_size-1)/2)
        self.deep += [
            activation_fn,
            nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=1, padding=padding), norm_fn(out_planes)]
        for i in range(num_layers-1):
            self.deep += [
                activation_fn,
                nn.Conv2d(out_planes, out_planes, kernel_size=kernel_size, stride=1, padding=padding),
                norm_fn(out_planes)]

    # 전치 합성곱은 업샘플링을 진행한다.
    def build_tconv2d_block(self, in_planes, out_planes, num_layers, stride, kernel_size, norm_fn, activation_fn):
        if stride == 1:
            padding = int(kernel_size/2)
            output_padding = stride
            self.deep += [
                activation_fn,
                nn.ConvTranspose2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,
                                   padding=padding, output_padding=output_padding),
                norm_fn(out_planes)]
        else:
            padding = int((kernel_size-1)/2)
            output_padding = stride - 2
            self.deep += [
                activation_fn,
                nn.ConvTranspose2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,
                                   padding=padding, output_padding=output_padding),
                norm_fn(out_planes)]
        #
        for i in range(num_layers-1):
            padding = int(kernel_size/2)
            self.deep += [
                activation_fn,
                nn.ConvTranspose2d(out_planes, out_planes, kernel_size=kernel_size, stride=1, padding=padding, output_padding=1),
                norm_fn(out_planes)]

    def forward(self, x):
        residual = x
        out = self.deep(x)
        if self.shortcut is not None:
            residual = self.shortcut(residual)
        out = out + residual
        return out

이 클래스를 바탕으로 get_conv_decoder라는 함수를 이용하여 convolution 기반 디코더를 생성한다. 여기서 오류가 발생했다.

def get_conv_decoder(output_nc, skip_layers=None):
    
    input_dim = 256
    output_dim = 128
    num_layers = 3
    dim_list =  [64, 96, 128, 256, 512]
    activation_fn = nn.ReLU(True)
    norm_fn=functools.partial(nn.BatchNorm2d, affine=True)
    
    layers=[]
    
    for i in range(num_layers + 1):
        input_dim=output_dim
        
        if i < 3:
            output_dim = dim_list[num_layers - 1 - i]
        else:
            output_dim = input_dim / 2

        DRBlock = DeconvResnetBlock(in_planes=input_dim, out_planes=output_dim, num_layers=1, stride=2,
                                  kernel_size=4, norm_fn=norm_fn, activation_fn=activation_fn)
        layers.append(DRBlock)

    layers.append(nn.Conv2d(output_dim, output_nc, kernel_size=3, padding=1, stride=1))

    return nn.Sequential(*layers)

며칠동안 구글링하며 디버깅해본 결과, 모델 생성시 입출력 차원에 대한 인수 type이 맞지 않아 위와 같은 오류가 발생한 것이었다.

    for i in range(num_layers + 1):
        input_dim=output_dim
        
        if i < 3:
            output_dim = dim_list[num_layers - 1 - i]
        else:
            #output_dim = input_dim / 2     # type: float
            output_dim = int(input_dim / 2) # type: int

input_dim / 2의 결과값을 int로 형변환 하여 해결했다.

 

나중에 ChatGPT한테 물어보니 한 방에 해결 되더라...

 

깨달은 바:

1. type error를 조심할 것.

2. ChatGPT를 잘 활용하자.

'전공 공부 > 파이썬 기초' 카테고리의 다른 글

make_dataset 함수  (1) 2023.10.02
하위 디렉토리를 모두 순회하는 os.walk()  (0) 2023.10.02
Pycharm에 arguments 넣는 법  (0) 2023.09.19
변수의 구분  (0) 2023.09.13
클래스  (0) 2023.09.13