이것저것 기록

[DL, PyTorch] CNN으로 MNIST 분류하기 본문

Data Science/ML & DL

[DL, PyTorch] CNN으로 MNIST 분류하기

anweh 2020. 10. 18. 15:38

사용하는 라이브러리, 데이터셋 로드, 클래스로 모델 설계 등 앞의 포스팅과 겹치는 부분이 많기 때문에 바로 구현 코드로 넘어가는걸로~~ 

 

 

1. 클래스로 CNN 구현

import torch
import torch.nn as nn
import torchvision.datasets 
import torchvision.transforms as transforms
import torch.nn.init 


device = 'cuda' if torch.cuda.is_available() else 'cpu' 
torch.manual_seed(105) 
if device == 'cuda': 
    torch.cuda.manual_seed_all(123)
print('{} is using for calculation...'.format(device))


# Hyperparameters 
lr = 0.001
epochs = 20 
batch_size = 100

mnist_train = torchvision.datasets.MNIST(root = 'MNIST_data/', 
                          train=True, 
                          transform=transforms.ToTensor(), 
                          download=True) 

mnist_test = torchvision.datasets.MNIST(root='MNIST_data/', 
                         train=False, 
                         transform=transforms.ToTensor(), 
                         download=True)
data_loader = torch.utils.data.DataLoader(dataset=mnist_train, 
                                          batch_size=batch_size, 
                                          shuffle=True, 
                                          drop_last=True)


class CNN(torch.nn.Module):

    def __init__(self):
        super(CNN, self).__init__()

        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))

        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))

        self.fc = torch.nn.Linear(7 * 7 * 64, 10, bias=True)

        torch.nn.init.xavier_uniform_(self.fc.weight)

    def forward(self, x):
        
        # print()
        # print('x_size: {}'.format(x.size()))
        out = self.layer1(x)
        # print('after layer1: {}'.format(out.size()))
        out = self.layer2(out)
        # print('after layer2: {}'.format(out.size()))
        out = out.view(out.size(0), -1)   
        # print('transforming to vector: {}'.format(out.size()))
        out = self.fc(out)
        # print('after fc: {}'.format(out.size()))
        # print()        
        
        return out
        
model = CNN().to(device)


criterion = torch.nn.CrossEntropyLoss().to(device)    # 비용 함수에 소프트맥스 함수 포함되어져 있음.
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
total_batch = len(data_loader)
print('총 배치의 수 : {}'.format(total_batch))

각 레이어 별 텐서 크기 변화

 

 

2. 합성곱 신경망이란? 

합성곱 신경망(Convolutional Neural Network; CNN)은 이미지 처리에 탁월한 성능을 보이는 신경망이다. 합성곱 신경망은 크게 합성곱층(Conv Layer)과 풀링층(Pooling Layer)으로 구성되며

위와 같은 구성 조합이 일반적이다. 

 

 

3. 합성곱 연산

합성곱층(Conv Layer)은 합성곱 연산을 통해서 이미지의 특징을 추출하는 역할을 한다. 합성곱이란 커널(또는 필터)라는 n x m 크기의 행렬로 높이(height) x 너비(width) 크기의 이미지를 처음부터 끝까지 훑으면서 n x m 크기의 겹치는 부분의 각 이미지와 커널의 원소값을 곱해서 모두 더한 값으로 출력하는 것을 말한다. 커널은 일반적으로 3 x 3이나 5 x 5를 사용한다. 

무지개색의 레이어들을 특성맵(Feature Map)이라고 하는데, 이 피쳐맵은 위와 같이 입력 이미지로부터 커널을 사용하여 합성곱 연산을 통해 나온 결과들인 것이다. 

다양한 커널을 사용한다는 것은, 어떠한 이미지에 대하여 다양한 특징을 배운다는 말과 같다.

 

 

4. 패딩

일반적으로 합성곱 층을 여러 개 쌓게 되면 최종적으로 얻게 되는 피쳐맵은 입력 이미지보다 점점 작아지게 된다.

합성곱 연산 이후에도 피쳐맵의 크기가 입력 이미지와 동일하게 유지하고 싶을 때 사용하는 것이 패딩이다.

그리고 패딩을 수행함으로써 엣지의 정보를 더 충분히 활용할 수 있게 된다.

입력 이미지의 가장자리 픽셀들은 커널이 한 번씩만 지나가기 때문에 중간 픽셀보다 상대적으로 중요도가 작게 나타난다. (피쳐맵에)

하지만 패딩을 더해주면 기존의 가장자리 픽셀들이 안으로 들어오게 되면서, 가장자리 픽셀들을 충분히 활용할 수 있게 되는 것이다.

 

 

5. 가중치와 편향

합성곱 신경망에서 가중치는 커널행렬의 원소들이다. 아래의 사진에서 알 수 있다싶이 합성곱 연산이 우측의 인공 신경망 (다층 퍼셉트론 혹은 단층 퍼셉트론)보다 훨씬 적은 양의 가중치를 사용한다는 것을 알 수 있다.

합성곱 연산에서 이미지 전체를 훑으면서 사용되는 가중치는 w0w1w2w3 4개 뿐이다.

그리고 각 합성곱 연산마다 이미지의 모든 픽셀을 사용하는 것이 아니라, 커널과 맵핑되는 픽셀만을 입력으로 사용하는 것을 볼 수 있다.

결국 합성곱 신경망은 다층 퍼셉트론을 사용할 때보다 훨씬 적은 수의 가중치를 사용하며 공간적 구조 정보를 보존한다는 특징이 있다는 것을 알 수 있다. 

그리고 합성곱 신경망의 은닉층에서도 다층 퍼셉트론과 마찬가지로, 비선형성을 추가하기 위해 활성화 함수를 통과시키게 된다.

이와 같이 합성곱 연산을 통해 피쳐맵을 얻고, 활성화 함수를 지나는 연산을 하는 합성곱 신경망의 은닉층을 합성곱 신경망에선 합성곱 층이라고 한다. 

다시 말해, Conv Layer에선 합성곱 연산 >> 활성화 함수 의 두 가지 프로세스를 거치게 된다는 것이다. 

 

 

6. 특성맵의 크기

 

 

7. 다수의 채널을 가질 때 합성곱 연산 

백마디 말보다 아래의 그림 하나가 더 설명을 잘해주는 듯.. (출처: ardino.tistory.com/39)

다수의 채널을 가질 때 합성곱 연산은 세개의 커널(채널)에 각각 합성곱 연산을 적용한 뒤에 얻은 결과 값을 같은 위치의 원소들끼리 더하기만 하면 (element-wise sum) 된다. 

 

 

8. 3차원 텐서의 합성곱 연산

3차원 텐서의 합성곱 연산

출처: wikidocs.net/62306

 

 

9. 풀링

일반적으로 합성곱층(합성곱 연산 + 활성화 함수) 다음에는 풀링층을 추가한다. 풀링층에선느 피쳐맵을 다운샘플링하여 피쳐맵의 크기를 줄이는 풀링 연산이 이루어진다. 풀링 연산의 종류에는 최대 풀링(max pooling)과 평균 풀링(average pooling)이 있다. 풀링을 하는 이유는 과적합을 방지하기 위해서라고 한다. 다음 링크 참조: ufldl.stanford.edu/tutorial/supervised/Pooling/

 

Unsupervised Feature Learning and Deep Learning Tutorial

Pooling: Overview After obtaining features using convolution, we would next like to use them for classification. In theory, one could use all the extracted features with a classifier such as a softmax classifier, but this can be computationally challenging

ufldl.stanford.edu

 

 

Comments