tensorflow:使用队列运行器有效地提供eval / train数据

时间:2016-08-28 03:27:25

标签: python tensorflow

我正在尝试运行张量流图来训练模型,并使用单独的评估数据集定期评估。训练和评估数据都是使用队列运行器实现的。

我目前的解决方案是在同一个图表中创建两个输入,并使用依赖于tf.cond占位符的is_training。我的问题由以下代码突出显示:

import tensorflow as tf
from tensorflow.models.image.cifar10 import cifar10
from time import time


def get_train_inputs(is_training):
    return cifar10.inputs(False)


def get_eval_inputs(is_training):
    return cifar10.inputs(True)


def get_mixed_inputs(is_training):
    train_inputs = get_train_inputs(None)
    eval_inputs = get_eval_inputs(None)

    return tf.cond(is_training, lambda: train_inputs, lambda: eval_inputs)


def time_inputs(inputs_fn, n_runs=10):
    graph = tf.Graph()
    with graph.as_default():
        is_training = tf.placeholder(dtype=tf.bool, shape=(),
                                     name='is_training')
        images, labels = inputs_fn(is_training)

    with tf.Session(graph=graph) as sess:
        coordinator = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess, coord=coordinator)
        t = time()
        for i in range(n_runs):
            im, l = sess.run([images, labels], feed_dict={is_training: True})
        dt = time() - t
        coordinator.request_stop()
        coordinator.join(threads)

    return dt / n_runs

print('Train inputs: %.3f' % time_inputs(get_train_inputs))
print('Eval inputs: %.3f' % time_inputs(get_eval_inputs))
print('Mixed inputs: %.3f' % time_inputs(get_mixed_inputs))

我还必须对image_summary的{​​{1}}行133发表评论。

这产生了以下结果:

tensorflow/models/image/cifar10/cifar10_inputs.py

在混合的情况下,即使只使用了1,也会读取/解析两个输入。有没有办法避免这种冗余计算?或者是否有更好的方法在仍然利用队列运行器设置的培训/评估数据之间切换?

2 个答案:

答案 0 :(得分:4)

您是否阅读了此link关于多输入的最后一部分? 我认为您可以在输入函数中添加is_training参数,以区分训练数据和eval数据。 然后,您可以重用共享变量来获取eval数据的logits,并为eval构建一个op。 然后在图表中,运行valudation_accuracy=sess.run(eval_op)以获得评估准确性。

更新

嗨,根据我的理解,如果你想训练n批,评估,训练,评估,你可以在同一个图中保留两个操作,不需要建立一个新操作。 假设您已经构建了所有需要的函数,那么代码应该是这样的:

#the following two steps will add train and eval input queue to the graph
train_inputs,train_labels = inputs(is_train=True)
eval_inputs,eval_labels = inputs(is_train=False)

with tf.variable_scope("inference") as scope:
    train_logits = inference(train_inputs)
    scope.reuse_variables()
    eval_logits = inference(eval_inputs)

loss = loss(train_logits,train_labels)
eval_accuracy = accuracy(eval_logits,eval_labels)

#...add train op here,start queue runner and train it ...

答案 1 :(得分:2)

经过一些实验,我目前的最佳解决方案是拥有一个主要图表,其中包含培训输入和一个仅包含评估数据操作的单独图表。我打开一个单独的会话来获取评估数据,并在我想要评估时将其提供给培训图表。非常不优雅(并且评估运行时间比理想情况要长,因为他们不得不将一个会话用于另一个会话),但假设评估运行与训练运行相比很少,这似乎比原始版本更好......

import tensorflow as tf
from tensorflow.models.image.cifar10 import cifar10
from time import time


class DataSupplier:
    def __init__(self, tensor_fn):
        graph = tf.Graph()
        with graph.as_default():
            with graph.device('/cpu:0'):
                self.tensor = tensor_fn()
        self.sess = tf.Session(graph=graph)
        self.coord = tf.train.Coordinator()
        self.threads = tf.train.start_queue_runners(sess=self.sess,
                                                    coord=self.coord)

    def get_tensor_val(self):
        return self.sess.run(self.tensor)

    def clean_up(self):
        self.coord.request_stop()
        self.coord.join(self.threads)


eval_batcher = DataSupplier(lambda: cifar10.inputs(True))

graph = tf.Graph()
with graph.as_default():
    images, labels = cifar10.inputs(False)

    out_images = tf.identity(images)
    out_labels = tf.identity(labels)

n_runs = 100

with tf.Session(graph=graph) as sess:
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(sess, coord)
    for i in range(n_runs):
        sess.run([out_images, out_labels])
    t = time()
    for i in range(n_runs):
        sess.run([out_images, out_labels])
    dt = (time() - t)/n_runs
    print('Train time: %.3f' % dt)
    t = time()
    for i in range(n_runs):
        eval_images, eval_labels = eval_batcher.get_tensor_val()
        sess.run([out_images, out_labels],
                 feed_dict={images: eval_images, labels: eval_labels})
    dt = (time() - t)/n_runs
    print('Eval time: %.3f' % dt)
    coord.request_stop()
    coord.join(threads)

eval_batcher.clean_up()

结果:

Train time: 0.050
Eval time: 0.064

更新:当使用这种方法训练tf.contrib.layers和正则化的问题时,如果DataSupplier图与训练图在同一设备上,我发现正则化损失无穷大。我不能为我的生活解释为什么会这样,但明确地将DataSupplier的设备设置到CPU(鉴于我的GPU上的训练图)似乎有效......