본문 바로가기
목차
ML

Autograd : In-place 연산

by ds31x 2026. 6. 23.
728x90
반응형

In-place 연산과 Autograd의 관계

backward에서 필요한 tensor를
in-place로 수정하면 안 되며,
backward에서
어떤 tensor가 필요한지는 연산마다 다르다.

PyTorch의 autograd

  • forward pass에서 계산 그래프를 만들고,
  • backward pass에서 이 그래프를 따라가며 gradient를 계산함.

 

이때 autograd는 backward 계산에 필요한 값을 내부적으로 저장해둠.

문제는 in-place 연산임.
in-place 연산은 기존 tensor의 값을 직접 바꾸는 연산임.

 

예를 들어 다음과 같은 연산들이 in-place 연산에 해당함.

x += 1
x.relu_()
x.add_(1)
  • 이런 연산은 새로운 tensor를 만드는 것이 아니라,
  • 기존 tensor의 값을 직접 수정함.

 

따라서 backward pass에서 필요한 값이 forward pass 이후에 바뀌어버리면,
autograd는 올바른 gradient를 계산할 수 없음.

 

이 경우 PyTorch는 보통 다음과 같은 RuntimeError를 발생시킴.

one of the variables needed for gradient computation has been modified by an inplace operation
  • 이 메시지는 backward 계산에 필요한 tensor가 in-place 연산으로 수정되었다는 의미임.

1. Output을 저장하는 연산

일부 연산은 forward pass에서 계산한 output을 저장해두었다가,
backward pass에서 저장된 output을 이용해 gradient를 계산함.

 

예:

exp(), relu(), rsqrt(), sigmoid(), sqrt(), tan(), tanh()

 

예를 들어 sigmoid의 경우를 생각해보면,
sigmoid의 derivative는 sigmoid의 output을 이용해 다음처럼 계산할 수 있음.

 

$$\frac{d}{dx}\sigma(x) = \sigma(x)(1-\sigma(x))$$

  • 이 경우, backward에서는 입력 $x$ 자체보다
  • forward에서 계산된 output $\sigma(x)$가 중요함.

 

따라서 이런 연산의 output을 in-place로 수정하면 안 됨.

y = torch.sigmoid(x)
y.add_(1)      # 위험함
loss = y.sum()
loss.backward()
  • 이 경우 backward에서 원래의 sigmoid output이 필요하지만,
  • 이미 y.add_(1) 때문에 값이 바뀌었음.

따라서 gradient를 올바르게 계산할 수 없고 RuntimeError가 발생할 수 있음.

 

정리하면 다음과 같음.

output을 저장하는 연산의 경우,
해당 연산의 output을 in-place로 수정하면 안 됨.

 


2. Input을 저장하는 연산

다른 일부 연산은 output이 아니라 input을 저장해두었다가,
backward pass에서 그 input을 이용해 gradient를 계산함.

 

예:

abs(), cos(), log(), sin(), square(), var()

 

예를 들어 $y = \log(x)$의 derivative는 다음과 같음.


$$\frac{d}{dx}\log(x) = \frac{1}{x}$$

 

즉, backward에서는 output인 $\log(x)$보다
input인 $x$가 필요함.

 

따라서 이런 연산은 output을 in-place로 수정하는 것은 상대적으로 문제가 되지 않을 수 있음.

y = torch.log(x)
y.add_(1)      # 보통 괜찮을 수 있음
loss = y.sum()
loss.backward()

 

하지만 input인 x를 backward 전에 in-place로 수정하면 문제가 됨.

y = torch.log(x)
x.add_(1)      # 위험함
loss = y.sum()
loss.backward()

 

  • 이 경우 backward에서 원래의 x가 필요한데,
  • x.add_(1) 때문에 값이 바뀌었음.

input을 저장하는 연산의 경우,
해당 연산의 input을 backward 전에 in-place로 수정하면 안 됨.

 


3. Input과 output을 모두 저장하는 연산

일부 연산은 backward 계산을 위해 input과 output을 모두 저장함.

 

예:

max(), min(), norm(), prod(), sgn(), std()

 

이런 연산은 input과 output 둘 다 backward에서 필요할 수 있음.

  • 따라서 input을 수정해도 안 되고,
  • output을 수정해도 안 됨.
y = torch.max(x)
x.add_(1)      # 위험함
y.add_(1)      # 위험함
loss = y.sum()
loss.backward()

 

input과 output을 모두 저장하는 연산의 경우,
둘 중 어느 것도 backward 전에 in-place로 수정하면 안 됨.


4. Input도 output도 저장하지 않는 연산

반대로 일부 연산은 backward 계산을 위해 input이나 output을 따로 저장할 필요가 없음.

 

예:

ceil(), floor(), mean(), round(), sum()

 

예를 들어 sum()의 경우,
gradient 계산에서 원래 input 값 자체가 꼭 필요하지 않음.

y = x.sum()

 

sum()은 단순히 여러 값을 더한 것이므로,
각 input에 대한 gradient는 기본적으로 1로 전달됨.

 

따라서 이런 연산의 결과는 in-place로 수정해도 상대적으로 안전함.

y = x.sum()
y.add_(1)      # 일반적으로 안전한 편
loss = y
loss.backward()

정리하면 다음과 같음.

input도 output도 저장하지 않는 연산은
in-place 수정에 비교적 안전함.

 


정리

Autograd 관점에서 중요한 질문은 다음임.

이 tensor가
backward pass에서
필요한 값인가?

필요한 값이면 in-place로 수정하면 안 됨.

 

필요하지 않은 값이면 in-place로 수정해도 문제가 없을 수 있음.

 

이를 표로 정리하면 다음과 같음.

연산 종류 예시 backward에서
필요한 값
주의할 점
output을
저장하는 연산
exp(), relu(), sigmoid(),
sqrt()
, tanh()
output output을
in-place로 수정하면 안 됨
input을
저장하는 연산
abs(), cos(), log(),
sin(), square()
input input을 backward 전에
in-place로 수정하면 안 됨
input과 output을
모두 저장하는 연산
max(), min(), norm(),
prod(), std()
input과 output input과 output 모두
in-place 수정하면 안 됨
둘 다 저장하지 않는 연산 ceil(), floor(), mean(),
round(), sum()
없음 상대적으로 안전함

 


실전 권장 방식

처음부터 in-place 연산을 많이 쓰는 것은 좋지 않음.

우선 모델을 작성할 때는 일반 연산을 사용하는 것이 안전함.

x = x + 1
y = torch.relu(x)

 

모델이 정상적으로 동작하고,
loss와 gradient가 잘 계산되는 것을 확인한 뒤에,
메모리 사용량이나 속도가 문제가 될 때만 일부 연산을 in-place 연산으로 바꾸는 것이 좋음.

 

x += 1
y = torch.relu_(x)

 

하지만 in-place 연산으로 바꾼 뒤에는 반드시 다음을 반드시 확인해야 함:

  1. forward 결과가 이전과 같은지 확인.
  2. backward가 RuntimeError 없이 실행되는지 확인.
  3. gradient가 의도한 대로 계산되는지 확인.

즉, in-place 연산은 성능 최적화를 위한 도구이지,
처음부터 습관적으로 사용할 연산은 아님.

 

가장 안전한 원칙은 다음과 같음.

모델을 처음 작성할 때는 in-place 연산을 피할 것.
(parameter 업데이트는 제외)
이후 메모리 절약이나 속도 개선이 필요할 때만
제한적으로 사용할 것.

PyTorch에서 RuntimeError가 발생한다면,
대부분은 backward에 필요한 tensor를 in-place로 수정했기 때문임.

 

따라서 이런 오류가 나면 먼저 다음을 확인하면 됨.

x += ...
x.add_(...)
x.relu_()

위의 예처럼 _로 끝나는 메서드나
+=, -=, *=, /= 같은 연산이 있는지 확인할 것.

 

PyTorch에서는 관례적으로 메서드 이름이 _로 끝나면 대부분 in-place 연산임.

 

relu()    # 새로운 tensor를 반환
relu_()   # 기존 tensor를 직접 수정

 

따라서

  • autograd를 사용하는 코드에서는
  • _로 끝나는 연산을 사용할 때 특히 주의해야 함.

같이 보면 좋은 자료들

2024.03.22 - [Python] - [DL] PyTorch: Autograd (Basic)

 

[DL] PyTorch: Autograd (Basic)

Autograd 사용하기.Autograd는reverse mode automatic differentiation을 구현하여backpropagation을 자동으로 수행하는 도구임.https://dsaint31.me/mkdocs_site/ML/ch08/back_propagation/ BMEBack propagation (역전파, 오차 역전파) 딥러

ds31x.tistory.com

 

2025.03.13 - [Python] - [PyTorch] in-place 연산이란?

 

[PyTorch] in-place 연산이란?

in-place 연산이란?in-place 연산은 원본 데이터 구조를 직접 수정하여 별도의 복사본을 만들지 않는 연산 방식을 가리킴.메모리 효율성이 높지만,원본 데이터가 변경된다는 점을 주의해야 함.주의

ds31x.tistory.com


 

728x90