컴퓨터비전

컨볼루션 연산(CNN용, pytorch 코드로 보기)

dokpin 2022. 3. 20. 23:07
728x90

컴퓨터 비젼 분야에서 컨볼루션 연산은 2D 데이터인 이미지의 특징(feature)을 구하는데 사용합니다.

컨볼루션 연산으로 구한 이미지의 특징은 이미지 분류(image classification), 물체 검출(object detection),

물체 추적(object tracking), 물체 분할(object segmentation) 등에 활용할 수 있습니다.

 

1. 1채널 2D 컨볼루션

녹색: 픽셀(6*6 이미지에 속함)

노란색: 컨볼루션 필터(3*3)

보라색: 컨볼루션 결과

 

컨볼루션 필터가 이미지의 픽셀들을 순회하면서 컨볼루션 결과(특징맵, 4*4)을 생성합니다.

노란색 필터의 크기를 receptive field라고 하며, 필터의 영역에 해당하는 픽셀들의 정보를 특징으로 나타냅니다.

이는 사람이 이미지의 어느 한 점을 볼 때, 그 점 뿐만 아니라 주위 영역들의 정보까지 함께 보고 판단하는 것과 유사합니다. 컨볼루션 연산을 3*3 필터로 한 번 했을 경우, 3*3 영역의 특징들만 반영하겠지만 컨볼루션 연산을 여러 번 한다면 더 넓은 범위의 픽셀 정보들 까지 특징에 반영됩니다. 따라서 컨볼루션 연산을 많이 사용하는 네트워크 모델이라면 넓은 범위의 세세한 특징까지 반영한 결과를 생성할 것입니다.

 

python 코드로 구현하면 아래와 같습니다.

import torch
import torch.nn as nn

inputs = torch.IntTensor([[[[1, 0, 1, 1, 1, 0], [0, 1, 0, 1, 1, 1], [1, 0, 0, 0, 1, 0], 
                         [1, 1, 0, 1, 1, 0], [1, 1, 0, 0, 0, 1], [1, 0, 1, 1, 0, 1]]]])
print(inputs.shape)

conv = nn.Conv2d(1, 1, 3, padding = 0, stride = 1, bias = False)
conv.weight.data = torch.nn.Parameter(
    torch.Tensor([[[[1, 1, 1],
                    [0, 0, 0],
                    [0, 0, 0]]]])
)

out = conv(inputs.float())
print(out.shape)
print(out.int())

입력 이미지의 값들과 컨볼루션 필터의 값을 그림과 같이 입력합니다.

그리고 Conv2d 함수로 컨볼루션 연산을 적용한 결과를 conv 변수로 받아서 출력합니다.

 

padding을 설정한다면 입력된 이미지와 같은 크기의 특징맵을 만들 수 있습니다.

위와 같이 0으로 테두리를 채우는 방법을 zero padding이라고 합니다.

 

import torch
import torch.nn as nn

inputs = torch.IntTensor([[[[1, 0, 1, 1, 1, 0], [0, 1, 0, 1, 1, 1], [1, 0, 0, 0, 1, 0], 
                         [1, 1, 0, 1, 1, 0], [1, 1, 0, 0, 0, 1], [1, 0, 1, 1, 0, 1]]]])
print(inputs.shape)

conv = nn.Conv2d(1, 1, 3, padding = 1, stride = 1, bias = False)
conv.weight.data = torch.nn.Parameter(
    torch.Tensor([[[[1, 1, 1],
                    [0, 0, 0],
                    [0, 0, 0]]]])
)

out = conv(inputs.float())
print(out.shape)
print(out.int())

Conv2d 함수에서 padding 파라미터를 1로 설정하였습니다. 입력 이미지 바깥 부분의 1칸씩을 0으로 채워넣고 컨볼루션을 진행합니다. 입력과 출력의 크기(가로,세로)가 같게 나옵니다.

 

2. n채널 컨볼루션

https://www.quora.com/How-does-a-convolutional-layer-convert-a-64-channel-input-into-a-3-channel-or-one-channel

입력 영상은 다채널일 경우가 많습니다.

당장 딥러닝 모델의 첫 입력만 봐도 컬러 영상인 3채널입니다.

3채널 입력 이미지에 3채널 필터가 적용되어 1채널 특징맵을 생성합니다.

이러한 3채널 필터가 n개 있으면 n개의 깊이를 가지는 특징맵이 생성됩니다.

 

python 코드로 보면 이러합니다.

import torch
import torch.nn as nn

inputs = torch.IntTensor([[
    [[0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0]],

    [[1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1, 1]],

    [[2, 2, 2, 2, 2, 2],
    [2, 2, 2, 2, 2, 2],
    [2, 2, 2, 2, 2, 2],
    [2, 2, 2, 2, 2, 2],
    [2, 2, 2, 2, 2, 2],
    [2, 2, 2, 2, 2, 2]]
    ]])
print(inputs.shape)
print(inputs)

conv = nn.Conv2d(3, 32, 3, padding = 1, stride = 1, bias = False)

#print(repr(conv.weight))
print(repr(conv.weight.shape))

out = conv(inputs.float())
print(out.shape)

입력은 3채널 6*6 크기의 이미지입니다.([1, 3, 6, 6])

Conv2d 함수에서 첫 번째 인자가 입력 이미지의 채널 크기이고, 두 번째 인자가 출력할 특징의 채널 크기입니다.

32개의 채널로 출력하므로, 32개의 특징이 생성됩니다. 입력되는 이미지의 채널에 맞게 3*3*3 크기의 컨볼루션 필터가 32번 적용되어 32채널 6*6 특징맵이 생성되네요.([1, 32, 6, 6])