새소식

딥러닝, 머신러닝

Fully Connected layer의 문제점과 Convolution 연산 정리

  • -

 

PyTorch로 딥러닝을 배운지 얼마 안됐나요? 아마 이런 코드를 시도때도 없이 봤을 겁니다.

 

self.layer1 = nn.Linear(1100, 100)
self.layer2 = nn.Linear(100, 100)

 

출처 : Nvidia, Fully Connected Layer

 

앞 layer와 뒷 layer가 전부 연결되어있다고 해서 Fully Connected Layer라고 하는데요. 사실 CNN 모델들이나 대부분 잘되는 모델 보면 Fully Connected Layer가 별로 없습니다. 왜 그럴까요?

 

 

Fully Connected Layer는 이런 문제가 있어서 그렇습니다.

  1. 계산 효율성이 떨어짐 : 모든 노드 간의 관계를 다 계산해야 하기 때문
  2. 학습 데이터에 overfitting 될 수 있음 : 모든 노드 간의 관계 계산 → 파라미터가 너무 많아짐 → 모델이 너무 복잡해짐

 

 

그래서 FC layer의 문제를 해결하기 위해 나온 게 Convolution layer 입니다. 

 

images = torch.rand(10, 1, 28, 28)
conv_filters = torch.nn.Conv2d(in_channels=1, out_channels=6, kernel_size=3, stride=3, padding=1)

out_feature = conv_filters(images)

 

보통 이런 코드로 많이 보셨을 것 같은데요. 사실 Convolution은 아래 2가지만 알면 됩니다.

 

 

1. 파라미터 세팅

  • in_channels : 쉽게 생각하면 input으로 들어오는 data의 depth(이미지의 경우 채널) 수 입니다.
  • kernel_size : Convolution Filter의 크기라고 보면 됩니다. 홀수로 설정하지 않으면 에러가 발생할 수 있습니다. 가로 세로 동일하게 설정합니다. (5로 설정한 경우 5x5)

2. Convolution 연산

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주차인데 앞으로도 더 많이 배울 수 있을 것 같습니다 :) 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.