🔥알림🔥
① 테디노트 유튜브 -
구경하러 가기!
② LangChain 한국어 튜토리얼
바로가기 👀
③ 랭체인 노트 무료 전자책(wikidocs)
바로가기 🙌
④ RAG 비법노트 LangChain 강의오픈
바로가기 🙌
⑤ 서울대 PyTorch 딥러닝 강의
바로가기 🙌
[tensorflow] Dataset, batch, window, flat_map을 활용한 loader 만들기
tf.data.Dataset
을 활용하여 다양한 Dataset 로더를 만들 수 있습니다.
그리고, 로더를 활용하여, shuffle
, batch_size
, window
데이터셋 생성등 다양한 종류를 데이터 셋을 상황에 맞게 생성하고 모델에 feed할 수 있도록 제공해 줍니다.
더 이상 numpy로 한땀 한땀 만들어 줄 필요없이, 간단한 옵션 몇 개면 데이터세트를 완성할 수 있습니다.
References: 텐서플로우 공식 도큐먼트
# 필요한 라이브러리 import
import numpy as np
import tensorflow as tf
1. dimension을 1만큼 늘려주기
1-1. tensorflow 의 expand_dim : 차원 늘리기
x = np.arange(20)
tf.expand_dims(x, 1).shape
1-2. numpy의 expand_dims와 동일
np.expand_dims(x, 1).shape
1-3. from_tensor_slices: numpy array나 list를 tensor dataset으로 변환
from_tensor_slices
는 list와 numpy array 모두 변환하도록 지원하고 있습니다.
ds = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5])
for d in ds:
print(d)
ds = tf.data.Dataset.from_tensor_slices(np.arange(10))
ds
for d in ds:
print(d)
2. batch
batch는 model에 학습시킬 때 batch_size
를 지정하여 size
만큼 데이터를 읽어 들여 학습시킬 때 유용한 method입니다.
이미지와 같은 큰 사이즈는 memory에 한 번에 올라가지 못하기 때문에, 이렇게 batch를 나누어서 학습시키기도 하구요.
또한, model이 weight를 업데이트 할 때, 1개의 batch가 끝나고 난 후 업데이트를 하게 되는데, 업데이트 빈도를 조절하는 효과도 있습니다.
drop_remainder
는 마지만 남은 데이터를 drop 할 것인지 여부
ds = tf.data.Dataset.range(8)
ds = ds.batch(3, drop_remainder=True)
list(ds.as_numpy_iterator())
원래는 6, 7 이 batch
로 출력되어야 하지만 drop_remainder=True
옵션이 나머지를 버린다
ds = tf.data.Dataset.range(8)
for d in ds.batch(3, drop_remainder=True):
print(d)
3. window: Time Series 데이터셋 생성에 유용
Time Series 데이터셋을 구성할 때 굉장히 유용하게 활용할 수 있습니다.
window
: 그룹화 할 윈도우 크기(갯수)drop_remainder
: 남은 부분을 버릴지 살릴지 여부shift
는 1 iteration당 몇 개씩 이동할 것인지
drop_remainder=False
인 경우
ds = tf.data.Dataset.range(10)
ds = ds.window(5, shift=1, drop_remainder=False)
for d in ds:
print(list(d.as_numpy_iterator()))
drop_remainder=True
인 경우
ds = tf.data.Dataset.range(10)
ds = ds.window(5, shift=1, drop_remainder=True)
for d in ds:
print(list(d.as_numpy_iterator()))
shift=2
로 설정: 2칸씩 이동
ds = tf.data.Dataset.range(10)
ds = ds.window(5, shift=2, drop_remainder=True)
for d in ds:
print(list(d.as_numpy_iterator()))
4. flat_map
flat_map
은 dataset에 함수를 apply해주고, 결과를 flatten하게 펼쳐 줍니다.
아래는 lambda 함수를 통해 3개의 batch를 읽어들인 뒤 flatten된 리턴값을 받습니다.
ds = tf.data.Dataset.range(10)
ds = ds.window(5, shift=1, drop_remainder=True)
ds = ds.flat_map(lambda w: w.batch(3))
for d in ds:
print(d)
ds = tf.data.Dataset.range(10)
ds = ds.window(5, shift=1, drop_remainder=True)
ds = ds.flat_map(lambda w: w.batch(5))
for d in ds:
print(d)
5. shuffle
shuffle은 Dataset
을 섞어주는 역할을 하며, 반드시 학습전에 shuffle을 통해 적절하게 Dataset을 섞어주어야 합니다.
# shuffle을 해주지 않은 경우
ds = tf.data.Dataset.from_tensor_slices(np.arange(10))#.shuffle()
for d in ds:
print(d)
# shuffle 설정
ds = tf.data.Dataset.from_tensor_slices(np.arange(10)).shuffle(buffer_size=5)
for d in ds:
print(d)
위의 shuffle함수에서 꼭 지정해주어야하는 인자는 buffer_size
입니다.
텐서플로우 공식 도큐먼트에 의하면,
데이터세트는
buffer_size
요소로 버퍼를 채운 다음이 버퍼에서 요소를 무작위로 샘플링하여 선택한 요소를 새 요소로 바꿉니다.완벽한 셔플 링을 위해서는 데이터 세트의 전체 크기보다 크거나 같은 버퍼 크기가 필요합니다.
예를 들어, 데이터 집합에 10,000 개의 요소가 있지만
buffer_size
가 1,000으로 설정된 경우 셔플은 처음에 버퍼의 처음 1,000 개 요소 중 임의의 요소 만 선택합니다.요소가 선택되면 버퍼의 공간이 다음 요소 (즉, 1,001-st)로 대체되어 1,000 요소 버퍼를 유지합니다.
6. map
Dataset의 map
함수는 pandas의 map
과 유사합니다.
Dataset 전체에 함수를 맵핑합니다.
Time Series Dataset을 만드려는 경우, train/label 값을 분류하는 용도로 활용할 수 있습니다.
x[:-1], x[-1:] 의 의도는 각 row의 마지막 index 전까지는 train data로, 마지막 index는 label로 활용하겠다는 의도입니다.
window_size=5
ds = tf.data.Dataset.range(10)
ds = ds.window(window_size, shift=1, drop_remainder=True)
ds = ds.flat_map(lambda w: w.batch(window_size))
ds = ds.shuffle(10)
# 첫 4개와 마지막 1개를 분리
ds = ds.map(lambda x: (x[:-1], x[-1:]))
for x, y in ds:
print('train set: {}'.format(x))
print('label set: {}'.format(y))
실습 예제: Sunspots 데이터셋을 활용하여 window_dataset 만들기
import csv
import tensorflow as tf
import numpy as np
import urllib
url = 'https://storage.googleapis.com/download.tensorflow.org/data/Sunspots.csv'
urllib.request.urlretrieve(url, 'sunspots.csv')
with open('sunspots.csv') as csvfile:
reader = csv.reader(csvfile, delimiter=',')
next(reader)
i = 0
for row in reader:
print(row)
i+=1
if i > 5:
break
각 row의 2번 index의 데이터를 우리가 time series 데이터로 만들어 보려고 합니다.
train_data = []
with open('sunspots.csv') as csvfile:
reader = csv.reader(csvfile, delimiter=',')
# 첫 줄은 header이므로 skip 합니다.
next(reader)
for row in reader:
train_data.append(float(row[2]))
train_data[:5]
일단, list에 모든 데이터를 담았습니다.
이제 Dataset 모듈을 통해 window_dataset
을 만들어 보겠습니다.
train_data = np.asarray(train_data)
train_data.shape
train_data의 dimension을 늘려주었습니다.
train_data = np.expand_dims(train_data, 1)
train_data.shape
tensor slices로 변환하겠습니다.
dataset = tf.data.Dataset.from_tensor_slices(train_data)
i=0
for data in dataset:
print(data)
i+=1
if i > 5:
break
그 다음으로는 원하는 window_size
만큼 묶어 주어야합니다.
내가 과거의 20일의 데이터를 보고 21일 째의 데이터를 예측해야한다라고 가정한다면,
window_size
= 20 + 1 로 잡아줍니다.
20개는 train data의 갯수, 1은 label의 갯수입니다.
window_size=20 + 1
dataset = dataset.window(window_size, shift=1, drop_remainder=True)
그 다음에는 flat_map
을 통해서 각 batch 별로 flatten하게 shape을 펼쳐줍니다.
dataset = dataset.flat_map(lambda w: w.batch(window_size + 1))
# 2개만 출력해서 결과를 살펴보겠습니다.
for data in dataset.take(2):
print(data)
그 다음은 batch
별로 shuffle을 해주면 좋겠네요~
buffer_size
는 임의로 500개를 지정하겠습니다.
dataset = dataset.shuffle(500)
가장 중요한 마지막 단계 입니다.
train/label이 섞여서 21개의 데이터가 각 batch
에 잡혀 있습니다.
train/label로 섞인 batch
를 train (20개), label (1개)로 분리해주면 됩니다.
분리해줄 때 tuple로 묶어주지 않으면 error를 내뱉습니다.
dataset = dataset.map(lambda x: (x[:-1], x[-1:]))
for train, label in dataset.take(2):
print('train: {}'.format(train))
print('label: {}'.format(label))
for d in dataset.batch(10).take(2):
print(d)
종합하여 함수형으로 만들면 다음과 같이 됩니다.
train_data = []
with open('sunspots.csv') as csvfile:
reader = csv.reader(csvfile, delimiter=',')
# 첫 줄은 header이므로 skip 합니다.
next(reader)
for row in reader:
train_data.append(float(row[2]))
def windowed_dataset(data, window_size, batch_size, shuffle_buffer):
data = np.expand_dims(data, axis=1)
ds = tf.data.Dataset.from_tensor_slices(data)
ds = ds.window(window_size + 1, shift=1, drop_remainder=True)
ds = ds.flat_map(lambda w: w.batch(window_size + 1))
ds = ds.shuffle(shuffle_buffer)
ds = ds.map(lambda w: (w[:-1], w[-1:]))
return ds.batch(batch_size)
window_ds = windowed_dataset(train_data, window_size=20, batch_size=10, shuffle_buffer=500)
window_ds
의 shape은 (10, 20, 1)로 출력이 되게 됩니다.
- 10은
batch_size
- 20은
window_size
(train data) - 1은
label
로 return 되는 것을 확인할 수 있습니다.
for d in window_ds:
print(d)
break
댓글남기기