A loss curve tells you the deep model is learning. It does not tell you whether the images reaching that model are the ones you think they are. In a hybrid pipeline that mixes classical feature extraction with deep components, that gap is where most of the hard debugging time goes — and it is exactly the gap a loss curve cannot see. The common way to use TensorBoard is as a loss-curve viewer bolted on at the end of training: you call SummaryWriter, log train/loss and val/accuracy, and open the dashboard when a run finishes. That works for a monolithic CNN. It falls apart the moment your pipeline has more than one stage that can be wrong. When a SIFT/ORB keypoint step, a HOG descriptor block, or an OpenCV contour extraction feeds a downstream network, the loss curve aggregates every failure mode into a single number. A regression shows up, and you have no way to tell whether the model got worse or the preprocessing quietly changed what the model was being shown. What TensorBoard actually is once you stop treating it as a plot TensorBoard is an instrumentation layer, not a dashboard. The distinction matters. A dashboard visualizes a metric someone decided to compute; an instrumentation layer records the state of a system at points you choose, so that later you can reconstruct what happened. TensorFlow’s tf.summary API — and the PyTorch torch.utils.tensorboard.SummaryWriter that writes the same event-file format — supports at least four summary types that map onto that job: scalars, images, histograms, and (less commonly used in CV) text and graph traces. The practical consequence: any tensor in your pipeline that you can name, you can log. That includes the output of a classical stage, not just the deep model. Once you internalize that, TensorBoard stops being a training-loss viewer and becomes a diagnostic tool for the seam between the classical and deep layers of a CV system. That reframing is the whole point of this article, and it is the difference between spending an afternoon bisecting a pipeline and spending ten minutes reading a panel. What should you log from a hybrid classical/deep CV pipeline beyond the loss curve? Start from the failure you are trying to diagnose, not from the metrics that are easy to compute. In a hybrid pipeline the recurring question is: when accuracy drops, which stage caused it? Answer that by instrumenting each stage so its contribution is separately visible. The three summary families each earn a distinct job: Scalars — per-stage numbers that should be stable run-to-run. Count of ROIs detected per frame, mean keypoint count from an ORB step, fraction of frames where the contour extractor returned nothing, descriptor dimensionality. These are cheap and you can log every step. A silent drift in “mean ROI count per image” is often the earliest signal that a preprocessing threshold moved. Images — the intermediate artifacts themselves. The ROI crops handed to the CNN, the edge or contour mask overlaid on the source frame, the warped patch after a homography. This is where you see a preprocessing bug rather than infer it from a number. Histograms — distributions that a scalar would hide. Pixel-intensity distribution of the crops feeding the model, per-channel statistics after normalization, the spread of descriptor magnitudes. A histogram catches a normalization regression (say, an uint8/float32 mixup that halves the input range) that leaves the mean unchanged. A useful discipline is to log one scalar and one image per classical stage on every validation pass, and reserve histograms for the inputs at the classical→deep boundary. That keeps event files small enough to stay usable while still covering the seam where hybrid pipelines break. When does each summary type earn its place? Summary type Log when Cost Primary failure it catches Scalar A stage produces a number that should be stable across runs Negligible; log every step Silent drift in a classical threshold or count Image You need to see an intermediate artifact to trust it Moderate; log a fixed sample every N steps Wrong crop, misaligned mask, bad warp Histogram A distribution shift would hide behind a stable mean Moderate; log at validation cadence Normalization/dtype regression, descriptor collapse Graph / text Documenting model structure or run config once One-off Architecture mismatch between prototype and prod The table is the rubric: pick the cheapest summary that would actually surface the failure you are worried about, and do not log a distribution when a count would do. How do you log intermediate images so you can inspect a preprocessing stage? The mechanics are simple; the discipline around them is what makes them useful. Both tf.summary.image and PyTorch’s writer.add_image / add_images expect a normalized tensor in a known layout (NHWC for TensorFlow, CHW per image for PyTorch), so the first thing to get right is the conversion from an OpenCV numpy array — which is HWC, BGR, and uint8 — into whatever the writer expects. A large fraction of “TensorBoard shows garbage” problems are just a BGR/RGB swap or a missing float32 scale, logged faithfully. Two habits make image logging diagnostic rather than decorative: Pin a fixed validation sample. Log the same handful of frames every validation pass, at the same tag, so the image panel becomes a time series you can scrub. If the ROI crop for frame 7 was correct at step 1,000 and wrong at step 5,000, that is immediately visible; a random sample hides it. Composite the classical artifact onto the source. Log the contour mask overlaid on the input image, not the raw mask alone. A bare mask tells you the extractor ran; the overlay tells you whether it ran on the right thing. The same applies to keypoints drawn on the frame after an ORB step, or bounding ROIs drawn before the crop. This is the same instrumentation posture that classical CV feature extraction on CPU benefits from: the classical stages are cheap to run but easy to mis-tune, and the only way to keep them honest is to make their output visible next to the deep stages that consume it. How does per-stage logging attribute a regression to a stage? This is where the reframing pays for itself. Consider a defect-inspection pipeline: an OpenCV preprocessing step segments candidate regions with edge and contour operations, crops them, and feeds the crops to a fine-tuned CNN classifier. Accuracy on the validation set drops from a stable baseline to something clearly worse after a code change. With only val/accuracy logged, you know that it regressed. You now bisect: revert the model change, revert the data change, revert the preprocessing change, re-run each. That is hours of compute and wall-clock time per iteration. With per-stage instrumentation, the diagnosis is a panel read. The scalar preproc/roi_count_per_image shows the mean crop count fell from roughly 4 to roughly 1 — an observed pattern in this class of pipeline, where a shifted Canny threshold suppresses weak edges. The image panel for the pinned validation frames confirms it: the contour masks now miss the low-contrast defects. The model never changed. The regression is attributed to the classical stage in minutes, not a day of bisection. Teams that instrument each stage rather than only the final model cut their mean-time-to-diagnose for accuracy regressions substantially (an observed-pattern from hybrid-pipeline engagements, not a benchmarked figure), because attribution replaces bisection. In hybrid systems this directly protects the 3–10× compute savings that come from doing cheap work in a classical stage instead of a heavier deep model — a mis-tuned preprocessing step that goes undiagnosed tends to get “fixed” by throwing a bigger model at the problem, which quietly erases the efficiency the classical stage was there to deliver. TensorBoard is one instrument in a wider practice. If you are tracking runs across many experiments and comparing hyperparameters over time, the discipline shades into full ML experiment tracking, which CV teams lean on for reproducibility; TensorBoard covers the within-run, per-stage diagnostic view rather than the cross-run ledger. What changes moving from a notebook prototype to production training code? Instrumentation that is convenient in a notebook becomes a liability in a deployable training job unless you tighten three things. Cadence and volume. Logging an image every step is fine for a 200-step notebook demo and catastrophic for a multi-day run — event files balloon and TensorBoard slows to a crawl. In production, gate image and histogram logging behind a step interval and a fixed sample, and keep only scalars at full cadence. Determinism of the logged sample. A notebook can log “the current batch.” Production code should log a pinned, seeded validation subset so the image time series is comparable across runs and across engineers. Separation from the training loop. Summary writes should not sit inside the hot path in a way that couples logging cadence to batch timing. Wrap them so a logging failure — a full disk, a permissions error on the log directory — degrades gracefully rather than killing an expensive run. These are the same portability concerns that surface when you ship classical and deep CV stages to production together: the code that was written to make development observable has to survive the move to a training environment it was not prototyped in. Getting the instrumentation right during development is part of what our computer vision practice validates before a pipeline architecture is signed off. FAQ How should you think about tensorboard logging in practice? TensorBoard reads event files written by a summary writer — tf.summary in TensorFlow or torch.utils.tensorboard.SummaryWriter in PyTorch — and renders them as scalars, images, histograms, and graphs. In practice it is an instrumentation layer, not just a plotting dashboard: any named tensor in your pipeline, including the output of a classical stage, can be logged and inspected. That reframing is what turns it from a loss-curve viewer into a diagnostic tool. What should you log from a hybrid classical/deep CV pipeline beyond the training loss curve? Log per-stage scalars (ROI counts, keypoint counts, empty-frame rates), intermediate images (ROI crops, edge and contour masks composited onto the source), and histograms at the classical→deep boundary (input pixel-intensity distributions, post-normalization statistics). The goal is to make each stage’s contribution separately visible so a regression can be attributed to a stage rather than to the pipeline as a whole. How do you log intermediate images so you can inspect a preprocessing stage in TensorBoard? Convert the OpenCV HWC/BGR/uint8 array to the layout the writer expects (NHWC for tf.summary.image, CHW for PyTorch’s add_image), fixing the common BGR/RGB and dtype-scale mistakes. Then pin a fixed validation sample and log it at the same tag every pass so the panel becomes a scrubbable time series, and composite classical artifacts — masks, keypoints, ROIs — onto the source frame rather than logging them bare. When do scalar, image, and histogram summaries each earn their place in a CV pipeline? Scalars for numbers that should stay stable across runs (log every step, negligible cost); images when you need to see an intermediate artifact to trust it (log a fixed sample every N steps); histograms when a distribution shift would hide behind a stable mean, such as a normalization or dtype regression. Pick the cheapest summary that would actually surface the failure you are worried about. How does TensorBoard help attribute an accuracy regression to a classical stage versus the deep model? With per-stage instrumentation, a regression becomes a panel read instead of a bisection. A scalar like mean ROI count per image dropping, plus pinned validation images showing masks that now miss low-contrast features, points at a shifted classical threshold while the model is unchanged — attributing the failure to the preprocessing stage in minutes rather than a day of reverting components one at a time. What changes when moving TensorBoard logging from a notebook prototype to deployable production training code? Tighten cadence and volume (gate image and histogram logging behind step intervals and fixed samples; keep only scalars at full cadence), make the logged sample deterministic and seeded so runs are comparable, and decouple summary writes from the training hot path so a logging failure degrades gracefully rather than killing an expensive run. The open question for any team adopting this is not how to call the summary API — that is a few lines — but which seam in your specific pipeline you cannot currently see. Name that seam, instrument the stage on either side of it, and you have turned TensorBoard from a plot you glance at into evidence you can act on.