본문 바로가기
목차
Python

[DL] PyTorch: Autograd (Basic)

by ds31x 2024. 3. 22.
728x90
반응형

Autograd 사용하기.

Autograd는

  • reverse mode automatic differentiation을 구현하여
  • backpropagation을 자동으로 수행하는 도구임.

https://dsaint31.me/mkdocs_site/ML/ch08/back_propagation/

 

BME

Back propagation (역전파, 오차 역전파) 딥러닝 모델을 학습시키기 위한 핵심 알고리즘. Back propagation은 다음 2가지를 조합하여 ANN을 학습시킴. "Reverse-mode AutoDiff" (Reverse-mode automatic differentiation) "Gradien

dsaint31.me

 

PyTorch에서는 autograd는 tensor와 함께 핵심 구성요소로,
모든 tensor 연산의 기울기 계산을 자동으로 처리하는 기반을 제공.

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 를 구하기 위해 필요한 연산 및 중간값을 추적하여 기록할지 여부를 나타냄.
    • autograd가 추적하는 계산 그래프에 포함 여부에 해당.
    • torch.no_grad() Context 내에서는 모든 텐서의 requires_grad 속성이 False가 설정됨.
  • x.is_leaf:
    • 계산 그래프에서 “leaf node"인지 여부를 나타냄.
    • 일단, 계산 그래프에 포함되지 않는 tensor들은, 해당 attribute의 값을 True로 가짐.
      • requires_grad=False인 경우
      • detach() 메서드를 통해 계산 그래프에서 분리된 tensor.
    • 반면, 계산 그래프에서 포함되면서 is_leaf=True인 경우는 계산 그래프 상에서 leaf node인 경우임.
      • leaf node는 계산 그래프에서 "다른 tensor를 기반으로하는 어떤 연산"을 통해 생성되지 않은 tensor (=시작점)임을 가리킴.
        • 여기서 다른 tensor들은 requires_grad=True인 텐서임.
        • detach() 메서드로 중도에 계산 그래프에서 끊어진 텐서나, 이처럼 끊어진 텐서들이 포함된 연산들을 통해 얻어진 텐서들은 is_leaf=True이지만 그래디언트 계산에 참여할 수 없음(이같은 텐서에서 backward 메서드 호출시 에러발생함)
          • 끊어진 텐서에 대해 in-place 메서드인 require_grad_() 메서드를 호출시 require_grad 속성이 True가 됨. 
          • 하지만 이처럼 require_grad=True 인 텐서는 is_leaf 도 True가 되어 일종의 계산의 시작점이 된다.
          • 즉, detach()가 호출된 텐서가 이어져 있던 앞서의 tensor와는 분리가 됨.
      • 위의 x 처럼 requires_grad=True를 지정하면서 직접적으로 생성한 것들로
      • 계산 그래프의 시작점에 해당함.
    • 만약 tensor 가 leaf tensor로부터 어떤 연산을 통해 생성되었거나, leaf tensor로부터의 연산으로 생성된 tensor들의 연산을 통해 생성된다면, is_leaf 속성은 False임.
      • 이 경우, 계산 그래프에 포함된 node임.
    • 중요!!
      • is_leaf=True 이고 requires_grad=True 인 tensor 들만이
      • grad 속성에 gradient값을 가지게 됨(backward 처리 이후)
      • 단, retain_grad() 메서드를 호출하여 retain_grad 속성을 True로 한 경우grad 속성에 gradient 값을 가짐.
  • x.grad_fn:
    • 텐서가 다른 텐서들의 연산을 통해 생성된 경우(=leaf node가 아닌 경우),
    • grad_fn해당 연산을 나타내며,
    • 이 정보를 통해 back-propagation 에서 gradient를 계산할 때 어떤 연산을 통해 편미분을 계산하는지 알 수 있음.
    • 해당 텐서가 만들어진 마지막 연산 만을 가지나, 해당 연산에서 앞서의 연산에 대한 정보를 가진 next_functions라는 속성을 가짐. 이를 재귀적으로 추적 가능.
  • x.grad:
    • tensor 인스턴스 x 에 대해 수행된 마지막 .backward() 연산으로부터 계산된 gradient가 저장됨.
    • xrequires_grad = True일 때,
      • PyTorch는 x에 대한 모든 연산을 추적하며
      • .backward()가 호출될 때 자동으로 gradient를 계산함.
      • 단, is_leaf=True인  텐서에만 grad 속성에 저장됨.
    • 주의할 점은 backward 메서드를 호출하는 텐서가 scalar가 아닌 경우, .backward() 호출 시 gradient의 shape를 지정하는 argument를 전달해야함
      • 이는 .backward()를 호출하는 tensor와 같은 shape.
      • 각 요소로 scalar 1을 가지는 tensor 인스턴스가 주로 argument로 사용됨: torch.ones_like(output)

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를 "유지"하게 됨.
해당 tensor 인스턴스의 grad 속성은 gradient값을 가지게 됨.

 

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

backpropagation이 시작되는 loss function 의 결과 Tensor 인스턴스 ( c )에서
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(c)
# 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 여야 한다.
참고로,
인자로 넘겨주는 gradient의 초기치를 이용하여 이어서 그래디언트 계산도 가능.

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

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

.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으로 이루어질 때,

  • 각 batch 처리(=하나의 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

 

728x90