Observability
DeepTab can record what happens during training without you writing a single callback. You attach an ObservabilityConfig to an estimator, and every fit() captures its hyperparameters, lifecycle events, and final metrics in one self-contained run directory. Optional experiment trackers (TensorBoard, MLflow) and structured logging build on the same configuration.
Note
Observability is entirely opt-in. Estimators created without an ObservabilityConfig train exactly as before and emit nothing, so notebooks stay quiet by default.
Attaching observability
There are two equivalent ways to enable it. Pass the config at construction time:
from deeptab.core.observability import ObservabilityConfig
from deeptab.models import MambularClassifier
obs = ObservabilityConfig(
experiment_name="churn_baseline",
structured_logging=True, # human-readable console + JSON event log
experiment_trackers=["mlflow"], # also supports "tensorboard"
)
model = MambularClassifier(observability_config=obs)
model.fit(X_train, y_train, max_epochs=50)
Or attach it to an already-constructed estimator. Changes take effect on the next fit() call:
model = MambularClassifier()
model.configure_observability(obs)
model.fit(X_train, y_train, max_epochs=50)
Important
Structured logging relies on structlog, which is an optional dependency. Install it with pip install 'deeptab[logs]'. The experiment trackers need their own packages too: tensorboard for TensorBoard and mlflow for MLflow.
The run directory
Every output path is derived from root_dir, producing a single organised tree per run:
deeptab_runs/
runs/churn_baseline/20260611_174830_8f3a2c/
config.yaml # estimator hyperparameters
lifecycle.jsonl # structured event log (when log_to_file=True)
summary.json # final metrics
checkpoints/best.ckpt
tensorboard/churn_baseline/20260611_174830_8f3a2c/
events.out.tfevents...
mlflow/
backend/mlflow.db
artifacts/
The run identifier combines a timestamp and a short hash, so concurrent or repeated runs never overwrite each other.
Configuration reference
ObservabilityConfig is a dataclass. All fields are optional and resolve sensible defaults relative to root_dir.
Field |
Default |
Purpose |
|---|---|---|
|
|
Base directory for all observability outputs. |
|
|
Logical label used to group related runs. |
|
|
Enable structured runtime logging via |
|
|
Stream compact human-readable output to stdout. |
|
|
Write a per-run |
|
|
Which lifecycle events are emitted when |
|
|
Lightning loggers to activate: |
|
|
Resolved to |
|
|
Sub-directory label inside the TensorBoard save dir. |
|
|
Name of the MLflow experiment. |
|
|
Resolved to a local SQLite store under |
|
|
Resolved to |
|
|
Human-readable label for the MLflow run. |
|
|
Upload model checkpoints as MLflow artifacts. |
|
|
A user-provided Lightning logger appended alongside any built-in trackers. |
Note
experiment_trackers is a list, not a single string. Pass ["tensorboard"], ["mlflow"], or ["mlflow", "tensorboard"] to activate one or both.
Verbosity levels
When structured_logging=True, verbosity controls how much is emitted. Higher levels are supersets of lower ones.
Level |
Emits |
|---|---|
|
Silent. |
|
Milestones: |
|
Level 1 plus |
|
Debug: all events. |
The default of 1 keeps console output to a few meaningful milestones.
Lifecycle events
Events are dot-namespaced and carry structured metadata, which makes them easy to filter, parse, and compare across runs. For example, fit.started records sample counts, model.created records the parameter count, and train.completed records the best validation loss.
Tip
For experiment sweeps, set log_to_file=True and read each run’s lifecycle.jsonl. Because every record is a JSON object tagged with the same run_id, you can load many runs into a DataFrame and compare them programmatically.
Bring your own framework
If you already have a logging and experiment-tracking stack (your own callbacks, a managed tracking service, or an in-house framework), you do not need DeepTab observability at all. Construct estimators without an ObservabilityConfig and they stay silent, leaving your existing setup in full control.
# No ObservabilityConfig: DeepTab emits nothing and your own stack runs as-is.
model = MambularClassifier()
model.fit(X_train, y_train, max_epochs=50)
When you do want DeepTab to coexist with an existing setup, you have two integration points.
Plug in your own Lightning logger. DeepTab trains through PyTorch Lightning, so any Lightning logger works. Pass it via the logger field and DeepTab appends it alongside any built-in trackers rather than replacing them:
from lightning.pytorch.loggers import WandbLogger
from deeptab.core.observability import ObservabilityConfig
obs = ObservabilityConfig(
logger=WandbLogger(project="churn"), # your existing tracker
experiment_trackers=["tensorboard"], # optional: keep DeepTab trackers too
)
model = MambularClassifier(observability_config=obs)
model.fit(X_train, y_train, max_epochs=50)
Note
The logger field accepts a single Lightning logger instance. To attach several at once, wire them through the trackers you control or compose them in your own framework, then hand DeepTab the one entry point.
Consume the lifecycle events yourself. With structured_logging=True, events are emitted through structlog. You can route them into your own sinks by configuring structlog processors at the application level, or by reading each run’s lifecycle.jsonl and forwarding the records to your tracking system. This keeps DeepTab’s run metadata available without committing to its built-in trackers.
Tip
A common pattern is to let your framework own the experiment dashboard while DeepTab owns the per-run artifact directory. Point root_dir at a path your pipeline already archives, and the config.yaml plus summary.json become a portable record your tooling can ingest.
Next Steps
Training and Evaluation: the fit pipeline, configs, and callbacks that observability wraps around
Model Operations: saving, loading, and inspecting fitted estimators
Config System: how
ObservabilityConfigfits alongside the model, preprocessing, and trainer configs