tf.datasets input_fn получает ошибку после 1 эпохи - PullRequest
0 голосов
/ 10 мая 2018

Итак, я пытаюсь переключиться на input_fn () с помощью tf.datasets, как описано в этом вопросе . Несмотря на то, что я смог добиться превосходных шагов в секунду, используя tf.datasets с input_fn () ниже, я, похоже, сталкиваюсь с ошибкой после 1 эпохи при запуске этого эксперимента на GCMLE. Учтите это input_fn ():

def input_fn(...):
    files = tf.data.Dataset.list_files(filenames).shuffle(num_shards)

    dataset = files.apply(tf.contrib.data.parallel_interleave(lambda filename: tf.data.TextLineDataset(filename).skip(1), cycle_length=num_shards))
    dataset = dataset.apply(tf.contrib.data.map_and_batch(lambda row:
        parse_csv_dataset(row, hparams = hparams), 
        batch_size = batch_size, 
        num_parallel_batches = multiprocessing.cpu_count())) 
    dataset = dataset.prefetch(1)
    if shuffle:
        dataset = dataset.shuffle(buffer_size = 10000)
    dataset = dataset.repeat(num_epochs)

    iterator = dataset.make_initializable_iterator()
    features = iterator.get_next()
    tf.add_to_collection(tf.GraphKeys.TABLE_INITIALIZERS, iterator.initializer)

    labels = {key: features.pop(key) for key in LABEL_COLUMNS}

    return features, labels

Я получаю следующую ошибку на GCMLE:

disable=protected-access InvalidArgumentError (see above for traceback): Inputs to operation loss/sparse_softmax_cross_entropy_loss/num_present/Select of type Select must have the same size and shape. Input 0: [74] != input 1: [110] [[Node: loss/sparse_softmax_cross_entropy_loss/num_present/Select = Select[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:GPU:0"](loss/sparse_softmax_cross_entropy_loss/num_present/Equal, loss/sparse_softmax_cross_entropy_loss/num_present/zeros_like, loss/sparse_softmax_cross_entropy_loss/num_present/ones_like)]] [[Node: global_step/add/_1509 = _Recv[client_terminated=false, recv_device="/job:localhost/replica:0/task:0/device:CPU:0", send_device="/job:localhost/replica:0/task:0/device:GPU:0", send_device_incarnation=1, tensor_name="edge_3099_global_step/add", tensor_type=DT_INT64, _device="/job:localhost/replica:0/task:0/device:CPU:0"]()]]

Это означает, что существует несоответствие формы Input 0: [74] != input 1: [110], однако моя старая функция input_fn (), работающая на основе очереди, прекрасно работает с теми же точными данными, поэтому я не верю, что это какая-либо проблема с базовыми данными. Это происходит в то, что, по моему мнению, является концом эпохи (потому что num_steps, когда ошибка GCMLE заканчивается, прямо около num_train_examples/batch_size, поэтому я предполагаю, что проблема может заключаться в том, что конечный пакет не равен batch_size, что равно 110 (как показано в ошибке), и вместо этого есть только 74 примера. Кто-нибудь может подтвердить, что это ошибка? Предполагая, что это так, есть ли какой-то другой флаг, который мне нужно установить, чтобы последняя партия может быть чем-то иным, чем spcified размер партии 110?

Для чего бы это ни стоило, я повторил это поведение с двумя разными наборами данных (тренируется для нескольких эпох с использованием старой очереди на основе input_fn, зависает в конце первой эпохи для tf.datasets input_fn)

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Как Робби предлагает в другом ответе , похоже, что ваша старая реализация использовала фиксированные размеры пакетов повсюду (предположительно, с использованием API, подобного tf.train.batch() или одной из его оболочек с Аргумент по умолчанию allow_smaller_final_batch=False), а поведение пакетирования по умолчанию в tf.data (через tf.data.Dataset.batch() и tf.contrib.data.map_and_batch()) состоит в том, чтобы включить меньшую конечную партию.

Ошибка наиболее вероятна в model_fn. Без этой функции трудно угадать, но я подозреваю, что существует либо явное (и неверное) утверждение формы тензора с помощью Tensor.set_shape() (возможно, в коде библиотеки), либо ошибка в реализация tf.losses.sparse_softmax_cross_entropy().

Во-первых, я предполагаю, что тензоры features и labels, возвращаемые из input_fn(), имеют статически неизвестный размер партии. Можете ли вы подтвердить это, напечатав объекты features и labels и убедившись в том, что их сообщенные свойства Tensor.shape имеют None для 0-го измерения?

Далее найдите вызов на tf.losses.sparse_softmax_cross_entropy() в вашем model_fn. Распечатайте объект, который передан в качестве аргумента weights этой функции, который должен быть tf.Tensor, и найдите его статическую форму. Учитывая ошибку, которую вы видите, я подозреваю, что она будет иметь форму, такую ​​как (110,), где 110 - указанный вами размер пакета. Если это так, в model_fn есть ошибка, которая неверно утверждает, что форма весов является полной партией, а может и не быть. (Если это не так, то в tf.losses.sparse_softmax_cross_entropy() есть ошибка! Пожалуйста, откройте проблему GitHub с примером, который позволяет нам воспроизвести проблему.)

В сторону: Почему это объясняет ошибку? Код , который вызывает сбой tf.where() op, выглядит следующим образом (отредактировано для удобства чтения):

num_present = tf.where(tf.equal(weights, 0.0),  # This input is shape [74]
                       tf.zeros_like(weights),  # This input is shape [110]
                       tf.ones_like(weights)    # This input is probably [110]
)

Этот вариант tf.where() op (названный "Select" в сообщении об ошибке по историческим причинам) требует, чтобы все три входа имели одинаковый размер. Внешне tf.equal(weights, 0.0), tf.ones_like(weights) и tf.zeros_like(weights) имеют одинаковую форму, которая является формой weights. Однако если статическая форма (результат Tensor.shape) отличается от динамической формы , то поведение не определено.

Что на самом деле происходит? В данном конкретном случае, скажем, статическая форма weights равна [110], но динамическая форма равна [74]. Статическая форма наших трех аргументов tf.where() будет [110]. Реализация tf.equal() не заботится о несоответствии, поэтому ее динамическая форма будет [74]. Реализации tf.zeros_like() и tf.ones_like() используют оптимизацию , которая игнорирует эту динамическую форму, когда статическая форма полностью определена, и поэтому их динамические формы будут [110], вызывая ошибку, которую вы видите.

Правильное исправление заключается в том, чтобы найти код, который устанавливает фиксированный размер пакета в вашем model_fn, и удалить его. Логика оптимизации и оценки в TensorFlow устойчива к переменным размерам партий, и это гарантирует, что все ваши данные будут использованы в процессах обучения и оценки.

Менее желательным краткосрочным решением было бы удаление небольшой партии в конце данных. Здесь есть несколько вариантов:

  • Случайно отбрасывать некоторые данные в конце каждой эпохи:

    • С TF 1.8 или более поздней, передать drop_remainder=False в tf.contrib.data.map_and_batch().
    • С TF 1.7 или более ранней, используйте dataset = dataset.filter(lambda features: tf.equal(tf.shape(features[LABEL_COLUMNS[0]])[0], batch_size)) после map_and_batch.
  • Удалите самую последнюю порцию данных:

    • Переместите dataset.repeat(NUM_EPOCHS) перед map_and_batch() и примените одно из двух исправлений, упомянутых выше.
0 голосов
/ 10 мая 2018

Кажется, что некоторая операция на вашем графике (из сообщения об ошибке, вероятно, sparse_softmax_cross_entropy_loss), ожидает фиксированный размер пакета. Это может быть ваш код (не являющийся частью input_fn), который обеспечивает это (например, передача batch_size в виде формы некоторого тензора, который используется в операции), или это может быть одна из библиотек TF.

Это не всегда проблема сама по себе. Однако тот факт, что задокументированное поведение из tf.data.Dataset.batch является:

ПРИМЕЧАНИЕ. Если количество элементов (N) в этом наборе данных не является точным кратный batch_size, последний пакет содержит меньшие тензоры с форма N% batch_size в размерности партии. Если ваша программа зависит для партий, имеющих одинаковую форму, рассмотрите возможность использования Вместо этого используется преобразование tf.contrib.data.batch_and_drop_remainder.

Как написано в настоящее время, ваш код (не входной_fn) находится в категории зависимости от партии с одинаковой формой.

Ваши варианты - отслеживать, где код проходит через статический размер пакета, или «отбрасывать остаток». Я считаю, что первое предпочтительнее, но больше работы.

Если вы выберете последнее, обратите внимание, что вы на самом деле не используете tf.data.Dataset.batch, а скорее tf.contrib.data.map_and_batch, который принимает параметр drop_remainder.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...