[인공지능] PyTorch AutoGrad & Optimizer

iMaeng·2022년 2월 2일
0

네이버 부스트캠프

목록 보기
3/10

PyTorch AutoGrad & Optimizer


딥러닝 학습은 데이터를 수많은 layer을 통과시키며 진행된다.
이 과정에서 동일한 layer가 여러 번 사용되며, 반복의 연속이다.
학습 과정에서 하나의 layer를 블록으로 상상해보면, 각 블록을 쌓고 쌓아서 하나의 완성체를 만드는 것이다.

PyTorch를 이용하면 이러한 반복을 손쉽게 다룰 수 있다.

torch.nn.Module

  • 딥러닝을 구성하는 layer의 기초가 되는 class이다.
  • Input, Output, Forward, Backward를 정의한다.
  • 학습의 대상이 되는 parameter(tensor)를 정의한다.

nn.Parameter

  • Tensor 객체의 상속 객체이다.
  • nn.Module 내에 attribute의 경우 required_grad=True로 지정되어 학습 대상이 된다.
  • 실제로 직접 지정할 일은 잘 없다.
    대부분의 layer에는 weights 값들이 지정되어 있다.(가져와서 사용하면 됨)
class MyLinear(nn.Module):
	def __init__(self, in_features, out_features, bias=True):
    	super().__init__()
        # 예를 들어, input이 (5,7)이고 output이 (5,12)인 경우 weight는 (7,12)인데,
        # 이 때 in_features가 7, out_features가 12이다.
        self.in_features = in_features
        self.out_features = out_features
        
		# weights를 지정해주는 부분, 실제로 직접 입력할 일은 없다.
    	self.weights = nn.Parameter(torch.randn(in_featrues, out_features))
        # Parameter가 아닌 Tensor로 지정해주어도 방식은 동일하긴 하다.
        # 그러나 autograd 지정이 어렵다.
        
        self.bias = nn.Parameter(torch.randn(out_features))
    
    def forward(self, x:Tensor): # y_hat 부분 (xw+b)
    	return x @ self.weights + self.bias
        # @ 연산자는 
        
x = torch.randn(5, 7) # 데이터 5개, feature는 7개.

layer = MyLinear(7, 12)
layer(x).shape # => torch.Size([5, 12])

Backward

  • Layer에 있는 Parameter들의 미분을 수행한다.
  • Forward의 결과값(model의 output)과 실제값의 차이(loss)에 대해 미분을 수행한다.
  • 해당 값을 기준으로 Parameter을 업데이트한다.

Backward는 기본적인 4단계를 거쳐서 진행된다.
1. 초기화
2. loss 구하기
3. backward
4. 업데이트

for epoch in range(epochs):
	... ...
    optimizer.zero_grad() # gradient가 업데이트 될 때, 이전 값이 지금에 영향을 주지 않도록 초기화.
    
    outputs = model(inputs) # y_hat에 해당.
    
    loss = criterion(outputs, labels) 
    
    loss.backward() # parameter(weight)에 대해 편미분해서 얻은 gradient
    
    optimizer.step() # 한번에 weight를 업데이트 진행(epoch이 돌아갈 때 마다)
  • 실제 backward는 Module 단계에서 직접 지정 가능하다.
  • Module에서 backward와 optimizer 오버라이딩해서 진행한다.
  • 사용자가 직접 미분 수식을 쓸 필요 없으므로 순서 이해 정도만 추천한다.
class LR(nn.Module):
	def __init__(self, dim, lr=torch.scalar_tensor(0.01)):
    	super(LR, self).__init__():
        # parameter 초기화
        self.w = torch.zeros(dim, 1, dtype=torch.float_.to(device)
        self.b = torch.scalar_tensor(0).to(device)
        self.grads={"dw":torch.zeros(dim, 1, dtype=torch.float).to(device),
        			"db": torch.scalar_tensor(0).to(device)}
        self.lr = lr.to(device)
        
    def forward(self, x): # y_hat 구하기 by Sigmoid
    	z = torch.mm(self.w.T, x)
    	a = self.sigmoid(z)
    	return a
    
    def sigmoid(self, z):
    	return 1/(1+torch.exp(-z))
        
    def backward(self, x, y_hat, y): # __init__에서 선언한 grads 사용.![](https://velog.velcdn.com/images%2Fausrn731%2Fpost%2F1e1e88f1-f17b-4a53-9471-e93651abc924%2FAIT3__CV.png)
    	
        self.grads["dw"] = (1/x.shape[1]) * torch.mm(x, (y_hat-y).T)
        self.grads["db"] = (1/x.shape[1]) * torch.sum(y_hat - y)
        
    def optimize(self): # 업데이트 스텝
    	self.w = self.w - self.lr * self.grads["dw"]
        self.b = self.b - self.lr * self.grads["db"]
        
profile
안녕하세요! 꾸준히 성장하고자하는 엔지니어 강면구입니다.

0개의 댓글