Tensorflow
tf.summary
Estimator API
Tensorflow 1.2
Machine Learning

Tensorflow - Using tf.summary with 1.2 Estimator API

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

The TensorFlow Estimator API provides a high-level interface for training, evaluation, and prediction. Adding tf.summary operations inside the model_fn lets you log metrics, images, histograms, and text to TensorBoard for visualization. In TF 1.x, tf.summary ops are added to the graph and collected automatically when using Estimators — you do not need to create a FileWriter or call sess.run() on summary ops manually. The Estimator handles summary writing during training. This article covers both the TF 1.x Estimator approach and the modern TF 2.x equivalent using Keras callbacks.

TF 1.x: Summaries in model_fn

The Estimator API requires a model_fn that defines the model, loss, optimizer, and any summaries:

python
1import tensorflow as tf
2
3def model_fn(features, labels, mode):
4    # Define the model
5    x = features["x"]
6    dense1 = tf.layers.dense(x, 128, activation=tf.nn.relu, name="dense1")
7    dense2 = tf.layers.dense(dense1, 64, activation=tf.nn.relu, name="dense2")
8    logits = tf.layers.dense(dense2, 10, name="logits")
9    predictions = tf.argmax(logits, axis=1)
10
11    # Add summaries — these are collected automatically by the Estimator
12    tf.summary.histogram("dense1_output", dense1)
13    tf.summary.histogram("dense2_output", dense2)
14    tf.summary.histogram("logits", logits)
15
16    if mode == tf.estimator.ModeKeys.PREDICT:
17        return tf.estimator.EstimatorSpec(mode, predictions={"class": predictions})
18
19    # Loss
20    loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)
21    tf.summary.scalar("loss", loss)
22
23    # Accuracy
24    accuracy = tf.metrics.accuracy(labels=labels, predictions=predictions)
25    tf.summary.scalar("accuracy", accuracy[1])
26
27    if mode == tf.estimator.ModeKeys.EVAL:
28        return tf.estimator.EstimatorSpec(
29            mode, loss=loss,
30            eval_metric_ops={"accuracy": accuracy}
31        )
32
33    # Training
34    optimizer = tf.train.AdamOptimizer(learning_rate=0.001)
35    train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())
36
37    # Log learning rate
38    tf.summary.scalar("learning_rate", 0.001)
39
40    return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

Creating and Training the Estimator

python
1# Create the Estimator — model_dir stores checkpoints and summaries
2estimator = tf.estimator.Estimator(
3    model_fn=model_fn,
4    model_dir="./model_output"
5)
6
7# Input function
8def train_input_fn():
9    dataset = tf.data.Dataset.from_tensor_slices((
10        {"x": x_train}, y_train
11    ))
12    return dataset.shuffle(10000).batch(32).repeat()
13
14# Train — summaries are written to model_dir automatically
15estimator.train(input_fn=train_input_fn, steps=10000)
16
17# View in TensorBoard
18# tensorboard --logdir=./model_output

The Estimator writes summaries every 100 steps by default. To change this frequency:

python
1# Save summaries every 50 steps
2run_config = tf.estimator.RunConfig(
3    model_dir="./model_output",
4    save_summary_steps=50,
5    log_step_count_steps=50
6)
7
8estimator = tf.estimator.Estimator(
9    model_fn=model_fn,
10    config=run_config
11)

Custom Summary Hook

For summaries that need to be computed at specific intervals or with custom logic:

python
1class CustomSummaryHook(tf.train.SessionRunHook):
2    def __init__(self, output_dir, save_steps=100):
3        self._output_dir = output_dir
4        self._save_steps = save_steps
5
6    def begin(self):
7        self._step = 0
8        self._writer = tf.summary.FileWriter(self._output_dir)
9
10    def before_run(self, run_context):
11        self._step += 1
12        return tf.train.SessionRunArgs(tf.get_collection(tf.GraphKeys.SUMMARIES))
13
14    def after_run(self, run_context, run_values):
15        if self._step % self._save_steps == 0:
16            for summary in run_values.results:
17                if summary is not None:
18                    self._writer.add_summary(summary, self._step)
19            self._writer.flush()
20
21    def end(self, session):
22        self._writer.close()
23
24# Use with Estimator
25estimator.train(
26    input_fn=train_input_fn,
27    steps=10000,
28    hooks=[CustomSummaryHook("./custom_summaries")]
29)

Image Summaries

python
1def model_fn(features, labels, mode):
2    images = features["images"]  # Shape: [batch, 28, 28, 1]
3
4    # Log input images
5    tf.summary.image("input_images", images, max_outputs=4)
6
7    conv1 = tf.layers.conv2d(images, 32, [3, 3], activation=tf.nn.relu)
8    # Log first conv layer filters
9    tf.summary.image("conv1_filters",
10                     tf.transpose(conv1[:1], [3, 1, 2, 0]),
11                     max_outputs=8)
12
13    # ... rest of model

TF 2.x: Modern Equivalent with Keras

In TensorFlow 2.x, use tf.keras with TensorBoard callback:

python
1import tensorflow as tf
2
3model = tf.keras.Sequential([
4    tf.keras.layers.Dense(128, activation='relu', input_shape=(784,)),
5    tf.keras.layers.Dense(64, activation='relu'),
6    tf.keras.layers.Dense(10, activation='softmax')
7])
8
9model.compile(
10    optimizer='adam',
11    loss='sparse_categorical_crossentropy',
12    metrics=['accuracy']
13)
14
15# TensorBoard callback handles all summaries automatically
16tensorboard_callback = tf.keras.callbacks.TensorBoard(
17    log_dir="./logs",
18    histogram_freq=1,        # Log weight histograms every epoch
19    write_graph=True,        # Log the computation graph
20    write_images=True,       # Log model weights as images
21    update_freq="epoch",     # Log metrics every epoch (or "batch")
22    profile_batch=(10, 20),  # Profile batches 10-20
23)
24
25model.fit(
26    x_train, y_train,
27    epochs=10,
28    validation_data=(x_val, y_val),
29    callbacks=[tensorboard_callback]
30)

Custom Summaries in TF 2.x

python
1# Custom training loop with tf.summary
2writer = tf.summary.create_file_writer("./logs/custom")
3
4for step, (x_batch, y_batch) in enumerate(train_dataset):
5    with tf.GradientTape() as tape:
6        predictions = model(x_batch, training=True)
7        loss = loss_fn(y_batch, predictions)
8
9    gradients = tape.gradient(loss, model.trainable_variables)
10    optimizer.apply_gradients(zip(gradients, model.trainable_variables))
11
12    with writer.as_default(step=step):
13        tf.summary.scalar("loss", loss)
14        tf.summary.scalar("learning_rate", optimizer.learning_rate)
15        tf.summary.histogram("dense1_weights", model.layers[0].weights[0])

Common Pitfalls

  • Adding summaries outside model_fn in TF 1.x: Summary ops must be defined inside model_fn where the computation graph is built. Defining them outside means they are not part of the Estimator's graph and are never executed.
  • Expecting summaries during PREDICT mode: The Estimator only writes summaries during TRAIN mode. Summaries added in the graph are ignored during PREDICT and EVAL modes unless explicitly included in eval_metric_ops.
  • Not running TensorBoard with the correct logdir: Summaries are written to the Estimator's model_dir. Running tensorboard --logdir=wrong_path shows an empty dashboard. Always match logdir to the Estimator's model_dir or the Keras callback's log_dir.
  • Mixing TF 1.x tf.summary with TF 2.x code: In TF 2.x, tf.summary.scalar("name", value) requires an active tf.summary.FileWriter context (with writer.as_default()). The TF 1.x pattern of just calling tf.summary.scalar without a writer does not work in TF 2.x eager mode.
  • Logging too frequently in production: Setting save_summary_steps=1 or update_freq="batch" generates massive log files and slows training. Use every 100-500 steps for training and histogram_freq=1 (per epoch) for weight distributions.

Summary

  • In TF 1.x Estimators, add tf.summary ops inside model_fn — the Estimator writes them automatically
  • Configure frequency with RunConfig(save_summary_steps=N) (default is 100 steps)
  • Use tf.summary.scalar, tf.summary.histogram, and tf.summary.image for different data types
  • In TF 2.x, use tf.keras.callbacks.TensorBoard for automatic logging or tf.summary.create_file_writer for custom summaries
  • View all summaries with tensorboard --logdir=<model_dir>

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.