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

TensorBoard - Обучение графику и валидация на одном графике?

Есть ли способ построить как потери на тренировки, так и потери валидации на одном и том же графике?

Легко иметь два отдельных скалярных сводки для каждого из них по отдельности, но это ставит их на отдельные графики. Если обе они отображаются на одном и том же графике, гораздо легче увидеть промежуток между ними и независимо от того, начинают ли они расходиться из-за переобучения.

Есть ли встроенный способ сделать это? Если нет, работа вокруг? Большое вам спасибо!

4b9b3361

Ответ 1

SummaryWriter я делал, - это использовать два SummaryWriter с разными SummaryWriter журналов для набора обучения и набора для перекрестной проверки соответственно. И вы увидите что-то вроде этого:

enter image description here

Ответ 2

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

Это не дает столько информации об одном графике (по сравнению с добавлением двух сводок), но помогает с возможностью сравнивать несколько прогонов (и не добавлять несколько сводок за прогон).

Ответ 3

Для полноты, начиная с тензорной доски 1.5.0, это теперь возможно.

Вы можете использовать пользовательский плагин скаляров. Для этого вам нужно сначала выполнить настройку макета тензорной доски и записать ее в файл событий. Из примера тензорной доски:

import tensorflow as tf
from tensorboard import summary
from tensorboard.plugins.custom_scalar import layout_pb2

# The layout has to be specified and written only once, not at every step

layout_summary = summary.custom_scalar_pb(layout_pb2.Layout(
  category=[
    layout_pb2.Category(
      title='losses',
      chart=[
          layout_pb2.Chart(
              title='losses',
              multiline=layout_pb2.MultilineChartContent(
                tag=[r'loss.*'],
              )),
          layout_pb2.Chart(
              title='baz',
              margin=layout_pb2.MarginChartContent(
                series=[
                  layout_pb2.MarginChartContent.Series(
                    value='loss/baz/scalar_summary',
                    lower='baz_lower/baz/scalar_summary',
                    upper='baz_upper/baz/scalar_summary'),
                ],
              )), 
      ]),
    layout_pb2.Category(
      title='trig functions',
      chart=[
          layout_pb2.Chart(
              title='wave trig functions',
              multiline=layout_pb2.MultilineChartContent(
                tag=[r'trigFunctions/cosine', r'trigFunctions/sine'],
              )),
          # The range of tangent is different. Let give it its own chart.
          layout_pb2.Chart(
              title='tan',
              multiline=layout_pb2.MultilineChartContent(
                tag=[r'trigFunctions/tangent'],
              )),
      ],
      # This category we care less about. Let make it initially closed.
      closed=True),
  ]))

writer = tf.summary.FileWriter(".")
writer.add_summary(layout_summary)
# ...
# Add any summary data you want to the file
# ...
writer.close()

Category - это группа Chart s. Каждая Chart соответствует одному графику, который отображает несколько скаляров вместе. Chart может MarginChartContent простые скаляры (MultilineChartContent) или заполненные области (MarginChartContent, например, когда вы хотите построить график отклонения некоторого значения). Член tag MultilineChartContent должен быть списком регулярных выражений, которые соответствуют tag скаляров, которые вы хотите сгруппировать в диаграмме. Для получения более подробной информации смотрите предварительные определения объектов в https://github.com/tensorflow/tensorboard/blob/master/tensorboard/plugins/custom_scalar/layout.proto. Обратите внимание, что если у вас есть несколько FileWriter пишущих в один и тот же каталог, вы должны записать макет только в один из файлов. Запись его в отдельный файл также работает.

Чтобы просмотреть данные в TensorBoard, вам нужно открыть вкладку Custom Scalars. Вот пример изображения того, что ожидать https://user-images.githubusercontent.com/4221553/32865784-840edf52-ca19-11e7-88bc-1806b1243e0d.png

Ответ 4

Большое спасибо Нико за подсказку о пользовательских скалярах.

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

Чтобы точно показать, что нужно сделать для создания собственного скалярного графа для существующей модели, я собрал следующий полный пример:

# + <
# We need these to make a custom protocol buffer to display custom scalars.
# See https://developers.google.com/protocol-buffers/
from tensorboard.plugins.custom_scalar import layout_pb2
from tensorboard.summary.v1 import custom_scalar_pb
#   > 
import tensorflow as tf
from time import time
import re

# Initial values
(x0, y0) = (-1, 1)

# This is useful only when re-running code (e.g. Jupyter).
tf.reset_default_graph()  

# Set up variables.
x = tf.Variable(x0, name="X", dtype=tf.float64)
y = tf.Variable(y0, name="Y", dtype=tf.float64)

# Define loss function and give it a name.
loss = tf.square(x - 3*y) + tf.square(x+y)
loss = tf.identity(loss, name='my_loss')

# Define the op for performing gradient descent.
minimize_step_op = tf.train.GradientDescentOptimizer(0.092).minimize(loss)

# List quantities to summarize in a dictionary 
# with (key, value) = (name, Tensor).
to_summarize = dict(
    X = x,
    Y_plus_2 = y + 2,
)

# Build scalar summaries corresponding to to_summarize.
# This should be done in a separate name scope to avoid name collisions
# between summaries and their respective tensors. The name scope also
# gives a title to a group of scalars in TensorBoard.
with tf.name_scope('scalar_summaries'):
    my_var_summary_op = tf.summary.merge(
        [tf.summary.scalar(name, var) 
            for name, var in to_summarize.items()
        ]
    )

# + <
# This constructs the layout for the custom scalar, and specifies
# which scalars to plot.
layout_summary = custom_scalar_pb(
    layout_pb2.Layout(category=[
        layout_pb2.Category(
            title='Custom scalar summary group',
            chart=[
                layout_pb2.Chart(
                    title='Custom scalar summary chart',
                    multiline=layout_pb2.MultilineChartContent(
                        # regex to select only summaries which 
                        # are in "scalar_summaries" name scope:
                        tag=[r'^scalar_summaries\/']
                    )
                )
            ])
    ])
)
#   >

# Create session.
with tf.Session() as sess:

    # Initialize session.
    sess.run(tf.global_variables_initializer())

    # Create writer.
    with tf.summary.FileWriter(f'./logs/session_{int(time())}') as writer:

        # Write the session graph.
        writer.add_graph(sess.graph) # (not necessary for scalars)

# + <
        # Define the layout for creating custom scalars in terms
        # of the scalars.
        writer.add_summary(layout_summary)
#   >

        # Main iteration loop.
        for i in range(50):
            current_summary = sess.run(my_var_summary_op)
            writer.add_summary(current_summary, global_step=i)
            writer.flush()
            sess.run(minimize_step_op)   

Вышесказанное состоит из "оригинальной модели", дополненной тремя блоками кода, обозначенного

# + <
        [code to add custom scalars goes here]
#   >

Моя "оригинальная модель" имеет эти скаляры:

enter image description here

и этот график:

enter image description here

Моя модифицированная модель имеет те же скаляры и граф, а также следующий пользовательский скаляр:

enter image description here

Эта пользовательская скалярная диаграмма - это просто компоновка, объединяющая две исходные скалярные диаграммы.

К сожалению, полученный график трудно читать, потому что оба значения имеют одинаковый цвет. (Они различаются только маркером.) Это, однако, согласуется с соглашением TensorBoard о наличии одного цвета на бревно.

объяснение

Идея заключается в следующем. У вас есть группа переменных, которые вы хотите построить на одном графике. В качестве предварительного условия TensorBoard должен отображать каждую переменную отдельно под заголовком "SCALARS". (Это достигается путем создания скалярной сводки для каждой переменной, а затем записи этих сводок в журнал. Ничего нового здесь нет.)

Чтобы отобразить несколько переменных на одной диаграмме, мы сообщаем TensorBoard, какую из этих сводок сгруппировать. Указанные сводные данные затем объединяются в один график под заголовком "ТАМОЖЕННЫЕ СКАЛЯРЫ". Мы достигаем этого, написав "Макет" один раз в начале журнала. Как только TensorBoard получает макет, он автоматически создает комбинированную диаграмму в разделе "ТАМОЖЕННЫЕ СКАЛЯРЫ", когда обновляются обычные "СКАЛЯРЫ".

Предполагая, что ваша "исходная модель" уже отправляет ваши переменные (в виде скалярных сводок) в TensorBoard, единственная необходимая модификация - это внедрить макет перед началом основного цикла итерации. Каждая пользовательская скалярная диаграмма выбирает, какие сводки строить с помощью регулярного выражения. Таким образом, для каждой группы переменных, которые должны быть нанесены на график вместе, может быть полезно поместить соответствующие резюме переменных в отдельную область имен. (Таким образом, ваше регулярное выражение может просто выбрать все резюме под этим именем области.)

Важное примечание: операция, которая генерирует сводку переменной, отличается от самой переменной. Например, если у меня есть переменная ns1/my_var, я могу создать сводку ns2/summary_op_for_myvar. Пользовательский макет диаграммы скаляров заботится только о сводной операции, а не об имени или области действия исходной переменной.

Ответ 5

Tensorboard - действительно хороший инструмент, но его декларативный характер может затруднить его выполнение именно того, что вы хотите.

Я рекомендую вам выставить Losswise (https://losswise.com) для построения и отслеживания функций потерь в качестве альтернативы Tensorboard. С помощью Losswise вы точно определяете, что следует графовать вместе:

import losswise

losswise.set_api_key("project api key")
session = losswise.Session(tag='my_special_lstm', max_iter=10)
loss_graph = session.graph('loss', kind='min')

# train an iteration of your model...
loss_graph.append(x, {'train_loss': train_loss, 'validation_loss': validation_loss})
# keep training model...

session.done()

И тогда вы получите что-то похожее:

Тренировка и потеря теста на одном и том же графе

Обратите внимание, как данные передаются на конкретный граф явно через вызов loss_graph.append, данные для которого затем отображаются в панели инструментов проекта.

Кроме того, для приведенного выше примера Losswise автоматически генерирует таблицу с столбцами для min(training_loss) и min(validation_loss), чтобы вы могли легко сравнивать сводную статистику в своих экспериментах. Очень полезно для сравнения результатов в большом количестве экспериментов.

Ответ 6

Вот пример, создающий два tf.summary.FileWriter которые совместно используют тот же корневой каталог. Создание tf.summary.scalar совместно используемого двумя tf.summary.FileWriter. На каждом шаге по времени получайте summary и обновляйте каждый tf.summary.FileWriter.

import os

import tqdm
import tensorflow as tf


def tb_test():
    sess = tf.Session()

    x = tf.placeholder(dtype=tf.float32)
    summary = tf.summary.scalar('Values', x)
    merged = tf.summary.merge_all()

    sess.run(tf.global_variables_initializer())

    writer_1 = tf.summary.FileWriter(os.path.join('tb_summary', 'train'))
    writer_2 = tf.summary.FileWriter(os.path.join('tb_summary', 'eval'))

    for i in tqdm.tqdm(range(200)):
        # train
        summary_1 = sess.run(merged, feed_dict={x: i-10})
        writer_1.add_summary(summary_1, i)
        # eval
        summary_2 = sess.run(merged, feed_dict={x: i+10})            
        writer_2.add_summary(summary_2, i)

    writer_1.close()
    writer_2.close()


if __name__ == '__main__':
    tb_test()

Вот результат:

enter image description here

Оранжевая линия показывает результат этапа оценки, и, соответственно, синяя линия иллюстрирует данные этапа обучения.

Также есть очень полезный пост от команды TF, на который вы можете сослаться.