TensorFlow DataSet `from_generator` с переменным размером пакета - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь использовать API набора данных TensorFlow для чтения файла HDF5, используя метод from_generator. Все работает нормально, если размер пакета не делится поровну на количество событий. Я не совсем понимаю, как сделать гибкую партию с помощью API.

Если вещи не делятся поровну, вы получите такие ошибки, как:

2018-08-31 13:47:34.274303: W tensorflow/core/framework/op_kernel.cc:1263] Invalid argument: ValueError: `generator` yielded an element of shape (1, 28, 28, 1) where an element of shape (11, 28, 28, 1) was expected.
Traceback (most recent call last):

  File "/Users/perdue/miniconda3/envs/py3a/lib/python3.6/site-packages/tensorflow/python/ops/script_ops.py", line 206, in __call__
    ret = func(*args)

  File "/Users/perdue/miniconda3/envs/py3a/lib/python3.6/site-packages/tensorflow/python/data/ops/dataset_ops.py", line 452, in generator_py_func
    "of shape %s was expected." % (ret_array.shape, expected_shape))

ValueError: `generator` yielded an element of shape (1, 28, 28, 1) where an element of shape (11, 28, 28, 1) was expected.

У меня есть скрипт, который воспроизводит ошибку (и инструкции, чтобы получить файл данных размером в несколько МБ - Fashion MNIST) здесь:

https://gist.github.com/gnperdue/b905a9c2dd4c08b53e0539d6aa3d3dc6

Возможно, самый важный код:

def make_fashion_dset(file_name, batch_size, shuffle=False):
    dgen = _make_fashion_generator_fn(file_name, batch_size)
    features_shape = [batch_size, 28, 28, 1]
    labels_shape = [batch_size, 10]
    ds = tf.data.Dataset.from_generator(
        dgen, (tf.float32, tf.uint8),
        (tf.TensorShape(features_shape), tf.TensorShape(labels_shape))
    )
    ...

где dgen - функция чтения генератора из hdf5:

def _make_fashion_generator_fn(file_name, batch_size):
    reader = FashionHDF5Reader(file_name)
    nevents = reader.openf()

    def example_generator_fn():
        start_idx, stop_idx = 0, batch_size
        while True:
            if start_idx >= nevents:
                reader.closef()
                return
            yield reader.get_examples(start_idx, stop_idx)
            start_idx, stop_idx = start_idx + batch_size, stop_idx + batch_size

    return example_generator_fn

Суть проблемы в том, что мы должны объявить формы тензора в from_generator, но нам нужна гибкость, чтобы изменить эту форму вниз по линии при итерации.

Есть несколько обходных путей - отбросьте последние несколько образцов, чтобы получить четное деление, или просто используйте размер партии 1 ... но первый вариант плох, если вы не можете потерять образцы, а размер партии 1 очень медленно.

Есть идеи или комментарии? Спасибо!

1 Ответ

0 голосов
/ 01 сентября 2018

Определяя фигуры Тензор в from_generator, вы можете использовать None в качестве элемента для указания размеров переменного размера. Таким образом, вы можете разместить партии разных размеров, в частности, «оставшиеся» партии, которые немного меньше требуемого размера партии. Таким образом, вы будете использовать

def make_fashion_dset(file_name, batch_size, shuffle=False):
    dgen = _make_fashion_generator_fn(file_name, batch_size)
    features_shape = [None, 28, 28, 1]
    labels_shape = [None, 10]
    ds = tf.data.Dataset.from_generator(
        dgen, (tf.float32, tf.uint8),
        (tf.TensorShape(features_shape), tf.TensorShape(labels_shape))
    )
    ...
...