оптимизация input_fn для tf.estimator.train_and_evaluate

Я создаю оценщик TensorFlow, который хочу обучить и оценить с помощью функции tf.estimator.train_and_evaluate(). doc для этой функции дает следующий совет:

Также рекомендуется обучить модель немного дольше, скажем, несколько эпох, прежде чем выполнять оценку, поскольку конвейер ввода начинается с нуля для каждого обучения.

Это имеет смысл, поскольку train_and_evaluate() работает, чередуя вызовы estimator.train() и estimator.evaluate(), разрушая вычислительный граф для каждого нового вызова. В моем случае это проблема, так как я хочу оценивать модель относительно часто, и мой input_fn, похоже, имеет много накладных расходов при настройке. Сейчас это выглядит примерно так:

def input_fn():
    # Build dataset from generator
    dataset = tf.data.Dataset.from_generator(
        generator=instance_generator,
        output_types=types,
        output_shapes=shapes,
    )

    dataset = dataset.shuffle(buffer_size=dataset_size)
    dataset = dataset.repeat(epochs_per_eval)
    dataset = dataset.batch(batch_size)
    dataset = dataset.prefetch(1)

    return dataset

Я подозреваю, что большая часть временных затрат на эту функцию связана с перетасовкой, поскольку для этого сначала требуется сгенерировать весь набор данных. Перетасовка, наверное, не медленная, но мой instance_generator медленный. В идеале я хотел бы найти способ избежать необходимости перестраивать набор данных из генератора для каждого вызова поезда / eval. Есть ли способ добиться этого с помощью класса Dataset? Есть ли способ кэшировать состояние набора данных после его создания, чтобы каждый новый вызов input_fn после первого становился менее затратным?


person Harald Husum    schedule 25.02.2018    source источник
comment
Вы не должны кэшировать ничего, связанное с тензорным потоком, за пределами input_fn, поскольку оценщик каждый раз создает новый график. Ваше узкое место в создании input_fn (маловероятно) или его выполнении? Кроме того, почему вы перемещаетесь во время eval?   -  person Alexandre Passos    schedule 27.02.2018
comment
Я знаю, что Оценщик каждый раз создает новый график. Я надеялся, что вы сможете поддерживать отдельный график вне оценщика, который вы подключаете к графику оценщика по мере его создания. Узким местом является получение первого пакета данных; после этого работает нормально. Я тоже не тасуюсь во время eval. Проблема в том, что каждый eval запускает перестройку входного конвейера обучения, который и должен быть перемешан.   -  person Harald Husum    schedule 28.02.2018
comment
По-прежнему звучит так, будто вы хотите кэшировать значение, а не график. Я не думаю, что сейчас это поддерживается.   -  person Alexandre Passos    schedule 02.03.2018


Ответы (1)


Возможно, вы можете использовать tf.data.Dataset.range, кроме tf.data.Dataset.from_generator. Вот пример кода: Сначала определите класс Python

import tensorflow as tf
import time

class instance_generator():
    def __init__(self):
        #doing some initialization
        self.data_index = {n:str(n) for n in range(1000)}# create index othre than pretreat data

    def _hard_work(self, n):
        time.sleep(1) #doing the pretreating work
        return self.data_index[n]

    def __call__(self):
        def get_by_index(i):
            return tf.py_func(lambda i: self._hard_work(i), inp=[i], Tout=types)

        dataset = tf.data.Dataset.range(len(self.data_index))
        dataset = dataset.shuffle(buffer_size=dataset_size)
        dataset = dataset.repeat(epochs_per_eval)
        dataset = dataset.map(get_by_index)
        dataset = dataset.batch(batch_size)
        dataset = dataset.prefetch(1)
        return dataset.make_one_shot_iterator().next()

Затем передайте класс instance_generator в tf.estimator:

data_train = instance_generator('train')
data_eval = instance_generator('eval')
model = tf.estimator.DNNClassifier(...)
tf.estimator.train_and_evaluate(
    estimator=model,
    train_spec=tf.estimator.TrainSpec(data_train),
    eval_spec=tf.estimator.Estimator(data_eval)
)

Если этап инициализации занимает много времени, он выполняется только один раз, всякий раз, когда оценщик создает новый граф, он создает только набор данных. Если предварительная обработка данных занимает много времени, она работает только с исходным пакетом данных, но не со всем набором данных. Перемешать и повторить по индексу довольно дешево. Надеюсь, это поможет.

person user8208125    schedule 20.05.2018