본문 바로가기
AI/딥러닝

[AI 부트캠프] DAY 66 - 딥러닝 2

by HOHHOH 2023. 10. 25.

[오늘의 일지]

딥러닝 실시간 강의 - 딥러닝 기본 실습 코드, 설정( Learning Rate Scheduling, Transfer Learning, Back-propagation)

[상세 내용]

딥러닝

기본 설정을 위한 실습 코드

# 파이토치 라이브러리와 필요한 모듈들을 불러옵니다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import random
from time import time
import os
from tqdm.auto import tqdm
import torch
import torchvision
from torchinfo import summary

seed = 2023
deterministic = True

random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
if deterministic:
	torch.backends.cudnn.deterministic = True
	torch.backends.cudnn.benchmark = False
    
# 전처리 함수 정의
# 이미지 전처리에 필요한 transformation 함수를 정의 (pipeline 형태)
from torchvision.transforms import transforms

transform = transforms.Compose([
    transforms.ToTensor(),  # numpy array를 torch.FloatTensor로 변환  &  [0, 255] -> [0.0, 1.0]
    transforms.Normalize(mean=0.5, std=0.5)
    
# torch에서 학습에 사용할 config variable들을 세팅합니다.
num_workers = 2
batch_size = 128
learning_rate = 10.0
epochs = 5

# show images

def imshow(img):
    img = img/2 + 0.5  # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

# iterator를 이용해서 데이터를 불러오게 만듭니다. (batch processing을 위해서)
dataiter = iter(trainloader)  # trainloader를 iterator로 선언.
images, labels = next(dataiter) # next 함수는 iterator의 반복 수행함.

imshow(torchvision.utils.make_grid(images))
print(' '.join(f'{classes[labels[j]]}' for j in range(batch_size)))

# 학습 모델 정의
import torch.nn as nn

# 모델 구현에 필요한 레이어들을 정의합니다.
class MLP(nn.Module):
    def __init__(self):   # class constructor  ## model 정의 (define layers)
        super().__init__()
        # 3 Layer-NN (input, hidden1, hidden2)
        # nn.Linear의 in_features는 input node 개수, out_features는 output node 개수.
        self.fc1 = nn.Linear(in_features=28*28, out_features=512) # input_layer -> hidden_layer1
        self.fc2 = nn.Linear(512, 128)  # hidden_layer1 -> hidden_layer2
        self.fc3 = nn.Linear(128, 10)   # hidden_layer2 -> output_layer
        self.relu = nn.ReLU()  # activation layer
        self.softmax = nn.Softmax(dim=1) # (batch_size, output_layer_size) ## 각 vector별로 softmax 적용.

    def forward(self, x):
        # feed-forward 연산을 구현합니다.
        # x = (bs, 1, 28, 28) --> (bs, 1*28*28)
        x = torch.flatten(input=x, start_dim=1, end_dim=-1) # 784d vector
        x = self.relu(self.fc1(x))
        x = self.relu(self.fc2(x))
        x = self.softmax(self.fc3(x))

        #x = self.softmax(self.fc3(self.relu(self.fc2(self.relu(self.fc1(x))))))
        return x


#model1 = MLP() <=> model1.__init__(model1) ---> model1.fc1

model = MLP().to(device)
model

summary(model)

# Optimizer와 Loss function 정의
# import optimizers
import torch.optim as optim

optimizer = optim.SGD(params=model.parameters(), lr=learning_rate)
#optimizer = optim.Adam(params=model.parameters(), lr=learning_rate)
criterion = nn.CrossEntropyLoss()

# 학습
from torchview import draw_graph

# Dynamic Computational Graph (Runtime) -> forward 함수가 호출이 되어야 빌드됨.
model_graph = draw_graph(model, input_size=(batch_size, 28*28))
model_graph.visual_graph

start = time()

# for문을 이용하여 epoch마다 학습을 수행하는 코드를 작성합니다.
# 1 epoch : 전체 데이터를 다 학습시킨 경우
# 1 iteration : 1 weight update
# 1 epoch = batch_size x iterations
## 60000 = 600 x 100 --> weight update를 100번.
## 60000 = 128 x 469 --> weight update를 469번.
# total iterations = epochs(5) x iterations(469)


# 데이터를 직접 로드해서, 직접 모델에 넣고, 직접 loss를 계산 (자동으로 loss update)
## mini-batch training!!!!
for epoch in tqdm(range(epochs)):
    n_correct = 0
    total_loss = 0.0
    for idx, data in enumerate(trainloader):

        optimizer.zero_grad()   # gradient 초기화.
        ## ReLU() ---> max(0, x)
        ## dReLU() --> if x < 0: 0, else: 1
        ## d(wx)/dw --> x (local gradient)

        #### feed forward ####
        #images, labels = data[0], data[1]  # CPU version
        images, labels = data[0].to(device), data[1].to(device)  # GPU version
        outputs = model(images) # forward(x)
        loss = criterion(outputs, labels) # compute loss (tensor)
        #print(f"Epoch {epoch} : {idx:4d} iteration -->\t{loss.item():.4f}") # loss value
        n_correct = n_correct + (torch.max(model(images), dim=1)[1] == labels).sum() # batch당 맞은 개수.
        total_loss += loss.item()

        #### back propagation ####
        loss.backward()  # loss를 가지고 backprop
        optimizer.step() # SGD를 이용해서 weight update를 수행함.

    print(f"Epoch {epoch}, Train Accuracy : {n_correct/len(trainset):4f}\
                        | Train (average)Loss : {total_loss/len(trainloader):4f}")

end = time()

print("Training Done.")
print(f"Elasped Time : {end-start:.4f} secs.")

# 학습 모델로 예측
# 예측 연산은 출력된 결과값중에서 argmax를 찾는 방식으로 수행됩니다.
## NN에서 예측 연산은 학습이 완료된 모델에 feed-forward를 하면 됩니다.
outputs = model(images)
preds = torch.max(outputs, dim=1)[1]
(preds == labels).sum() / batch_size
#outputs.shape # 4장의 데이터에 대해서 10개 숫자.
# make prediction for each class
correct_pred = {classname: 0 for classname in classes}
total_pred = {classname: 0 for classname in classes}

# weight update를 하지 않는 모드 (inference only)
with torch.no_grad():  # test time 때, local gradient를 따로 저장하지 않음. (속도, 메모리)

    ## TO-DO ##
    ## testloader를 이용해서 학습이 완료된 모델에 대해 test accuracy를 계산해보세요.
    n_correct = 0
    total_loss = 0.0

    for idx, data in enumerate(testloader):
        images, labels = data[0], data[1]
        outputs = model(images)
        loss = criterion(outputs, labels)
        preds = torch.max(outputs, dim=1)[1]
        n_correct += (preds == labels).sum()
        total_loss += loss.item()

    print(f"Test Accuracy : {n_correct/len(testset):4f} | Test (average)Loss : {total_loss/len(testloader):4f}")

 

설정

Learning Rate Scheduling

- Learning rate scheduling은 훈련 중에 학습률(learning rate)을 동적으로 조절하는 기술로, 모델의 수렴을 더 빠르게 만들고 훈련 안정성을 향상시킬 수 있습니다. 학습률은 모델이 가중치를 업데이트하는 속도를 제어하며, 적절한 학습률은 모델의 성능을 향상시키는 데 중요합니다.

  • 특정 에포크마다 학습률을 고정된 비율로 감소시킵니다. 예를 들어, 처음에는 높은 학습률로 시작하고, 일정한 에포크 간격으로 학습률을 줄입니다.
  • 학습률을 지수적으로 감소시킵니다. 학습률을 처음에는 높게 설정하고 시간이 지날수록 학습률을 지수 함수로 줄입니다.
  • 학습률을 코사인 함수 형태로 주기적으로 감소시킵니다. 이러한 스케줄링은 학습률을 주기적으로 크게 높이고 낮춤으로써 모델이 지역 최소값에서 벗어나도록 도와줍니다.
  • 학습률을 한 번의 주기 동안 선형 또는 삼각 함수 형태로 조절하는 방식으로, 주기적으로 학습률을 높이고 낮춥니다. 이는 주로 학습률과 모멘텀을 조절하여 훈련 속도와 정확도를 높이는 데 사용됩니다.
  • 모델의 성능이 향상되지 않을 때 학습률을 감소시키는 방식으로, 모델이 수렴할 때 더 작은 학습률을 사용하도록 합니다.
  • 주기적으로 학습률을 증가 및 감소시키며 학습률의 범위를 탐색하도록 하는 방식입니다. 학습률이 주기적으로 바뀌므로 다양한 가중치 업데이트 속도를 탐색할 수 있습니다.

 

Transfer Learning 

- Transfer Learning은 딥러닝 모델을 특정 작업에서 훈련한 후, 이를 다른 작업에 활용하는 기술입니다. 이는 이미 훈련된 모델의 가중치 및 특징 추출 능력을 다른 작업에 적용하여 더 적은 데이터와 노력으로 새로운 작업을 수행하는 데 도움이 됩니다. 

  • 새로운 작업에 대한 대량의 데이터가 없어도 이전 작업에서 학습한 모델을 활용할 수 있습니다.
  • 새로운 모델을 처음부터 훈련하는 대신 사전 훈련된 모델의 일부 레이어를 재사용하면 시간과 계산 비용을 절감할 수 있습니다.
  • 사전 훈련된 모델은 일반적으로 다양한 데이터에서 특징을 추출하는 데 뛰어나며, 이를 이용하면 성능을 향상시키는 데 도움이 됩니다.

 

Back-propagation

- Backpropagation(역전파)은 인공 신경망에서 가중치 및 편향을 조정하기 위한 핵심 알고리즘 중 하나입니다. 이 알고리즘은 학습 데이터로부터 모델의 예측과 실제 타깃 간의 오차를 계산하고, 이 오차를 최소화하도록 가중치와 편향을 업데이트합니다.

  • Forward Propagation: 입력 데이터가 모델을 통과하여 예측을 만듭니다. 각 레이어에서는 가중치와 편향을 사용하여 활성화 함수를 적용하여 출력을 생성합니다.
  • Loss 함수 계산: 예측과 실제 타깃 간의 오차를 계산합니다. 일반적으로 평균 제곱 오차(Mean Squared Error, MSE) 또는 교차 엔트로피 오차(Cross-Entropy Loss)와 같은 손실 함수를 사용합니다.
  • Backpropagation: 오차를 출력 레이어부터 입력 레이어까지 다시 전파합니다. 이 과정에서 가중치와 편향을 업데이트하기 위한 그래디언트(기울기)를 계산합니다. 오차의 변화율에 따라 각 가중치와 편향이 얼마나 업데이트되어야 하는지 계산하는 것이 중요합니다.
  • 가중치 및 bias 업데이트: 계산된 그래디언트를 사용하여 가중치와 bias을 업데이트합니다. 일반적으로 경사 하강법(Gradient Descent) 또는 그 변형 알고리즘을 사용하여 가중치와 편향을 업데이트합니다.
  • 반복: 위의 과정을 여러 번 반복하면서 모델이 훈련 데이터에 더 잘 적응하도록 합니다.

 

[마무리]

 딥러닝에 대해서 조금 자세하게 배우기 시작했는데 배경지식을 이해하는데 꽤나 어려운 거 같습니다. 특히 역전파와 같은 용어는 살면서 처음 듣는 단어인데 그 내용도 꽤나 어려운 측면이 있어서 그런 거 같았습니다. 유튜브에 이미지로 설명해 주는 내용을 찾아가면서 복습해야 이해하는데 도움이 될 거 같습니다.

반응형

댓글