[기초 3] data 가공
근 2달 만에 블로그에 글을 쓸 여유가 생겼다.
기존에는 data 가공 부분에 generator를 서술하려고 했지만
tensorflow 2의 dataset과 비교해본 결과, 이 것이 좀 더 자원을 효율적으로 쓰는 이유로 dataset를 뼈대로 삼아 서술하려 한다.
튜토리얼은 tensorflow 사이트에 공식 문서화되어 있어서 이 것만 따라해도 쉽게 할 수 있다.
www.tensorflow.org/guide/data_performance?hl=ko
tf.data API로 성능 향상하기 | TensorFlow Core
Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도 불구하고 공식 영문 문서의 내용과 일치하지 않을 수
www.tensorflow.org
dataset 라이브러리 설명은 아래 링크에 나와있어서 필요한 기능은 찾아서 하면 된다.
www.tensorflow.org/api_docs/python/tf/data/Dataset
tf.data.Dataset | TensorFlow Core v2.2.0
See Stable See Nightly Represents a potentially large set of elements. tf.data.Dataset( variant_tensor ) Used in the notebooks The tf.data.Dataset API supports writing descriptive and efficient input pipelines. Dataset usage follows a common pattern: Creat
www.tensorflow.org
데이터 가공을 하는 부분은 이전에 설명했던 모델 생성 부분과는 독립적으로 진행이 된다.
다음에 설명할 train 코드를 작성하는 부분에서 model instance와 dataset을 연결시켜주기 때문에
dataset 코드를 작성할 때는 모델에 대해 신경을 쓸 필요가 없다.
이제 코드로 보자.
import tensorflow as tf
import numpy as np
AUTOTUNE = tf.data.experimental.AUTOTUNE
def map_func(x, y):
return x, y/255
def getTrainDataset(x, y, batch_size=16, shuffle_buffer_size=1000):
_dataset = tf.data.Dataset.from_tensor_slices((x,y))
_dataset = _dataset.cache()
_dataset = _dataset.shuffle(shuffle_buffer_size)
_dataset = _dataset.map(map_func, num_parallel_calls=AUTOTUNE)
_dataset = _dataset.batch(batch_size)
_dataset = _dataset.repeat(-1)
_dataset = _dataset.prefetch(buffer_size=AUTOTUNE)
return _dataset
def getTestDataset(x, batch_size=16):
_tmp_y = np.array([-1 for _ in range(len(x))])
_dataset = tf.data.Dataset.from_tensor_slices((x,_tmp_y))
_dataset = _datset.map(map_func, num_parallel_calls=AUTOTUNE)
_dataset = _dataset.batch(batch_size)
_dataset = _dataset.prefetch(buffer_size=AUTOTUNE)
return _dataset
if __name__ == "__main__":
x = np.array([[0,1,0,0], [1,0,0,0], [0,0,0,1]])
y = np.array([4, 8, 1])
train_dataset = getTrainDataset(x, y)
위 코드는 임시로 x, y를 만들어서 dataset를 생성한 코드이다.
getTrainDataset과 getTestDataset으로 나눴는데 목적에 따라 필요한 dataset function이 다르기 때문이다.
train에서는 test와 비교했을 때, cache, shuffle, repeat이 추가적으로 쓰였다.
cache는 처음 불러온 데이터를 저장해놓고, 이후 필요하면 저장된 데이터를 불러다가 쓰는 방식이어서 지속적으로 데이터를 불러오는 학습에서 효율적이다.
shuffle은 당연히 train할 때 섞어줘야해서 쓰는 것이고, repeat(-1)은 데이터를 끊임없이 불러오는 용도이다.
예를 들어, repeat(3)을 하게 되면 data length * 3 만큼 데이터를 불러온 후, 더 부를 경우 더이상 데이터를 부를 없다고 하면서 에러를 토해내는데 이를 방지하기 위해 -1을 넣었다.
repeat(1)은 안하는 것과 동일하다.
prefetch는 데이터 로딩과 학습이 병렬적으로 이루어져서 데이터 로딩에서 병목 현상이 일어나는 것을 방지하기 때문에 train, test 양 쪽에서 사용하였다.
유의할 점은 map은 데이터를 로딩할 때 map function을 거쳐서 호출하는데 cache 이전에 사용하게 되면 막대한 메모리를 사용하게 되므로 resource가 충분하지 않는 경우 cache 다음에 map 을 사용하는 것이 중요하다.
이 모든 내용은 위 링크 중 tf.data API로 성능 향상하기 에 명시가 되어있고, 이 포스트에서는 간단하게 구현한 코드만 예시로 작성한 것이다.
좀 더 복잡하고 다양한 기능들을 사용하고 싶다면 위 쪽의 두 링크를 참조하면 된다.
여기까지 완료됐으면 학습 직전의 단계까지 모두 완성이 된 것이다.