이 페이지는 Cloud Translation API를 통해 번역되었습니다.
Switch to English

tf.data : TensorFlow 입력 파이프 라인 빌드

TensorFlow.org에서보기 Google Colab에서 실행 GitHub에서 소스보기 노트북 다운로드

tf.data API를 사용하면 간단하고 재사용 가능한 조각으로 복잡한 입력 파이프 라인을 구축 할 수 있습니다. 예를 들어, 이미지 모델의 파이프 라인은 분산 파일 시스템의 파일에서 데이터를 집계하고 각 이미지에 임의의 섭동을 적용하며 무작위로 선택한 이미지를 배치를 위해 병합하여 학습 할 수 있습니다. 텍스트 모델의 파이프 라인에는 원시 텍스트 데이터에서 심볼을 추출하고이를 룩업 테이블이있는 식별자를 포함시키는 것으로 변환하고 길이가 다른 시퀀스를 일괄 처리하는 것이 포함될 수 있습니다. tf.data API를 사용하면 많은 양의 데이터를 처리하고 다른 데이터 형식에서 읽고 복잡한 변환을 수행 할 수 있습니다.

tf.data API는 일련의 요소를 나타내는 tf.data.Dataset 추상화를 소개합니다. 각 요소는 하나 이상의 구성 요소로 구성됩니다. 예를 들어, 이미지 파이프 라인에서 요소는 이미지와 해당 레이블을 나타내는 텐서 구성 요소 쌍이있는 단일 학습 예일 수 있습니다.

데이터 세트를 생성하는 방법에는 두 가지가 있습니다.

  • 데이터 소스 는 메모리 또는 하나 이상의 파일에 저장된 Dataset 로 데이터 Dataset 를 구성합니다.

  • 데이터 변환 은 하나 이상의 tf.data.Dataset 객체에서 데이터 세트를 구성합니다.

 import tensorflow as tf
 
 import pathlib
import os
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

np.set_printoptions(precision=4)
 

기본 역학

입력 파이프 라인을 만들려면 데이터 소스로 시작해야합니다. 예를 들어 메모리의 Dataset 에서 데이터 Dataset 를 구성하려면 tf.data.Dataset.from_tensors() 또는 tf.data.Dataset.from_tensor_slices() 사용할 수 있습니다. 또는 입력 데이터가 권장 TFRecord 형식의 파일에 저장된 경우 tf.data.TFRecordDataset() 사용할 수 있습니다.

Dataset 객체가 있으면 tf.data.Dataset 객체의 메서드 호출을 연결하여 새로운 Dataset 으로 변환 할 수 있습니다. 예를 들어 Dataset.map() 과 같은 요소 별 변환과 Dataset.batch() 와 같은 다중 요소 변환을 적용 할 수 있습니다. 전체 변환 목록은 tf.data.Dataset 설명서를 참조하십시오.

Dataset 객체는 Python iterable입니다. 이를 통해 for 루프를 사용하여 요소를 사용할 수 있습니다.

 dataset = tf.data.Dataset.from_tensor_slices([8, 3, 0, 8, 2, 1])
dataset
 
<TensorSliceDataset shapes: (), types: tf.int32>
 for elem in dataset:
  print(elem.numpy())
 
8
3
0
8
2
1

또는 iter 사용하여 명시 적으로 Python iterator를 작성하고 next 사용하여 요소를 소비함으로써 :

 it = iter(dataset)

print(next(it).numpy())
 
8

또는 reduce 변환을 사용하여 데이터 세트 요소를 사용할 수 있습니다. 그러면 모든 요소가 줄어들어 단일 결과가 생성됩니다. 다음 예제는 reduce 변환을 사용하여 정수 데이터 집합의 합계를 계산하는 방법을 보여줍니다.

 print(dataset.reduce(0, lambda state, value: state + value).numpy())
 
22

데이터 세트 구조

데이터 세트 각각은 동일한 (중첩) 구조를 가지며, 구조의 각 구성 요소에 의한 입력 표현할 될 수있는 요소가 포함 tf.TypeSpec 포함 tf.Tensor , tf.sparse.SparseTensor , tf.RaggedTensor , tf.TensorArray , 또는 tf.data.Dataset 입니다.

Dataset.element_spec 속성을 사용하면 각 요소 구성 요소의 유형을 검사 할 수 있습니다. 이 속성은 단일 구성 요소, 구성 요소 튜플 또는 구성 요소의 중첩 튜플 일 수있는 요소의 구조와 일치하는 tf.TypeSpec 객체의 중첩 구조 를 반환합니다. 예를 들면 다음과 같습니다.

 dataset1 = tf.data.Dataset.from_tensor_slices(tf.random.uniform([4, 10]))

dataset1.element_spec
 
TensorSpec(shape=(10,), dtype=tf.float32, name=None)
 dataset2 = tf.data.Dataset.from_tensor_slices(
   (tf.random.uniform([4]),
    tf.random.uniform([4, 100], maxval=100, dtype=tf.int32)))

dataset2.element_spec
 
(TensorSpec(shape=(), dtype=tf.float32, name=None),
 TensorSpec(shape=(100,), dtype=tf.int32, name=None))
 dataset3 = tf.data.Dataset.zip((dataset1, dataset2))

dataset3.element_spec
 
(TensorSpec(shape=(10,), dtype=tf.float32, name=None),
 (TensorSpec(shape=(), dtype=tf.float32, name=None),
  TensorSpec(shape=(100,), dtype=tf.int32, name=None)))
 # Dataset containing a sparse tensor.
dataset4 = tf.data.Dataset.from_tensors(tf.SparseTensor(indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]))

dataset4.element_spec
 
SparseTensorSpec(TensorShape([3, 4]), tf.int32)
 # Use value_type to see the type of value represented by the element spec
dataset4.element_spec.value_type
 
tensorflow.python.framework.sparse_tensor.SparseTensor

Dataset 변환은 모든 구조의 데이터 세트를 지원합니다. 사용시 Dataset.map()Dataset.filter() 각각의 요소에 적용될 변환 함수를, 소자 구조가 함수의 인수를 결정

 dataset1 = tf.data.Dataset.from_tensor_slices(
    tf.random.uniform([4, 10], minval=1, maxval=10, dtype=tf.int32))

dataset1
 
<TensorSliceDataset shapes: (10,), types: tf.int32>
 for z in dataset1:
  print(z.numpy())
 
[8 1 2 6 1 7 2 6 1 3]
[6 5 6 5 3 5 2 5 3 6]
[5 8 4 8 3 1 4 6 4 8]
[2 4 5 8 3 5 7 9 4 2]

 dataset2 = tf.data.Dataset.from_tensor_slices(
   (tf.random.uniform([4]),
    tf.random.uniform([4, 100], maxval=100, dtype=tf.int32)))

dataset2
 
<TensorSliceDataset shapes: ((), (100,)), types: (tf.float32, tf.int32)>
 dataset3 = tf.data.Dataset.zip((dataset1, dataset2))

dataset3
 
<ZipDataset shapes: ((10,), ((), (100,))), types: (tf.int32, (tf.float32, tf.int32))>
 for a, (b,c) in dataset3:
  print('shapes: {a.shape}, {b.shape}, {c.shape}'.format(a=a, b=b, c=c))
 
shapes: (10,), (), (100,)
shapes: (10,), (), (100,)
shapes: (10,), (), (100,)
shapes: (10,), (), (100,)

입력 데이터 읽기

NumPy 배열 소비

자세한 예는 NumPy 배열로드를 참조하십시오.

모든 입력 데이터가 메모리에 맞는 경우 Dataset 를 작성하는 가장 간단한 방법은 tf.Tensor 오브젝트로 변환하고 Dataset.from_tensor_slices() 사용하는 Dataset.from_tensor_slices() 입니다.

 train, test = tf.keras.datasets.fashion_mnist.load_data()
 
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
8192/5148 [===============================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step

 images, labels = train
images = images/255

dataset = tf.data.Dataset.from_tensor_slices((images, labels))
dataset
 
<TensorSliceDataset shapes: ((28, 28), ()), types: (tf.float64, tf.uint8)>

파이썬 생성기 소비

tf.data.Dataset 으로 쉽게 수집 할 수있는 또 다른 일반적인 데이터 소스는 python generator입니다.

 def count(stop):
  i = 0
  while i<stop:
    yield i
    i += 1
 
 for n in count(5):
  print(n)
 
0
1
2
3
4

Dataset.from_generator 생성자는 파이썬 생성기를 완전한 기능의 tf.data.Dataset 변환합니다.

생성자는 반복자가 아닌 입력 가능 항목을 입력으로 사용합니다. 이를 통해 생성기가 끝에 도달하면 다시 시작할 수 있습니다. 선택적인 args 인수를 취하는데,이 인수는 호출 가능 인수로 전달됩니다.

output_types 때문에 인수 필요 tf.data 빌드 tf.Graph 내부적으로, 그래프의 에지는 필요 tf.dtype .

 ds_counter = tf.data.Dataset.from_generator(count, args=[25], output_types=tf.int32, output_shapes = (), )
 
 for count_batch in ds_counter.repeat().batch(10).take(10):
  print(count_batch.numpy())
 
[0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
[20 21 22 23 24  0  1  2  3  4]
[ 5  6  7  8  9 10 11 12 13 14]
[15 16 17 18 19 20 21 22 23 24]
[0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
[20 21 22 23 24  0  1  2  3  4]
[ 5  6  7  8  9 10 11 12 13 14]
[15 16 17 18 19 20 21 22 23 24]

output_shapes 인수는 필수는 아니지만 많은 tensorflow 조작이 알 수없는 순위의 텐서를 지원하지 않으므로 권장됩니다. 특정 축의 길이를 알 수 없거나 가변적 인 경우 output_shapes 에서 None 으로 설정하십시오.

output_shapesoutput_types 는 다른 데이터 세트 메소드와 동일한 중첩 규칙을 따릅니다.

다음은 두 가지 측면을 모두 보여주는 예제 생성기입니다. 두 배열은 길이가 알려지지 않은 벡터입니다.

 def gen_series():
  i = 0
  while True:
    size = np.random.randint(0, 10)
    yield i, np.random.normal(size=(size,))
    i += 1
 
 for i, series in gen_series():
  print(i, ":", str(series))
  if i > 5:
    break
 
0 : [-1.978  -1.0531  0.1959 -2.1618]
1 : [ 1.9185 -0.1874  0.5084]
2 : [0.1441 0.3987 0.7737 0.9266 1.5057 0.9151]
3 : [ 0.681  -0.6155 -0.1231 -0.2429  0.6892  1.2571 -1.7588 -1.6575 -0.5375]
4 : [-0.5567  1.5298  0.7242  0.2213]
5 : [ 1.5572 -0.6856]
6 : [-1.0965 -0.336   1.2405  0.6006]

첫 번째 출력은 int32 이고 두 번째 출력은 float32 입니다.

첫 번째 항목은 스칼라 모양 () 이고 두 번째 항목은 길이, 모양이 알 수없는 벡터 (None,)

 ds_series = tf.data.Dataset.from_generator(
    gen_series, 
    output_types=(tf.int32, tf.float32), 
    output_shapes=((), (None,)))

ds_series
 
<FlatMapDataset shapes: ((), (None,)), types: (tf.int32, tf.float32)>

이제 일반 tf.data.Dataset 처럼 사용할 수 있습니다. 가변 모양으로 데이터 집합을 일괄 처리 할 때는 Dataset.padded_batch 를 사용해야 Dataset.padded_batch .

 ds_series_batch = ds_series.shuffle(20).padded_batch(10)

ids, sequence_batch = next(iter(ds_series_batch))
print(ids.numpy())
print()
print(sequence_batch.numpy())
 
[ 2 10 18  3  6 15 25 23  0  4]

[[ 1.2665 -0.6274  0.4076  1.0146  0.      0.      0.      0.    ]
 [ 0.8091 -0.0683 -0.1464  0.2734  0.7461 -0.1009  0.      0.    ]
 [-0.9381  1.5075  0.      0.      0.      0.      0.      0.    ]
 [ 1.5705  0.4438  0.      0.      0.      0.      0.      0.    ]
 [-0.4692 -1.8328 -2.2838  0.7418  0.0172 -0.3547 -1.4502 -1.2786]
 [-1.574   0.      0.      0.      0.      0.      0.      0.    ]
 [-0.9274  1.4758  0.      0.      0.      0.      0.      0.    ]
 [-0.5043  0.7066  0.9599 -1.2986  0.      0.      0.      0.    ]
 [ 0.      0.      0.      0.      0.      0.      0.      0.    ]
 [-0.4893 -0.6937  0.      0.      0.      0.      0.      0.    ]]

보다 현실적인 예를 보려면 preprocessing.image.ImageDataGeneratortf.data.Dataset .

먼저 데이터를 다운로드하십시오.

 flowers = tf.keras.utils.get_file(
    'flower_photos',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
    untar=True)
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz
228818944/228813984 [==============================] - 2s 0us/step

이미지를 만듭니다 image.ImageDataGenerator

 img_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255, rotation_range=20)
 
 images, labels = next(img_gen.flow_from_directory(flowers))
 
Found 3670 images belonging to 5 classes.

 print(images.dtype, images.shape)
print(labels.dtype, labels.shape)
 
float32 (32, 256, 256, 3)
float32 (32, 5)

 ds = tf.data.Dataset.from_generator(
    img_gen.flow_from_directory, args=[flowers], 
    output_types=(tf.float32, tf.float32), 
    output_shapes=([32,256,256,3], [32,5])
)

ds
 
<FlatMapDataset shapes: ((32, 256, 256, 3), (32, 5)), types: (tf.float32, tf.float32)>

TFRecord 데이터 소비

엔드 투 엔드 예제는 TFRecord로드를 참조하십시오.

tf.data API는 다양한 파일 형식을 지원하므로 메모리에 맞지 않는 큰 데이터 세트를 처리 할 수 ​​있습니다. 예를 들어, TFRecord 파일 형식은 많은 TensorFlow 애플리케이션이 데이터 학습에 사용하는 간단한 레코드 지향 이진 형식입니다. tf.data.TFRecordDataset 클래스를 사용하면 입력 파이프 라인의 일부로 하나 이상의 TFRecord 파일 내용을 스트리밍 할 수 있습니다.

다음은 FNSS (French Street Name Signs)의 테스트 파일을 사용하는 예입니다.

 # Creates a dataset that reads all of the examples from two files.
fsns_test_file = tf.keras.utils.get_file("fsns.tfrec", "https://storage.googleapis.com/download.tensorflow.org/data/fsns-20160927/testdata/fsns-00000-of-00001")
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/fsns-20160927/testdata/fsns-00000-of-00001
7905280/7904079 [==============================] - 0s 0us/step

TFRecordDataset 초기화 프로그램의 filenames 인수는 문자열, 문자열 목록 또는 tf.Tensor 문자열 일 수 있습니다. 따라서 교육 및 검증 목적으로 두 파일 세트가있는 경우 파일 이름을 입력 인수로 사용하여 데이터 세트를 생성하는 팩토리 메소드를 작성할 수 있습니다.

 dataset = tf.data.TFRecordDataset(filenames = [fsns_test_file])
dataset
 
<TFRecordDatasetV2 shapes: (), types: tf.string>

많은 TensorFlow 프로젝트는 TFRecord 파일에서 직렬화 된 tf.train.Example 레코드를 사용합니다. 검사하기 전에이를 해독해야합니다.

 raw_example = next(iter(dataset))
parsed = tf.train.Example.FromString(raw_example.numpy())

parsed.features.feature['image/text']
 
bytes_list {
  value: "Rue Perreyon"
}

텍스트 데이터 소비

엔드 투 엔드 예제는 텍스트로드를 참조하십시오.

많은 데이터 세트가 하나 이상의 텍스트 파일로 배포됩니다. tf.data.TextLineDataset 은 하나 이상의 텍스트 파일에서 행을 쉽게 추출 할 수있는 방법을 제공합니다. 하나 이상의 파일 이름이 주어지면 TextLineDataset 은 해당 파일의 라인 당 하나의 문자열 값 요소를 생성합니다.

 directory_url = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/'
file_names = ['cowper.txt', 'derby.txt', 'butler.txt']

file_paths = [
    tf.keras.utils.get_file(file_name, directory_url + file_name)
    for file_name in file_names
]
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/cowper.txt
819200/815980 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/derby.txt
811008/809730 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/butler.txt
811008/807992 [==============================] - 0s 0us/step

 dataset = tf.data.TextLineDataset(file_paths)
 

첫 번째 파일의 처음 몇 줄은 다음과 같습니다.

 for line in dataset.take(5):
  print(line.numpy())
 
b"\xef\xbb\xbfAchilles sing, O Goddess! Peleus' son;"
b'His wrath pernicious, who ten thousand woes'
b"Caused to Achaia's host, sent many a soul"
b'Illustrious into Ades premature,'
b'And Heroes gave (so stood the will of Jove)'

파일 사이에서 줄을 Dataset.interleave 려면 Dataset.interleave 사용 Dataset.interleave . 이렇게하면 파일을 쉽게 섞을 수 있습니다. 각 번역의 첫 번째, 두 번째 및 세 번째 줄은 다음과 같습니다.

 files_ds = tf.data.Dataset.from_tensor_slices(file_paths)
lines_ds = files_ds.interleave(tf.data.TextLineDataset, cycle_length=3)

for i, line in enumerate(lines_ds.take(9)):
  if i % 3 == 0:
    print()
  print(line.numpy())
 

b"\xef\xbb\xbfAchilles sing, O Goddess! Peleus' son;"
b"\xef\xbb\xbfOf Peleus' son, Achilles, sing, O Muse,"
b'\xef\xbb\xbfSing, O goddess, the anger of Achilles son of Peleus, that brought'

b'His wrath pernicious, who ten thousand woes'
b'The vengeance, deep and deadly; whence to Greece'
b'countless ills upon the Achaeans. Many a brave soul did it send'

b"Caused to Achaia's host, sent many a soul"
b'Unnumbered ills arose; which many a soul'
b'hurrying down to Hades, and many a hero did it yield a prey to dogs and'

기본적으로 TextLineDataset 은 각 파일의 모든 줄을 생성합니다. 예를 들어 파일이 헤더 줄로 시작하거나 주석이 포함 된 경우 바람직하지 않을 수 있습니다. 이러한 행은 Dataset.skip() 또는 Dataset.filter() 변환을 사용하여 제거 할 수 있습니다. 여기서 첫 번째 줄을 건너 뛰고 생존자 만 찾기 위해 필터링합니다.

 titanic_file = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")
titanic_lines = tf.data.TextLineDataset(titanic_file)
 
Downloading data from https://storage.googleapis.com/tf-datasets/titanic/train.csv
32768/30874 [===============================] - 0s 0us/step

 for line in titanic_lines.take(10):
  print(line.numpy())
 
b'survived,sex,age,n_siblings_spouses,parch,fare,class,deck,embark_town,alone'
b'0,male,22.0,1,0,7.25,Third,unknown,Southampton,n'
b'1,female,38.0,1,0,71.2833,First,C,Cherbourg,n'
b'1,female,26.0,0,0,7.925,Third,unknown,Southampton,y'
b'1,female,35.0,1,0,53.1,First,C,Southampton,n'
b'0,male,28.0,0,0,8.4583,Third,unknown,Queenstown,y'
b'0,male,2.0,3,1,21.075,Third,unknown,Southampton,n'
b'1,female,27.0,0,2,11.1333,Third,unknown,Southampton,n'
b'1,female,14.0,1,0,30.0708,Second,unknown,Cherbourg,n'
b'1,female,4.0,1,1,16.7,Third,G,Southampton,n'

 def survived(line):
  return tf.not_equal(tf.strings.substr(line, 0, 1), "0")

survivors = titanic_lines.skip(1).filter(survived)
 
 for line in survivors.take(10):
  print(line.numpy())
 
b'1,female,38.0,1,0,71.2833,First,C,Cherbourg,n'
b'1,female,26.0,0,0,7.925,Third,unknown,Southampton,y'
b'1,female,35.0,1,0,53.1,First,C,Southampton,n'
b'1,female,27.0,0,2,11.1333,Third,unknown,Southampton,n'
b'1,female,14.0,1,0,30.0708,Second,unknown,Cherbourg,n'
b'1,female,4.0,1,1,16.7,Third,G,Southampton,n'
b'1,male,28.0,0,0,13.0,Second,unknown,Southampton,y'
b'1,female,28.0,0,0,7.225,Third,unknown,Cherbourg,y'
b'1,male,28.0,0,0,35.5,First,A,Southampton,y'
b'1,female,38.0,1,5,31.3875,Third,unknown,Southampton,n'

CSV 데이터 소비

자세한 예는 CSV 파일 로드Pandas DataFrames로드를 참조하십시오.

CSV 파일 형식은 표 형식의 데이터를 일반 텍스트로 저장하는 데 널리 사용되는 형식입니다.

예를 들면 다음과 같습니다.

 titanic_file = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")
 
 df = pd.read_csv(titanic_file, index_col=None)
df.head()
 

데이터가 메모리에 맞는 경우 동일한 Dataset.from_tensor_slices 메소드가 사전에서 작동하여이 데이터를 쉽게 가져올 수 있습니다.

 titanic_slices = tf.data.Dataset.from_tensor_slices(dict(df))

for feature_batch in titanic_slices.take(1):
  for key, value in feature_batch.items():
    print("  {!r:20s}: {}".format(key, value))
 
  'survived'          : 0
  'sex'               : b'male'
  'age'               : 22.0
  'n_siblings_spouses': 1
  'parch'             : 0
  'fare'              : 7.25
  'class'             : b'Third'
  'deck'              : b'unknown'
  'embark_town'       : b'Southampton'
  'alone'             : b'n'

보다 확장 가능한 접근 방식은 필요에 따라 디스크에서로드하는 것입니다.

tf.data 모듈은 RFC 4180 을 준수하는 하나 이상의 CSV 파일에서 레코드를 추출하는 방법을 제공합니다.

experimental.make_csv_dataset 함수는 csv 파일 세트를 읽기위한 고급 인터페이스입니다. 열 형식 유추와 일괄 처리 및 셔플 링과 같은 많은 다른 기능을 지원하여 사용이 간편합니다.

 titanic_batches = tf.data.experimental.make_csv_dataset(
    titanic_file, batch_size=4,
    label_name="survived")
 
 for feature_batch, label_batch in titanic_batches.take(1):
  print("'survived': {}".format(label_batch))
  print("features:")
  for key, value in feature_batch.items():
    print("  {!r:20s}: {}".format(key, value))
 
'survived': [0 1 0 0]
features:
  'sex'               : [b'male' b'female' b'male' b'male']
  'age'               : [28. 42. 43. 21.]
  'n_siblings_spouses': [0 0 0 0]
  'parch'             : [0 0 0 0]
  'fare'              : [47.1    13.      8.05    8.6625]
  'class'             : [b'First' b'Second' b'Third' b'Third']
  'deck'              : [b'unknown' b'unknown' b'unknown' b'unknown']
  'embark_town'       : [b'Southampton' b'Southampton' b'Southampton' b'Southampton']
  'alone'             : [b'y' b'y' b'y' b'y']

열의 서브 세트 만 필요한 경우 select_columns 인수를 사용할 수 있습니다.

 titanic_batches = tf.data.experimental.make_csv_dataset(
    titanic_file, batch_size=4,
    label_name="survived", select_columns=['class', 'fare', 'survived'])
 
 for feature_batch, label_batch in titanic_batches.take(1):
  print("'survived': {}".format(label_batch))
  for key, value in feature_batch.items():
    print("  {!r:20s}: {}".format(key, value))
 
'survived': [1 0 1 1]
  'fare'              : [24.15    0.     13.8583 53.1   ]
  'class'             : [b'Third' b'Second' b'Second' b'First']

보다 세밀한 제어를 제공하는 하위 수준의 experimental.CsvDataset 클래스도 있습니다. 열 형식 유추를 지원하지 않습니다. 대신 각 열의 유형을 지정해야합니다.

 titanic_types  = [tf.int32, tf.string, tf.float32, tf.int32, tf.int32, tf.float32, tf.string, tf.string, tf.string, tf.string] 
dataset = tf.data.experimental.CsvDataset(titanic_file, titanic_types , header=True)

for line in dataset.take(10):
  print([item.numpy() for item in line])
 
[0, b'male', 22.0, 1, 0, 7.25, b'Third', b'unknown', b'Southampton', b'n']
[1, b'female', 38.0, 1, 0, 71.2833, b'First', b'C', b'Cherbourg', b'n']
[1, b'female', 26.0, 0, 0, 7.925, b'Third', b'unknown', b'Southampton', b'y']
[1, b'female', 35.0, 1, 0, 53.1, b'First', b'C', b'Southampton', b'n']
[0, b'male', 28.0, 0, 0, 8.4583, b'Third', b'unknown', b'Queenstown', b'y']
[0, b'male', 2.0, 3, 1, 21.075, b'Third', b'unknown', b'Southampton', b'n']
[1, b'female', 27.0, 0, 2, 11.1333, b'Third', b'unknown', b'Southampton', b'n']
[1, b'female', 14.0, 1, 0, 30.0708, b'Second', b'unknown', b'Cherbourg', b'n']
[1, b'female', 4.0, 1, 1, 16.7, b'Third', b'G', b'Southampton', b'n']
[0, b'male', 20.0, 0, 0, 8.05, b'Third', b'unknown', b'Southampton', b'y']

일부 열이 비어있는 경우이 낮은 수준의 인터페이스를 통해 열 유형 대신 기본값을 제공 할 수 있습니다.

 %%writefile missing.csv
1,2,3,4
,2,3,4
1,,3,4
1,2,,4
1,2,3,
,,,
 
Writing missing.csv

 # Creates a dataset that reads all of the records from two CSV files, each with
# four float columns which may have missing values.

record_defaults = [999,999,999,999]
dataset = tf.data.experimental.CsvDataset("missing.csv", record_defaults)
dataset = dataset.map(lambda *items: tf.stack(items))
dataset
 
<MapDataset shapes: (4,), types: tf.int32>
 for line in dataset:
  print(line.numpy())
 
[1 2 3 4]
[999   2   3   4]
[  1 999   3   4]
[  1   2 999   4]
[  1   2   3 999]
[999 999 999 999]

기본적으로 CsvDataset 은 파일의 모든 줄의 모든 열을 생성합니다. 예를 들어 파일이 무시되어야하는 헤더 줄로 시작하거나 일부 열이 입력에 필요하지 않은 경우 바람직하지 않을 수 있습니다. 이 행과 필드는 각각 headerselect_cols 인수로 제거 할 수 있습니다.

 # Creates a dataset that reads all of the records from two CSV files with
# headers, extracting float data from columns 2 and 4.
record_defaults = [999, 999] # Only provide defaults for the selected columns
dataset = tf.data.experimental.CsvDataset("missing.csv", record_defaults, select_cols=[1, 3])
dataset = dataset.map(lambda *items: tf.stack(items))
dataset
 
<MapDataset shapes: (2,), types: tf.int32>
 for line in dataset:
  print(line.numpy())
 
[2 4]
[2 4]
[999   4]
[2 4]
[  2 999]
[999 999]

파일 세트 소비

파일 세트로 분배 된 많은 데이터 세트가 있으며, 여기서 각 파일은 예입니다.

 flowers_root = tf.keras.utils.get_file(
    'flower_photos',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
    untar=True)
flowers_root = pathlib.Path(flowers_root)

 

루트 디렉토리에는 각 클래스에 대한 디렉토리가 있습니다.

 for item in flowers_root.glob("*"):
  print(item.name)
 
sunflowers
daisy
LICENSE.txt
roses
tulips
dandelion

각 클래스 디렉토리의 파일은 예입니다.

 list_ds = tf.data.Dataset.list_files(str(flowers_root/'*/*'))

for f in list_ds.take(5):
  print(f.numpy())
 
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/7243478942_30bf542a2d_m.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/4525067924_177ea3bfb4.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/7002703410_3e97b29da5_n.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/daisy/6299910262_336309ffa5_n.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/sunflowers/6140661443_bb48344226.jpg'

tf.io.read_file 함수를 사용하여 데이터를 읽고 경로에서 레이블을 추출하여 (image, label) 쌍을 리턴하십시오.

 def process_path(file_path):
  label = tf.strings.split(file_path, os.sep)[-2]
  return tf.io.read_file(file_path), label

labeled_ds = list_ds.map(process_path)
 
 for image_raw, label_text in labeled_ds.take(1):
  print(repr(image_raw.numpy()[:100]))
  print()
  print(label_text.numpy())
 
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xff\xe2\x0cXICC_PROFILE\x00\x01\x01\x00\x00\x0cHLino\x02\x10\x00\x00mntrRGB XYZ \x07\xce\x00\x02\x00\t\x00\x06\x001\x00\x00acspMSFT\x00\x00\x00\x00IEC sRGB\x00\x00\x00\x00\x00\x00'

b'tulips'

배치 데이터 세트 요소

간단한 배치

가장 간단한 형태의 배치는 데이터 세트의 연속 된 n 개의 요소를 단일 요소로 쌓습니다. Dataset.batch() 변화가 같은 제약 정확히이를 수행 tf.stack() 의 요소의 각각의 요소에 적용 연산자 : 즉 각 성분의 I, 모든 요소를 동일한 형상의 텐서를 가져야한다.

 inc_dataset = tf.data.Dataset.range(100)
dec_dataset = tf.data.Dataset.range(0, -100, -1)
dataset = tf.data.Dataset.zip((inc_dataset, dec_dataset))
batched_dataset = dataset.batch(4)

for batch in batched_dataset.take(4):
  print([arr.numpy() for arr in batch])
 
[array([0, 1, 2, 3]), array([ 0, -1, -2, -3])]
[array([4, 5, 6, 7]), array([-4, -5, -6, -7])]
[array([ 8,  9, 10, 11]), array([ -8,  -9, -10, -11])]
[array([12, 13, 14, 15]), array([-12, -13, -14, -15])]

tf.data 가 셰이프 정보를 전파하려고 시도하는 동안 tf.data 의 기본 설정은 마지막 배치가 가득 Dataset.batch 않을 수 있으므로 배치 크기를 알 수 없습니다. 모양의 None 참고하십시오.

 batched_dataset
 
<BatchDataset shapes: ((None,), (None,)), types: (tf.int64, tf.int64)>

drop_remainder 인수를 사용하여 마지막 배치를 무시하고 전체 모양 전파를 얻습니다.

 batched_dataset = dataset.batch(7, drop_remainder=True)
batched_dataset
 
<BatchDataset shapes: ((7,), (7,)), types: (tf.int64, tf.int64)>

패딩이있는 배치 텐서

위의 레시피는 모두 같은 크기의 텐서에 적용됩니다. 그러나 많은 모델 (예 : 시퀀스 모델)은 다양한 크기 (예 : 다른 길이의 시퀀스)를 가질 수있는 입력 데이터로 작동합니다. 이 경우를 처리하기 위해 Dataset.padded_batch 변환을 사용하면 채워질 수있는 하나 이상의 치수를 지정하여 다른 모양의 텐서를 배치 할 수 있습니다.

 dataset = tf.data.Dataset.range(100)
dataset = dataset.map(lambda x: tf.fill([tf.cast(x, tf.int32)], x))
dataset = dataset.padded_batch(4, padded_shapes=(None,))

for batch in dataset.take(2):
  print(batch.numpy())
  print()

 
[[0 0 0]
 [1 0 0]
 [2 2 0]
 [3 3 3]]

[[4 4 4 4 0 0 0]
 [5 5 5 5 5 0 0]
 [6 6 6 6 6 6 0]
 [7 7 7 7 7 7 7]]


Dataset.padded_batch 변환을 사용하면 각 구성 요소의 각 차원에 대해 서로 다른 패딩을 설정할 수 있으며 가변 길이 (위 예제에서 None 으로 표시됨) 또는 상수 길이 일 수 있습니다. 패딩 값을 무시할 수도 있습니다. 기본값은 0입니다.

교육 워크 플로우

여러 시대를 처리

tf.data API는 동일한 데이터의 여러 시대를 처리하는 두 가지 주요 방법을 제공합니다.

여러 시대의 데이터 집합을 반복하는 가장 간단한 방법은 Dataset.repeat() 변환을 사용하는 Dataset.repeat() 입니다. 먼저 타이타닉 데이터의 데이터 세트를 만듭니다.

 titanic_file = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")
titanic_lines = tf.data.TextLineDataset(titanic_file)
 
 def plot_batch_sizes(ds):
  batch_sizes = [batch.shape[0] for batch in ds]
  plt.bar(range(len(batch_sizes)), batch_sizes)
  plt.xlabel('Batch number')
  plt.ylabel('Batch size')
 

인수없이 Dataset.repeat() 변환을 적용하면 입력이 무기한 반복됩니다.

Dataset.repeat 변환은 한 에포크의 끝과 다음 에포크의 시작을 알리지 않고 인수를 연결합니다. 이 때문에 Dataset.batch 후에 적용된 Dataset.repeat 는 에포크 경계를 넘어서는 배치를 생성합니다.

 titanic_batches = titanic_lines.repeat(3).batch(128)
plot_batch_sizes(titanic_batches)
 

png

명확한 에포크 분리가 필요한 경우 반복하기 전에 Dataset.batch 를 배치하십시오.

 titanic_batches = titanic_lines.batch(128).repeat(3)

plot_batch_sizes(titanic_batches)
 

png

각 에포크의 끝에 사용자 정의 계산 (예 : 통계 수집)을 수행하려면 각 에포크에서 데이터 세트 반복을 다시 시작하는 것이 가장 간단합니다.

 epochs = 3
dataset = titanic_lines.batch(128)

for epoch in range(epochs):
  for batch in dataset:
    print(batch.shape)
  print("End of epoch: ", epoch)
 
(128,)
(128,)
(128,)
(128,)
(116,)
End of epoch:  0
(128,)
(128,)
(128,)
(128,)
(116,)
End of epoch:  1
(128,)
(128,)
(128,)
(128,)
(116,)
End of epoch:  2

입력 데이터를 임의로 섞기

Dataset.shuffle() 변환은 고정 크기 버퍼를 유지하고 해당 버퍼에서 무작위로 다음 요소를 균일하게 선택합니다.

효과를 볼 수 있도록 데이터 세트에 색인을 추가하십시오.

 lines = tf.data.TextLineDataset(titanic_file)
counter = tf.data.experimental.Counter()

dataset = tf.data.Dataset.zip((counter, lines))
dataset = dataset.shuffle(buffer_size=100)
dataset = dataset.batch(20)
dataset
 
<BatchDataset shapes: ((None,), (None,)), types: (tf.int64, tf.string)>

buffer_size 가 100이고 배치 크기가 20이므로 첫 번째 배치에는 120 이상의 인덱스를 가진 요소가 없습니다.

 n,line_batch = next(iter(dataset))
print(n.numpy())
 
[ 63  48 101  12 103  52   6  39   4   9  93  91   5  86  79  64  95  33
 102  50]

와 마찬가지로 Dataset.batch 을 기준으로 순서 Dataset.repeat 문제.

Dataset.shuffle 은 셔플 버퍼가 비워 질 때까지 에포크의 끝을 Dataset.shuffle 않습니다. 따라서 반복하기 전에 셔플을하면 다음 시대로 이동하기 전에 한 시대의 모든 요소가 표시됩니다.

 dataset = tf.data.Dataset.zip((counter, lines))
shuffled = dataset.shuffle(buffer_size=100).batch(10).repeat(2)

print("Here are the item ID's near the epoch boundary:\n")
for n, line_batch in shuffled.skip(60).take(5):
  print(n.numpy())
 
Here are the item ID's near the epoch boundary:

[613 609 624 553 608 583 493 617 611 610]
[217 508 579 601 319 616 606 549 618 623]
[416 567 404 622 283 458 503 602]
[ 87  68  56  16   6  62   1  89  58 106]
[98 80 43 10 67 44 19 34 13 57]

 shuffle_repeat = [n.numpy().mean() for n, line_batch in shuffled]
plt.plot(shuffle_repeat, label="shuffle().repeat()")
plt.ylabel("Mean item ID")
plt.legend()
 
<matplotlib.legend.Legend at 0x7fe0a00a1d68>

png

그러나 셔플이 반복되기 전에 반복이 에포크 경계를 혼합합니다.

 dataset = tf.data.Dataset.zip((counter, lines))
shuffled = dataset.repeat(2).shuffle(buffer_size=100).batch(10)

print("Here are the item ID's near the epoch boundary:\n")
for n, line_batch in shuffled.skip(55).take(15):
  print(n.numpy())
 
Here are the item ID's near the epoch boundary:

[440  15   8 599 567  18 550   5  19  17]
[ 12 501 571 473 466  21 531 596 580 555]
[  3 573  38 563  25 416 595  29  46 602]
[485 566 561  16 331 615 386  28 609  41]
[611 622 575  10 589  61 598 527  52  35]
[ 55 597  42  23  13  47  11 505  68 582]
[612 613  75  43   7 392  74 452  82 509]
[  9  44  62 491  71 343  51 590  60  98]
[  6  95 619  86 625 537 617  85 465   0]
[ 88  27  92 101 109 111 104  24  36 113]
[103 118  79  53  70  40 121 100  65  33]
[562 588 124 125  64  84  83  67 610 130]
[  4 142 131  90 518 129 143 112   2 551]
[377  91 140  76  50  48 526 553 156 591]
[105 128  69 114  93 520 154  56 145 115]

 repeat_shuffle = [n.numpy().mean() for n, line_batch in shuffled]

plt.plot(shuffle_repeat, label="shuffle().repeat()")
plt.plot(repeat_shuffle, label="repeat().shuffle()")
plt.ylabel("Mean item ID")
plt.legend()
 
<matplotlib.legend.Legend at 0x7fe0582fbb70>

png

전처리 데이터

Dataset.map(f) 변환은 주어진 함수 f 를 입력 데이터 세트의 각 요소에 적용하여 새 데이터 세트를 생성합니다. 함수형 프로그래밍 언어의 목록 (및 기타 구조)에 일반적으로 적용되는 map() 함수를 기반으로합니다. 함수 f 는 입력에서 단일 요소를 나타내는 tf.Tensor 객체를 가져 와서 새 데이터 세트에서 단일 요소를 나타내는 tf.Tensor 객체를 반환합니다. 구현시 표준 TensorFlow 작업을 사용하여 한 요소를 다른 요소로 변환합니다.

이 섹션에서는 Dataset.map() 사용 방법에 대한 일반적인 예를 다룹니다.

이미지 데이터 디코딩 및 크기 조정

실제 이미지 데이터에서 신경망을 학습 할 때 종종 크기가 다른 이미지를 일반 크기로 변환하여 고정 크기로 배치 될 수 있도록해야합니다.

꽃 파일 이름 데이터 세트를 다시 작성하십시오.

 list_ds = tf.data.Dataset.list_files(str(flowers_root/'*/*'))
 

데이터 세트 요소를 조작하는 함수를 작성하십시오.

 # Reads an image from a file, decodes it into a dense tensor, and resizes it
# to a fixed shape.
def parse_image(filename):
  parts = tf.strings.split(filename, os.sep)
  label = parts[-2]

  image = tf.io.read_file(filename)
  image = tf.image.decode_jpeg(image)
  image = tf.image.convert_image_dtype(image, tf.float32)
  image = tf.image.resize(image, [128, 128])
  return image, label
 

작동하는지 테스트하십시오.

 file_path = next(iter(list_ds))
image, label = parse_image(file_path)

def show(image, label):
  plt.figure()
  plt.imshow(image)
  plt.title(label.numpy().decode('utf-8'))
  plt.axis('off')

show(image, label)
 

png

데이터 세트에 매핑하십시오.

 images_ds = list_ds.map(parse_image)

for image, label in images_ds.take(2):
  show(image, label)
 

png

png

임의의 파이썬 로직 적용

성능상의 이유로 가능할 때마다 데이터를 사전 처리하기 위해 TensorFlow 조작을 사용하십시오. 그러나 입력 데이터를 구문 분석 할 때 외부 Python 라이브러리를 호출하는 것이 유용한 경우가 있습니다. Dataset.map() 변환에서 tf.py_function() 연산을 사용할 수 있습니다.

예를 들어, 임의 회전을 적용하려는 경우 tf.image 모듈에는 tf.image.rot90 만 있으므로 이미지 확대에는 그다지 유용하지 않습니다.

tf.py_function 을 시연하려면 scipy.ndimage.rotate 함수를 대신 사용해보십시오.

 import scipy.ndimage as ndimage

def random_rotate_image(image):
  image = ndimage.rotate(image, np.random.uniform(-30, 30), reshape=False)
  return image
 
 image, label = next(iter(images_ds))
image = random_rotate_image(image)
show(image, label)
 
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

png

이 기능을 사용하려면 Dataset.map 같은주의 사항이와 마찬가지로 적용 Dataset.from_generator , 당신은 당신이 기능을 적용 할 때 반환 모양과 유형을 설명합니다 :

 def tf_random_rotate_image(image, label):
  im_shape = image.shape
  [image,] = tf.py_function(random_rotate_image, [image], [tf.float32])
  image.set_shape(im_shape)
  return image, label
 
 rot_ds = images_ds.map(tf_random_rotate_image)

for image, label in rot_ds.take(2):
  show(image, label)
 
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

png

png

프로토콜 버퍼 메시지 tf.Example

많은 입력 파이프 라인이 TFRecord 형식에서 tf.train.Example 프로토콜 버퍼 메시지를 추출합니다. 각 tf.train.Example 레코드에는 하나 이상의 "기능"이 포함되며 입력 파이프 라인은 일반적으로 이러한 기능을 텐서로 변환합니다.

 fsns_test_file = tf.keras.utils.get_file("fsns.tfrec", "https://storage.googleapis.com/download.tensorflow.org/data/fsns-20160927/testdata/fsns-00000-of-00001")
dataset = tf.data.TFRecordDataset(filenames = [fsns_test_file])
dataset
 
<TFRecordDatasetV2 shapes: (), types: tf.string>

당신은 작업 할 수 tf.train.Example 의 PROTOS 외부 tf.data.Dataset 데이터를 이해하기 :

 raw_example = next(iter(dataset))
parsed = tf.train.Example.FromString(raw_example.numpy())

feature = parsed.features.feature
raw_img = feature['image/encoded'].bytes_list.value[0]
img = tf.image.decode_png(raw_img)
plt.imshow(img)
plt.axis('off')
_ = plt.title(feature["image/text"].bytes_list.value[0])
 

png

 raw_example = next(iter(dataset))
 
 def tf_parse(eg):
  example = tf.io.parse_example(
      eg[tf.newaxis], {
          'image/encoded': tf.io.FixedLenFeature(shape=(), dtype=tf.string),
          'image/text': tf.io.FixedLenFeature(shape=(), dtype=tf.string)
      })
  return example['image/encoded'][0], example['image/text'][0]
 
 img, txt = tf_parse(raw_example)
print(txt.numpy())
print(repr(img.numpy()[:20]), "...")
 
b'Rue Perreyon'
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02X' ...

 decoded = dataset.map(tf_parse)
decoded
 
<MapDataset shapes: ((), ()), types: (tf.string, tf.string)>
 image_batch, text_batch = next(iter(decoded.batch(10)))
image_batch.shape
 
TensorShape([10])

시계열 윈도우

엔드 투 엔드 시계열 예는 시계열 예측을 참조하십시오.

시계열 데이터는 종종 시간 축을 그대로 유지하여 구성됩니다.

간단한 Dataset.range 를 사용하여 Dataset.range 을 보여줍니다.

 range_ds = tf.data.Dataset.range(100000)
 

일반적으로 이러한 종류의 데이터를 기반으로하는 모델은 인접한 시간 조각을 원할 것입니다.

가장 간단한 방법은 데이터를 일괄 처리하는 것입니다.

batch 사용

 batches = range_ds.batch(10, drop_remainder=True)

for batch in batches.take(5):
  print(batch.numpy())
 
[0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
[20 21 22 23 24 25 26 27 28 29]
[30 31 32 33 34 35 36 37 38 39]
[40 41 42 43 44 45 46 47 48 49]

또는 한 단계 씩 밀집된 예측을하려면 기능과 레이블을 서로 한 단계 씩 이동할 수 있습니다.

 def dense_1_step(batch):
  # Shift features and labels one step relative to each other.
  return batch[:-1], batch[1:]

predict_dense_1_step = batches.map(dense_1_step)

for features, label in predict_dense_1_step.take(3):
  print(features.numpy(), " => ", label.numpy())
 
[0 1 2 3 4 5 6 7 8]  =>  [1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18]  =>  [11 12 13 14 15 16 17 18 19]
[20 21 22 23 24 25 26 27 28]  =>  [21 22 23 24 25 26 27 28 29]

고정 오프셋 대신 전체 창을 예측하려면 배치를 두 부분으로 나눌 수 있습니다.

 batches = range_ds.batch(15, drop_remainder=True)

def label_next_5_steps(batch):
  return (batch[:-5],   # Take the first 5 steps
          batch[-5:])   # take the remainder

predict_5_steps = batches.map(label_next_5_steps)

for features, label in predict_5_steps.take(3):
  print(features.numpy(), " => ", label.numpy())
 
[0 1 2 3 4 5 6 7 8 9]  =>  [10 11 12 13 14]
[15 16 17 18 19 20 21 22 23 24]  =>  [25 26 27 28 29]
[30 31 32 33 34 35 36 37 38 39]  =>  [40 41 42 43 44]

한 배치의 기능과 다른 배치의 레이블이 약간 겹치게하려면 Dataset.zip 사용 Dataset.zip .

 feature_length = 10
label_length = 5

features = range_ds.batch(feature_length, drop_remainder=True)
labels = range_ds.batch(feature_length).skip(1).map(lambda labels: labels[:-5])

predict_5_steps = tf.data.Dataset.zip((features, labels))

for features, label in predict_5_steps.take(3):
  print(features.numpy(), " => ", label.numpy())
 
[0 1 2 3 4 5 6 7 8 9]  =>  [10 11 12 13 14]
[10 11 12 13 14 15 16 17 18 19]  =>  [20 21 22 23 24]
[20 21 22 23 24 25 26 27 28 29]  =>  [30 31 32 33 34]

window 사용

Dataset.batch 사용하는 동안 더 세밀한 제어가 필요한 상황이 있습니다. Dataset.window 메서드는 완전한 제어를 제공하지만 약간의주의가 필요합니다. Dataset of Datasets 반환합니다. 자세한 내용은 데이터 세트 구조 를 참조하십시오.

 window_size = 5

windows = range_ds.window(window_size, shift=1)
for sub_ds in windows.take(5):
  print(sub_ds)
 
<_VariantDataset shapes: (), types: tf.int64>
<_VariantDataset shapes: (), types: tf.int64>
<_VariantDataset shapes: (), types: tf.int64>
<_VariantDataset shapes: (), types: tf.int64>
<_VariantDataset shapes: (), types: tf.int64>

Dataset.flat_map 메소드는 데이터 세트의 데이터 세트를 가져와 단일 데이터 세트로 병합 할 수 있습니다.

  for x in windows.flat_map(lambda x: x).take(30):
   print(x.numpy(), end=' ')
 
WARNING:tensorflow:AutoGraph could not transform <function <lambda> at 0x7fe0582dbbf8> and will run it as-is.
Cause: could not parse the source code:

for x in windows.flat_map(lambda x: x).take(30):

This error may be avoided by creating the lambda in a standalone statement.

To silence this warning, decorate the function with @tf.autograph.experimental.do_not_convert
WARNING: AutoGraph could not transform <function <lambda> at 0x7fe0582dbbf8> and will run it as-is.
Cause: could not parse the source code:

for x in windows.flat_map(lambda x: x).take(30):

This error may be avoided by creating the lambda in a standalone statement.

To silence this warning, decorate the function with @tf.autograph.experimental.do_not_convert
0 1 2 3 4 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9 

거의 모든 경우에, 데이터 세트를 먼저 .batch 하려고합니다.

 def sub_to_batch(sub):
  return sub.batch(window_size, drop_remainder=True)

for example in windows.flat_map(sub_to_batch).take(5):
  print(example.numpy())
 
[0 1 2 3 4]
[1 2 3 4 5]
[2 3 4 5 6]
[3 4 5 6 7]
[4 5 6 7 8]

이제 shift 인수가 각 창의 shift 제어한다는 것을 알 수 있습니다.

이것을 합치면 다음 함수를 작성할 수 있습니다.

 def make_window_dataset(ds, window_size=5, shift=1, stride=1):
  windows = ds.window(window_size, shift=shift, stride=stride)

  def sub_to_batch(sub):
    return sub.batch(window_size, drop_remainder=True)

  windows = windows.flat_map(sub_to_batch)
  return windows

 
 ds = make_window_dataset(range_ds, window_size=10, shift = 5, stride=3)

for example in ds.take(10):
  print(example.numpy())
 
[ 0  3  6  9 12 15 18 21 24 27]
[ 5  8 11 14 17 20 23 26 29 32]
[10 13 16 19 22 25 28 31 34 37]
[15 18 21 24 27 30 33 36 39 42]
[20 23 26 29 32 35 38 41 44 47]
[25 28 31 34 37 40 43 46 49 52]
[30 33 36 39 42 45 48 51 54 57]
[35 38 41 44 47 50 53 56 59 62]
[40 43 46 49 52 55 58 61 64 67]
[45 48 51 54 57 60 63 66 69 72]

그런 다음 이전과 같이 라벨을 쉽게 추출 할 수 있습니다.

 dense_labels_ds = ds.map(dense_1_step)

for inputs,labels in dense_labels_ds.take(3):
  print(inputs.numpy(), "=>", labels.numpy())
 
[ 0  3  6  9 12 15 18 21 24] => [ 3  6  9 12 15 18 21 24 27]
[ 5  8 11 14 17 20 23 26 29] => [ 8 11 14 17 20 23 26 29 32]
[10 13 16 19 22 25 28 31 34] => [13 16 19 22 25 28 31 34 37]

리샘플링

클래스 불균형이 매우 높은 데이터 세트로 작업 할 때 데이터 세트를 다시 샘플링 할 수 있습니다. tf.datatf.data 위한 두 가지 방법을 제공합니다. 신용 카드 사기 데이터 세트는 이러한 종류의 문제의 좋은 예입니다.

 zip_path = tf.keras.utils.get_file(
    origin='https://storage.googleapis.com/download.tensorflow.org/data/creditcard.zip',
    fname='creditcard.zip',
    extract=True)

csv_path = zip_path.replace('.zip', '.csv')
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/creditcard.zip
69156864/69155632 [==============================] - 10s 0us/step

 creditcard_ds = tf.data.experimental.make_csv_dataset(
    csv_path, batch_size=1024, label_name="Class",
    # Set the column types: 30 floats and an int.
    column_defaults=[float()]*30+[int()])
 

이제 클래스의 분포를 확인하십시오.

 def count(counts, batch):
  features, labels = batch
  class_1 = labels == 1
  class_1 = tf.cast(class_1, tf.int32)

  class_0 = labels == 0
  class_0 = tf.cast(class_0, tf.int32)

  counts['class_0'] += tf.reduce_sum(class_0)
  counts['class_1'] += tf.reduce_sum(class_1)

  return counts
 
 counts = creditcard_ds.take(10).reduce(
    initial_state={'class_0': 0, 'class_1': 0},
    reduce_func = count)

counts = np.array([counts['class_0'].numpy(),
                   counts['class_1'].numpy()]).astype(np.float32)

fractions = counts/counts.sum()
print(fractions)
 
[0.996 0.004]

불균형 데이터 세트를 사용하여 교육하는 일반적인 방법은 균형을 맞추는 것입니다. tf.data 에는이 워크 플로우를 가능하게하는 몇 가지 방법이 있습니다.

데이터 세트 샘플링

데이터 세트를 리샘플링하는 한 가지 방법은 sample_from_datasets 를 사용하는 것입니다. 각 클래스마다 별도의 data.Dataset 이있는 경우 더 적합합니다.

여기서는 필터를 사용하여 신용 카드 사기 데이터에서 생성합니다.

 negative_ds = (
  creditcard_ds
    .unbatch()
    .filter(lambda features, label: label==0)
    .repeat())
positive_ds = (
  creditcard_ds
    .unbatch()
    .filter(lambda features, label: label==1)
    .repeat())
 
WARNING:tensorflow:AutoGraph could not transform <function <lambda> at 0x7fe0a01fd1e0> and will run it as-is.
Cause: could not parse the source code:

    .filter(lambda features, label: label==0)

This error may be avoided by creating the lambda in a standalone statement.

To silence this warning, decorate the function with @tf.autograph.experimental.do_not_convert
WARNING: AutoGraph could not transform <function <lambda> at 0x7fe0a01fd1e0> and will run it as-is.
Cause: could not parse the source code:

    .filter(lambda features, label: label==0)

This error may be avoided by creating the lambda in a standalone statement.

To silence this warning, decorate the function with @tf.autograph.experimental.do_not_convert
WARNING:tensorflow:AutoGraph could not transform <function <lambda> at 0x7fe058159620> and will run it as-is.
Cause: could not parse the source code:

    .filter(lambda features, label: label==1)

This error may be avoided by creating the lambda in a standalone statement.

To silence this warning, decorate the function with @tf.autograph.experimental.do_not_convert
WARNING: AutoGraph could not transform <function <lambda> at 0x7fe058159620> and will run it as-is.
Cause: could not parse the source code:

    .filter(lambda features, label: label==1)

This error may be avoided by creating the lambda in a standalone statement.

To silence this warning, decorate the function with @tf.autograph.experimental.do_not_convert

 for features, label in positive_ds.batch(10).take(1):
  print(label.numpy())
 
[1 1 1 1 1 1 1 1 1 1]

tf.data.experimental.sample_from_datasets 를 사용하려면 데이터 세트와 각 가중치를 전달하십시오.

 balanced_ds = tf.data.experimental.sample_from_datasets(
    [negative_ds, positive_ds], [0.5, 0.5]).batch(10)
 

이제 데이터 세트는 50/50 확률로 각 클래스의 예를 생성합니다.

 for features, labels in balanced_ds.take(10):
  print(labels.numpy())
 
[0 0 0 1 0 0 1 1 0 0]
[1 1 0 0 1 1 0 0 0 1]
[1 1 0 0 0 0 0 0 1 1]
[1 0 0 1 1 0 0 0 1 0]
[1 1 0 0 0 1 1 0 0 1]
[0 0 1 1 1 0 0 1 1 0]
[0 0 0 1 0 0 0 1 1 1]
[1 1 0 1 0 0 1 0 1 1]
[0 1 0 0 1 1 0 0 0 1]
[0 1 0 0 1 0 0 1 1 0]

거부 리샘플링

위의 experimental.sample_from_datasets 접근법의 한 가지 문제는 클래스마다 별도의 tf.data.Dataset 이 필요하다는 것입니다. Dataset.filter 사용 Dataset.filter 작동하지만 모든 데이터가 두 번로드됩니다.

data.experimental.rejection_resample 함수는 데이터 세트에 적용하여 한 번만로드하면서 재조정 할 수 있습니다. 균형을 이루기 위해 데이터 세트에서 요소가 삭제됩니다.

data.experimental.rejection_resampleclass_func 인수를 사용합니다. 이 class_func 는 각 데이터 세트 요소에 적용되며 밸런싱을 위해 예제가 속하는 클래스를 결정하는 데 사용됩니다.

creditcard_ds 의 요소는 이미 (features, label) 쌍입니다. 따라서 class_func 해당 레이블을 반환하면됩니다.

 def class_func(features, label):
  return label
 

리 샘플러에는 대상 분포와 선택적으로 초기 분포 추정이 필요합니다.

 resampler = tf.data.experimental.rejection_resample(
    class_func, target_dist=[0.5, 0.5], initial_dist=fractions)
 

unbatch 는 개별 예제를 다루므로 리 unbatch 를 적용하기 전에 데이터 세트의 배치를 해제해야합니다.

 resample_ds = creditcard_ds.unbatch().apply(resampler).batch(10)
 
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/data/experimental/ops/resampling.py:156: Print (from tensorflow.python.ops.logging_ops) is deprecated and will be removed after 2018-08-20.
Instructions for updating:
Use tf.print instead of tf.Print. Note that tf.print returns a no-output operator that directly prints the output. Outside of defuns or eager mode, this operator will not be executed unless it is directly specified in session.run or used as a control dependency for other operators. This is only a concern in graph mode. Below is an example of how to ensure tf.print executes in graph mode:


class_funcclass_func 의 출력에서 class_func (class, example) 쌍을 반환합니다. 이 경우 example 는 이미 (feature, label) 쌍이므로 map 을 사용하여 레이블의 추가 사본을 삭제하십시오.

 balanced_ds = resample_ds.map(lambda extra_label, features_and_label: features_and_label)
 

이제 데이터 세트는 50/50 확률로 각 클래스의 예를 생성합니다.

 for features, labels in balanced_ds.take(10):
  print(labels.numpy())
 
[1 0 1 1 1 1 0 1 1 1]
[0 0 1 1 1 0 1 0 1 1]
[1 0 0 1 0 0 0 0 0 1]
[1 1 1 1 1 1 0 1 1 1]
[1 1 0 1 0 0 0 0 1 0]
[1 0 0 0 1 0 1 0 1 0]
[0 0 0 0 0 0 1 0 0 0]
[0 0 0 1 1 0 0 1 0 1]
[0 0 1 1 1 1 0 0 1 1]
[0 0 1 1 0 1 0 1 1 0]

반복자 검사 점

Tensorflow는 체크 포인트를 지원하므로 교육 프로세스가 다시 시작될 때 최신 체크 포인트를 복원하여 대부분의 진행 상황을 복구 할 수 있습니다. 모델 변수를 체크 포인트하는 것 외에도 데이터 세트 반복기의 진행 상태를 체크 포인트 할 수 있습니다. 이 방법은 큰 데이터 집합이 있고 다시 시작할 때마다 데이터 집합을 시작하지 않으려는 경우에 유용 할 수 있습니다. 그러나 shuffleprefetch 와 같은 변환에는 반복기 내의 버퍼링 요소가 필요하므로 반복기 체크 포인트가 클 수 있습니다.

체크 포인트에 반복자를 포함 시키려면 반복자를 tf.train.Checkpoint 생성자로 전달하십시오.

 range_ds = tf.data.Dataset.range(20)

iterator = iter(range_ds)
ckpt = tf.train.Checkpoint(step=tf.Variable(0), iterator=iterator)
manager = tf.train.CheckpointManager(ckpt, '/tmp/my_ckpt', max_to_keep=3)

print([next(iterator).numpy() for _ in range(5)])

save_path = manager.save()

print([next(iterator).numpy() for _ in range(5)])

ckpt.restore(manager.latest_checkpoint)

print([next(iterator).numpy() for _ in range(5)])
 
[0, 1, 2, 3, 4]
[5, 6, 7, 8, 9]
[5, 6, 7, 8, 9]

고급 API 사용

tf.keras

tf.keras API는 기계 학습 모델 작성 및 실행의 여러 측면을 단순화합니다. .fit().fit().evaluate() .predict() API는 데이터 세트를 입력으로 지원합니다. 빠른 데이터 셋 및 모델 설정은 다음과 같습니다.

 train, test = tf.keras.datasets.fashion_mnist.load_data()

images, labels = train
images = images/255.0
labels = labels.astype(np.int32)
 
 fmnist_train_ds = tf.data.Dataset.from_tensor_slices((images, labels))
fmnist_train_ds = fmnist_train_ds.shuffle(5000).batch(32)

model = tf.keras.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(10)
])

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), 
              metrics=['accuracy'])
 

Model.fitModel.evaluate 필요한 모든 (feature, label) 쌍을 전달하면 Model.evaluate .

 model.fit(fmnist_train_ds, epochs=2)
 
Epoch 1/2
WARNING:tensorflow:Layer flatten is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because it's dtype defaults to floatx.

If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.

To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.

1875/1875 [==============================] - 4s 2ms/step - loss: 0.6031 - accuracy: 0.7937
Epoch 2/2
1875/1875 [==============================] - 3s 2ms/step - loss: 0.4620 - accuracy: 0.8416

<tensorflow.python.keras.callbacks.History at 0x7fe13f9ed3c8>

예를 들어 Dataset.repeat() 를 호출하여 무한한 데이터 세트를 전달하는 경우 steps_per_epoch 인수도 전달하면 steps_per_epoch .

 model.fit(fmnist_train_ds.repeat(), epochs=2, steps_per_epoch=20)
 
Epoch 1/2
20/20 [==============================] - 0s 2ms/step - loss: 0.4050 - accuracy: 0.8672
Epoch 2/2
20/20 [==============================] - 0s 2ms/step - loss: 0.4077 - accuracy: 0.8703

<tensorflow.python.keras.callbacks.History at 0x7fe0ca13edd8>

평가를 위해 여러 평가 단계를 통과 할 수 있습니다.

 loss, accuracy = model.evaluate(fmnist_train_ds)
print("Loss :", loss)
print("Accuracy :", accuracy)
 
1875/1875 [==============================] - 3s 2ms/step - loss: 0.4474 - accuracy: 0.8439
Loss : 0.4474281072616577
Accuracy : 0.843916654586792

긴 데이터 세트의 경우 평가할 단계 수를 설정하십시오.

 loss, accuracy = model.evaluate(fmnist_train_ds.repeat(), steps=10)
print("Loss :", loss)
print("Accuracy :", accuracy)
 
10/10 [==============================] - 0s 2ms/step - loss: 0.5262 - accuracy: 0.8156
Loss : 0.5262183547019958
Accuracy : 0.815625011920929

Model.predict 호출 할 때는 레이블이 필요하지 않습니다.

 predict_ds = tf.data.Dataset.from_tensor_slices(images).batch(32)
result = model.predict(predict_ds, steps = 10)
print(result.shape)
 
(320, 10)

그러나 레이블이 포함 된 데이터 집합을 전달하면 레이블이 무시됩니다.

 result = model.predict(fmnist_train_ds, steps = 10)
print(result.shape)
 
(320, 10)

tf.estimator

사용하려면 Datasetinput_fntf.estimator.Estimator , 단순히 반환 Dataset 으로부터 input_fn 와 프레임 워크는 당신을 위해 요소를 소모 처리됩니다. 예를 들면 다음과 같습니다.

 import tensorflow_datasets as tfds

def train_input_fn():
  titanic = tf.data.experimental.make_csv_dataset(
      titanic_file, batch_size=32,
      label_name="survived")
  titanic_batches = (
      titanic.cache().repeat().shuffle(500)
      .prefetch(tf.data.experimental.AUTOTUNE))
  return titanic_batches
 
 embark = tf.feature_column.categorical_column_with_hash_bucket('embark_town', 32)
cls = tf.feature_column.categorical_column_with_vocabulary_list('class', ['First', 'Second', 'Third']) 
age = tf.feature_column.numeric_column('age')
 
 import tempfile
model_dir = tempfile.mkdtemp()
model = tf.estimator.LinearClassifier(
    model_dir=model_dir,
    feature_columns=[embark, cls, age],
    n_classes=2
)
 
INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': '/tmp/tmpefmfuc4o', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': allow_soft_placement: true
graph_options {
  rewrite_options {
    meta_optimizer_iterations: ONE
  }
}
, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_device_fn': None, '_protocol': None, '_eval_distribute': None, '_experimental_distribute': None, '_experimental_max_worker_delay_secs': None, '_session_creation_timeout_secs': 7200, '_service': None, '_cluster_spec': ClusterSpec({}), '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

 model = model.train(input_fn=train_input_fn, steps=100)
 
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/resource_variable_ops.py:1666: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/training_util.py:236: Variable.initialized_value (from tensorflow.python.ops.variables) is deprecated and will be removed in a future version.
Instructions for updating:
Use Variable.read_value. Variables in 2.X are initialized automatically both in eager and graph (inside tf.defun) contexts.
INFO:tensorflow:Calling model_fn.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/feature_column/feature_column_v2.py:540: Layer.add_variable (from tensorflow.python.keras.engine.base_layer_v1) is deprecated and will be removed in a future version.
Instructions for updating:
Please use `layer.add_weight` method instead.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/ftrl.py:144: calling Constant.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 0...
INFO:tensorflow:Saving checkpoints for 0 into /tmp/tmpefmfuc4o/model.ckpt.
INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 0...
INFO:tensorflow:loss = 0.6931472, step = 0
INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 100...
INFO:tensorflow:Saving checkpoints for 100 into /tmp/tmpefmfuc4o/model.ckpt.
INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 100...
INFO:tensorflow:Loss for final step: 0.58668363.

 result = model.evaluate(train_input_fn, steps=10)

for key, value in result.items():
  print(key, ":", value)
 
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2020-07-23T01:23:29Z
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from /tmp/tmpefmfuc4o/model.ckpt-100
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Evaluation [1/10]
INFO:tensorflow:Evaluation [2/10]
INFO:tensorflow:Evaluation [3/10]
INFO:tensorflow:Evaluation [4/10]
INFO:tensorflow:Evaluation [5/10]
INFO:tensorflow:Evaluation [6/10]
INFO:tensorflow:Evaluation [7/10]
INFO:tensorflow:Evaluation [8/10]
INFO:tensorflow:Evaluation [9/10]
INFO:tensorflow:Evaluation [10/10]
INFO:tensorflow:Inference Time : 0.83507s
INFO:tensorflow:Finished evaluation at 2020-07-23-01:23:30
INFO:tensorflow:Saving dict for global step 100: accuracy = 0.675, accuracy_baseline = 0.58125, auc = 0.71750116, auc_precision_recall = 0.6480325, average_loss = 0.64111984, global_step = 100, label/mean = 0.41875, loss = 0.64111984, precision = 0.85714287, prediction/mean = 0.30204886, recall = 0.26865673
INFO:tensorflow:Saving 'checkpoint_path' summary for global step 100: /tmp/tmpefmfuc4o/model.ckpt-100
accuracy : 0.675
accuracy_baseline : 0.58125
auc : 0.71750116
auc_precision_recall : 0.6480325
average_loss : 0.64111984
label/mean : 0.41875
loss : 0.64111984
precision : 0.85714287
prediction/mean : 0.30204886
recall : 0.26865673
global_step : 100

 for pred in model.predict(train_input_fn):
  for key, value in pred.items():
    print(key, ":", value)
  break
 
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from /tmp/tmpefmfuc4o/model.ckpt-100
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
logits : [-0.5965]
logistic : [0.3551]
probabilities : [0.6449 0.3551]
class_ids : [0]
classes : [b'0']
all_class_ids : [0 1]
all_classes : [b'0' b'1']