web-dev-qa-db-ja.com

TensorBoard-同じグラフにトレーニングと検証の損失をプロットしますか?

同じグラフにトレーニング損失と検証損失の両方をプロットする方法はありますか?

それぞれに個別の2つのスカラーサマリーを用意するのは簡単ですが、これによりそれらは別々のグラフに配置されます。両方が同じグラフに表示されている場合、それらの間のギャップや、オーバーフィットにより発散し始めているかどうかを確認するのがはるかに簡単です。

これを行う方法が組み込まれていますか?そうでない場合、回避策ですか?どうもありがとう!

32
golmschenk

私がやってきた回避策は、トレーニングセットとクロス検証セットにそれぞれ異なるログディレクトリを持つ2つのSummaryWriterを使用することです。そして、次のようなものが表示されます。

enter image description here

23
Lifu Huang

2行を別々に表示するのではなく、検証損失とトレーニング損失の差を独自のスカラーサマリーとしてプロットして、相違を追跡できます。

これは、2つの要約を追加する場合と比較して、単一のプロットに関する情報を多く提供しませんが、複数の実行を比較できるようにします(実行ごとに複数の要約を追加しません)。

9
golmschenk

完全を期すために、tensorboard 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's 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's 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()

CategoryChartsのグループです。各Chartは、いくつかのスカラーを一緒に表示する単一のプロットに対応します。 Chartは、単純なスカラー(MultilineChartContent)または塗りつぶされた領域(MarginChartContent、たとえば、ある値の偏差をプロットする場合)をプロットできます。 tagMultilineChartContentメンバーは、チャートでグループ化するスカラーのtagsに一致する正規表現のリストでなければなりません。詳細については、 https://github.com/tensorflow/tensorboard/blob/master/tensorboard/plugins/custom_scalar/layout.proto にあるオブジェクトのプロト定義を確認してください。同じディレクトリに複数のFileWritersを書き込む場合、1つのファイルのみにレイアウトを書き込む必要があることに注意してください。別のファイルに書き込むこともできます。

TensorBoardでデータを表示するには、[カスタムスカラー]タブを開く必要があります。以下は、何を期待するかのイメージ例です https://user-images.githubusercontent.com/4221553/32865784-840edf52-ca19-11e7-88bc-1806b1243e0d.png

4
niko

カスタムスカラーのヒントをくれたnikoに感謝します。

公式の 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)   

上記は、以下によって示される3つのコードブロックによって拡張された「元のモデル」で構成されます。

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

私の「元のモデル」には次のスカラーがあります。

enter image description here

そしてこのグラフ:

enter image description here

変更したモデルには、次のカスタムスカラーと同じスカラーとグラフがあります。

enter image description here

このカスタムスカラーチャートは、元の2つのスカラーチャートを組み合わせた単純なレイアウトです。

残念ながら、両方の値が同じ色であるため、結果のグラフは読みにくいです。 (マーカーによってのみ区別されます。)ただし、これは、ログごとに1つの色を持つというTensorBoardの規則と一致しています。

説明

その考え方は次のとおりです。単一のチャート内にプロットする変数のグループがあります。前提条件として、TensorBoardは「SCALARS」見出しの下に各変数を個別にプロットする必要があります。 (これは、各変数のスカラーサマリーを作成し、それらのサマリーをログに書き込むことで実現されます。ここでは新しいことはありません。)

同じチャートに複数の変数をプロットするために、これらのサマリーのどれをグループ化するかをTensorBoardに伝えます。指定されたサマリーは、「カスタムスカラー」見出しの下の単一のチャートに結合されます。これを実現するには、ログの最初に「レイアウト」を1回書き込みます。 TensorBoardがレイアウトを受け取ると、通常の「SCALARS」が更新されると、「CUSTOM SCALARS」の下に結合チャートが自動的に生成されます。

「元のモデル」がすでに変数を(スカラーサマリーとして)TensorBoardに送信していると仮定すると、必要な変更は、メインの反復ループが開始する前にレイアウトを挿入することだけです。各カスタムスカラーチャートは、正規表現を使用してプロットするサマリーを選択します。したがって、変数の各グループを一緒にプロットするには、変数のそれぞれの要約を別々の名前スコープに入れると便利です。 (そのように正規表現は、その名前の範囲内のすべての要約を選択するだけです。)

重要な注意:変数の要約を生成するopは、変数自体とは異なります。たとえば、変数ns1/my_varがある場合、サマリーns2/summary_op_for_myvarを作成できます。カスタムスカラーチャートレイアウトは、サマリーop、not元の変数の名前またはスコープのみを考慮します。

4
Ben Mares

同じルートディレクトリを共有する2つのtf.summary.FileWritersを作成する例を次に示します。 2つの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チームによる非常に便利な post があります。

1
GoingMyWay

Tensorboardは本当に素晴らしいツールですが、その宣言的な性質により、望みどおりの動作を実現するのが困難になる場合があります。

Tensorboardの代替として損失関数をプロットして追跡するために、Losswise( https://losswise.com )をチェックアウトすることをお勧めします。 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()
_

そして、次のようなものが得られます:

Training and test loss on the same graph

_loss_graph.append_呼び出しを介してデータが特定のグラフに明示的に供給されることに注目してください。データはプロジェクトのダッシュボードに表示されます。

さらに、上記の例では、Losswiseはmin(training_loss)およびmin(validation_loss)の列を持つテーブルを自動的に生成するため、実験全体の要約統計を簡単に比較できます。多数の実験で結果を比較するのに非常に便利です。

1
nicodjimenez

@ Lifu Huangで与えられた答えにいくつかのコードサンプルを提供させてください。最初にloger.pyhere からダウンロードし、次に:

from logger import Logger
def train_model(parameters...):
    N_EPOCHS = 15
    # Set the logger
    train_logger = Logger('./summaries/train_logs')
    test_logger = Logger('./summaries/test_logs')
    for Epoch in range(N_EPOCHS):

        # Code to get train_loss and test_loss

        # ============ TensorBoard logging ============#
        # Log the scalar values
        train_info = {
            'loss': train_loss,
        }
        test_info = {
            'loss': test_loss,
        }

        for tag, value in train_info.items():
            train_logger.scalar_summary(tag, value, step=Epoch)
        for tag, value in test_info.items():
            test_logger.scalar_summary(tag, value, step=Epoch)

最後にtensorboard --logdir=summaries/ --port=6006を実行すると、以下が得られます:

enter image description here

0
Darkmoor