네이버 부스트캠프 AI Tech 2기

[08.18] Day12 - 👍 'PyTorch 구조'

Jay x 2 2021. 8. 21. 19:31
728x90
반응형

[PyTorch] AutoGrad, Optimizer, Dataset, Dataloader

[수업 내용]

강사 : 최성철 교수님

논문을 구현할때 → 수많은 반복의 연속이다.

(Layer들을 블록처럼 쌓아서 다음으로 넘기는 구조. 그래서 하나의 블록을 정의하고 이것들을 연결해 Forward, BackPropagation 하는 과정)

블록 ⇒ torch.nn.Module

: 딥러닝을 구성하는 Layer의 base class이다.

Input, Output, Forward, Backward를 정의하면 된다. 학습의 대상이 되는 파라미터를 정의해야 한다.

nn.Parameter 라고 하는 클래스에 Weight를 저장하고

Tensor 객체의 상속 객체이다. nn.Module 내에 attribute 가 될 때, required_grad = True 를 설정해야 AutoGrad의 대상이 된다.

Forward

class Linear(nn.Module):
    def __init__(self, input, output, bias=True):
        super().__init__()
        self.input = input
        self.output = output

        self.weights = nn.Parameter(torch.randn(input, output))
        #파라미터 정의 input, output 사이즈에 맞게 가중치 행렬을 만든다.
        self.bias = nn.Parameter(torch.randn(output))
        #bias 정의 output 사이즈에 맞게 bias 벡터를 정의한다.

    def forward(self, x):
        return x @ self.wieghts + self.bias

==============================
#Weights 보고 싶으면?
for param in 모델.parameters():
    print(param)

#Tensor로 선언하면? => 방식은 거의 동일한다.
#하지만 파라미터를 보여주지 않는다.

Backward

Layer에 있는 파라미터들의 미분을 수행한다.

Forward의 결과값과 실제값의 차이 → Loss에 대해 미분을 진행한다.

그리고 해당 값으로 파라미터를 업데이트 한다.

for epoch in range(epochs): #epoch마다 Update 진행된다.
    optimizer.zero_grad() #optimizer를 초기화한다. 학습할때, gradient update가 업데이트 되기 때문에 이전이 영향을 주지 않게 하기 위해서
    output = model(input)

    loss = criterion(outputs, labels)
    #criterion으로 loss값을 구함
    loss.backward()
    #Auto grad
    optimizer.step()
    #한번에 업데이트 된다.

criterion = torch.nn.MSELoss() #criterion이라는 loss 객체를 만듬
optimizer = torch.optim.SGD(model.parameters(), lr=0.01) #optimizer종류를 고르고 파라미터와 학습량을 결정한다.

보통은 Module에서 backward와 optimizer를 오버라이드해서 사용한다.

밑단부터 뜯어서 계산해보자!

class LinearModel(nn.Module):
    def __init__(self, dim, lr,):
        super(LR,self).__init__()
        self.w =torch.zeros(dim, 1, dtype = torch.float).to(device)
        self.b = torch.scalar_tensor(0).to(device)
        self.grad = {'dw': torch.zeros(dim,1,dtype = torch.float).to(device),
                                    'db' : torch.scalar_tensor(0).to(device_}
        self.lr = lr.to(device)

    #forawrd 과정
    def forward(self, x):
        z = torch.mm(self.w.T, w) + self.b #formula 정의
        a = self.sigmoid(z) #activation function 적용
        return 

    #sigmoid함수정의
    def sigmoid(self, z):
        return 1/(1+ torch.exp(-z))

    #backward정의 -> 보통 AutoGrad지원
    def backward(self, x, yhat, z):
        self.grad['dw'] = (1/x.shape[1]) * torch.mm(x, (yhat-y).T)
        self.grad['db'] = (1/x.shape[1]) * torch.sum(yhat-y)

    #미분에 대한 업데이트 정의
    def optimize(self):
            self.w = self.w - self.lr * self.grad['dw']
            self.b = self.b - self.lr * self.grad['db']

#loss function
def loss(yhat, y):
    m = y.size()[1]
    return -(1/m) * torch.sum(y*torch.log(yhat) + (1-y) * torch.log(1-yhat))

#prediction 하는 함수
def predict(yhat, y):
    y_pred = torch.zeros(1, y.size()[1])
    for i in range(yhat.size()[1]):
        if yhat[0, i] <= 0.5:
            y_pred[0,i] = 0
        else:
            y_pred[0,i] = 1
    return 100 - torch.mean(torch.abs(y_pred -y)) * 100 

결론 : 이런 과정들, 각 함수들을 PyTorch에서 제공해주니, 우리는 파라미터와 구조만 잘 맞춰서 조립하자!

DataLoad 와 Dataset

: PyTorch에서는 Dataset API를 제공하기 때문에 쉽게 데이터를 feeding 시켜줄 수 있다.

  1. 데이터를 모아서 폴더에 넣어놓는다.
  2. Dataset class 에서 여러개의 함수를 지원해준다.
  3. Transform은 전처리, 변형시에 처리해준다. 또한 Tensor로 바꿔준다.
  4. DataLoader는 데이터들을 모아서 feeding시켜준다. (batch를 만들거나, shuffle되어 들어간다.)

DataSet 클래스

: 데이터 입력 형태를 정의하는 클래스이다. 데이터를 입력하는 방식의 표준화

import torch
from torch.utils.data import Dataset

class CustomDataset(Dataset):
    #초기 데이터 생성 방법 설정
    def __init__(self, text, labels):
        self.labels = labels
        self.data = text

    #데이터 전체 길이 return
    def __len__(self):
        return len(self.labels)

    #idx 값을 주면 데이터 형태를 반환한다.
    def __getitem__(self, idx):
        label = self.labels[idx]
        text = self.data[idx]
        sample = {"Text" : text, "Class" : label}
        return sample

유의할 점

  • 데이터 형태에 따라 각 함수를 다르게 정의한다.
  • 모든 것을 데이터 생성 시점에 처리할 필요는 없다.
  • 데이터 셋에 대한 표준화된 처리방법을 제공할 필요가 있다.
  • 최근에는 HuggingFace 등 표준화된 라이브러리를 이용한다.

DataLoader 클래스

: Data의 배치를 생성해주는 클래스이다.

학습 직전 데이터 변환을 책임을 맡는다. Tensor로 변환 + Batch 처리가 메인 업무이다.

Loader = DataLoader(DataSet, batch_size= 묶을 크기, shuffle= True)
next(iter(Loader)
#Loader 같은 경우 iterable한 객체이기 때문에 호출하는 시점에 메모리에 올라가 처리가 된다.
#iter() -> Generator로 뽑아줌.

####DataLoader 클래스####
DataLoader(dataset, batch_size=1, shffle=False, smapler=None,
                        batch_sampler=None, num_workers=0, collate_fn=None,
                        pin_memory=False, drop_last=False, timeout=0,
                        worker_init_fn=None, * , prefetch_factor=2,
                        persistent_workers=False)

[수업 회고]

  1. forward 함수에서 layer와 선언한 변수들을 활용해서 하나씩 적용되는 모습이라는 것을 알았다.
  2. backward 같은 경우 .backward() 함수를 사용하면 자동적으로 gradient를 구할 수 있다는 것을 알았다, 또한 step() 함수도 optimize 하는 기능이라는 것도 알게 되었다.
  3. DataLoader와 DataSet의 각각의 기능에 대해서 알게 되었고, 과제를 통해 들어가는 파라미터들을 더 자세히 보게 되었다.

[피어세션 정리]

 

Python Generators: Memory-efficient programming tool

The idea behind writing this article was to provide a comprehensive understanding of the basics of generators which might take days to…

medium.com

 

반응형