Тензорный поток: эффективная подача данных eval/train с использованием бегунов очереди

Я пытаюсь запустить граф тензорного потока для обучения модели и периодически оценивать с использованием отдельного набора данных оценки. Данные обучения и оценки реализуются с использованием бегунов очереди.

Мое текущее решение состоит в том, чтобы создать оба входа в одном графике и использовать 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 133 tensorflow/models/image/cifar10/cifar10_inputs.py.

Это дало следующие результаты:

Train inputs: 0.055
Eval inputs: 0.050
Mixed inputs: 0.105

Казалось бы, в смешанном случае оба входа считываются/анализируются, хотя используется только 1. Есть ли способ избежать этого избыточного вычисления? Или есть более удобный способ переключения между данными обучения/оценки, которые все еще используют настройку очереди?

Ответ 1

Прочитали ли вы последний раздел этой о нескольких входах? Я думаю, вы можете добавить аргумент is_training к вашей функции ввода, чтобы отличить данные обучения от данных eval. Затем вы можете повторно использовать переменные совместного доступа, чтобы получить логиты для данных eval и построить op для eval. Затем на вашем графике запустите valudation_accuracy=sess.run(eval_op), чтобы получить точность оценки.


Update:

Привет, из моего понимания, если вы хотите тренироваться для n партий, оценивать, тренировать, оценивать, вы можете сохранить там два ops на одном графике, не нужно строить новый. Предположим, что вы уже создали всю необходимую функцию, тогда код должен выглядеть так:

#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 ...

Ответ 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 (учитывая, что график обучения находится на моем графическом процессоре), похоже, работает...