[Pytorch] 02 - 자동미분(autograd)
본문에서는 Pytorch의 가장 중요한 기능 중 하나인 자동미분, 즉 Autograd에 대해 다룬다. Deep Neural Network(이하 DNN)에서 미분은 Back propagation을 위한 필수적인 개념이다. 이를 Pytorch에서 제공함으로써 DNN을 쉽게 구현할 수 있다.
2.1 - 자동미분
pytorch에서 autograd는 tensor 단위로 실행된다. 이때, 역전파를 통해 계산된 gradient는 leaf tensor에만 저장된다.
- leaf tensor : tensor로 이루어진 연산 graph의 마지막에 위치한 tensor를 의미하며, 다른 tensor의 연산으로 생성되지 않은 tensor이다. 즉, 사용자가 명시적으로 정의한 tensor를 말한다.
requires_grad=True로 설정하여 gradient 계산을 허용한다. -
즉,
x라는 tensor를 정의하고y는x**2라면y에 대한x의 gradient가x에 저장된다. 미분을 시행할 시에는y.backward()명령어를 통해 실행한다. 아래 code를 보면 이해가 수월할 것이다.
(code)
x = torch.tensor([1.], requires_grad=True) y = x**2 print(x.grad) y.backward() # 미분 실행 print(x.grad)(결과)
None tensor([2.])위 code에서
y.backward()실행 전에는 미분이 되지 않았기 때문에x.grad의 값이None인 것을 확인할 수 있다. 그러나 실행 후에는y를 미분한2x에x의 값인 1을 대입한 2가 나온다.
2.2 - 미분 불가능
그렇다면 자동 미분은 모든 형태의 함수에 사용할 수 있을까? 답은 아니다. 수학에서의 미분이 그러하듯 자동 미분 또한 미분 가능한 함수에서만 적용 가능하다.
예시로, argmax 함수는 미분 불가능하다. 따라서 이를 실행한다면 error가 발생한다.
(code)
x = torch.tensor([1.], requires_grad=True)
y = x.argmax()
y.backward()
print(x.grad)
(결과)
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
위 code의 결과는 RuntimeError로, 미분 불가능한 함수라는 이유를 볼 수 있다. 즉, 미분 불가능한 함수는 자동미분이 적용되지 않는다.
2.3 - non leaf tensor의 gradient 확인
위에서 gradient는 leaf tensor에만 저장된다고 설명하였다. 그렇다면 non-leaf tensor의 gradient를 저장하고 싶을 때에는 어떻게 해야 할까. .retain_grad() 를 사용하면 된다.
(code)
x = torch.tensor([1.], requires_grad=True)
y = x**2
y.retain_grad()
z = 3*y
z.backward()
print(x.grad)
print(y.grad)
print(z.grad)
(결과)
tensor([6.])
tensor([3.])
None
위 결과에서 y 는 gradient가 존재하고, z 에는 gradient가 존재하지 않는다. 이는 y 에만 .retain_grad() 를 적용했기 때문이다.
2.4 - training 시 autograd
model을 training 시 또는 transfer learning에 이용할 때는 parameter를 update하면 안 된다. 이 때, 크게 세 가지 방법을 통해 gradient update를 막을 수 있다.
-
tensor.requires_grad=False를 통해 gradient update를 중지한다.x = torch.tensor([1.],requires_grad=True) y = x**2 x.requires_grad=False -
tensor.detach()를 통해 gradient를 중지한다.x = torch.tensor([1.],requires_grad=True) y = x**2 x = x.detach() -
tensor.no_grad()를 통해 gradient를 일시중지한다.x = torch.tensor([1.], requires_grad=True) with torch.no_grad(): y=x**2 y = x**2
댓글남기기