[핸즈온 머신러닝] 13장. 텐서플로에서 데이터 적재와 전처리하기
본 글은 [핸즈온 머신러닝 2판 (Hands-On Machine Learning with Scikit-Learn, keras & TensorFlow)] - (박해선 옮김) 책을 개인공부하기 위해 요약, 정리한 내용입니다.
전체 코드는 https://github.com/ingu627/handson-ml2에 기재했습니다.(원본 코드 fork)
뿐만 아니라 책에서 설명이 부족하거나 이해가 안 되는 것들은 외부 자료들을 토대로 메꿔 놓았습니다.
오타나 오류는 알려주시길 바라며, 도움이 되길 바랍니다.
13 텐서플로에서 데이터 적재와 전처리하기
- 텐서플로는 데이터 API로 대규모 데이터셋을 쉽게 처리할 수 있다.
TFRecord
는 프로토콜 버퍼(protocol buffer)를 담은 유연하고 효율적인 이진 포맷이다.- TF 변환(tf.Transform) : (실행 속도를 높이기 위해) 훈련 전에 전체 훈련 세트에 대해 실행하는 전처리 함수를 작성할 수 있다.
- TF 데이터셋 (TFDS) : 각종 데이터셋을 다운로드할 수 있는 편리한 함수를 제공한다.
- 이미지넷과 같은 대용량 데이터셋도 포함된다.
- 데이터 API로 조작할 수 있는 편리한 데이터셋 객체도 제공한다.
13.1 데이터 API
- 데이터셋(dataset)은 연속된 데이터 샘플을 나타낸다.
tf.data.Dataset.from_tensor_slices()
: 를 이용해 메모리에서 전체 데이터셋을 생성
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
로 호출하면 길이가 모자란 마지막 배치를 버리고 모든 배치를 동일한 크기로 맞춘다.
- batch() 메서드를
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 데이터 셔플링
- 경사 하강법은 훈련 세트에 있는 샘플이 독립적이고 동일한 분포일 때 최고의 성능을 발휘한다.
shuffle()
을 이용하여 샘플을 섞는다.
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)
- 메모리 용량보다 큰 대규모 데이터셋은 버퍼가 데이터셋에 비해 작기 때문에 해결책으로 원본 데이터 자체를 섞는다.
13.2 TFRecord 포맷
- TFRecord는 대용량 데이터를 저장하고 효율적으로 읽기 위해 텐서플로가 선호하는 포맷
- TFRecord는 크기가 다른 연속된 이진 레코드를 저장하는 단순한 이진 포맷이다.
tf.io.TFecordWriter
클래스를 사용해 TRecord를 손쉽게 만들 수 있다.
댓글남기기