Keras와 HDF5으로 

대용량 데이터 학습하기



"Keras 내 HDF5Matrix 클래스를 이용하면 된다."







Keras에서 학습을 위한 데이터를 만들거나 가져올 때, numpy array로 변환해 모델에 넣어주는 것이 일반적이다. 

데이터셋의 크기가 컴퓨터 사양에 비해 충분히 작으면, 누구나 자신이 원하는 데이터를 numpy array로 바꾸어 넣어줄 수 있고, 이런 점이 굉장히 편리하다. 


그러나 numpy array로 만드는 작업이 결국 모든 데이터를 담은 자료구조를 메모리에 올리는 행위이기 때문에, 

내 컴퓨터 메모리 용량에 비해 데이터셋의 크기가 압도적으로 큰 경우 메모리에 데이터를 전부 올리지 못하고 MemoryError를 뱉으며 프로그램이 죽어버린다. 


위 같은 경우 데이터셋을 줄이는 방법이 있을 수 있지만, 모델의 크기나 풀고 싶은 문제의 난이도에 따라 그럴 수 없는 경우도 많다. 


이 때 해결 방법은 두 가지인데, Keras 에서 제공하는  keras.models.Model.fit_generator()  를 사용해서, generator 가 매 batch 마다 데이터를 생성하도록 만들어 줄 수 있다. 물론 이 생성이라는 부분은 파일로 되어 있는 데이터를 로드하는 것을 포함하기 때문에, 일정 부분만 로드해서 사용할 수 있게 된다. 


만약 데이터를 내가 생성하거나, 혹은 generator 함수를 이용하는 것이 느리고 불편하다면 다른 방법이 있는데,  HDF 파일 포맷을 이용하는 것이다. 


HDF5 포맷은 대용량 데이터를 처리하기 위한 파일 형식으로, 많은 양의 데이터를 안정적으로 저장할 뿐만 아니라, Random Access 및 빠른 검색 등을 지원한다. 위키에 조금 더 자세한 내용이 나와 있다. 


Python에서 HDF5 포맷을 다루는 방법은, 일단  h5py  라는 모듈을 설치해야 한다. pip이나 anaconda 등으로 쉽게 설치할 수 있다. 

h5py를 이용해 새로운 데이터셋을 만드는 방법은 다음과 같다. 

#
import numpy as np
import h5py

with h5py.File(filename, 'w') as f:

    f.create_dataset('image', (1000, 32, 32, 3), dtype='float32')    # 1000개의 32x32 RGB 이미지를 담는 데이터 공간을 생성한다. 
    f.create_dataset('label', (1000,), dtype='float32')              # 1000개의 float을 담는 데이터 공간을 생성한다. 
    image_set = f['image']    # 실 데이터 공간에 접근할 변수를 할당한다. 
    label_set = f['label']


위 코드는 filename 경로에 .hdf5 파일을 생성하고, 그 파일에 자료를 저장할 데이터셋을 생성하는 코드이다. 

filename 은  "path/to/hdf5file/name.hdf5"  형식으로 주면 된다. 


데이터셋은 마치 딕셔너리와 같은데, HDF5 파일 내부에 세부 경로를 만들고 그 경로에 주어진 데이터가 들어간다. 즉, 경로를 key로, 데이터를 value로 가지는 대용량의 딕셔너리로 봐도 된다. 


데이터셋을 생성한 뒤에, 실제 저장된 파일의 인덱스에 값을 대입하는 방법은 다음과 같다. 

#
    labels = label_set[:]    # 이미지 데이터 전체를 반환하지만, 메모리에 올리지는 않는다. 값에 접근할 때 메모리에 올린다. 
    array = label_set[:50]   # 데이터셋을 numpy array 와 비슷한 형태로 불러올 수 있다. 역시 이 명령으로 메모리에 올라가지는 않는다. 
    label_set[0] = 3.0       # dataset에 값을 대입할 수 있다. 
    label_set[10:20] = np.arange(10.)       # 배열을 직접 대입할 수도 있다.  


위와 같이 HDF5 파일의 자료는 원하는 양 만큼 잘라낸 후 numpy array 를 다루듯이 사용할 수 있다. 이 때, HDF5 파일은 실제 데이터 값에 접근하기 전까지는 메모리로 올라오지 않고, 데이터에 접근할 때도 메모리 제한 내에서 load와 close 를 반복하기 때문에 데이터 양과 무관하게 마음껏 사용할 수 있게 된다. 물론 데이터가 저장된 디스크의 File I/O 가 bottleneck 으로 작용할 수 있다는 문제가 있지만, 이 정도는 많은 데이터 양을 다루는 데에 필요한 trade-off 라 생각할 수 있다. 


특히, Keras 에선 이 HDF5 파일을 쉽게 학습 데이터로 사용할 수 있게 지원해주고 있다.  keras.utils.io_utils.HDF5Matrix  가 그것인데, 이 클래스를 이용해 HDF5 파일을 읽어오면, Keras 내에서 자동으로 처리가 되기 때문에 학습용 데이터를 넣어줄 때 별다른 처리 없이 넣어줘도 된다. 다음 예제를 보면서 이해해보자. 

#
from keras.utils.io_utils import HDF5Matrix

n_epoch = 1000
batch_size = 32
split_pos = 800

x_data = HDF5Matrix(filename, 'image')    # 위에서 생성한 HDF5 파일의 image 경로의 데이터를 가져오게 된다. 
x_train = HDF5Matrix(filename, 'image', end=split_pos)    # HDF5 파일의 데이터 중 일부만 가져오는 것도 가능하다. 
x_test = HDF5Matrix(filename, 'image', start=split_pos)
y_train = HDF5Matrix(filename, 'label', end=split_pos)
y_test = HDF5Matrix(filename, 'label', start=split_pos)

# 이미 .compile() 이 된 모델이라고 가정하자
model.fit(x_train, y_train, epochs=n_epoch, batch_size=batch_size, validation_data=(x_test, y_test))    # numpy array 를 쓰듯이 사용하면 된다. 


위처럼 데이터를 파일로 저장해 두어도 HDF5포맷과 keras의 HDF5Matrix를 이용하면, 복잡한 처리 없이 대용량 데이터를 쉽게 학습할 수 있다. 

학습에 필요한 데이터가 많을 때 고려해볼 만 한 방법이다. 




* 2018.05.17 수정 - batch_size 추가




[NUXLEAR]

+ Recent posts