TensorFlow.org で表示 | Google Colab で実行 | GitHubでソースを表示 | ノートブックをダウンロード |
注意: このドキュメントは、TensorFlow 1.x TensorBoard に精通している方で大規模な TensorFlow コードベースを TensorFlow 1.x から 2.0 に移行したい方を対象としています。TensorBoard にまだ新しい方は、基礎ドキュメントをご覧ください。
tf.keras
を使用している場合は、TensorFlow 2.0 にアップグレードするための作業が必要ない場合があります。
import tensorflow as tf
TensorFlow 2.0 では、TensorBoard での視覚化に使用する要約データを書き込む際の tf.summary
API が大幅に変更されています。
変更点
tf.summary
API を 2 つのサブ API として考えると良いでしょう。
- 個別の要約を記録するための一連の演算 -
summary.scalar()
、summary.histogram()
、summary.image()
、summary.audio()
、およびsummary.text()
。これらはモデルコードからインラインで呼び出されます。 - 上記の個別の要約を収集して特別にフォーマットされたログファイル(TensorBoard が読み取って視覚化を生成するファイル)に書き込む書き込みロジック。
TF 1.x の場合
上記の 2 つは、Session.run()
でサマリー演算の出力をフェッチし、FileWriter.add_summary(output, step)
で呼び出す、というように手動でつなぐ必要がありました。v1.summary.merge_all()
演算によって、グラフコレクションを使ってすべてのサマリー演算出力を集計するという方法で、この処理が簡単になっていますが、Eager execution と制御フローではあまりよく機能しなかったため、TF 2.0 には特に適していません。
TF 2.X の場合
上記の 2 つは密接に統合されており、個別の tf.summary
演算は実行時に直ちにデータを書き込むようになっています。モデルコードから API を使用する方法はあまり変わっていませんが、Eager execution との相性が改善されており、ほかのグラフモードとの互換性もそのままです。この 2 つの API を統合することで、summary.FileWriter
は TensorFlow 実行コンテキストの一環となり、tf.summary
演算で直接アクセスできるため、ライターの構成が外見的な主な違いと言えます。
次は、TF 2.x のデフォルトのモードである Eager execution を使用した例です。
writer = tf.summary.create_file_writer("/tmp/mylogs/eager")
with writer.as_default():
for step in range(100):
# other model code would go here
tf.summary.scalar("my_metric", 0.5, step=step)
writer.flush()
ls /tmp/mylogs/eager
次は、tf.function グラフ実行の使用例です。
writer = tf.summary.create_file_writer("/tmp/mylogs/tf_function")
@tf.function
def my_func(step):
with writer.as_default():
# other model code would go here
tf.summary.scalar("my_metric", 0.5, step=step)
for step in tf.range(100, dtype=tf.int64):
my_func(step)
writer.flush()
ls /tmp/mylogs/tf_function
次は、レガシー TF 1.x グラフ実行の使用例です。
g = tf.compat.v1.Graph()
with g.as_default():
step = tf.Variable(0, dtype=tf.int64)
step_update = step.assign_add(1)
writer = tf.summary.create_file_writer("/tmp/mylogs/session")
with writer.as_default():
tf.summary.scalar("my_metric", 0.5, step=step)
all_summary_ops = tf.compat.v1.summary.all_v2_summary_ops()
writer_flush = writer.flush()
with tf.compat.v1.Session(graph=g) as sess:
sess.run([writer.init(), step.initializer])
for i in range(100):
sess.run(all_summary_ops)
sess.run(step_update)
sess.run(writer_flush)
ls /tmp/mylogs/session
コードを変換する
既存の tf.summary
の使用箇所を TF 2.x API に変換する作業を確実に変換することは困難であるため、tf_upgrade_v2
スクリプトは、すべてを tf.compat.v1.summary
に書き換えることだけを行い、自動的に TF 2.x の動作を有効化することはありません。
部分移行
tf.compat.v1.summary.scalar()
といった TF 1.x サマリー API のロギング演算に大きく依存しているモデルコードを使用するユーザーが TF 2.x により簡単に移行できるようにするには、先にライター API のみを移行して、後でモデルコード内の個別の TF 1.x サマリー演算を完全に移行することができます。
このような移行をサポートするために、tf.compat.v1.summary
は以下の条件で TF 2.x 相当に自動的に転送されます。
- 最も外側のコンテキストが Eager モードである
- デフォルトの TF 2.x サマリーライターが設定されている
- 空でないステップの値がライターに設定済みである(
tf.summary.SummaryWriter.as_default
、tf.summary.experimental.set_step
、またはtf.compat.v1.train.create_global_step
を使用)
TF 2.x サマリー実装が呼び出されると、戻り値は空のバイト文字列テンソルになり、サマリーの書き込みが重複しないようにされることに注意してください。また、入力引数のフォワーディングはベストエフォートであり、すべての引数が保持されるとは限りません(たとえば、family
引数はサポートされていますが、collections
は取り除かれます)。
以下は、tf.compat.v1.summary.scalar
で tf.summary.scalar
の動作を呼び出す例です。
# Enable eager execution.
tf.compat.v1.enable_v2_behavior()
# A default TF 2.x summary writer is available.
writer = tf.summary.create_file_writer("/tmp/mylogs/enable_v2_in_v1")
# A step is set for the writer.
with writer.as_default(step=0):
# Below invokes `tf.summary.scalar`, and the return value is an empty bytestring.
tf.compat.v1.summary.scalar('float', tf.constant(1.0), family="family")
完全移行
TF 2.x に全移行するには、コードを次のように適合させる必要があります。
サマリー演算を使用するには、
.as_default()
によるデフォルトのライターセットが存在する必要がある- つまり、演算を Eager で実行するか、グラフ構造で演算を使用する
- デフォルトのライターがない場合、サマリー演算はサイレントの no-op になる
- デフォルトのライターは(まだ)
@tf.function
実行境界に伝搬しません。関数がトレースされた場合にのみ検出されるため、関数の本文でwriter.as_default()
を呼び出し、@tf.function
が使用される限りライターオブジェクトが存在し続けられるようにすることが、ベストプラクティスと言えます。
「step」値は
step
引数で各演算に渡される必要がある- TensorBoard には、時系列としてデータをレンダリングするステップ値が必要です
- TF 1.x のグローバルステップは削除されており、各演算は読み取るための希望する step 変数を知っておくために、明示的に渡す必要があります
- ボイラープレートを減らすために、デフォルトステップを登録するための実験的サポートは
tf.summary.experimental.set_step()
として提供されていますが、これは暫定機能であり、予告なく変更される場合があります
個々のサマリー演算の関数シグネチャが変更されている
- 戻り値はブール型になっています(要約が実際に書き込まれたかどうかを示す)
- 2 番目のパラメータ名(使用される場合)が
tensor
からdata
に代わっています collections
パラメータが削除されています。collections は TF 1.x のみのパラメータですfamily
パラメータが削除されています。tf.name_scope()
を使用してください
[レガシーグラフモードのみ / セッション実行ユーザー]
最初に
v1.Session.run(writer.init())
でライターを初期化しますv1.summary.all_v2_summary_ops()
を使用して、現在のグラフに関するすべての TF 2.0 サマリー演算を取得します(Session.run()
で実行するためなど)。v1.Session.run(writer.flush())
でライターをフラッシュし、close()
でも同様にフラッシュします
TF 1.x コードで tf.contrib.summary
API を使用していた場合は、TF 2.0 API にはるかに似ているため、tf_upgrade_v2
スクリプトを使って、ほとんどの移行ステップ(および完全に移行できない使用箇所の発行警告またはエラー)を自動化できます。ほとんどにおいて、API 呼び出しを tf.compat.v2.summary
に書き直すだけであるため、TF 2.0+ との互換性のみが必要である場合は、compat.v2
を削除して、tf.summary
として参照するようにすることができます。
その他のヒント
上記の重要な分野に加え、一部の補助的な側面も変更されています。
条件付き記録(「100 ステップごとにログ」など)が新しくなりました
- 演算と関連するコードを制御するには、通常の if ステートメント(Eager モードと自動グラフ作成経由の
@tf.function
で機能)か、tf.cond
でラップします - 要約のみを制御するには、新しい
tf.summary.record_if()
コンテキストマネージャを使用して、選択したブール条件を渡します TF 1.x パターンを置き換えます
if condition: writer.add_summary()
- 演算と関連するコードを制御するには、通常の if ステートメント(Eager モードと自動グラフ作成経由の
tf.compat.v1.Graph
を直接書き込めない代わりにトレース関数を使用します- TF 2.x のグラフ実行では、明示的な Graph の代わりに
@tf.function
が使用されます - TF 2.0 では、新しいトレース式 API である
tf.summary.trace_on()
とtf.summary.trace_export()
を使用して、実行した関数グラフを記録します
- TF 2.x のグラフ実行では、明示的な Graph の代わりに
tf.summary.FileWriterCache
の使用により、logdir ごとのグローバルライターのキャッシュが不要になります- ユーザーは、ライターオブジェクトの独自のキャッシュ/共有を実装するか、個別のライターを使用する必要があります(TensorBoard の後者のサポートは開発中です)
イベントファイルのバイナリ表現が変更されました
- TensorBoard 1.x は、新しい形式をサポート済みです。この違いは、要約データをイベントファイルから手動で解析しているユーザーのみに影響します)
- 要約データはテンソルバイトとして保存されるようになりました。
tf.make_ndarray(event.summary.value[0].tensor)
を使って numpy に変換できます。