Ch13. Custom Data Loader 1 - Pre-load Data
보통의 경우 GPU, RAM, Hard Disk의 크기
- GPU: rtx3090기준 24GB
- RAM: 연구실 서버 기준 128GB
- Hard Disk: 연구실 서버기준 4TB
모델 훈련 관련 사전지식
- 모델은 GPU위에서 훈련하게 된다.
- CPU위에서 훈련할 수 있지만, 단순한 Tensor계산의 경우 CPU를 쓰게 되면 자원 낭비가 심하다.
- RAM은 바로 사용할 수 있도록 불러오는 저장소로, 파이썬에서 변수를 선언하면 이 램에 할당되게 된다. (비싼 메모리라 많이 확보하기 어렵다)
- Hard Disk는 저렴한 메모리장치로 많은 양의 데이터를 저장할 수 있지만 바로 활용가능은 불가능하다. (램위에 올려야함)
===
모델 훈련시 발생 가능한 문제 해결
- 이전 ch12에서 진행한 Pre-load의 경우 모든 데이터를 램 위에 올려놓고 GPU에 배치사이즈만큼 할당하는 방식이다.
- 데이터가 적으면 괜찮지만, 만약 데이터가 너무 커서 램 위에 모든 데이터를 올릴 수 없다면?
- 이 문제를 해결하기 위해 배치사이즈를 램에 올릴 때도 활용해주는 것이 배치별 로드 후 훈련 기법이다.
배치별 훈련
- 데이터의 경로를 먼저 로드한다.(이게 x, y의 기준이 된다.)
- 경로 어레이를 기준으로 배치를 만든다.
- 해당 배치만큼 램 위로 로드한다 (변수로 불러온다)
- 로드된 배치만큼 GPU에 할당하여 훈련을 진행한다.
- 위의 방식대로 배치별 훈련이 진행된다. ch12에서 진행한 코드를 변경해보자.
from tensorflow.keras.utils import Sequence
class CustomDataloader(Sequence):
def __init__(self, x_set, y_set, batch_size, shuffle=False):
self.x, self.y = x_set, y_set
self.batch_size = batch_size
self.shuffle=shuffle
def __len__(self):
return math.ceil(len(self.x) / self.batch_size)
def on_epoch_end(self):
self.indices = np.arange(len(self.x))
if self.shuffle == True:
np.random.shuffle(self.indices)
def __getitem__(self, index):
indices = self.indices[index*self.batch_size:(index+1)*self.batch_size]
return self.x[indices], self.y[indices]
- 이전 단원을 잘 진행했다면 위와 같은 데이터로더가 생성되었을 것이다.
- 여기서 x_set을 데이터가 있는 파일 경로를 담은 넘파이 어레이라 가정해보자. y_set은 실제 라벨 파일이라 가정
class CustomDataloader(Sequence):
def __init__(self, x_set, y_set, batch_size, shuffle=False):
self.x, self.y = x_set, y_set
self.batch_size = batch_size
self.shuffle=shuffle
def __len__(self):
return math.ceil(len(self.x) / self.batch_size)
def on_epoch_end(self):
self.indices = np.arange(len(self.x))
if self.shuffle == True:
np.random.shuffle(self.indices)
def loader(self, filepath):
...
하나의 이미지, 넘파이 등을 로드하는 함수
...
return file
def __getitem__(self, index):
indices = self.indices[index*self.batch_size:(index+1)*self.batch_size]
batch_x, batch_y = self.x[indices], self.y[indices]
return np.array([self.loader(x) for x in batch_x]), batch_y
- 다음과 같은 방식으로 코딩하게 되면, 마지막 __getitem__ 부분에서 배치만큼의 데이터를 램에서 불러와 GPU에 할당한다.
단점
- 그러나 데이터를 로딩하는 시간이 오래걸려서 pre-load보다 오래걸릴 것이다.
- 그러므로 이미지의 경우 전처리를 미리 수행하여 로드가 빠른 넘파이를 바꾸어 놓는 등의 기법을 적용해볼 수 있다.
- 혹은 램이 가능한 만큼의 데이터를 램 배치로 설정하여 로드하고, 해당 배치에서 데이터를 GPU 배치로 할당하고 램 배치가 다 되면 새로 램 배치를 업데이트 하는 식으로 코드를 짜도 효율적일 것이다.