DynVision Logging Modernization Notes¶
This living document tracks the ongoing effort to centralize and structure logging across DynVision. Update it as changes land.
Task Statement¶
- Reduce redundant or overly chatty logging between params modules and runtime scripts.
- Provide consistent, structured summaries owned by Pydantic parameter classes.
- Establish reusable logging utilities and document the patterns for future development.
Current Strategy¶
- Map existing logging surfaces — audit params, runtime scripts, workflow rules, and model utilities to understand current verbosity and duplication.
- Centralize configuration — rely on
dynvision.utils.configure_logginginBaseParamsso every entrypoint respects CLIlog_level, standard formatters, and optional log files. - Structured summaries — let each params class define
summary_sections(withSummaryItem) and surface them throughBaseParams.log_summary/CompositeParams.log_overview. - Runtime integration — refactor scripts (init/train/test) to call the param summaries instead of reformatting dictionaries; use
log_sectionfor any runtime-only context. - Helper ecosystem — expand
logging_utilswith formatters that keep info concise (tables, diffs); encourage DEBUG for large payloads. - Documentation pass — once behavior stabilizes, fold this plan into the official dev guides alongside examples of expected log output.
Provenance Tagging Plan¶
Goal: replace the generic (override) / (adjusted) markers with explicit provenance metadata that explains which precedence layer produced the value and whether it was later mutated.
Dimensions to Track¶
-
Precedence Source – which tier in the resolution stack provided the value last:
default– implicit value (none provided by config/CLI/override). Note: Pydantic models often rely on upstream defaults (config files) rather than defining Python defaults directly; if a field remains unset, downstream consumers (model/dataloader classes) may fall back to their own defaults.config:<path>– loaded from a config file;<path>can encode mode sections (e.g.,config:init.model).cli– provided via CLI/Snakemake arguments after alias resolution.override– supplied throughoverride_kwargs/ programmatic injection (highest static priority).
-
Mutation Type – whether the value was changed after instantiation:
runtime– adjusted viaupdate_field(dataset inference, validation correction).derived– computed from other fields during validators (e.g., implicit defaults that are functions of other params).
We record both dimensions so a log entry can say (config:init.model; runtime) if a config value was later tweaked by inference.
Implementation Sketch¶
-
Source tracking:
- While merging parameters in
BaseParams.get_params_from_cli_and_config, maintain_value_provenance: Dict[str, Provenance]whereProvenancecapturessourceand optionalscope(config section or alias). - When
update_fieldmutates a value, append the mutation marker (runtime). Validators that compute fields can flagderived. - For composites, flatten keys (
model.n_classes) and merge child provenance maps when constructing the parent.
- While merging parameters in
-
Log rendering:
- Extend
SummaryItem/build_sectionto accept aprovenance_formattercallback that turns the provenance record into a compact suffix string. - Format as
(source[; scope][; mutation]), omitting segments that are redundant. Examples:(default),(config:init.model),(cli; runtime).
- Extend
-
Legend (for docs/log appendix):
default– Field used its class default.config:<section>– Value came from configuration files;<section>points to the nested key (e.g.,train.trainer).cli– Provided on the command line or via Snakemake wildcards.override– Injected programmatically (e.g., fromoverride_kwargs).runtime– Modified after instantiation (dataset inference, validators callingupdate_field).derived– Computed during validation rather than specified directly.
Multiple tags combine with
;. If a config section ultimately came from CLI (e.g., Snakemake templating), we show the highest-precedence layer actually applied (cli). -
Presentation tweaks:
- Skip entries when
include_defaults=Falseand provenance isdefaultwith no mutations. Clarify in docs thatdefaulthere means “no explicit value supplied” (the instantiated class may still apply its own internal default at construction time). - Always show mutation tags (
runtime,derived) even if the final value equals the original to make adjustments visible. - Surface the legend in developer docs and optionally provide a
--show-provenance-legendflag or DEBUG-level print during CLI runs for onboarding.
- Skip entries when
Progress Log¶
- [Done] Created
dynvision/utils/logging_utils.pywithconfigure_logging,log_section,format_value,SummaryItem, andbuild_sectionhelpers. - [Done] Updated
BaseParamsto track dynamic overrides, exposesummary_sections, and providelog_summary. - [Done] Extended
CompositeParams.log_overviewto cascade component summaries. - [Done] Added structured summaries to
DataParams,TestingParams, andModelParamsviasummary_sections. - [Done] Refactored
runtime/init_model.pyto use the new logging helpers and delegate configuration summaries toInitParams. - [Done] Introduced provenance tracking across
BaseParams/CompositeParams, so summaries label values with their source (config,cli,override,runtime) instead of the generic(override)/(adjusted)markers. - [Done] Applied the same integration to
runtime/train_model.pyandruntime/test_model.py, delegating their run summaries toTrainingParams.log_training_overviewandTestingParams.log_testing_overview. - [Done] Wired dataset creation logging through
DataParams.log_dataset_creationso init/train/test emit(default)markers sourced fromget_datasetsignatures. - [Done] Swept remaining params classes (trainer/optimizer controls) so summaries now cover gradient clipping, validation limits, strategy kwargs, and early stopping provenance.
- [Done] Extracted dataset/dataloader wiring into
dynvision/data/datamodule.py, giving training (DataModule), initialization (SimpleDataModule), and testing (TestingDataModule) a sharedDataInterfaceand the same logging diff helpers. - [Done] Migrated
runtime/test_model.pyontoTestingDataModule, so sampler instantiation, preview logging, and dataloader provenance flow throughDataParamsinstead of bespoke helpers. - [Done] Demoted preview-phase dataset/dataloader logs in
DataInterfaceto DEBUG while keeping diff tracking for active contexts, reducing INFO noise during init/train/test. - [Done] Auto-null
prefetch_factorwhennum_workers=0, including values injected throughdataloader_kwargs, so Lightning no longer emits multiprocessing warnings for intentional single-thread loaders. - [Done] Updated
_build_callable_entriesso dataset/dataloader logs only emit default markers the first time—subsequent stages now show deltas/new/removed entries instead of restating unchanged defaults. - [Done] Gated preview batch summaries in
runtime/train_model.pyandruntime/test_model.pyso they stay at DEBUG by default but automatically elevate to INFO whenverboseis set, giving opt-in noise when diagnosing data issues. - [Done] Replaced the ad-hoc resume banners in
runtime/train_model.pywith a structuredcheckpoint_selectionsection that documents whether the run is resuming from a Lightning checkpoint or initializing from the saved state dict (including the effective weight source). - [Done] Upgraded
TrainingParams._validate_required_pathsto emit atraining_dataset_pathsDEBUG section instead of a rawprint, recording which dataset link/FFCV trio was validated without polluting stdout. - [Planned] Document the logging pattern in
docs/development/guidesonce the refactor settles.
Latest Observations (Train Run 2025-11-13)¶
- Provenance labels now render as
(config:data)/(cli:model)etc.; INFO stream is readable but still lengthy. Evaluate collapsing repeated path/value rows that appear in both the params overview and subsequentcreating_*sections. - Preview logs default to DEBUG but flip to INFO automatically when
verboseis requested, so operators can surface the preview diffs without changing code; consider whether a dedicated CLI switch is still needed. creating_standarddataloadernow only prints actual diffs, but we still duplicate a few context headers; consider collapsing nested sections or adding a compact summary banner atop each run.- Lightning still emits the
prefetch_factorwarning whennum_workers=0; decide whether to auto-null that field or downgrade the warning to DEBUG when the configuration intentionally forces single-thread loading. torch.load(... weights_only=False)future warning surfaces during state dict loads; track follow-up to adopt the safer default once PyTorch updates land.- Coordination dtype warning (
list index out of range) remains; log is informative but might warrant a one-time INFO followed by DEBUG repeats if it persists each run. - The new
checkpoint_selectionsection keeps resume/fresh metadata in a single place, but we still need before/after samples to ensure downstream tools parse it correctly. training_dataset_pathsnow captures the validated dataset link/train/val trio at DEBUG level; validate that this provides enough breadcrumbing when path resolution fails outside of verbose mode.ModelParams.log_model_creationandModelParams.log_configurationcurrently emit overlapping summaries; consolidate them so a single helper owns the structured model overview (ideally reusinglog_section).
Open Questions / Follow-Ups¶
- Should
configure_loggingsupport structured JSON outputs for cluster monitoring, or stick with plain text for now? - How to best expose debug-level deep dives (full config dumps) without cluttering INFO logs—dedicated CLI flag?
- Need to confirm Snakemake entrypoints call
setup_loggingexactly once to avoid handler duplication.
Next Actions¶
- Extend provenance tagging through derived/preprocessor-driven adjustments (mark as
derived) and ensure runtime scripts surface the legend when verbose output is requested. - Consolidate
ModelParams.log_model_creation/log_configurationinto a single helper that emits sectioned tables vialog_section, then update runtime entrypoints to call only that surface. Capture before/after log snippets to validate INFO-volume improvements. - Audit remaining ad-hoc logging statements across runtime/scripts; for each, decide whether to remove, demote to DEBUG, or migrate into the owning Params helper so the structure stays consistent with the formalized logging style.
- Restructure
creating_dataset/creating_standarddataloaderoutputs to highlight deltas instead of repeating full config dumps; keep preview dataset logs at DEBUG unlessverboseis set. - ✅ (2025-11-17) Guard dataloader kwargs so
prefetch_factordisappears whenevernum_workers=0, with an INFO log explaining the adjustment. - Provide guidance for adopting
torch.load(..., weights_only=True)once dependent codepaths are ready; track in follow-up issue. - Verify CLI/Snakemake workflows respect log levels after noise demotion; capture before/after log excerpts for documentation and the forthcoming developer guide update.
- Update
docs/development/guides/claude-guide.md(or a newdata-processing.mdcompanion) with the new DataModule responsibilities so DynVision-specific logging expectations stay in the toolbox docs while the generic AI style guide remains framework-agnostic. -
Explore beautifying high-level summaries (tables, headers, minimal visual markers) to improve scanability while staying within plain-text logging constraints.
- Prototype a
log_section_tablehelper (inspired by the weight-check tables insidedynvision/base/monitoring.py) that auto-aligns columns and keeps headers to 1–2 lines while still emitting plain text. - Apply the helper to the heaviest INFO blocks first (
training_run,creating_trainer,checkpoint_selection) so operators can skim the columns, keeping richer provenance data in the suffix markers. - Gate the textual table rendering behind INFO, but emit a one-line summary and keep the detailed tables at DEBUG when
verboseis off; document the convention alongside examples so Snakemake logs remain predictable.
- Prototype a
-
Add regression notes/tests (even simple scripts) to ensure
SimpleDataModule/TestingDataModulecontinue logging provenance correctly when new params are introduced and that the preview→active diff remains obvious despite the DEBUG demotion. - Review
dynvision/base/monitoring.pyand port the existing banners/memory diagnostics ontolog_sectionhelpers (e.g.,training_start,system_resources) so model-internal instrumentation matches the Params-driven style.
Monitoring Alignment Gameplan¶
- Snapshot current behavior — grab a short training log to capture the existing
_log_system_info,_log_memory_usage, and batch preview outputs so we can verify the new structure preserves content. - Refactor batching hooks — have
_log_system_info,_log_memory_usage,_validate_batch_data(first batch), and_log_training_summaryemitlog_sectionblocks with the same keys the params summaries use (model_name,n_classes, memory stats, batch shapes). - Keep warnings loud — retain emoji/⚠️ warnings for NaNs, invalid labels, and high loss, but make the “happy path” info flow through
log_sectionso INFO streams stay tabular. - Rollout plan — update MonitoringMixin first, then rerun
runtime/train_model.pyon a dry run to capture before/after logs and link them back here before touching downstream docs.