가끔 내가 짠 코드도 아닌데 에러 났다고 하고...
그냥 다른 거 하나 고쳐봤는데 디버깅이 되는 어이없는 상황들을 마주하기 쉽다.
이번 포스팅은 그 늪에서 탈출하기 위한 방법들이다.
이런 문제는 왜 발생했는지, 어디서 발생했는지 알기 어렵다...
Error backtracking이 이상한데로 갈 때도 있고
메모리 이전 상황을 파악하기도 어렵다.
그러면 이런 문제들은 어떻게 해결할까?
가장 기본적인 방법으로는
Batch Size 줄이고 ⇒ GPU clean ⇒ RUN
import GPUtil
GPUtil.showUtilization()이전 메모리로 부터 영향을 덜 받기 위해
학습 전에 한 번 돌려보는 것이 좋다!!
del 은 memory free를 시켜주지만 시점을 잘 봐야한다.
이 메모리를 쓸 수 있는 시점은 garbage collector가 작동을 할 때부터 사용할 수 있다.
from GPUil import showUtilization as gpu_usage
#gpu 상태 확인
gpu_usage()
# empty cache
torch.cuda.empty_cache()
gpu_usage() # 비어있는 것 확인 가능
연산 시 많은 메모리를 잡아먹고 특히 require_grad=True일 때는 버퍼까지 써야하기 때문에 더욱 많은 메모리를 필요로 한다.
이런 연산이 loop안에 있다면 GPU에 computational graph를 생성하면서 메모리를 잠식하는 현상이 나타난다.
예시로
for i in range(1000):
optimizer.zero_grad()
output = model(input)
loss= criterion(output)
loss.backward()
optimizer.step()
total_loss += loss
여기서 loss가 한 번만 필요한데 loss는 tensor 형태로 total loss에 계속해서 쌓인다. 그래서 쓸데없이 computational graph를 그리게 된다.
해결책으로 1-d tensor의 경우에는 python 기본객체로 변환하여 처리하는 것이 좋다
그래서 loss.item으로 받거나 float(loss) 바꿔주는 것이 좋다.
for i in range(5):
intermediate = f(input[i])
result += g(intermediate)
output = h(result)
return output
이 경우 for문 밖에서 intermediate를 사용할 수 있다.
그러나 result에 저장을 하고 있기 때문에 intermediate는 그다지 필요가 없다.
그래서 output전에 del intermediate를 넣어주는 것이 좋다.
배치 사이즈가 어디까지 가능한지 실험해보는 것도 하나의 좋은 방법이다.
oom = False
try:
run_model(batch_size)
except RuntimeError:
oom = True
if oom:
for _ in range(batch_size):
run_model(1)
with torch.no_grad():
pass
OOM말고 유사한 에러들이 발생할 수 있다.
CUDNN_STATUS_NOT_INIT, device-side-assert 등으로 OOM의 일종으로 생각 될 수 있다.
그럴 경위 이 블로그를 참고하는 것도 좋을 것 같다. 블로그
이외에 에러를 줄이기 위한 추천방법으로는