2 분 소요

본 글은 [핸즈온 머신러닝 2판 (Hands-On Machine Learning with Scikit-Learn, keras & TensorFlow)] - (박해선 옮김) 책을 개인공부하기 위해 요약, 정리한 내용입니다. 전체 코드는 https://github.com/ingu627/handson-ml2에 기재했습니다.(원본 코드 fork) 뿐만 아니라 책에서 설명이 부족하거나 이해가 안 되는 것들은 외부 자료들을 토대로 메꿔 놓았습니다. 오타나 오류는 알려주시길 바라며, 도움이 되길 바랍니다.

13 텐서플로에서 데이터 적재와 전처리하기

  • 텐서플로는 데이터 API(tf.data)로 대규모 데이터셋을 효율적으로 적재하고 전처리할 수 있다.1
  • TFRecord는 프로토콜 버퍼(protocol buffer)를 담은 유연하고 효율적인 이진 포맷이다.2
  • TF 변환(tf.Transform) : 훈련 연산 효율을 높이기 위해 훈련 전에 전체 훈련 세트에 대해 실행하는 전처리 함수를 작성할 수 있다.
  • TF 데이터셋 (TFDS) : 각종 데이터셋을 다운로드할 수 있는 편리한 함수를 제공한다.3
    • 이미지넷과 같은 대용량 데이터셋도 포함된다.
    • 데이터 API로 조작할 수 있는 편리한 데이터셋 객체도 제공한다.

13.1 데이터 API

  • 데이터셋(dataset)은 연속된 데이터 샘플을 나타낸다.
  • tf.data.Dataset.from_tensor_slices() : 메모리에 있는 텐서로부터 데이터셋을 생성한다.4
import tensorflow as tf

X = tf.range(10)
dataset = tf.data.Dataset.from_tensor_slices(X)
dataset
# <TensorSliceDataset shapes: (), types: tf.int32>

for item in dataset:
    print(item)
    
# tf.Tensor(0, shape=(), dtype=int32)
# tf.Tensor(1, shape=(), dtype=int32)
# tf.Tensor(2, shape=(), dtype=int32)
# tf.Tensor(3, shape=(), dtype=int32)
# tf.Tensor(4, shape=(), dtype=int32)
# tf.Tensor(5, shape=(), dtype=int32)
# tf.Tensor(6, shape=(), dtype=int32)
# tf.Tensor(7, shape=(), dtype=int32)
# tf.Tensor(8, shape=(), dtype=int32)
# tf.Tensor(9, shape=(), dtype=int32)
  • from_tensor_slices() : 텐서를 받아 X의 각 원소가 아이템(item)으로 표현되는 tf.data.Dataset을 만든다.

13.1.1 연쇄 변환

dataset = dataset.repeat(3).batch(7)
for item in dataset:
    print(item)

# tf.Tensor([0 1 2 3 4 5 6], shape=(7,), dtype=int32)
# tf.Tensor([7 8 9 0 1 2 3], shape=(7,), dtype=int32)
# tf.Tensor([4 5 6 7 8 9 0], shape=(7,), dtype=int32)
# tf.Tensor([1 2 3 4 5 6 7], shape=(7,), dtype=int32)
# tf.Tensor([8 9], shape=(2,), dtype=int32)
  • repeat() : 원본 데이터셋의 아이템을 지정한 횟수만큼 반복하는 새로운 데이터셋을 반환한다.
  • 새로운 데이터셋에서 batch()를 호출하면 다시 새로운 데이터셋이 만들어진다.
    • batch() 메서드를 drop_remainder=True로 호출하면 길이가 모자란 마지막 배치를 버리고 모든 배치를 동일한 크기로 맞춘다.
  • map() 메서드를 호출하여 각 아이템에 사용자 정의 변환 함수를 적용할 수도 있다.
dataset = dataset.map(lambda x: x * 2)
  • filter() 메서드를 사용하여 조건에 맞는 데이터만 남기도록 데이터셋을 필터링한다.
dataset = dataset.filter(lambda x: x < 10)
  • 몇 개의 아이템만 확인하고 싶을 때는 take() 메서드를 사용한다.
for item in dataset.take(3):
    print(item)

# tf.Tensor([ 0  8 16 24 32 40 48], shape=(7,), dtype=int32)
# tf.Tensor([56 64 72  0  8 16 24], shape=(7,), dtype=int32)
# tf.Tensor([32 40 48 56 64 72  0], shape=(7,), dtype=int32)

13.1.2 데이터 셔플링

  • 경사 하강법은 훈련 세트에 있는 샘플이 독립적이고 동일한 분포(IID)를 따를 때 편향을 줄이고 안정적으로 수렴한다.5
    • shuffle() 메서드를 이용하여 버퍼 크기(buffer_size)만큼 메모리에 로드한 뒤 무작위로 샘플을 섞는다.
dataset = tf.data.Dataset.range(10).repeat(3) # 0에서 9까지 세 번 반복
dataset = dataset.shuffle(buffer_size=5, seed=42).batch(7)
for item in dataset:
    print(item)

# tf.Tensor([0 2 3 6 7 9 4], shape=(7,), dtype=int64)
# tf.Tensor([5 0 1 1 8 6 5], shape=(7,), dtype=int64)
# tf.Tensor([4 8 7 1 2 3 0], shape=(7,), dtype=int64)
# tf.Tensor([5 4 2 7 8 9 9], shape=(7,), dtype=int64)
# tf.Tensor([3 6], shape=(2,), dtype=int64)
  • 메모리 용량을 초과하는 대규모 데이터셋은 단일 버퍼만으로 충분한 무작위 셔플을 보장하기 어려우므로, 원본 데이터 파일을 여러 개로 분할하여 샤딩(sharding)한 뒤 파일 단위 셔플과 샘플 단위 셔플을 병행한다.

13.2 TFRecord 포맷

  • TFRecord는 대용량 데이터를 저장하고 네트워크나 디스크 I/O 병목을 줄이며 효율적으로 읽기 위한 텐서플로의 표준 이진 포맷이다.
  • TFRecord는 크기가 다른 연속된 이진 레코드(길이, CRC 체크섬, 데이터, 데이터 CRC)를 순차 저장하는 단순한 이진 포맷이다.
  • tf.io.TFRecordWriter 클래스를 사용해 TFRecord 파일을 생성할 수 있다.

한계 및 트레이드오프

  • 버퍼 크기와 메모리 트레이드오프: shuffle(buffer_size)에서 버퍼 크기를 크게 설정할수록 균일한 무작위 추출(IID)에 근접하지만 RAM 사용량이 증가하여 OOM(Out of Memory) 위험이 발생하며, 작게 설정하면 국소적 상관관계가 남아 학습 편향을 유발한다.
  • CPU 전처리 및 GPU 대기 병목: map() 변환에서 복잡한 전처리를 수행할 경우 CPU 연산 지연으로 인해 GPU가 유휴 상태에 빠질 수 있으므로, num_parallel_calls=tf.data.AUTOTUNE 병렬화와 prefetch() 파이프라인 결합이 필수적이다.
  • TFRecord 이진 직렬화의 디버깅 한계: TFRecord는 I/O 성능이 우수하지만 이진 프로토콜 버퍼 구조상 원본 데이터를 직접 육안으로 검사하거나 부분 수정하기 어렵고 파싱 스키마 정의 불일치 시 런타임 오류 추적이 까다롭다.

References

  1. Aurélien Géron, Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow, 2nd Edition, Chapter 13 Notebook, https://github.com/ageron/handson-ml2/blob/master/13_loading_and_preprocessing_data.ipynb ↩

  2. TensorFlow Documentation, TFRecord and tf.train.Example, https://www.tensorflow.org/tutorials/load_data/tfrecord ↩

  3. TensorFlow Datasets Documentation, TFDS Overview, https://www.tensorflow.org/datasets ↩

  4. TensorFlow API Documentation, tf.data.Dataset.from_tensor_slices, https://www.tensorflow.org/api_docs/python/tf/data/Dataset#from_tensor_slices ↩

  5. TensorFlow Guide, Better performance with the tf.data API, https://www.tensorflow.org/guide/data_performance ↩

댓글남기기