Tensorflow : Data API

숭글·2021년 2월 18일
0

딥러닝

목록 보기
1/3

동영상인 데이터셋을 사용하다보니까 메모리에 다 올라가지 않는 문제가 있었다... train_on_batch()사용으로 버텨보다가,,
텐서플로에서 제공하는 data API 사용을 도전!!!!

data API는 데이터셋 객체를 만들고 데이터를 읽어 올 위치와 변환 방법을 지정함으로서 대규모 데이터셋을 효율적으로 로드하고 전처리마저 구현할 수 있다고 한다!

  • 데이터셋 객체를 만들고 데이터를 읽어 올 위치와 변환 방법을 지정하면 됨

멀티스레팅, 큐, 배치, 프리페치와 같은 사항도 대신 처리해주고 tf.keras와도 잘 동작한다고 한다~! (fit() 못잃어,,)

텍스트 파일(ex. CSV파일), 고정 길이의 레코드를 가진 이진 파일, 텐서 플로의 TFRecord 포맷을 사용하는 이진 파일에서 데이터를 읽을 수 있음(TFRecord 포맷은 길이가 다른 레코드를 지원함)
SQL 데이터베이스에서 읽는 기능도 지원하고 구글 빅쿼리와 같은 다양한 데이터 소스에서 읽을 수 있는 오픈 소스도 있다고한다~~

TF 변환 (tf.Transform)
: 훈련 전에 전체 훈련 세트에 대해 실행하는 전처리 함수 작성

데이터셋(dataset)

연속된 데이터 샘플(디스크에서 데이터를 점진적으로 읽는 데이터셋 사용)

tf.data.Dataset.from_tensor_slices(X)

from_tensor_slices() 함수는 텐서를 받아 X의 각 원소가 아이템으로 표현되는 tf.data.Dataset을 만듦

아이템 순회법

X = tf.range(10)으로 dataset을 만듦

for item in dataset:
  print(item)
output:
  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)

연쇄 변환

repeat()

repeart()메소드를 호출하여 원본 데이터셋의 아이템을 반복

  • 메모리에서 계속 반복하는 것은 x

매개변수 없이 호출하면 끝없이 반복되므로 반복하는 코드가 중지하는 때를 결정해야함

dataset = dataset.repeat(3).batch(7)

for item in dataset:
  print(item)
  

output:

  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)

데이터셋을 3번 반복하고 아이템을 7개씩 묶어 출력함
마지막 아이템처럼 크기가 다른 아이템은 batch()메서드에 drop_remainder = True 로 호출하여 버릴 수 있음

map()

전처리 작업에도 적용할 수 있으나 복잡한 계산을 포함하는 경우엔 여러 스레드로 나누어 속도를 높이는 것이 좋음

  • num_parallel_calls 매개변수 지정하면 됨
dataset = dataset.map(lambda x: x * 2)

apply()

각 아이템에 변환을 적용하는 map()과 달리 데이터셋 전체에 변환을 적용

filter()

데이터셋 필터링

dataset = dataset.filter(lambda x: x < 10)

take()

데이터셋에 있는 몇 개의 아이템만 볼 때 사용

데이터 셔플링

경사 하강법은 train set에 있는 샘플이 독립적이고 동일한 분포일 때 최고의 성능을 발휘함
--> shuffle() 메소드를 사용하여 샘플을 섞음

shuffle()

데이터셋의 처음 아이템을 buffer_size 만큼 채운 후, 아이템이 요청되면 버퍼에서 랜덤하게 하나를 꺼내 반환한 후, 원본 데이터셋의 모든 아이템이 사용될 때까지 원본 데이터셋에서 새로운 아이템을 꺼내 버퍼를 채움

  • 셔플링의 효과를 보기 위해 버퍼 크기를 보유한 메모리 크기는 넘기지 않는 안에서 충분히 크게 해야함
dataset = tf.data.Dataset.range(10).repeat(3)

dataset = dataset.shuffle(buffer_size=5, seed=42).batch(7)

for item in dataset:
  print(item)
  
output:

  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)

대규모 데이터셋은 버퍼가 데이터셋에 비해 작기 때문에 위와 같은 간단한 셔플링 버퍼 방식으로 충분하지 않음
-->원본 데이터 자체를 섞어야함
-->많이 사용하는 방법으론 원본 데이터를 여러 파일로 나눈 다음 훈련하는 동안 무작위로 읽음

data API를 사용하면 간단!

list_files()

파일 경로를 섞은 데이터셋을 반환
매개변수로 파일 경로를 담은 리스트를 줌

데이터 전처리

데이터 적재와 전처리 합치기

def csv_reader_dataset(filepaths, repeat = 1, n_readers = 5, n_read_threads = None, shuffle_buffer_size = 10000, n_parse_threads = 5, batch_size = 32):
  dataset = tf.data.Dataset.list_files(filepaths).repeat(repeat)
  dataset - dataset.interleave(
      lambda filepath: tf.data.TextLineDataset(filepath).skip(1), 
      cycle_length = n_readers, num_parallel_calls = n_read_threads
  )
  dataset = dataset.shuffle(shuffle_buffer_size)
  dataset = dataset.map(preprocess, num_parallel_calls= n_parse_threads)

  return dataset.batch(batch_size).prefetch(1)

앞에 한 걸 다 정리해주는 듯한 함수

이제 내 코드를 짜러,,~!

profile
Hi!😁 I'm Soongle. Welcome to my Velog!!!

0개의 댓글