https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html#sphx-glr-beginner-blitz-autograd-tutorial-py
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
'컴퓨터' 카테고리의 다른 글
[pytorch] 파이토치 튜토리얼 4 (0) | 2020.02.10 |
---|---|
[pytorch] 파이토치 튜토리얼3 (0) | 2020.02.10 |
[pytorch] 파이토치 튜토리얼 1 (0) | 2020.02.03 |
visual studio LNK1168: 쓰기용으로 열 수 없습니다 오류 (12) | 2020.02.01 |
파이토치(pytorch) 설치 방법 (0) | 2020.01.31 |
댓글