[파이토치로 시작하는 딥러닝 기초] 3.1 Convolution Neural Network

이번 글에서는 PyTorch로 Convolution Neural Network 하는 것에 대해서 배워보도록 하겠습니다. 이번 글은 EDWITH에서 진행하는 파이토치로 시작하는 딥러닝 기초를 토대로 하였고 같이 스터디하는 팀원분들의 자료를 바탕으로 작성하였습니다. 

목차

  • Convolution? 
  • Neuron과 Convolution 
  • Pooling 
  • Mnist 구현

1. Convolution 

Convolution Neural Network(CNN)의 구조는 위의 사진과 같습니다. 이미지가 들어오면 Convolutions 작업으로 feature maps를 만들어 내고 Subsampling을 통해서 그 사이즈를 줄입니다. 마찬가지로 Convolutions - Subsampling 작업을 반복하다가 마지막에 Full Connection이라는 작업을 통해서 Output(Fully Connected layer)을 산출합니다. 

Convolution이란, 이미지 위에서 stride 값 만큼 filter(kernel)을 이동시키면서 겹쳐지는 부분의 각 원소의 값을 곱해서 모두 더한 값을 출력으로 하는 연산입니다. Convolved Feature의 첫 번째 칸은 (1x1) + (1x0) + (1x1) + (0x0) + (1x1) + (1x0) + (0x1) + (0x0) + (1x1) = 4의 과정을 통해서 나온 값입니다. 이런 Convolution은 두 가지 장점이 있습니다. 

  • Local Invariance : 국소적으로 비슷하다. convolution filter가 전체이미지를 돌아다니기 때문에, 우리가 찾고자 하는 물체가 어디에 있는지는 알지 못하지만 물체의 정보를 잘 포함하고 있다. 
  • Compositionality : 앞에서 봤던 구조를 의미. 반복적으로 계층 구조를 쌓음 

2. Neuron과 Convolution  

Convolution의 정의에 stride라는 표현이 나오는데, stride는 filter를 한번에 얼마나 이동할 것인가입니다. 아래의 왼쪽 예시에서는 1이고 오른쪽 예시에서는 2인 것을 볼 수 있습니다. stride를 2보다 크게 하는 것은 뒤에서 나오게 되는 Pooling이라는 개념과 같이 데이터 사이즈를 줄이는 것에 있습니다. 가장자리 정보의 손실이 발생하지도 않으면서 특징을 추출하고 같은 정보를 여러 번 선택하지 않으므로 overfitting의 위험도 떨어집니다. 

padding은 input이미지의 가장자리에 값을 채워넣는 것을 의미합니다. 

위의 Image처럼 가장자리에 0으로 채워넣는 것을 zero-padding이라 합니다. 이렇게 되면 장점이 3가지가 있습니다. 

  • 가장자리에 있던 정보의 손실이 사라진다. zero padding을 하지 않으면 사이즈가 계속 줄어들면서 가장자리의 정보가 줄어든다. 
  • Convolved Feature의 크기가 줄어들지 않는다. (이미지의 경우 구조 자체가 중요할 수 있기에 구조가 바뀌지 않는다는 것이 큰 장점) 
  • 0이라는 값을 Feature에 반영시켜서 Overfitting을 방지 
  • 참고 : zero-padding을 하지 않으면 이미지가 줄어들면서 가장자리의 정보가 손실되지만, stride의 경우는 가장자리의 정보가 손실되는 것은 아님 

  • input type : torch.Tensor 
  • input shape : (N x C x H x W) = (batch_size, channel, height, width) 

위에서 배운 내용을 한번 정리해보면, 주황색 (3x3x3) filter(3x4x4)의 batch를 돌면서 빨간색의 특징을 추출하게 됩니다. Output size는 위의 식처럼 ((4x4) - (3x3) + (2))/1 + 1 = (4x4)가 나오고 마지막 7은 filter의 갯수를 의미합니다. (주황색 filter가 7개가 있음) 참고로 parameter의 수는 3x3x3x7(filter x filter 수)으로 189입니다. 

3. Pooling (subsampling) 

처음 CNN의 구조를 다시 살펴보면 Convolution의 과정 이후에 Subsampling이라는 과정이 있습니다. 이러한 subsampling은 아래의 사진처럼 이미지의 특징을 보존하면서 크기를 줄여주는 역할을 합니다. 

출처 : https://www.slideshare.net/agdatalab/deep-learning-convolutional-neural-network

Pooling을 해주는 방법으로는 크게 2가지가 있습니다. 평균적인 정보를 담는 Average pooling과 가장 큰 정보를 담는 max pooling입니다. 이러한 Pooling은 차원을 축소하는 것뿐만 아니라 Overfitting을 방지하는 장점도 있습니다. Stride도 비슷한 역할을 하지만 차이점은 Pooling은 모든 정보를 가진 채 정보를 희석한다는 점이 다릅니다. 

4. Mnist CNN

# CNN Model
class CNN(torch.nn.Module):

    def __init__(self):
        super(CNN, self).__init__()
        self.keep_prob = 0.5
        # L1 ImgIn shape=(?, 28, 28, 1)
        #    Conv     -> (?, 28, 28, 32)
        #    Pool     -> (?, 14, 14, 32)
        self.layer1 = torch.nn.Sequential(
            torch.nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2, stride=2))
        # L2 ImgIn shape=(?, 14, 14, 32)
        #    Conv      ->(?, 14, 14, 64)
        #    Pool      ->(?, 7, 7, 64)
        self.layer2 = torch.nn.Sequential(
            torch.nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2, stride=2))
        # L3 ImgIn shape=(?, 7, 7, 64)
        #    Conv      ->(?, 7, 7, 128)
        #    Pool      ->(?, 4, 4, 128)
        self.layer3 = torch.nn.Sequential(
            torch.nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2, stride=2, padding=1))

        # L4 FC 4x4x128 inputs -> 625 outputs
        self.fc1 = torch.nn.Linear(4 * 4 * 128, 625, bias=True)
        torch.nn.init.xavier_uniform_(self.fc1.weight)
        self.layer4 = torch.nn.Sequential(
            self.fc1,
            torch.nn.ReLU(),
            torch.nn.Dropout(p=1 - self.keep_prob))
        # L5 Final FC 625 inputs -> 10 outputs
        self.fc2 = torch.nn.Linear(625, 10, bias=True)
        torch.nn.init.xavier_uniform_(self.fc2.weight)

    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = self.layer3(out)
        out = out.view(out.size(0), -1)   # Flatten them for FC
        out = self.layer4(out)
        out = self.fc2(out)
        return out

댓글(0)

Designed by JB FACTORY