본문 바로가기
AI | 딥러닝/Concept

[AI/딥러닝] 딥러닝 모델을 GPU에 구동시키는 방법 (Feat. Framework)

by 고뭉나무 2021. 8. 8.

지난 포스팅까지 딥러닝 모델에 대해 알아보았습니다.

인간의 신경망을 본떠 어떤 종류의 Layer들을 구성하고 어떻게 Convolution을 하는 것이 최적의 훈련이고 최적의 추론인 지에 대한 고민들이었죠.

2021.07.10 - [SW programming/Computer Vision] - AI, 머신러닝, 딥러닝 이란? 그리고 딥러닝 모델 종류

2021.07.11 - [SW programming/Computer Vision] - [딥러닝 모델] CNN (Convolutional Neural Network) 설명

2021.08.01 - [SW programming/Computer Vision] - [AI/딥러닝] CNN Network layer 모델들 (AlexNet, GoogLeNet, ResNet)

2021.08.01 - [SW programming/Computer Vision] - [AI/딥러닝] 객체 검출(Object Detection) 모델의 종류 R-CNN, YOLO, SSD

 

 

근데 아직 딥러닝 분야에 내공이 얕은 저에게는 '그래서 이 딥러닝 모델을 어떻게 GPU에 가속화 시킨다는 것인지' 감이 오지 않았습니다.

그래서 오늘은 그 방법에 대해 소개하려 합니다.

 

 

딥러닝 Framework

딥러닝을 위한 Framework로 유명한 세 가지가 있습니다.

TensorFlow, Keras, PyTorch 이렇게 있습니다. 그리고 각각의 사용 언어, CNN과 RNN에서의 성능 등 특징이 모두 다양합니다.

그 내용은 아래 표를 통해 자세히 알 수 있습니다.

딥러닝 Framework의 종류 및 특징

이 많은 특징 중 제가 궁금했던 '그래서 이 딥러닝 모델을 어떻게 GPU에 가속화 시킨다는 것인지' 에 답은 'Multiple GPU support' 에 연관이 있습니다.

이는 GPU 에서 해당 Framework로 코드 제어가 가능하다는 뜻이며 '+'의 갯수에 따라 GPU 가속 효율을 높일 수 있습니다.

CNN 모델링이 좋으면서 GPU support가 잘되는 Framework는 'Tensorflow' 와 'Torch(or Pytorch)'가 됩니다.

 

 

해당 Framework로 원하는 Dataset을 특정 딥러닝 모델에 적용시켜 구현을 시킨 후, NVIDIA GPU를 가동시키는 CUDA 언어로 cnDNN 라이브러리를 이용하여 GPU 가속화를 진행할 수 있습니다.

 

 

 

아래 표는 결과를 시각화 해주는 프로그램과 Computing device에 대한 특징 입니다.

딥러닝 Framework의 종류 및 Computing device

 

이 표 또한 다른 특징을 분류한 것이니 참고하기에 좋습니다.

딥러닝 Framework의 종류 및 사용 언어

 

 

Pytorch로 직접 Coding 해보기

그럼 먼저 Pytorch Framework로 하나의 딥러닝 모델을 구현해보겠습니다.

 

신경망 모델 구성하기

신경망은 데이터에 대한 연산을 수행하는 계층(layer)/모듈(module)로 구성되어 있습니다. torch.nn 네임스페이스는 신경망을 구성하는데 필요한 모든 구성 요소를 제공합니다. PyTorch의 모든 모듈은 nn.Module 의 하위 클래스(subclass) 입니다. 신경망은 다른 모듈(계층; layer)로 구성된 모듈입니다. 이러한 중첩된 구조는 복잡한 아키텍처를 쉽게 구축하고 관리할 수 있습니다.

이어지는 장에서는 FashionMNIST 데이터셋의 이미지들을 분류하는 신경망을 구성해보겠습니다.

 

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

 

학습을 위한 장치 얻기

가능한 경우 GPU와 같은 하드웨어 가속기에서 모델을 학습합니다. torch.cuda 를 사용할 수 있는지 확인하고 그렇지 않으면 CPU를 계속 사용합니다.

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('Using {} device'.format(device))

 

클래스 정의하기

신경망 모델을 nn.Module 의 하위클래스로 정의하고, __init__ 에서 신경망 계층들을 초기화합니다. nn.Module 을 상속받은 모든 클래스는 forward 메소드에 입력 데이터에 대한 연산들을 구현합니다.

class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__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),
            nn.ReLU()
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

 

NeuralNetwork 의 인스턴스(instance)를 생성하고 이를 device 로 이동한 뒤, 구조(structure)를 출력합니다.

model = NeuralNetwork().to(device)
print(model)

 

모델을 사용하기 위해 입력 데이터를 전달합니다. 이는 일부 백그라운드 연산들 과 함께 모델의 forward 를 실행합니다. model.forward() 를 직접 호출하지 마세요!

모델에 입력을 호출하면 각 분류(class)에 대한 원시(raw) 예측값이 있는 10-차원 텐서가 반환됩니다. 원시 예측값을 nn.Softmax 모듈의 인스턴스에 통과시켜 예측 확률을 얻습니다.

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(f"Predicted class: {y_pred}")

 

모델 계층(Layer)

FashionMNIST 모델의 계층들을 살펴보겠습니다. 이를 설명하기 위해, 28x28 크기의 이미지 3개로 구성된 미니배치를 가져와, 신경망을 통과할 때 어떤 일이 발생하는지 알아보겠습니다.

input_image = torch.rand(3,28,28)
print(input_image.size())

//******* nn.Flatten *******//
//nn.Flatten 계층을 초기화하여 각 28x28의 2D 이미지를 784 픽셀 값을 갖는 연속된 배열로 변환함
flatten = nn.Flatten()
flat_image = flatten(input_image)
print(flat_image.size())

//******* nn.Linear *******//
//선형 계층 은 저장된 가중치(weight)와 편향(bias)을 사용하여 입력에 선형 변환(linear transformation)을 적용하는 모듈
layer1 = nn.Linear(in_features=28*28, out_features=20)
hidden1 = layer1(flat_image)
print(hidden1.size())

//******* nn.ReLU *******//
//비선형 활성화(activation)는 모델의 입력과 출력 사이에 복잡한 관계(mapping)를 만듦
//비선형 활성화는 선형 변환 후에 적용되어 비선형성(nonlinearity) 을 도입하고, 
//신경망이 다양한 현상을 학습할 수 있도록 도움
print(f"Before ReLU: {hidden1}\n\n")
hidden1 = nn.ReLU()(hidden1)
print(f"After ReLU: {hidden1}")

//******* nn.Sequential *******//
//nn.Sequential 은 순서를 갖는 모듈의 컨테이너. 데이터는 정의된 것과 같은 순서로 모든 모듈들을 통해 전달함
seq_modules = nn.Sequential(
    flatten,
    layer1,
    nn.ReLU(),
    nn.Linear(20, 10)
)
input_image = torch.rand(3,28,28)
logits = seq_modules(input_image)

//******* nn.Softmax *******//
//nn.Softmax 모듈에 전달될 ([-infty, infty] 범위의 원시 값(raw value)인) logits 를 반환함
//logits는 모델의 각 분류(class)에 대한 예측 확률을 나타내도록 [0, 1] 범위로 비례하여 조정(scale)됨
softmax = nn.Softmax(dim=1)
pred_probab = softmax(logits)


//******* 모델 매개변수 *******//
//신경망 내부의 많은 계층들은 매개변수화(parameterize) 됨
//즉, 학습 중에 최적화되는 가중치와 편향과 연관지어짐
//nn.Module 을 상속하면 모델 객체 내부의 모든 필드들이 자동으로 추적(track)되며, 
//모델의 parameters() 및 named_parameters() 메소드로 모든 매개변수에 접근할 수 있게 됨
print("Model structure: ", model, "\n\n")

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

 

 

출력 결과

Model structure:  NeuralNetwork(
  (flatten): Flatten(start_dim=1, end_dim=-1)
  (linear_relu_stack): Sequential(
    (0): Linear(in_features=784, out_features=512, bias=True)
    (1): ReLU()
    (2): Linear(in_features=512, out_features=512, bias=True)
    (3): ReLU()
    (4): Linear(in_features=512, out_features=10, bias=True)
    (5): ReLU()
  )
)


Layer: linear_relu_stack.0.weight | Size: torch.Size([512, 784]) | Values : tensor([[-0.0071, -0.0260,  0.0311,  ...,  0.0099, -0.0002,  0.0102],
        [ 0.0024, -0.0296,  0.0093,  ..., -0.0091,  0.0080,  0.0004]],
       device='cuda:0', grad_fn=<SliceBackward>)

Layer: linear_relu_stack.0.bias | Size: torch.Size([512]) | Values : tensor([-0.0294, -0.0280], device='cuda:0', grad_fn=<SliceBackward>)

Layer: linear_relu_stack.2.weight | Size: torch.Size([512, 512]) | Values : tensor([[-0.0435, -0.0110,  0.0110,  ...,  0.0429, -0.0348, -0.0375],
        [-0.0166, -0.0264,  0.0406,  ...,  0.0188,  0.0344, -0.0395]],
       device='cuda:0', grad_fn=<SliceBackward>)

Layer: linear_relu_stack.2.bias | Size: torch.Size([512]) | Values : tensor([0.0296, 0.0216], device='cuda:0', grad_fn=<SliceBackward>)

Layer: linear_relu_stack.4.weight | Size: torch.Size([10, 512]) | Values : tensor([[ 3.3242e-02,  9.6526e-03, -2.1534e-02,  ...,  5.6896e-03,
         -7.0137e-03,  2.6827e-02],
        [-1.0889e-02,  1.2723e-05, -3.3012e-02,  ...,  7.6711e-03,
          6.8862e-03, -8.8320e-03]], device='cuda:0', grad_fn=<SliceBackward>)

Layer: linear_relu_stack.4.bias | Size: torch.Size([10]) | Values : tensor([-0.0014, -0.0122], device='cuda:0', grad_fn=<SliceBackward>)

 

 

그럼 이제 CUDA 언어로 cnDNN 라이브러리를 이용하여 GPU 가속화하는 코딩을 해주어야 AI 가속화에 대한 목적이 달성됩니다.

하지만 현재 NVIDIA GPU가 없는 관계로... 추후에 생기게 된다면 다음 포스팅에서 이어가도록 하겠습니다. 부디..!

 

 


https://tutorials.pytorch.kr/beginner/basics/buildmodel_tutorial.html

 

Flatten

https://tykimos.github.io/2017/01/27/CNN_Layer_Talk/

https://opentutorials.org/module/5268/29787

 

Linear

ReLU

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=handuelly&logNo=221824080339 

 

Sequential 

Softmax

https://teddylee777.github.io/machine-learning/softmax-%ED%95%A8%EC%88%98%EB%9E%80

 

그리고 

http://weekly.tta.or.kr/weekly/files/20204206074225_weekly.pdf

 

반응형

댓글