TensorFlowを活用するうえで、TensorBoardは非常に役立つツールだ。スカラー値やデータフローグラフをログファイルとして出力し、可視化する方法を説明する。
ご注意:本記事は、@IT/Deep Insider編集部(デジタルアドバンテージ社)が「deepinsider.jp」というサイトから、内容を改変することなく、そのまま「@IT」へと転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。
本連載の最後に、TensorBoardを紹介しておく。TensorBoardは、今後読者がTensorFlowを活用していく際に欠かせないツールである。
TensorFlowには、TensorBoardというダッシュボードツールが付属している。TensorBoardはデータフローグラフの可視化や学習の履歴(損失関数の変化など)の可視化、あるいは途中過程で生成される画像や音声の表示を行うことができる。これにより、モデルの最適化やパラメーターチューニングに対する示唆が得られる。
典型的な利用方法としては、「損失関数の出力値が学習ステップを通して、どのように変化していくか」を折れ線グラフで表示するものである。前回のRNNの損失関数の出力過程を出力してみよう。
TensorBoardで可視化に利用されるデータは、ログとして出力された結果である。そのログは、tf.summaryモジュールにより提供される。
ここでは損失関数の出力すなわちスカラー値を可視化したいので、スカラー値のログを出力するためのtf.summary.scalarメソッドを用いる。tf.summaryモジュールにはログを出力するためのtf.summary.FileWriterクラスが定義されており、これを用いてログを出力できる。ログの出力はadd_summaryメソッドを用いればよい。
次にログ出力に必要なコードの骨格のみを示す。適宜、前回のリスト14のコードに、今回のリスト1の太字部分のコードを差し込めばよい。
# 学習回数
NUM_TRAIN = 10_000
# 学習中の出力頻度
OUTPUT_BY = 500
# 標準化
train_mean = train_dataset.mean()
train_std = train_dataset.std()
standardized_train_dataset = train_dataset.standardize()
# 損失関数の出力をトレース対象とする
loss_summary = tf.summary.scalar('MAE', loss)
# logsディレクトリに出力するライターを作成して利用
with tf.summary.FileWriter('logs') as writer:
# 学習の実行
sess.run(tf.global_variables_initializer())
for i in range(NUM_TRAIN):
batch = standardized_train_dataset.next_batch(SERIES_LENGTH, BATCH_SIZE)
summary, mae, _ = sess.run([loss_summary, loss, optimizer], feed_dict={ x: batch[0], y: batch[1]})
if i % OUTPUT_BY == 0:
print('step {:d}, error {:.2f}'.format(i, mae))
# ログの出力
writer.add_summary(summary, global_step=i)
# ログの出力
writer.add_summary(summary, global_step=NUM_TRAIN)
通常は、損失関数以外にもさまざまな途中過程をログとして出力したいというケースが多い。つまりトレース対象とする変数が増えるわけだが、そのような場合、複数のスカラー値を1つの変数にマージできる。具体的には、tf.summary.merge_allメソッドを用いると、これまでに定義したスカラー値などのトレース対象をまとめた変数が定義できる。
これを評価すれば、すべての変数についてのログがとれる。リスト2がそのコード例だ。
すべての変数ではなく明示的に変数をまとめたい場合は、tf.summary.mergeメソッドを用いる。
# 学習回数
NUM_TRAIN = 10_000
# 学習中の出力頻度
OUTPUT_BY = 500
# 標準化
train_mean = train_dataset.mean()
train_std = train_dataset.std()
standardized_train_dataset = train_dataset.standardize()
# ログ対象とするスカラー値を複数定義する
# 損失関数の出力をトレース対象とする
tf.summary.scalar('MAE', loss)
# ……中略(他にもたくさんのログを対象とする)……
# ログ対象をまとめる
merged = tf.summary.merge_all()
# logsディレクトリに出力するライターを作成して利用
with tf.summary.FileWriter('logs') as writer:
# 学習の実行
sess.run(tf.global_variables_initializer())
for i in range(NUM_TRAIN):
batch = standardized_train_dataset.next_batch(SERIES_LENGTH, BATCH_SIZE)
summary, mae, _ = sess.run([merged, loss, optimizer], feed_dict={ x: batch[0], y: batch[1]})
if i % OUTPUT_BY == 0:
print('step {:d}, error {:.2f}'.format(i, mae))
# ログの出力
writer.add_summary(summary, global_step=i)
# ログの出力
writer.add_summary(summary, global_step=NUM_TRAIN)
tf.summary.FileWriterクラスのインスタンス作成時にgraph引数を指定するか、インスタンス作成後にadd_graphメソッドを用いると、データフローグラフを可視化できる。なお、本稿では省略しているが、各テンソルに名前を付けておけば、その名前が可視化の際に利用される。
# ……省略……
# logsディレクトリに出力するライターを作成して利用
# データフローグラフを出力する
with tf.summary.FileWriter('logs', sess.graph) as writer:
# ……省略……
そのまま出力すると、データフローグラフのノードがそのままバラバラに表示されてしまい、見づらくなってしまう(どのように表示されるかは最後にまとめる)。tf.name_scopeメソッドで名前スコープを定義しておくことで、表示単位をまとめることができる。次のリスト4はその例で、前回のリスト12の前半「最終出力(予測)」を「prediction」という名前スコープでまとめたものだ。
# 全結合
with tf.name_scope('prediction'):
# 重み
w = tf.Variable(tf.zeros([20, FEATURE_COUNT]))
# バイアス
b = tf.Variable([0.1] * FEATURE_COUNT)
# 最終出力(予測)
prediction = tf.matmul(last_state, w) + b
本稿の例では、同様の手順で、前回示したリスト10/11/12に対して、
を定義すればよい。
以上の手順でログが取れたら、TensorBoardを起動する。TensorBoardはtensorboardコマンド(リスト5)で起動できる。当然ながら、カレントディレクトリを適切な場所(Jupyter Notebookを使っている場合は.ipynbファイルのあるディレクトリ)に変更してから実行すること。
$ tensorboard --logdir=logs/
デフォルトでは6006番ポートでWebサーバーが起動するので*1、http://localhost:6006/にアクセスするとTensorBoardが表示される(図1)。
*1 ポート番号は--portオプションで指定することもできる。
画面上部のタブ、具体的には[SCALARS]タブでログ出力したスカラー値(図1)や、[GRAPHS]タブでデータフローグラフ(図2)などの表示を切り替えることができる。前述の通り、名前スコープがない場合(図2)とある場合(図3)で異なる。
図2では全要素が表示されるため全体の内容をつかみづらい。スコープを定義しておけば、図3のようにすっきりと表示される。
以上で本連載は完結である。続編としてChainerで同様の内容を解説するので、ぜひそちらも併せて参照してほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.