Programming/Python

PyTorch란 무엇일까?! with GANomaly

어쩌다통계 2022. 10. 19. 00:58
728x90

이번 포스팅에서는 PyTorch에 대해 알아보도록 하겠습니다.

매년 10월에 발표하는 AI 현황 보고서, State of AI Report에서는 2020년에 발표된 논문에 가장 많이 사용한 Framework로 PyTorch가 선정되었습니다.

항상 TensorFlow가 앞서 다 사상 처음으로 PyTorch가 TensorFlow보다 18% 많은 47%를 차지했다고 합니다.

 

 

Framework?

응용 프로그램을 개발하기 위한 여러 라이브러리나 모듈 등을 효율적으로 사용할 수 있도록 하나로 묶어 놓은 일종의 패키지라고 할 수 있습니다. 일종의 개발 템플릿

가장 유명한 딥러닝 프레임 워크로 구글브레인-텐서플로우 / 페이스북-파이토치가 있습니다.

 

TensorFlow vs PyTorch

Tensorflow(2015)는 연산 그래프르 먼저 만든 다음, 값을 전달해 결과를 얻는 Define and Run 방식으로 학습 중에 조건에 따라 변화를 줄 수 없는 정적인 모델 Static Model이라고 합니다.

딥러닝 자체에 대한 연구보다 응용 목적으로 실제 산업 현장에서 많이 사용되며 아직까지도 많은 사용자들이 사용하고 있어 커뮤니티가 크다는 장점이 있습니다.

 

PyTorch(2017)는 연산 그래프를 만드는 동시에 값에 할당되는 Define by Run 방식으로 학습시키는 도중에 단계마다 조건을 바꿔줄 수 있는 동적인 모델 Dynamic Model이라고 합니다.

딥러닝 연구에서 많이 사용하는 추세이며 텐서 플로우에 비해 커뮤니티는 작지만 자체 운영 포럼이 있어서 개발자들이 직접 답변을 달아주기도 합니다.

 

자 그럼 PyTorch에 대해 알아보겠습니다.

 

PyTorch

PyTorch의 전반적인 구성은 다음과 같습니다.

1. torch

메인 네임 스페이스로 텐서 등의 다양한 수학 함수가 포함되어 있으며, numpy와 유사한 구조를 가집니다.

- tensor: 기본 연산 단위로 numpy array와 유사한 구조를 가지며 numpy->tensor / tensor->numpy가 가능합니다.

2. torch.autograd

자동 미분을 위한 함수들이 포함되어 있습니다. 자동 미분의 on/off를 제어하는 콘텍스트 매니저(enable_grad/no_grad)나 자체 미분 가능 함수를 정의할 때 사용하는 기반 클래스인 'Function' 등이 포함되어져 있습니다.

3. torch.nn

신경망을 구축하기 위한 다양한 데이터 구조나 레이어 등이 정의되어 있습니다. 예를 들어 RNN, LSTM과 같은 레이어, ReLU와 같은 활성화 함수, MSELoss와 같은 손실 함수들이 있습니다.

- nn은 모델을 정의하고 미분하는데 autograd를 사용하고 nn.Module은 layer와 output을 반환하는 forward(input) 메서드를 포함하고 있습니다.

- nn.Module은 매개변수를 캡슐화하는 간편한 방법으로, GPU로 이동, 내보내기, 불러오기 등의 작업을 위한 헬퍼를 제공합니다.

- forward 함수만 정의하면 변화도를 계산하는 backward함수는 autograd를 사용하여 자동으로 정의됩니다.

4. torch.optim

확률적 경사 하강법(Stochastic Gradient Descent, SGD)을 중심으로 한 파라미터 최적화 알고리즘이 구현되어 있습니다.

5. torch.utils.data

SGD의 반복 연산을 실행할 때 사용하는 미니 배치용 유틸리티 함수가 포함되어 있습니다.

6. torch.onnx

ONNX(Open Neural Network Exchange)의 포맷으로 모델을 익스포트(export)할 때 사용합니다. ONNX는 서로 다른 딥 러닝 프레임워크 간에 모델을 공유할 때 사용하는 포맷입니다.

 

 

Kaggle 코드로 이해해보기

Kaggle notebook에서 PyTorch로 구현된 GANomaly로 위에서 설명한 구성요소들이 어떻게 활용되는지 알아보겠습니다.

import torch
import torchvision
from torch import nn
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms

 

0. Data Load - MinMaxScaler - Train/Test

1. 먼저 numpy 형식의 데이터를 tensor로 바꿔줍니다.

#transform numpy to pytorch tensor
X_train_tensor=torch.from_numpy(X_train).float()
X_test_tensor=torch.from_numpy(X_test).float()

 

2. torch.utils.data의 DataLoader함수 활용하여 배치작업 준비합니다.

#fitting by batches (using dataloader)
X_train_dataloader=DataLoader(X_train_tensor,batch_size=batch_size,shuffle=False,drop_last=True)

 

3. nn.Module로 GANomaly구현에 필요한 generator 클래스를 정의합니다.

   discriminator도 같은 방법으로 정의

class generator(nn.Module):
  def __init__(self,input_size,act_fun,deep=False):
    super(generator,self).__init__()

    #deeper neural network or not?
    if not deep:
      hidden_size=input_size//2

      self.encoder_1=nn.Sequential(
        nn.Linear(input_size,hidden_size),
        act_fun
        )

      self.decoder_1=nn.Sequential(
        nn.Linear(hidden_size,input_size)
        )

      self.encoder_2=nn.Sequential(
        nn.Linear(input_size,hidden_size),
        act_fun
        )
      
    elif deep:
      hidden_size_1=input_size//2
      hidden_size_2=hidden_size_1//2

      self.encoder_1=nn.Sequential(
        nn.Linear(input_size,hidden_size_1),
        act_fun,
        nn.Linear(hidden_size_1,hidden_size_2),
        act_fun
        )

      self.decoder_1=nn.Sequential(
        nn.Linear(hidden_size_2,hidden_size_1),
        act_fun,
        nn.Linear(hidden_size_1,input_size)
        )

      self.encoder_2=nn.Sequential(
        nn.Linear(input_size,hidden_size_1),
        act_fun,
        nn.Linear(hidden_size_1,hidden_size_2),
        act_fun
        )

  def forward(self,input):
    z=self.encoder_1(input)
    X_hat=self.decoder_1(z)
    z_hat=self.encoder_2(X_hat)
    return z,X_hat,z_hat
net_generator=generator(input_size=X_train_tensor.size(1),act_fun=nn.Tanh(),deep=True)
net_discriminator=discriminator(input_size=X_train_tensor.size(1),act_fun=nn.Tanh(),deep=False)

 

4. nn을 활용하여 Loss function을 정의합니다.

L1_criterion=nn.L1Loss()
L2_criterion=nn.MSELoss()
BCE_criterion=nn.BCELoss()

 

5. 모델의 가중치를 갱신할 Optimizer를 정의합니다.

여기서는 Stochastic Gradient Descent(확률적 경사하강법)+momentum을 사용하였습니다.

SGD: 임의로 추출된 데이터 한 개에 대해서 Gradient를 계산하고 경사 하강 알고리즘 적용

새로운 가중치(weight) = 가중치(weight) - 학습률(learning rate) * 변화도(Grdient)

optimizer_G=torch.optim.SGD(net_generator.parameters(),lr=0.01,momentum=0.5)
optimizer_D=torch.optim.SGD(net_discriminator.parameters(),lr=0.01,momentum=0.5)

 

6. 모델을 학습합니다.

running_loss_G_vis=np.array([])
running_loss_D_vis=np.array([])

for epoch in range(20):
  running_loss_G=0
  running_loss_D=0

  for X in X_train_dataloader:
    #training the discriminator with real sample
    
    # 변화도 버퍼를 0으로(기본적으로 .backward()를 호출할 때마다 변화도가 버퍼(buffer)에 (덮어쓰지 않고) 누적되기 때문에 수동 설정)
    net_discriminator.zero_grad() 

    X=Variable(X)
    y_real=torch.FloatTensor(batch_size).fill_(0)#real label=0,size=batch_size
    y_real=Variable(y_real)
    
    # 순전파 단계: 모델에 X를 전달하여 Y를 예측
    _,output=net_discriminator(X) 
    
    # Loss 계산
    loss_D_real=BCE_criterion(output,y_real) 

    #training the discriminator with fake sample
    _,X_hat,_=net_generator(X)
    y_fake=torch.FloatTensor(batch_size).fill_(1)#fake label=1,size=batch_size

    _,output=net_discriminator(X_hat)

    loss_D_fake=BCE_criterion(output,y_fake)

    #entire loss in discriminator
    loss_D=loss_D_real+loss_D_fake
    running_loss_D+=loss_D
    
    # 역전파 단계: 모델의 가중치에 대한 Loss의 변화도 계산
    loss_D.backward() 
    
    # 가중치 업데이트
    optimizer_D.step() 

    #training the generator based on the result from the discriminator
    net_generator.zero_grad()

    z,X_hat,z_hat=net_generator(X)

    #loss_1
    latent_vector_real,_=net_discriminator(X)
    latent_vector_fake,_=net_discriminator(X_hat)

    loss_G_1=L2_criterion(latent_vector_fake,latent_vector_real)
    
    #loss_2
    loss_G_2=L1_criterion(X,X_hat)

    #loss_3
    loss_G_3=L1_criterion(z,z_hat)

    #entire loss in generator
    loss_G=loss_G_1+loss_G_2+loss_G_3
    running_loss_G+=loss_G
    loss_G.backward()

    optimizer_G.step()

  running_loss_G=running_loss_G/len(X_train_dataloader)
  running_loss_D=running_loss_D/len(X_train_dataloader)

  running_loss_G_vis=np.append(running_loss_G_vis,running_loss_G.detach().numpy())
  running_loss_D_vis=np.append(running_loss_D_vis,running_loss_D.detach().numpy())

  print(f'Generator Loss in Epoch {epoch}: {running_loss_G:.{4}}')
  print(f'Discriminator Loss in Epoch {epoch}: {running_loss_D:.{4}}\n')

 

 

 

[참고 url]

PyTorch 공식 홈페이지를 한국어로 번역한 사이트

pytorch.kr/

PyTorch로 시작하는 딥 러닝 입문

wikidocs.net/book/2788

GANomaly with Pytorch_credit card fraud detection

www.kaggle.com/jmq19950824/ganomaly-with-pytorch

 

반응형