더 이상 tistory 블로그를 운영하지 않습니다. glanceyes.github.io에서 새롭게 시작합니다.

새소식

AI/AI 기본

PyTorch 딥 러닝 과정에서 자주 발생하는 문제 해결을 위한 팁

  • -

 

2022년 1월 24일(월)부터 28일(금)까지 네이버 부스트캠프(boostcamp) AI Tech 강의를 들으면서 개인적으로 중요하다고 생각되거나 짚고 넘어가야 할 핵심 내용들만 간단하게 메모한 내용입니다. 틀리거나 설명이 부족한 내용이 있을 수 있으며, 이는 학습을 진행하면서 꾸준히 내용을 수정하거나 추가해 나갈 예정입니다.

 

 

PyTorch로 딥러닝 하는 과정에서 문제 발생 시 해결하기

 

ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory

 

e48c007d-8e14-4b44-855d-62c53f220386.

DL 모델링을 하면서 자주 보게 될 오류로 GPU 상에서의 OOM(Out Of Memory)가 있다.

이는 다음과 같은 문제를 지닌다.

 

 

  • 왜 발생했는지 알기 어렵다.
  • 어디서 발생했는지 알기 어렵다.
  • Error BackTracking이 이상한 데로 간다.
  • 메모리의 이전 상황의 파악이 어렵다.

 

주로 iteration을 돌면서 특정한 시점에 문제가 발생하는데, 이를 해결할 수 있는 가장 좋은 방법은 Batch Size를 줄여서 Launch를 다시 하거나 kernel을 다시 켜서 실행하는 방법이다.

 

Batch Size ↓ + GPU clean + Run

 

# 가능한 배치사이즈들을 실험하고, OOM이 발생하면 batch_size = 1로 만드는 방법
oom = False
try:
  run_model(batch_size)
except RuntimeError: # Out of memory
  oom = True
if oom:
  for _ in range(batch_size):
    run_model(1)

 

이 외에도 시도할 수 있는 방법들이 있다.

 

 

GPUUtil 사용하기

 

  • nvidia-smi처럼 GPU의 상태를 보여주는 모듈
  • Colab은 환경에서 GPU 상태를 보여주기에 편하다.
  • iteration마다 메모리가 늘어나는지 확인한다.

 

예시 코드

!pip install GPUtil

import GPUtil

GPUtil.showUtilization()

 

 

torch.cuda.empty_cache() 사용해 보기

  • 사용되지 않은 GPU상 cache를 정리한다.
  • 가용 메모리를 확보할 수 있다.
  • del과는 구분이 필요하다. del은 관계를 끊어놓는 것이다. del을 사용하면 garbage collector이 수행된 이후에 메모리를 확보한다.
  • torch.cuda.empty_cache()를 사용하면 원하는 시점에 메모리를 확보할 수 있다.
  • reset 대신 쓰기 좋은 함수이다.
  • 학습 전에 실행해주면 이전 학습에 의한 메모리 낭비를 줄일 수 있다.

 

 

trainning loop에 tensor로 축적되는 변수 확인하기

  • tensor로 처리된 변수는 GPU상의 메모리를 사용한다.
  • 특히 loop 안에 tensor 변수에 대한 연산이 있을 때 GPU에 computational graph를 생성하여 메모리를 잠식한다.
  • 1-d tensor의 경우에는 python 기본 객체로 변환하여 처리한다.

 

예시 코드

# 메모리 잠식 예시(1)
total_loss = 0
for i in range(10000):
  optimizer.zero_grad()
  output = model(input)
  loss = criterion(output)
  loss.backward()
  optimizer.step()
  # 한번만 필요한 loss들이 불필요하게 메모리를 차지
  total_loss += loss

# 메모리 잠식 예시(2)
total_loss = 0
for x in range(10):
  # assume loss is computed
  iter_loss = torch.randn(3,4).mean()
  iter_loss.requires_grad = True
  # total_loss가 가지고 있는 iter_loss들이 tensor
  # 또한 requires_grad = True인 상태로 많은 메모리 차지
  total_loss += iter_loss

# 메모리 잠식 해결 예시
total_loss = 0
for x in range(10):
  # assume loss is computed
  iter_loss = torch.randn(3,4).mean()
  iter_loss.requires_grad = True
  total_loss += iter_loss.item
  # 또는
  total_loss += float(iter_loss)

 

 

 

del 명령어 사용

  • 필요 없어진 변수는 적절한 삭제가 필요하다.
  • python의 메모리 배치 특성상 loop이 끝나도 메모리를 차지한다.

 

예시 코드

# output을 얻는 것만이 목적이라면,
# loop이 끝난 시점에서는 i, intermediate, result 모두 불필요한 변수가 된다.
for i in range(5):
  intermediate = f(input[i])
  result += g(intermediate)
output = h(result)

 

 

가능한 batch 사이즈 실험해보기

  • 학습 시 OOM이 발생했다면 batch size를 1로 해서 실험해보고, 이를 점차 늘려볼 수 있다.

 

 

torch.no_grad() 사용하기

  • inference 시점(학습하는 과정이 아닌 경우)에서는 torch.no_grad() 구문을 사용한다.
  • Backward pass로 인해 쌓이는 메모리에서 자유롭다.
  • 학습이 끝나고 성능 평가하는 시점에서 사용하면 유용하다.

 

예시 코드

with torch.no_grad():
    for data, target in test_loader:
        output = network(data)
        test_loss += F.nll_loss(output, target, size_average=False).item()
        pred = output.data.max(1, keepdim=True)[1]
        correct += pred.eq(target.data.view_as(pred)).sum()

 

Contents

글 주소를 복사했습니다

부족한 글 끝까지 읽어주셔서 감사합니다.
보충할 내용이 있으면 언제든지 댓글 남겨주세요.