자세한 설명은 가이드 참조.


Dataset API를 사용하면 input pipelines / Threading and Queue 과정을 손쉽게 처리할 수 있다. 

( 1.4부터 `` contrib``에서 코어로 옮겨졌다. )


`` dataset``은 `` element``들로 이루어져 있으며 `` element``는 `` tf.Tensor``들로 이루어져 있다.

  • `` element1``
        - image1
        - label1
  • `` element2``
        - image2
        - label2
  • ...


Basic mechanics

```python

>>> sess.run(tf.random_uniform([2, 4]))                                                   

array([[ 0.77109301,  0.34201586,  0.0554806 ,  0.96262276],

       [ 0.99343991,  0.84189892,  0.8897506 ,  0.27429628]], dtype=float32)

>>> dataset1 = tf.data.Dataset.from_tensor_slices(tf.random_uniform([2, 4]))              

>>> dataset1.output_types

tf.float32

>>> dataset1.output_shapes

TensorShape([Dimension(4)])

```

한 행이 한 `` element``라고 생각하면 된다.

한 row 씩 반환하게 되고, 한 row는 한 `` element``이기 때문에 `` output_shapes``은 `` element``의 shape이다.


`` dataset``에서 `` element``를 꺼내기 위해서는 `` tf.data.Iterator``를 사용한다.

```python

>>> dataset = tf.data.Dataset.range(10)

>>> iterator = dataset.make_one_shot_iterator()

>>> next_element = iterator.get_next()

>>> sess = tf.Session()

>>> sess.run(next_element)

0

>>> sess.run(next_element)

1

```

Note: Currently, one-shot iterators are the only type that is easily usable with an `` Estimator``. (17.11.17)


그러나 다음과 같은 parameterization은 지원하지 않는다.

```python

>>> max_value = tf.placeholder(tf.int64, shape=[])

>>> dataset = tf.data.Dataset.range(max_value)

>>> iterator = dataset.make_one_shot_iterator()

ValueError: Cannot capture a placeholder (name:Placeholder_1, type:Placeholder) by value.

```

그래서 이와같이 사용하려면 ``py dataset.make_initializable_iterator()`` 등등을 사용해야 한다.

가장 유연하고 좋은 방식은 feedable iterator를 사용하는 것인데, 위에 적어놓았듯 `` Estimator``와 같이 쓰기가 좀 그렇다.


그리고 주의해야 할 점은, ``py Iterator.get_next()``가 호출될 때 마다 Iterator에서 새로운 `` element``를 꺼내는 것이 아니라는 점이다. ``py sess.run()``에 집어넣어야 다음 `` element``를 반환한다.

```python

>>> dataset = tf.data.Dataset.range(5)

>>> iterator = dataset.make_one_shot_iterator()

>>> next_element = iterator.get_next()

>>> # 여기서 next_element가 두 번 호출된다고 두 번 꺼내는게 아니다.

>>> result = tf.add(next_element, next_element)

>>> sess.run(result)

0

>>> sess.run(result)

2    # 1+1 = 2

>>> sess.run(next_element)

2    # 2

>>> sess.run(result)

6    # 3+3 = 2

```


그래서 다음과 같이 사용한다.

```python

sess.run(iterator.initializer)

while True:

  try:

    sess.run(result)

  except tf.errors.OutOfRangeError:

    break

```


Decoding image data and resizing it

이런 식으로 사용한다.
```python
# Reads an image from a file, decodes it into a dense tensor, and resizes it
# to a fixed shape.
def _image_processing(filename, label):
    image_string = tf.read_file(filename)
    image_decoded = tf.image.decode_png(image_string)
    # tf.image.decode_image를 사용하면 더 좋지만 에러 발생
    image_resized = tf.image.resize_images(image_decoded, [28, 28])
    return image_resized, label

# A vector of filenames.

fnames = tf.constant(glob.glob("./mnist_test/*"))
labels = tf.constant([2])

dataset = tf.data.Dataset.from_tensor_slices((fnames, labels))
dataset = dataset.map(_image_processing)

```


Applying arbitrary Python logic with tf.py_func()

텐서플로우의 동작 방식이 일반적인 python logic과는 달리 그래프를 구성하고, 나중에 실행하는 방식이다 보니 원래대로라면 OpenCV같은 다른 API의 파일 처리와 연계하기가 조금 복잡스럽다.
그러나 이를 간단히 처리할 수 있도록 ``py tf.py_func()``라는 API를 지원한다.
```python

import cv2


# Use a custom OpenCV function to read the image, instead of the standard

# TensorFlow `tf.read_file()` operation.

def _read_py_function(filename, label):

  image_decoded = cv2.imread(image_string, cv2.IMREAD_GRAYSCALE)

  return image_decoded, label


# Use standard TensorFlow operations to resize the image to a fixed shape.

def _resize_function(image_decoded, label):

  image_decoded.set_shape([None, None, None])

  image_resized = tf.image.resize_images(image_decoded, [28, 28])

  return image_resized, label


filenames = ["/var/data/image1.jpg", "/var/data/image2.jpg", ...]

labels = [0, 37, 29, 1, ...]


dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))

dataset = dataset.map(

    lambda filename, label: tuple(tf.py_func(

        _read_py_function, [filename, label], [tf.uint8, label.dtype])))

dataset = dataset.map(_resize_function)

```


shuffle, epoch, batch

```python
>>> dataset = tf.data.Dataset.range(10)

>>> dataset = dataset.map(...)

>>> dataset = dataset.shuffle(buffer_size = 10)

>>> dataset = dataset.batch(2)     # batch

>>> dataset = dataset.repeat(3)    # epoch. 지정하지 않으면 무한히 제공.

```