
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(), , 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 연산으로 바꾼 뒤에는 반드시 다음을 반드시 확인해야 함:
- forward 결과가 이전과 같은지 확인.
- backward가 RuntimeError 없이 실행되는지 확인.
- 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
'ML' 카테고리의 다른 글
| optuna : Automatic Hyperparameter Optimization Framework (0) | 2026.06.27 |
|---|---|
| [ML] Dataset: California Housing Dataset (0) | 2026.06.26 |
| torch_xla 간단 사용법: TPU로 PyTorch 사용하기 (0) | 2026.06.23 |
| 2026 정리 (0) | 2026.06.10 |
| Hugging Face Trainer Callback과 JSONL 기반 Curve Logger (0) | 2026.06.04 |