【问题标题】:input_fn optimisation for tf.estimator.train_and_evaluatetf.estimator.train_and_evaluate 的 input_fn 优化
【发布时间】:2018-02-25 18:26:11
【问题描述】:

我正在构建一个 TensorFlow Estimator,我想使用 tf.estimator.train_and_evaluate() 函数对其进行训练和评估。该函数的doc 给出以下建议:

还建议在执行评估之前对模型进行更长时间的训练,比如多个 epoch,因为每次训练的输入管道都是从头开始的。

这是有道理的,因为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 是。理想情况下,我想找到一种方法来避免必须从生成器为每个 train/eval 调用重建数据集。有什么方法可以使用 Dataset 类实现这一点?有没有办法在数据集生成后缓存它的状态,以便在第一次调用之后对input_fn 的每次新调用都变得更便宜?

【问题讨论】:

  • 您不应该在 input_fn 之外缓存任何与 tensorflow 相关的内容,因为 Estimator 每次都会创建一个新图。您是构建 input_fn(不太可能)还是执行它的瓶颈?另外,为什么在评估期间洗牌?
  • 我知道 Estimator 每次都会创建一个新图表。我希望您可以在估算器之外维护一个单独的图形,您可以在构建估算器的图形时插入该图形。瓶颈是返回第一批数据;之后它工作正常。我也没有在评估期间洗牌。问题是每个 eval 都会触发 training 输入管道的重建,该管道已经并且应该被改组。
  • 听起来您仍然想缓存一个值而不是图形。我认为现在不支持此功能。

标签: python performance tensorflow tensorflow-datasets tensorflow-estimator


【解决方案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)
)

如果初始化步骤很耗时,它只运行一次,每当估算器创建新图时,它只创建数据集。 如果数据预处理很耗时,则它仅适用于输入批次的数据,而不适用于整个数据集。随机播放和重复索引非常便宜。 希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 2018-06-03
    • 2019-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多