Pytorch로 행렬을 미분해보자, autograd
Pytorch로 행렬을 미분하는 방법 2020-03-28
주의! Caution!
해당 게시글은 Archive된 게시글 입니다.
Archive된 사유는 다음 중 하나에 해당 됩니다.
  • 작성 된지 너무 오랜 시간이 경과 하여, API가 변경 되었을 가능성이 높은 경우
  • 주인장의 Data Engineering으로의 변경으로 질문의 답변이 어려워진 경우
  • 글의 퀄리티가 좋지 않아 글을 다시 작성 할 필요가 있을 경우
이 점 유의하여 게시글을 참고 하시길 바랍니다.

Pytorch로 행렬을 미분해보자, autograd

딥러닝 이론에 대해서 공부 해 보신 분들은, 딥러닝의 핵심은 미분을 통해서 **손실 함수(loss function)**의 값을 최소화 하는 것을 알고 계실 겁니다. 그렇기 때문에 Deep Learning 연구 플랫폼Pytorch에선, 당연하게도 행렬 미분을 위한 기능들을 Tensor 객체에 내장 시켜 놓았습니다. 한 번 알아볼까요?

autograd 활성화 시키기

requires_grad=True

첫 번째 방법은, Tensor를 생성하기 위해 사용하는 함수들의 파라미터로 requires_grad=True 를 넘겨 주는 것 입니다.

입력

x = torch.ones(2, 2, requires_grad=True)
print(x)

출력

tensor([[1., 1.],
        [1., 1.]], requires_grad=True)

Tensor.requires_grad_(True)

두 번째 방법은, 이미 생성된 Tensor의 멤버 함수인 requires_grad_를 이용하여 autograd를 활성화 시키는 것입니다.

입력

x = torch.ones(2, 2)
x.requires_grad_(True)
print(x)

출력

tensor([[1., 1.],
        [1., 1.]], requires_grad=True)

역전파 시키기

**역전파 (Back Propagation)**를 시키는 방법은 생각보다 간단합니다. 최종 연산 된 Tensor 객체의 backward() 함수만 호출해 주면 됩니다.

미분한 값 알아보기.

그렇다면, 역전파를 시킨 후, 미분한 값을 알기 위해선, 어떻게 하면 될까요?

  1. Tensor 객체로 연산을 끝낸 후, 마지막 연산 결과로 나온 Tensorbackward() 함수를 호출해 줍니다. backward() 함수의 파라미터 값으로는 d(최종결과 전 행렬)/d(최종결과 직전 행렬) 을 삽입해 줍니다. backward() 함수는 야코비안 행렬연쇄 법칙을 이용, 역전파를 통해 경사 하강법을 시도 하기 위해 사용합니다.
  2. 최종 연산 결과의 Tensor를 최초에 requires_grad=True를 설정해준 Tensor로 미분한 값을 알고 싶다면, 최초 Tensor 객체의 grad 속성을 통해 알 수 있습니다.

스칼라 연산

입력

x = torch.ones(2, 2, requires_grad=True)  # 최초 Tensor 객체
y = x + 2
z = y * y * 3
out = z.mean()  # 미분 대상

out.backward()	# out.backward(torch.tensor(1.)) 과 동일
print(x.grad)   # dout/dx

출력

tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

out = z/4 = y * y * 3/4 = (x + 2)^2 * 3 / 4 이고, 이를 x에 대해서 미분하면 dout/dx = 3(2x + 4) / 4 입니다. x = 1일 경우 18 / 4 = 4.5 가 정답이므로, 잘 작동 하고 있다고 볼 수 있습니다.

주의: out에 한 연산은 스칼라 연산입니다. 행렬 곱등을 사용하지 않았습니다.

행렬 연산

입력

x = torch.ones(2, 3, requires_grad=True)  # 최초 Tensor 객체
y = torch.ones(3, 6)
z = x @ y	# x @ y 행렬 곱, 더 이상 스칼라 값이 아니다.
out = z * 2
print(out)

out.backward(torch.ones(2, 6) * 2)   # dout/dz
print(x.grad)   # dout/dx

출력

tensor([[6., 6., 6., 6., 6., 6.],
        [6., 6., 6., 6., 6., 6.]], grad_fn=<MulBackward0>)
tensor([[24., 24., 24.],
        [24., 24., 24.]])

행렬 미분에 대해서 궁금한 점이 있다면, 해당 링크의 글을 참고 해 주시기 바랍니다.

autograd 연산 멈추기

autograd 연산과 별개로, 다른 연산을 통해서 테스트를 하고 싶을 때가 있을 수 있습니다. 이럴 때에는 두가지 방법이 있습니다.

  1. torch.no_grad() 를 이용하여 연산하기.
  2. Tensor.detech() 를 이용하여, autograd 연산을 하지 않은 Tensor 복사하기.

입력

x = torch.ones(2, 2, requires_grad=True)

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

with torch.no_grad():	# autograd 연산 생략
  print((x ** 2).requires_grad)

print('')

y = x.detach()			# autograd가 없이 내용물만 복사.
print(y.requires_grad)
print(x.eq(y).all())	# x와 y의 내용물은 같다.

출력

True
True
False

False
tensor(True)

마치며

다음 시간에는, 신경망 학습을 위한, torch.nn 모듈에 대해서 알아보겠습니다. 잘못된 내용이 있다면, 이메일 justkode@kakao.com 이나, 댓글을 통해 알려주세요!

Reference

Recent Posts in Deep-Learning Category