본문 바로가기

필기정리

[DeepLearning] DNN(Deep Neural Net) 강의 필기

320x100
본 게시글은 Deeplearning 관련 강의와 필기 정리를 진행한 글입니다.

순서에 관하여


이번 시간에는 Deep Neural Network(심층 신경망)에 대한 여러가지 개념들과
기초가 되는 문제의식에 대해 서술할 예정입니다.

지난 시간에는 CNN에 대해서 풀어보았었던 상황인데, 순서상으로는 DNN의 문제의식이
CNN 이전에 나왔기 때문에 본 글이 순서상 앞으로 와야 합니다.
순서상 CNN의 구조가 더 중요하다고 판단하여 먼저 설명했습니다.


먼저 Fahion MNIST가 무엇인지에 대하여 살펴봐야 할 것 같습니다.

Deeplearning의 튜토리얼이나 개념, 실습 파일에서 쉽게 볼 수 있는 Fashion MNIST파일은
일종의 테스트용 이미지 데이터 모음입니다. 쉽게 찾아볼 수 있어서 단위가 작다고 생각될 때도 있지만
실제로 들어가보면 방대한 규모를 자랑하고 있습니다.

필자도 아래 doc을 참조했습니다.

원본 제공처

Zalando Technology - Rewrite the rules of fashion

Fashion-MNIST 데이터셋에 대하여 설명한 GITHUB
하단 참조

GitHub - zalandoresearch/fashion-mnist: A MNIST-like fashion product database. Benchmark

A MNIST-like fashion product database. Benchmark :point_down: - GitHub - zalandoresearch/fashion-mnist: A MNIST-like fashion product database. Benchmark

github.com


일반적으로 9가지 정도의 분류로 모든 옷들을 나누고 있으며
60,000개의 이미지를 28 x 28 pixel로 나누고 있습니다.


Fashion MNIST의 종류는, 위부터 티셔츠/탑, 트라우져(바지), 풀오버(긴팔 류), 드레스, 코트, 샌달,
셔츠, 스니커즈(운동화), 가방, 앵클 부츠로 구성되어 있습니다만, 해외 패션 유형으로
한국인이 잘 입지 않는 분류도 포함하고 있습니다.

특히나 색깔이 RGB로 입혀져 있지 않고 Grayscale 흑백으로 입혀져 있기 때문에
그나마 큰 시간을 투자하지 않고도 분류된다는 이점도 있습니다.

아래 이미지는 FashionMNIST의 몇가지 이미지만 예시로 가져와본 것입니다.


pytorch에서 필요한 라이브러리들을 모두 들고 오는 것부터 시작했습니다.

import torch
import torch.nn as nn
import torch.optim as optim 
import torch.nn.functional as F
from torchvision import transforms, datasets

nn → 인공 신경망 모델 재료로서 사용하는 객체. nn.Linear, nn.ReLU, nn.Sigmoid처럼 사용합니다
optim → 최적화하는 알고리즘. optim.SGD, optim.Adam처럼 사용합니다.
F → nn의 함수 버전으로 activation function들이 들어갑니다. F.relu, F.cross_entropy 처럼 사용합니다.
transforms, datasets → 데이터셋 조작


그 이후의 학습셋 불러오기, 배치 사이즈 정의, 데이터로더,
class 정의는 생략했습니다. 계속 반복되는 내용이기도 하고, 기본적인 부분이라
숙지가 요구되진 않습니다.
참고사항으로 배치 사이즈는 16을 사용했습니다.

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(784, 256)
        self.fc2 = nn.Linear(256, 128)
        self.fc3 = nn.Linear(128, 10)
    def forward(self, x):
        x = x.view(-1, 784)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

hidden layer가 3인 neural network를 구성합니다.
처음 테스트 해보는 것이기 때문에 hidden layer를 많이 더 많이 만들 필요는 없었습니다.

fc1, fc2, fc3은 fully connected의 약자로 matrix형태로 된 이미지를
1차원으로 찌부해버리는 작업을 통해 이미지를 분류하는데 사용합니다.


1) matrix 찌부
2) activation 함수로 net을 활성화
3) softmax 함수로 분류


그다음으로 사용하는 것이 Stochastic Gradient Descent 즉 SGD 입니다.

SGD를 보겠습니다.


일반적인 Gradient Descent(경사 하강법)은 가중치를 조정하기 위해서
사용하는 방법입니다. loss function을 최소화 하는 패러미터들을 찾아야 하는 것이죠.

이때 사용되는 것이 Batch Gradient Descent입니다.
Batch gradient descent의 경우 한번 step을 지날때마다 trainset의 전체 데이터를
들고와서 계산하기 때문에 결과는 나오지만 그렇게되기 까지 너무나 많은 계산을 필요로 합니다.

그렇다면 Batch들을 일부만 사용하는 것은 어떨까요?


SGD는 Batch 대신 일부 데이터의 mini-batch 혹은 batch 크기가 1로 하여 gradient를 계산합니다.

그럼 무엇이 좋아질까요?

속도가 훨씬 빨라집니다.

GD는 곧 batch gradient descent 의 함수를 뜻합니다.

계산을 많이 진행하기 전까지는 다소 부정확할 수 있지만
계속 반복해서 몇 십번 , 몇 백번 이상 반복할 경우 Batch를 통으로 처리한 결과로 수렴합니다.
그렇기 때문에 같은 시간동안 더 많은 횟수를 반복할 수 있습니다. 물론 loss의 가능성은
계속 존재하긴 합니다.


다시 돌아와서, 학습 모드 정의합니다.

def train(model: nn.Module, train_loader, optimizer):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(DEVICE), target.to(DEVICE)
        optimizer.zero_grad()
        output = model(data)
        loss = F.cross_entropy(output, target)
        loss.backward()
        optimizer.step()

(평가모드의 반대입니다)
학습할 model, 데이터를 공급해주는 train loader, 최적화가 들어있는 optimizer를 넣어줍니다.
data는 모델에 입력할 이미지 텐서, target은 해당 이미지의 분류값입니다.

DEVICE는 구글 코랩의 GPU 장치구요.
zero_grad()로 기울기를 새로 계산(0으로 초기화)해서 만듭니다.
output으로 모델의 예측값을 내보냅니다.
loss로 손실함수 cross entropy를 넣도록 했습니다.

또 개념이 등장했습니다.

Cross entropy란?


크로스 엔트로피는 MSE, Squared loss 와 같이 NN에 사용되는 중요한 Loss function이었습니다.
빠르게 설명하자면 엔트로피는 정보량을 맞출 수 있는 최소한의 자원량 입니다.
다양한 설명이 존재합니다만 정보량의 기댓값이라고 하겠습니다. cross entropy는 이제 이를
다른 사건의 확률을 곱해서 entropy를 계산한 것입니다.




특히 binary cross entropy(이진 크로스 엔트로피)는 클래스가 2개인 경우 사용하고,
cross entropy는 클래스가 3개 이상일때 사용한다는 점을 알아야 할것 같습니다.



이제부터 배치를 반복하면서 train합니다.


평가함수도 만들어줍니다.

def evaluate(model, test_loader): 
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(DEVICE), target.to(DEVICE)
            output = model(data)
            test_loss += F.cross_entropy(output, target, reduction='sum').item()
            pred = output.max(1, keepdim=True)[1]
            print(pred.eq(target.view_as(pred)))
            correct += pred.eq(target.view_as(pred)).sum().item()
    test_loss /= len(test_loader.dataset)
    test_accuracy = 100. * correct / len(test_loader.dataset)
    return test_loss, test_accuracy


model.eval : 평가모드로 진입합니다.

test_loss : 테스트셋의 오차
correct : 예측이 맞은 count를 담아줄 변수
for문은 학습 모드와 유사합니다.

pred : 가장 큰 값을 가진 클래스가 모델의 예측값
pred.dq : 모델의 예측 패션 아이템과 레이블이 일치하는지 0 or 1로 표시

test_accuracy : 얼마나 맞췄는지 {맞힌 개수의 합}을 {전체 데이터셋의 오차}로 나누어 계산



epoch 1부터 30까지 진행해보며, train과 evaluate를 반복해줍니다.
결과는 epochtest_loss test_accuracy를 출력해줍니다.

for epoch in range(1, 31):
    train(model, train_loader, optimizer)
    test_loss, test_accuracy = evaluate(model, test_loader)
    
    print(f'[{epoch}] Test Loss: {test_loss:.4f}, Accuracy: {test_accuracy:.2f}%')

출력값은 약 3분 이상의 epoch 진행후 출력됩니다만
지면이 너무 길어져, 마지막 회차만 뽑아봤습니다.

[30] Test Loss: 0.4059, Accuracy: 85.32%


필기 완

728x90