How to create only one copy of graph in tensorboard events file with custom tf.Estimator?
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.
Introduction
If you see multiple copies of a graph in TensorBoard while using a custom tf.Estimator, the problem is usually not TensorBoard itself. It is usually caused by writing the graph more than once, often through manual summary writers, reusing the same log directory for different modes, or creating separate train and eval runs that each export a graph.
Understand why duplicates happen with Estimator
tf.estimator.Estimator builds separate graphs for different modes such as TRAIN, EVAL, and PREDICT. On top of that, custom hooks or manual FileWriter calls can add the graph repeatedly.
Common duplicate sources are:
- calling
writer.add_graph(...)in more than one place - using the same events directory for both train and eval summaries
- rebuilding the graph and exporting it again in each session
For modern TensorFlow projects, Keras plus callbacks is usually the preferred stack. But if you are still maintaining an Estimator codebase, the fix is to decide exactly one place where the graph should be written.
The simplest fix: let training own the graph
If your training job already writes summaries, the cleanest approach is often:
- write the graph only for
TRAIN - do not manually write the graph in
EVAL - keep train and eval summaries in separate directories
Conceptually, that means your model_fn should avoid extra graph-writing logic unless it is strictly necessary.
For example, this is the pattern to avoid:
If that code appears in multiple sessions or hooks, you will get repeated graph exports.
If you must write it yourself, guard it explicitly
When you really need manual control, write the graph once through a hook that only runs for training:
Then attach it only in TRAIN mode:
The important part is not the hook itself. The important part is that the graph export path is centralized and restricted to one mode.
Keep train and eval logs separate
Even without manual graph writing, mixing all summaries into one directory can make debugging harder. A clearer setup is:
Then let Estimator place evaluation outputs in its own subdirectory during train_and_evaluate. That keeps the training event stream cleaner and reduces confusion about which graph belongs to which execution mode.
If you are launching TensorBoard against the entire experiment directory, remember that multiple runs can still appear in the UI. That does not necessarily mean the same graph was written into one single event stream.
Avoid writing graphs inside every step or summary callback
Another common mistake is treating graph export like a scalar summary and writing it repeatedly. The graph definition is structural metadata, not a per-step metric.
Write scalar summaries often if needed. Write the graph once.
If a custom callback or hook is running every step, it should not call add_graph(...). That guarantees duplication and grows event files unnecessarily.
Common Pitfalls
The biggest mistake is manually calling add_graph(...) while also relying on Estimator or another hook to manage summary writing.
Another common issue is assuming every graph shown in TensorBoard is a duplicate bug. Sometimes you are looking at separate train and eval runs, which is expected.
People also reuse the same log directory for unrelated experiments. That makes TensorBoard look noisy even when each individual run is correct.
Finally, keep in mind that tf.Estimator is a legacy API. If you are building something new, Keras with TensorBoard callbacks is usually easier to control.
Summary
- Duplicate graphs usually come from multiple graph exports, not from TensorBoard itself.
- With Estimator, write the graph in one place, ideally only for
TRAIN. - Avoid manual
add_graph(...)calls unless you really need them. - Keep train and eval event directories separate so runs stay understandable.
- For new projects, prefer Keras and TensorBoard callbacks over fresh Estimator-based code.
Related reading
- How to create own dataset for using Mask-RCNN models from the Tensorflow Object Detection API?
- How to deal with batches with variable-length sequences in TensorFlow?
- How to deal with large2GB embedding lookup table in tensorflow?
- How to deal with multi step time series forecasting in multivariate LSTM in keras
- How to deal with array of string features in traditional machine learning?
- How to deal with different state space size in reinforcement learning?
- How to Create Own HashMap in Java?
- How to create the most compact mapping n → isprimen up to a limit N?

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack 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.