본문 바로가기
  • Deep dive into Learning
  • Deep dive into Optimization
  • Deep dive into Deep Learning
Deep dive into Pytorch

Pytorch 3 : Neural network 구현

by Sapiens_Nam 2023. 7. 15.

 

import os
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

 

오늘은 Neural network 모델 설계를 위한 코드를 보도록 하자.

우선, 그 전에 다음과 같은 코드를 한 번 살펴보자.

이 코드는 만약에 파이토치가 CUDA, CUDNN등의 nvidia gpu를 위한 라이브러리와 제대로 연동이 되었는지, 즉 Tensor를 GPU에서 저장하고 연산을 GPU를 활용하여 수행할 수 있는지를 확인할 수 있는 코드이다.

 

device = (
	"cuda"
    if torch.cuda.is_available()
    else "cpu"
)

 

만약 'cuda'가 파이토치와 잘 연동이 되었다면 gpu 메모리를 사용하여 텐서 저장 및 연산등을 할 수 있고, 그렇지 않다면 cpu를 사용할 것이다.

 

다음으로 Neural network를 구현해보자.

이를 위해서는 우리는 'nn.Module'을 사용해야 한다.

class NeuralNetwork(nn.Module):
	def __init__(self):
    	super().__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
        	nn.Linear (28 * 28, 512),
            nn.ReLU(),
            nn.Linear(512, 512),
            nn.ReLU(),
            nn.Linear(512, 10)
        )
    def forward(self, x):
    	x  = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

model = NeuralNetwork().to(device)

 

Neural Network 설계는 class를 활용하여 구현한다.

우선, nn.Module을 상속받도록 하고 이 안에 구현된 다양한 layer 메소드들을 불러와서 우리의 모델을 설계하면 된다.

만약 우리가 이미지 데이터를 input으로 받는데 CNN이 아닌 MLP로 모델 설계를 한다면 이미지를 1D로 'flatten'해주어야 한다.

nn.Sequential은 Module의 'ordered container'이다. 데이터가 이 Sequential에 정의된 '순서대로' layer를 통과하도록 해준다. 

1장의 이미지는 Channel, Height, Width로 이뤄진 3차원 텐서이고 MLP는 2차원 (또는 1차원) 텐서를 input으로 받을 수 있기 때문에 위와 같이 flatten을 수행해준다.

만약 input data의 크기가 $(1, 28, 28)$인 흑백 이미지 1장이라면 flatten을 통과하면 $(1, 784)$로 변환될 것이다.

 

물론, 일반적으로 이미지 데이터는 CNN을 활용하므로 CNN에서는 flatten이 필요하지 않다. 

다만 지금은 기초 단계이므로 일단 Fully connected neural network로 진행하겠다.

위 모델은 Linear layer (=fully connected layer) 3개로 이뤄져 있고 각 layer의 output은 ReLU 함수를 거치도록 설계하였다.

ReLU는 activation function의 일종으로 $ReLU(x) = \max (0, x)$로 정의된다.

activation function은 비선형 연산을 수행해주는 함수로 알면 된다.

 

실제 모델을 train하거나 test할 때는, class의 instance를 생성하여 진행한다.

그리고 우리는 gpu 또는 cpu를 활용할 수 있도록 이 모델을 device로 옮겨준다.

만약, gpu를 사용한다면 이 모델은 gpu 상에 저장되어 거기서 연산이 train / test가 이뤄질 것이다.

 

이제 이 모델을 데이터를 사용하여 학습하려면 우리는 forward 연산을 진행해야 한다.

그래서 모델 클래스에 forward 메소드를 선언해주었다.

 

또한, 첫 번째 linear layer를 보면 $(28 \times 28)$를 input으로 받고 $512$를 output으로 내놓게 설정돼있다.

즉, 이 layer에 파라미터는 총 $28 \times 28 \times 512$개가 존재할 것이다.

실제로 다음과 같은 코드를 통해 각 layer별로 파라미터의 크기 등을 확인할 수 있다. 

for name, param in model.named_parameters():
	print(f"Layer : {name} | Size : {param.size()} | Values : {param[:2]} \n")

각각의 layer는 위와 같이 파라미터를 가지고 있고 이들이 최적화의 대상이 되는 변수들이다.

우리는 모델의 각 layer 파라미터를 'parameters(), named_parameters()' 등을 통해 확인해볼 수 있다.

 

당연히 이미지 데이터를 받는다고 가정하면 이 데이터는 Height와 Width가 $28 \times 28$로 크기 조정이 이뤄져있어야 한다.  그렇지 않다면 버그가 출력될 것이다.

 

input을 넣고 출력값을 얻어보자.

 

X = torch.rand(1, 28, 28, device=device)
logits = model(X)
pred_probab = nn.Softmax(dim=1)(logits)
y_pred = pred_probab.argmax(1)
print(y_pred)

먼저 input으로 흑백 이미지 (Height와 Width 모두 28인)를 집어넣는다고 가정하였다. 

당연히 data도 gpu상에서 텐서로 이뤄져있어야 한다.

이제 모델에 이를 집어넣으면 logits이라는 변수가 model 출력값을 가리킬 것이다.

이때 output tensor (logits)는 2차원 텐서일 것이다. $( 1 \times 10 )$

이때 각 성분의 값은 각각의 클래스에 해당하는 원시값일 것이고 이를 softmax 함수를 거쳐주면 일종의 확률분포로 만들어줄 수 있다. (softmax는 값들을 0과 1사이이면서 총합이 1이게끔 만들어준다.)

그렇다면 softmax를 거친 'pred_probab'이란 변수가 가리키는 2차원 텐서의 각 성분은 위 데이터 X가 각각의 클래스에 속할 확률을 나타내준다. 그리고 우리는 이 중 가장 큰 값 (즉, 모델이 예측하기에 정답으로서 가장 가능성이 높은 값)을 모델의 output으로 정의해준다.

그것이 y_pred이다.

 

다음 번 글에서는 이렇게 구현된 모델을 학습하고 (backpropagation) 최종적으로 저장하고 불러오는 것까지 살펴보도록 하자.

728x90

'Deep dive into Pytorch' 카테고리의 다른 글

Pytorch 5 : Save and Load  (0) 2023.07.17
Pytorch 4 : Training  (1) 2023.07.16
Pytorch 2  (0) 2023.07.11
Pytorch 1. Tensor  (0) 2023.07.06
Pytorch 첫 번째  (1) 2023.06.29

댓글