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]


AutoEncoder 에서 뽑은 Z vector

Tensorboard 에서 보기



"numpy와 Tensorflow를 통해 Tensorboard로 불러오기."






최근에 AutoEncoder를 Keras로 코딩하던 중 내 모델이 feature를 얼마나 잘 뽑아내는지 알아볼 필요가 생겼다. 


Keras에서 callback 중 하나인  keras.callbacks.Tensorboard()  를 사용하면 Tensorboard에서 loss 및 acc 등을 확인할 수 있는 데이터를 함수 내 인자로 지정해준 경로에 생성한다. 문제는 이 callback 함수가 Tensorboard에서 loss 및 acc 그래프 정도는 잘 보여주지만, 자동으로 Keras model이 가지고 있는 다양한 정보를 한 번에 볼 수 없다는 것이었다. 


특히 나는 각 z vector 값 간의 interpolation이 자연스러운지를 확인해야 했는데, 기존에 확인하던 방법은 Test set에서 랜덤으로 두 이미지를 선택해 z vector 값 사이를 움직이도록 했었다. 다양한 이미지 간의 interpolation을 확인할 수 있었지만, 그 이미지 간의 z vector 의 차이, 즉 유사도를 확인할 수 없다는 것과 그 점 때문에 내 모델이 학습한 z vector가 이미지의 feature를 잘 뽑아냈는지를 확인할 수 없었다. 


따라서 Tensorboard에 있는 embedding 기능을 이용하기로 했다. embedding에 대해 검색해보면 자세히 알 수 있지만, 간단히 이야기해서 현재 64 차원인 z vector의 좌표 및 거리 등 정보를 2차원 혹은 3차원과 같은 저차원으로 낮추어 데이터의 cluster나 분포를 확인할 수 있게 하는 것이 목적이다. embedding은 다양한 방법으로 가능한데, Tensorboard에서 지원하는 방법은  t-SNE   PCA  라는 방법이다. 설명하기엔 나도 모르는 것이 많아 궁금한 사람은 직접 검색해 보는 것을 추천한다. 


사실 위에 언급한 callback 함수에서 인자로  embedding_freq  와  embedding_layer_name  을 설정하면 Tensorboard에서 embedding space를 바로 확인할 수 있다고 하지만, 내 모델의 구조 상 embedding_layer_name에서 내가 원하는 layer를 가져오지 못했다. 따라서 다른 방법을 찾아봐야 했다. 


인터넷에 Keras model에서 구한 vector를 Tensorboard에 embedding하는 방법을 찾던 중, 다음 글을 발견했다. 글에 나와 있는 방법을 간단하게 설명하자면, Keras model 내의 Keras tensor를 구한 뒤, Tensorflow를 이용해 데이터를 저장하고 Tensorboard에서 그 정보를 읽는 것이다. 다행히 Tensorboard에서는  tensorflow.train.Saver()  로 저장한 Tensor를 불러오는 기능이 있다. 위 글 역시 이 기능을 사용했으며, Keras의 backend로 Tensorflow가 쓰일 수 있기 때문에 backend 에서 session을 얻어와 동작하게 하는 식으로 프로그래밍했다. 


위 예제는 Tensorflow 1.5 버전부터 사용할 수 없는데, 중간에 사용된  tensorflow.train.SummaryWriter()  함수가 사라지고 그 기능이 다른 곳으로 refactoring 되었기 때문이다. 물론 기능은 남아있기 때문에 다른 방법으로 구현할 수 있었다.  tensorflow.summary.FileWriter()  함수가 그 기능을 대신하기 때문에, 위 함수로 해당 부분을 대체하면 된다. 


또한 Keras backend에서 session을 가져오는 것에서 약간의 내부적 순서 문제가 있었는지, 선언과 함수 실행부들을 이리저리 바꿔봐도 계속 오류가 났다. 여러 번의 삽질 끝에 찾은 방법은, 아예 다른 파일에 Tensorflow를 불러오고, Tensorflow의 session을 열어 session 내에서 해당 작업을 전부 수행하는 것이다. 


코드는 길지 않은데 아래와 같다. 


import
tensorflow as tf import numpy as np with tf.Session() as sess: fw = tf.summary.FileWriter('emb') # 위에서 말한 함수를 대체한 부분 z_list = np.load('z_vector.npy') # 따로 저장해 둔 z vector의 numpy array를 저장해둔 파일을 읽어왔다. init = tf.constant_initializer(z_list) z = tf.get_variable('z_tf', shape=[len(z_list), 64], initializer=init) # 불러온 z vector의 shape에 맞는 tensor를 만든다. z.initializer.run() saver = tf.train.Saver()

# configuration file을 만드는 부분

from tensorboard.plugins.projector.projector_config_pb2 import ProjectorConfig cfg = ProjectorConfig() embed = cfg.embeddings.add() embed.tensor_name = 'z_tf'

# embedding vector를 보여주기 위해 visualize 하는 부분

from tensorboard.plugins.projector import visualize_embeddings visualize_embeddings(fw, cfg)


saver.save(sess, 'emb/model.ckpt') # 임의의 경로에 .ckpt 파일을 저장한다


이런 방식으로 저장한 .ckpt 파일의 경로를 Tensorboard 명령어에 log_dir 로 넣어주면, 비로소 Tensorboard의  Projector  탭에 embedding space가 보여지게 된다. Tensorboard 의 사용법은 검색하면 바로 찾을 수 있으니 따로 적지는 않는다. 





[NUXLEAR]

+ Recent posts