본문 바로가기
Python

[DL] PyTorch: Autograd (Basic)

by ds31x 2024. 3. 22.

Autograd 사용하기.

1. requires_gradTrue로 설정.

 

편미분을 구할 Tensor 인스턴스에 대해 requires_grad=True 가 되도록하여,

해당 Tensor 인스턴스에 대한 연산을 추적하고, 자동으로 gradient를 계산할 수 있도록 수행.

x = torch.tensor([2.0], requires_grad=True)

 

autograd와 관련된 attributes는 다음과 같음.

  • x.requires_grad :
    • grad 를 구하기위해 forward propagation에서
    • gradient를 구하기 위해 필요한 연산 및 중간값을 추적하여 기록할지 여부를 나타냄
  • x.is_leaf:
    • 계산 그래프에서 “leaf node"인지 여부를 나타냄.
    • leaf node는 다른 tensor를 기반으로하는 어떤 연산을 통해 생성되지 않은 tensor로서 직접적으로 생성한 것들임.
    • 만약 tensor 가 다른 tensor로부터 어떤 연산을 통해 생성되었다면, is_leaf 속성은 False임.
  • x.grad_fn:
    • 텐서가 다른 텐서들의 연산을 통해 생성된 경우(=leaf node가 아닌 경우),
    • grad_fn은 해당 연산을 나타내며,
    • 이 정보를 통해 back-propagation 에서 gradient를 계산할 때 어떤 연산을 통해 편미분을 계산하는지 알 수 있음.
  • x.grad:
    • tensor 인스턴스 x 에 대해 수행된 마지막 .backward() 연산으로부터 계산된 gradient가 저장됨.
    • xrequires_grad = True일 때,
      • PyTorch는 x에 대한 모든 연산을 추적하며
      • .backward()가 호출될 때 자동으로 gradient를 계산하여 x.grad에 저장
    • 만약 x가 scalar가 아닌 경우, .backward() 호출 시 gradient의 shape를 지정하는 argument를 전달해야함
      (.backward()를 호출하는 tensor와 같은 shape 이며 각 요소로 scalar 1을 가지는 tensor 인스턴스가 주로 argument로 사용됨.)

2. 앞서 tensor 인스턴스에 대한 연산을 기재.

# 간단한 연산으로 구성한 예. 실제 구현에서는 매우 복잡해질 것임.
a = 2*x +10  
b = 3*a
b.retain_grad()
c = 2*b
  • 1번 과정에서 requires_grad=True인 tensor 인스턴스에 연결된 모든 tensor 인스턴스도 다 requires_grad=True 임.
  • 맨 처음 requires_grad=True 로 지정한 tensor 인스턴스는 is_leaf는 True로 설정되고, 이후 해당 인스턴스에 연결되는 Tensor들은 is_leaf가 False 임.
  • 이들 연결된 tensor들의 grad_fnBackward function이 할당됨

leaf node 가 아닌
다른 tensor 와 연산으로 만들어진 tensor 인스턴스에 대해
Gradient를 구하고 싶을때는
해당 tensor 인스턴스의 메서드 .retain_grad()
.backward() 호출 전에 호출하면 됨:
이를 통해 해당 tensor 인스턴스의 gradient를 "유지"하게 됨.

 

3. 결과값의 tensor 부터 back-propagation 수행

backpropagation이 시작되는 loss function 의 결과 Tensor 인스턴스 ( b )에서
backward() 메서드를 수행하여 gradient를 계산하고,

computational graph의 leaf node의 attribute 인 .grad 에 계산된 gradient를 accumulate 시킴.

.backward()
Computes the sum of gradients of given tensors
with respect to graph leaves.

c.backward( torch.ones(c.shape) )
# 아니면,
# l = torch.sum(b)
# l.backward()

torch.autograd provides classes and functions
implementing automatic differentiation of arbitrary scalar valued functions.

때문에 .backward()가 호출될 때 넘겨지는 argument는
"호출에 사용되는 tensor 인스턴스"와 같은 shape이면서 값은 scalar 1을 가지는 tensor 인스턴스 이어야 함.
아니면 .backward() 메서드를 호출하는 tensor 인스턴스가 scalar 여야 한다.

argument로 retain_graph=True 를 넘겨줄 경우, .backward()를 여러차례 호출이 가능함.

  • 해당 argument를 True로 설정하지 않으면,
  • .backward() 가 gradient를 계산하면서, forward phase에서 구해진 intermediate value들을 모두 free 시켜서
  • 이후 forward phase 수행 없이 곧바로 다시 .backward()를 호출할 경우 runtime error가 발생함.

.backward()를 여러차례 호출할 경우, leaf node의 grad에 계산된 gradient가 accumulated 되는 것을 쉽게 확인 가능함.

(모델의 파라메터를 제대로 갱신하려면, 꼭 leaf node의 grad의 초기화가 필요함.)

 

4. 이후, gradient를 다음으로 확인 가능.

# gradient를 출력.
print(x.grad)

참고로, DL등에서 다음 backward()를 수행하기 전에 꼭 구한 gradient를 초기화해야함 (아래 예제 참조).

x.grad.zeros_() # leaf node x의 grad를 0으로 초기화 하는 in-place op.
  • 이 초기화를 하지 않을 경우, grad에 gradient 값이 누적이 되어
  • 제대로 된 gradient를 구하지 못하게 됨.

초기화 관련하여 좀 더 자세히

일반적으로,

Training 과정 중 "한 번의 iteration (단일 batch에 대해)"이 끝난 후에는 grad 를 0으로 초기화해야 함.

  • grad 를 초기화하지 않으면, 각 batch에 대한 grad가 이전 batch의 grad에 더해져 누적됨.
  • 이후 (gradient decent 기반의 ) optimizer를 통해 누적된 grad 를 기반으로 model의 parameters가 update되며,
  • 이는 잘못된 parameter update를 의미하고, 결국 제대로 학습이 이루어지지 못하는 결과로 이어짐.

즉, 한 epoch가 여러 batch의 iteration으로 이루어질 때,

  • 각 배치 처리(=하나의 iteration) 후에 구해진 grad 들을 0으로 초기화하지 않으면
  • 첫 번째 batch 에 대한 grad 계산이 두 번째 batch 의 grad 에 영향을 주고,
  • 이는 모든 이어지는 batch들에 마찬가지로 영향을 줌.
  • 결국 한 epoch에서의 gradient가 제대로 반영되지 못하게 된다.

이를 막기위해 대부분의 training loop 에서는

  • 적절한 위치에 x.grad.zero_() (또는 optimizer.zero_grad())를 호출하여
  • gradient를 초기화함.

다음은 이를 보여주는 예제 코드임. :

for data, target in dataset:  
    optimizer.zero_grad() # model의 모든 parameters의 grad를 0으로 초기화  
    output = model(data)  
    loss = loss_function(output, target)  
    loss.backward()   # back-propagation을 통해 gradient 계산  
    optimizer.step()  # 계산된 gradient를 통해 model의 parameters 갱신 (or 수정).

다음의 ipynb 는 PyTorch에서 AutoGrad를 쓰는 간단한 예제를 보여줌.

https://gist.github.com/dsaint31x/5642ae694a4bb1ec5887fc3642b7d91d

 

dl_tensor_pytorch_autograd.ipynb

dl_tensor_pytorch_autograd.ipynb. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com


기타 참고자료.

https://teamdable.github.io/techblog/PyTorch-Autograd: 꼭 읽어볼 것.

 

PyTorch Autograd

안녕하세요. 오태호입니다.

teamdable.github.io

 

https://velog.io/@olxtar/PyTorch-Autograd-03-Practice02

 

[PyTorch] Autograd-03 : Practice02

retain_graph() / Stem 추가 / Leaf 추가 / Operation / .no_grad()

velog.io