Подтвердить что ты не робот

Как суммировать резюме по нескольким партиям?

Предполагая, что у меня есть свод сводок, определенных как:

loss = ...
tf.scalar_summary("loss", loss)
# ...
summaries = tf.merge_all_summaries()

Я могу оценить тензор summaries каждые несколько шагов на обучающих данных и передать результат на SummaryWriter. Результатом будет шумное резюме, потому что они вычисляются только по одной партии.

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

Есть ли способ усреднить эти сводки так, чтобы они выглядели так, как если бы сумма вычислялась по всему набору проверки?

4b9b3361

Ответ 1

Сделайте усреднение вашей меры в Python и создайте новый объект Summary для каждого значения. Вот что я делаю:

accuracies = []

# Calculate your measure over as many batches as you need
for batch in validation_set:
  accuracies.append(sess.run([training_op]))

# Take the mean of you measure
accuracy = np.mean(accuracies)

# Create a new Summary object with your measure
summary = tf.Summary()
summary.value.add(tag="%sAccuracy" % prefix, simple_value=accuracy)

# Add it to the Tensorboard summary writer
# Make sure to specify a step parameter to get nice graphs over time
summary_writer.add_summary(summary, global_step)

Ответ 2

Я бы не стал рассчитывать среднее за пределами графика.

Вы можете использовать tf.train.ExponentialMovingAverage:

ema = tf.train.ExponentialMovingAverage(decay=my_decay_value, zero_debias=True)
maintain_ema_op = ema.apply(your_losses_list)

# Create an op that will update the moving averages after each training step.
with tf.control_dependencies([your_original_train_op]):
    train_op = tf.group(maintain_ema_op)

Затем используйте:

sess.run(train_op)

Это вызовет maintain_ema_op потому что он определен как управляющая зависимость.

Чтобы получить свои экспоненциальные скользящие средние, используйте:

moving_average = ema.average(an_item_from_your_losses_list_above)

И получить его значение, используя:

value = sess.run(moving_average)

Это вычисляет скользящее среднее в вашем графике расчета.

Ответ 3

Я думаю, что всегда лучше позволить тензорному потоку делать вычисления.

Посмотрите на потоковые метрики. У них есть функция обновления для подачи информации о вашей текущей партии и функция для получения усредненной сводки. Это будет выглядеть примерно так:

accuracy = ... 
streaming_accuracy, streaming_accuracy_update = tf.contrib.metrics.streaming_mean(accuracy)
streaming_accuracy_scalar = tf.summary.scalar('streaming_accuracy', streaming_accuracy)

# set up your session etc. 

for i in iterations:
      for b in batches:
               sess.run([streaming_accuracy_update], feed_dict={...})

     streaming_summ = sess.run(streaming_accuracy_scalar)
     writer.add_summary(streaming_summary, i)

Также см. Документацию по тензорному потоку: https://www.tensorflow.org/versions/master/api_guides/python/contrib.metrics.

и этот вопрос: как накапливать сводную статистику в тензорном потоке

Ответ 4

Вы можете усреднить сохранение текущей суммы и пересчитать среднее значение после каждой партии, например:

loss_sum = tf.Variable(0.)
inc_op = tf.assign_add(loss_sum, loss)
clear_op = tf.assign(loss_sum, 0.)
average = loss_sum / batches
tf.scalar_summary("average_loss", average)

sess.run(clear_op)
for i in range(batches):
    sess.run([loss, inc_op])

sess.run(average)

Ответ 5

Для дальнейшего использования API метрик TensorFlow теперь поддерживает это по умолчанию. Например, взгляните на tf.mean_squared_error:

Для оценки метрики по потоку данных функция создает операцию update_op которая обновляет эти переменные и возвращает mean_squared_error. Внутри операция squared_error вычисляет поэлементный квадрат разницы между predictions и labels. Затем update_op увеличивает total с уменьшенной суммой произведений weights и squared_error и увеличивает count с уменьшенной суммой weights.

Эти переменные total и count добавляются к набору метрических переменных, поэтому на практике вы должны сделать что-то вроде:

x_batch = tf.placeholder(...)
y_batch = tf.placeholder(...)
model_output = ...
mse, mse_update = tf.metrics.mean_squared_error(y_batch, model_output)
# This operation resets the metric internal variables to zero
metrics_init = tf.variables_initializer(
    tf.get_default_graph().get_collection(tf.GraphKeys.METRIC_VARIABLES))
with tf.Session() as sess:
    # Train...
    # On evaluation step
    sess.run(metrics_init)
    for x_eval_batch, y_eval_batch in ...:
        mse = sess.run(mse_update, feed_dict={x_batch: x_eval_batch, y_batch: y_eval_batch})
    print('Evaluation MSE:', mse)

Ответ 6

Я нашел одно решение сам. Я думаю, что это немного странно, и я надеюсь, что есть более элегантное решение.

Во время настройки:

valid_loss_placeholder = tf.placeholder(dtype=tf.float32, shape=[])
valid_loss_summary = tf.scalar_summary("valid loss", valid_loss_placeholder)

Или для версий тензорного потока после 0.12 (изменение имени для tf.scalar_summary):

valid_loss_placeholder = tf.placeholder(dtype=tf.float32, shape=[])
valid_loss_summary = tf.summary.scalar("valid loss", valid_loss_placeholder) 

В рамках цикла обучения:

# Compute valid loss in python by doing sess.run() for each batch
# and averaging
valid_loss = ...

summary = sess.run(valid_loss_summary, {valid_loss_placeholder: valid_loss})
summary_writer.add_summary(summary, step)

Ответ 7

По состоянию на август 2018 года показатели потоковой передачи были исключены. Тем не менее, нетрудно понять, что все показатели являются потоковыми. Итак, используйте tf.metrics.accuracy.

Однако, если вы хотите, чтобы точность (или другая метрика) превышала только подмножество пакетов, вы можете использовать экспоненциальную скользящую среднюю, как в ответе @MZHm, или сбросить любой из tf.metric, следуя этому очень информативному сообщению в блоге.

Ответ 8

В течение некоторого времени я сохраняю резюме только один раз за эпоху. Я никогда не знал, что сводка TensorFlows сохранит сводку только для последнего запуска.

В шоке я заглянул в эту проблему. Вот решение, которое я придумал (используя API набора данных):

loss = ...
train_op = ...

loss_metric, loss_metric_update = tf.metrics.mean(ae_loss)
tf.summary.scalar('loss', loss_metric)

merged = tf.summary.merge_all()
train_writer = tf.summary.FileWriter(os.path.join(res_dir, 'train'))
test_writer = tf.summary.FileWriter(os.path.join(res_dir, 'test'))

init_local = tf.initializers.local_variables()
init_global = tf.initializers.global_variables()

sess.run(init_global)

def train_run(epoch):
    sess.run([dataset.train_init_op, init_local]) # test_init_op is the operation that switches to test data
    for i in range(dataset.num_train_batches): # num_test_batches is the number of batches that should be run for the test set
        sess.run([train_op, loss_metric_update])

    summary, cur_loss = sess.run([merged, loss_metric])
    train_writer.add_summary(summary, epoch)

    return cur_loss

def test_run(epoch):
    sess.run([dataset.test_init_op, init_local]) # test_init_op is the operation that switches to test data
    for i in range(dataset.num_test_batches): # num_test_batches is the number of batches that should be run for the test set
        sess.run(loss_metric_update)

    summary, cur_loss = sess.run([merged, loss_metric])
    test_writer.add_summary(summary, epoch)

    return cur_loss

for epoch in range(epochs):
    train_loss = train_run(epoch+1)
    test_loss = test_run(epoch+1)
    print("Epoch: {0:3}, loss: (train: {1:10.10f}, test: {2:10.10f})".format(epoch+1, train_loss, test_loss))

Для tf.metrics.mean() я просто tf.metrics.mean() интересующий меня тензор в tf.metrics.mean(). Для каждого пакетного запуска я вызываю операцию обновления метрик. В конце каждой эпохи тензор метрик будет возвращать правильное среднее значение всех результатов партии.

Не забывайте инициализировать локальные переменные каждый раз, когда вы переключаетесь между тренировочными и тестовыми данными. В противном случае ваши показатели поезда и теста будут практически идентичны.

Ответ 9

У меня возникла та же проблема, когда я понял, что мне нужно перебирать свои данные проверки, когда пространство памяти ограничено и переполнены ошибки OOM.

Как говорится в нескольких ответах, в tf.metrics это встроено, но я не использую tf.metrics в своем проекте. Вдохновленный этим, я сделал это:

import tensorflow as tf
import numpy as np


def batch_persistent_mean(tensor):
    # Make a variable that keeps track of the sum
    accumulator = tf.Variable(initial_value=tf.zeros_like(tensor), dtype=tf.float32)
    # Keep count of batches in accumulator (needed to estimate mean)
    batch_nums = tf.Variable(initial_value=tf.zeros_like(tensor), dtype=tf.float32)
    # Make an operation for accumulating, increasing batch count
    accumulate_op = tf.assign_add(accumulator, tensor)
    step_batch = tf.assign_add(batch_nums, 1)
    update_op = tf.group([step_batch, accumulate_op])
    eps = 1e-5
    output_tensor = accumulator / (tf.nn.relu(batch_nums - eps) + eps)
    # In regards to the tf.nn.relu, it a hacky zero_guard:
    # if batch_nums are zero then return eps, else it'll be batch_nums
    # Make an operation to reset
    flush_op = tf.group([tf.assign(accumulator, 0), tf.assign(batch_nums, 0)])
    return output_tensor, update_op, flush_op

# Make a variable that we want to accumulate
X = tf.Variable(0., dtype=tf.float32)
# Make our persistant mean operations
Xbar, upd, flush = batch_persistent_mean(X)

Теперь вы отправляете Xbar в свое резюме, например, tf.scalar_summary("mean_of_x", Xbar), и там, где вы должны выполнить sess.run(X) ранее, вы будете выполнять sess.run(upd). И между эпохами вы бы делали sess.run(flush).

Тестирование поведения:

sess = tf.InteractiveSession()
with tf.Session() as sess:
    sess.run([tf.global_variables_initializer(), tf.local_variables_initializer()])
    # Calculate the mean of 1+2+...+20
    for i in range(20):
        sess.run(upd, {X: i})
    print(sess.run(Xbar), "=", np.mean(np.arange(20)))
    for i in range(40):
        sess.run(upd, {X: i})
    # Now Xbar is the mean of (1+2+...+20+1+2+...+40):
    print(sess.run(Xbar), "=", np.mean(np.concatenate([np.arange(20), np.arange(40)])))
    # Now flush it
    sess.run(flush)
    print("flushed. Xbar=", sess.run(Xbar))
    for i in range(40):
        sess.run(upd, {X: i})
    print(sess.run(Xbar), "=", np.mean(np.arange(40)))