보통 이런 코드로 많이 보셨을 것 같은데요. 사실 Convolution은 아래 2가지만 알면 됩니다.
1. 파라미터 세팅
in_channels : 쉽게 생각하면 input으로 들어오는 data의 depth(이미지의 경우 채널) 수 입니다.
kernel_size : Convolution Filter의 크기라고 보면 됩니다. 홀수로 설정하지 않으면 에러가 발생할 수 있습니다. 가로 세로 동일하게 설정합니다. (5로 설정한 경우 5x5)
2. Convolution 연산
Convolution 연산은 위의 이미지처럼 진행됩니다. 32x32x3이 입력 이미지, 5x5x3이 convolution filter라고 보면 되는데요. 이미지와 convolution 필터 간의 내적을 한다고 볼 수 있습니다.
쉽게 설명하면 위의 이미지처럼 5x5x3 영역 안에서 1x1x1의 1개 점을 뽑는 거죠. 입력 이미지 크기가 32x32x3 이고, convolution filter 사이즈가 5x5x3이라면 가로로 이동할 때 index 0부터 몇까지 이동할 수 있을까요? 한번에 한 칸씩 이동한다면 27에서 막힐 겁니다. convolution 필터 사이즈가 5이므로 [27, 28, 29, 30, 31]로 끝이니까요. 그러면 가로 크기는 28이 되겠죠?(0~27) 세로도 마찬가지입니다.
그래서 우측 이미지를 보시면 Convolution 연산 결과 output의 크기가 28x28x1이 된 걸 보실 수 있습니다.
그럼 만약에 아래 코드처럼 (1, 28, 28) shape의 흑백 이미지가 input으로 들어간다고 해보죠. 이 때 아래 코드에서 conv1을 거치게 된다면 output의 shape은 어떻게 될까요? (아래 print 부분)
import torch
import torch.nn as nn
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(in_channels=1, out_channels=5, kernel_size=3, padding=1)
def forward(self, x):
x = self.conv1(x)
print('conv1', x.shape)
return x
if __name__ == '__main__':
model = Net()
model(torch.rand((1, 28, 28)))
.
.
.
정답은 "[5, 28, 28]" 입니다. 혹시 [5, 26, 26] 일거라 생각하셨나요? 저도 처음엔 그렇게 생각했습니다. 하지만 값이 28, 28 인 건 "padding=1" 때문입니다!
padding 값을 0으로 하면 전에 봤던 것처럼 convolution 필터의 output 사이즈가 줄어듭니다.([5, 26, 26]) 하지만 위의 코드에서는 padding 값을 1로 주었기에 시작할 때, 끝날 때(좌우 끝) 1칸씩 패딩이 먹게 됩니다.(맨 위, 맨 아래도 동일) 그래서 2칸씩 더 먹기 때문에 26 → 28이 된 겁니다. 만약 padding 값이 2였다면? 30이 되겠죠.
왜 이런 짓을 하냐구요? padding을 쓰지 않으면 입력 이미지의 가장자리에 중요한 포인트가 있는 경우 그 특징을 잘 쓸 수 없기 때문입니다.
인공지능 엔지니어로서 모델을 계속 쓰다가도 "이걸 설명해봐" 하면 막힐 때가 있습니다. Convolution도 그 중 하나였는데요. 이번에 이론 공부를 다시 하면서 부족했던 부분이 많이 보완되는 것 같습니다. 가짜연구소에서 DSF 프로그램에 참여하게 되어 Datacamp 강의들을 듣고 있는데 도움이 많이 되네요. 아직 1주차인데 앞으로도 더 많이 배울 수 있을 것 같습니다 :)