본문 바로가기
컴퓨터

[pytorch] 파이토치 튜토리얼2

by skyjwoo 2020. 2. 7.
728x90
반응형

https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html#sphx-glr-beginner-blitz-autograd-tutorial-py

 

Autograd: Automatic Differentiation — PyTorch Tutorials 1.4.0 documentation

Note Click here to download the full example code Autograd: Automatic Differentiation Central to all neural networks in PyTorch is the autograd package. Let’s first briefly visit this, and we will then go to training our first neural network. The autograd

pytorch.org

 

Autograd: automatic differentiation, 자동 차분

autograd package는 pytorch 신경망에 가장 중심이 되는 package Tensor 연산에 있어서 자동 미분을 제공한다. define-by-run framework를 이용하는데, 역전파(backprop)시에 코드가 어떻게 실행되느냐에 따라 역전파가 정의된다. 매 iteration마다 달라질 수 있다.

 

 

Tensor

torch.Tensor는 가장 중심이 되는 class이다. 이 class의 attribute인 .requires_grad를 True로 설정할 경우 이와 관련한 모든 연산들을 추적한다. 모든 연산이 끝나면, .backward()를 호출하여 모든 계산된 gradients한마디로 한 tensor에 대해 그와 관련한 gradient를 자동으로 계산한다.

 

tensor 연산의 history가 추적되는 것을 멈추려면, .detach() method를 호출한다. 이를 통해 tensor를 history에 대한 연산에서 떨어뜨려, 추적된 것들에 대한 앞으로의 연산을 막을 수 있다.

 

autograd implementation에 관한 매우 중요한 class가 하나 더 있다. Function이다. Tensor와 Function은 상호 연관돼 있고, acyclic graph(사이클이 없는 그래프)를 만드는데. 이 그래프가 연산 에 대한 완전한 history를 부호화한다. 각각의 tensor는 .grad_fn attribute를 갖고 있으며 이는 Tensor를 만든 Function을 참조한다. (user에 의해 만들어진 Tensor는 제외-이 tensor의 grad_fn은 None이다.)

 

미분값들을 계산하고 싶다면 Tensor에서 .backward()를 호출하면 되고, 만일 Tensor가 scalar값(원소가 하나)일 경우에는 .backward()에 아무런 argument도 없이 호출해도 되지만, Tensor의 원소가 두 개 이상의 경우에는 gradient argument에 해당 tensor의 shape에 맞게 값을 명시해주어야 한다.

 

import torch

 

# Tensor을 생성하고, 연산을 추적하기 위해 requrires_grad = True를 해 준다. 
x = torch.ones(2, 2, requires_grad=True)
print(x)

# Tensor 연산을 해 준다. grad_fn에 어떤 연산이 적용 됐는지 기록됨(history)
y = x + 2
print(y)

# y가 연산의 결과로 만들어졌기에, grad_fn이 존재한다. 
print(y.grad_fn)

# y에 대해 연산을 추가한다. 곱한 뒤 평균을 구한다. 그리고 이를 z에 대입한다. 
z = y * y * 3
out = z.mean()

print(z, out)

a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True) #해당 Tensor의 현재 requires_grad 값을 수정한다. requires_gradd의 default값은 false이다.
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)

 

Gradient, 경사/기울기

 

#out은 하나의 scalar값을 갖고 있기에 out.backward()는 out.backward(torch.tensor(1.))과 동일하다.
out.backward() #out은 위에서 out = z.mean()을 했음

 

print(x.grad) #계산된 결과 x의 grad attribute에 backprop의 결과가 저장된다.

여기서 '*'는 내적(dot product)이 아닌 원소별(element-wise) 곱이다.

 

 

보통, torch.autograd는 vector-jacobian 곱을 계산하는 engine이다. 즉, 주어진 vector에 대해 자코비안 행렬을 곱한다.

만일 해당 벡터가 y를 입력으로 하는 scalar 함수의 gradient인 경우(위의 경우처럼 Zmean과 같은 scalar값이 나왔을 때)

c = f(y), c의 값을 y에 대해 편미분한 벡터를 구해준 후 이를 jacobian 행렬에 곱하여 vector-jacobian곱으로 만든 후 값을 구한다.

#vector-Jacobian 곱의 예시
x = torch.randn(3, requires_grad=True)

y = x * 2
while y.data.norm() < 1000:
    y = y * 2

print(y) #마지막 output인 y가 scalar값이 아니다.

print(x.requires_grad)
print((x ** 2).requires_grad)

#torch.no_grad()로 tensor의 history를 추적하는 것을 멈춘다
with torch.no_grad():
    print((x ** 2).requires_grad)

#.detach()를 써서 새로운 tensor인데 gradient를 필요로하지 않는 tensor를 만들 수 있다. 
print(x.requires_grad)
y = x.detach()
print(y.requires_grad)
print(x.eq(y).all())
print(x.eq(y))#eq(): 원소 별 비교, all()은 모든 요소가 같으면 true 반환

#autograd.Function에 대한 문서
#https://pytorch.org/docs/stable/autograd.html#function
728x90
반응형

댓글