[PyTorch] 구조 & 활용

PyTorch Datasets & Dataloaders

Dataset 클래스

  • 데이터 입력 형태를 정의하는 클래스
  • 데이터를 입력하는 방식의 표준화
  • Image, Text, Audio 등에 따른 다른 입력 정의

보통 밑의 코드와 같이 생겼다.
__init__, __len__, __getitem__으로 구성.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import torch
from torch.utils.data import Dataset, DataLoader

class CustomDataset(Dataset):
    # 초기데이터 생성방법 지정
    def __init__(self, text, labels):
        self.labels = labels
        self.data = text
	
    # 데이터의 전체길이 반환
    def __len__(self):
        return len(self.labels)

    # index값을 주었을 때 반환되는 데이터의 형태(X,y)
    def __getitem__(self, idx):
        label = self.labels[idx]
        text = self.data[idx]
        sample = {"Text": text, "Class": label}
        return sample

Dataset 클래스 유의점

  • 데이터 형태에 따라 각 함수를 다르게 정의함
  • 모든 것을 데이터 생성 시점에 처리할 필요는 없음… 예를 들어, image의 Tensor 변화는 학습에 필요한 시점에 변환
  • 데이터 셋에 대한 표준화된 처리 방법 제공하는데, 이는 후속 연구자 또는 동료에게는 빛과 같은 존재
  • 최근에는 HuggingFace등 표준화된 라이브러리 사용

DataLoader 클래스

  • Data의 Batch를 생성해주는 클래스
  • 학습직전(GPU feed전) 데이터의 변환을 책임
  • Tensor로 변환 + Batch 처리가 메인 업무
  • 병렬적인 데이터 전처리 코드의 고민 필요
1
2
3
4
5
6
7
8
9
10
11
12
text = ['Happy', 'Amazing', 'Sad', 'Unhapy', 'Glum']
labels = ['Positive', 'Positive', 'Negative', 'Negative', 'Negative']
MyDataset = CustomDataset(text, labels)

# 방법 1
MyDataLoader = DataLoader(MyDataset, batch_size=2, shuffle=True)
next(iter(MyDataLoader))

# 방법 2
MyDataLoader = DataLoader(MyDataset, batch_size=2, shuffle=True)
for dataset in MyDataLoader:
print(dataset)

그런데…DataLoader에 쓰이는 파라미터가 좀 많다

batch_size

  • int, optional, default = 1

배치(batch)의 크기이다. 만약에 batch_size가 10일 때 데이터셋에 데이터가 100개라면, iteration 열 번만에 모든 데이터를 볼 수 있다.
Tensor를 반환하기에 Tensor로 반환되지 않는 데이터라면 에러가 발생한다.

shuffle

  • bool, optional, default = False

데이터를 섞을지 말지 결정한다.

sampler

  • Sampler, optional

index 컨트롤을 하려면 써야 한다. 종류가 몇 가지 있는데 그 중 하나를 소개하자면,

WeightedRandomSampler: 각 샘플에 가중치를 부여해 샘플링한다.

batch_sampler

  • Sampler, optional

이 아이는 잘 모르겠다. sampler와 크게 차이가 없는 거 같다.

num_workers

  • int, optional, default = 0

데이터를 불러올 때의 subprocess 개수를 설정한다. 다만 값이 너무 높으면 CPU에서 GPU로의 교류에서 병목 현상이 발생할 수 있다.

collate_fn

  • callable, optional

배치 단위의 데이터 변환할 때 사용한다고 한다. NLP처럼 길이가 가변적인 데이터를 사용할 때, zero-padding이나 Variable Size 데이터 등 데이터 사이즈를 맞추기 위해 많이 사용한다.
데이터와 레이블을 따로 묶어서 출력할 때 사용한다.

pin_memory

  • bool, optional

True로 설정하면 Tensor를 CUDA 고정 메모리에 올린다.

drop_last

  • bool, optional

배치 사이즈에 따라 데이터를 불러온다면 마지막 배치의 크기가 달라질 수도 있다. 나머지가 생기는 현상인데, 이렇게 배치 사이즈에 맞게 나눠 떨어지지 않는 경우에 마지막 배치를 사용하지 않는다.

time_out

  • numeric, optional, default = 0

데이터 불러오는 데에 제한 시간을 설정한다.

worker_init_fn

  • callable, optional, default = ’None’

어떤 worker를 불러올 것인지 결정.


모델 불러오기

model.save()

  • model.save 학습의 결과를 저장하는 함수
  • 모델 형태와 파라미터 저장
  • 덕분에 학습 중간 과정을 저장해서 가장 좋은 결과 모델을 선택할 수 있다.

참고로..from torchsummary import summary …모델 정보 보는 방법 중 하나

checkpoints

학습의 중간 과정을 저장하여 최선의 결과를 선택할 수 있게끔 한다.
early stopping 기법 사용 시에 이전 학습의 결과물 저장.
epoch, loss, metric 값을 일반적으로 함께 저장.
특히 colab 환경에서 지속적인 학습을 위해 필요하다.

체크포인트

참고로 파일 읽어올 때 ‘UserWarning’ 뜨는 경우 있는데, 이럴 땐 import warnings warnings.filterwarnings(“ignore”)

transfer learning

  • 모델을 가져와서 쓰고 싶을 때 사용
  • 다른 데이터셋으로 만든 모델을 현재 데이터에 적용하고 싶을 때 사용한다.
  • 딥러닝에서는 일반적인 학습 방법.
  • backbone architecture가 잘 학습된 모델을 부분 수정한 후 쓸 수 있다.
  • 대용량 데이터셋으로 pretrained 된 좋은 모델을 가져온다. e.g) TorchVision, HuggingFace

freezing 혹은 frozen?

pretrained model 사용할 때 모델의 일부 과정을 고정시킨 후 더 이상 손 대지 않는 것.


Monitoring tools for PyTorch

Tensorboard, weight & biased가 대표적.

Tensorboard

우선 텐서보드는 학습 그래프, metric, 학습 결과 시각화 지원.
파이토치도 연결 가능에서 사실상 딥러닝 시각화 핵심 도구

  • scalar : metric 등 상수 값의 연속(epoch)을 표시
  • graph : 모델의 computational graph 표시
  • histogram : weight 등 값의 분포를 표현
  • Image : 예측 값과 실제 값을 비교 표시
  • mesh : 3d 형태의 데이터를 표현하는 도

weight & biased

머신러닝 실험을 지원하는 상용도구.
협업, code versioning, 실험 결과 기록 기능 제공
최근 MLOps 대표적인 도구
다만 부분 유료

checkpoint = torch.load(PATH)

model.load_state_dict(checkpoint[‘model_state_dict’])

optimizer.load_state_dict(checkpoint[‘optimizer_state_dict’])


Multi GPU 학습

single 하나
multi 2개 이상의 gpu
node는 system 혹은 컴퓨터를 가리킨다.
single node single gpu 한 대의 컴퓨터에 gpu 하나
multi node multi gpu 서버실의 gpu 같은 거

multi GPU로 학습하는 두 가지 방법

모델을 나누는 model parallel

오래 쓰인 방법이지만 병목 현상과 파이프라인 문제로 구현하기 어렵다.
좋은 병렬화는 일이 동시에 잘 진행되게 하는 것.

data parallel

데이터를 분할해서 GPU에 할당한 후에 결과의 평균을 취한다.
미니배치와 비슷한 느낌. 다만 한 번에 여러 GPU에서 수행.
각각의 GPU에서 할당된 데이터를 각자의 모델로 학습한다.
그리고 각각 연산의 결과를 하나의 GPU에 모은다. 그러면 모아준 GPU에서 loss를 바탕으로 gradient를 뿌려준다. 이런 작업 반복.

PyTorch에서는 DataParallel과 DistributedDataParellel 방법으로 한다.

전자는 단순히 데이터 분배 후에 평균을 계산하는데, gpu 사용 불균형 문제, batch 사이즈 감소…한 gpu가 일을 너무 많이 부담하는 병목 문제 발생.
왜냐면 gpu마다 성능이 동일하다면 나눠서 몰아줘봐자 몰아진 gpu에선 부담이 가기에 처음부터 배치 사이즈를 줄여야 한다.

후자는 각 cpu에서 프로세스를 생성한 후에 개별 gpu에 할당.


Hyperparameter Tuning

모델 스스로 학습하지 않는 걸 사람이 직접 설정하는 것…learning rate, 모델 크기, optimizer 따위
근데 이건 큰 효과를 기대하지 않는 게 좋다.

grid 일정한 간격으로 값을 설정해서 최적 값을 찾아내는 것.
random 말 그대로 랜덤 값을 넣으면서 최적 값을 찾는 것.
최근엔 베이지안 기법이 많이 쓰인다.

Hyperparameter Tuning을 위한 도구 중에 ray라는 모듈이 있다.
multi node multi processing 지원 모듈
머신러닝과 딥러닝 병렬 처리를 위해 개발됨
현재 분산병렬 학습 모듈의 표준


Trouble shooting

  • 몇 가지 팁 소개.

OOM : Out of Memory…왜, 어디서 발생하는지 알기 어렵다.

배치 사이즈를 줄이거나 gpu를 재가동해서 돌리는 게 일반적인 해결 방법.

GPUUtil 사용하기.

코랩에서 사용하기 좋은 모듈.
nvidia-smi처럼 gpu의 상태를 보여주는 모듈이다.
iter마다 메모리가 늘어나는지 확인.

torch.cuda.empty_cache()

사용 안하는 gpu의 cashe 정리
가용 메모리 확보
reset 대신 쓰기 좋다.
del과는 다르다. del은 메모리 주소와의 관계를 끊는 것뿐.

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

tensor로 처리된 변수는 gpu에서 메모리를 사용한다.
1-d tensor의 경우 파이썬 기본 객체로 변환해서 쓸 것.

del을 써보기

torch.no_grad() 써보기.
이걸 쓰면 backward propagation에서 생기는 memory buffer가 발생하지 않는다.

일단 코랩에선 너무 큰 사이즈의 모델을 만들지 않는 게 좋다. linear, CNN, LSTM…
근데 CNN은 대개 크기가 안 맞아서 에러가 발생한다. torchsummary 등으로 사이즈를 맞추자.
tensor의 float precision을 16bit로 줄이는 방법도 있다.