nvalchemi.training.ValidationConfig#

pydantic model nvalchemi.training.ValidationConfig[source]#

Configuration for strategy-owned validation passes.

ValidationConfig is a plain, declarative data object that tells a TrainingStrategy what validation data to evaluate, how often to evaluate it, and how to run the forward pass. You pass an instance to the strategy’s validation_config argument; leaving that argument None disables validation entirely. The strategy then drives validation itself — reading this config directly and running passes through ValidationLoop at TrainingStrategy.validate() — rather than dispatching validation through the hook system. To react to validation results, register a hook on the AFTER_VALIDATION stage and read the summary from ctx.validation.

validation_data must be a re-iterable container (list, DataLoader, Dataset, …); a fresh iterator is drawn for every pass, so one-shot generators and bare iterators are rejected at construction time (see _ensure_reiterable_validation_data). The scheduling fields every_n_epochs and every_n_steps are mutually exclusive: set at most one to control cadence, or leave both unset to run validation only at the end of TrainingStrategy.run(). When validation_fn or loss_fn is None, the strategy reuses its own training_fn / loss_fn with the matching single-model or named-model call convention; a leaf loss passed here is normalized to a ComposedLossFunction.

The remaining fields tune inference behavior: grad_mode selects the autograd policy ("auto" enables gradients only when a loss component reports requires_eval_grad=True), set_eval toggles eval mode with restore, use_ema decides whether the strategy’s inference_model (EMA) weights replace live weights, use_mixed_precision reuses a registered MixedPrecisionHook autocast context, and batch_callback streams per-batch predictions and losses to a custom sink.

Examples

Validate on a held-out list of batches after every epoch, reusing the strategy’s own training_fn and loss_fn:

>>> from nvalchemi.training import ValidationConfig
>>> config = ValidationConfig(
...     validation_data=val_batches,
...     every_n_epochs=1,
... )

Validate every 500 optimizer steps with an explicit validation loss and gradients enabled (e.g. force/stress evaluation that needs autograd):

>>> config = ValidationConfig(
...     validation_data=val_loader,
...     loss_fn=EnergyMSELoss() + ForceMSELoss(normalize_by_atom_count=True),
...     every_n_steps=500,
...     grad_mode="enabled",
... )

Evaluate EMA weights instead of the live model, then wire the config into a strategy:

>>> config = ValidationConfig(
...     validation_data=[val_batch],
...     loss_fn=EnergyMSELoss(),
...     use_ema="always",
...     grad_mode="enabled",
... )
>>> strategy = TrainingStrategy(
...     models=model,
...     optimizer_configs=optimizer_config,
...     loss_fn=EnergyMSELoss(),
...     num_steps=1000,
...     training_fn=default_training_fn,
...     validation_config=config,
...     hooks=[EMAHook(model_key="main", decay=0.999)],
... )

Notes

  • every_n_epochs and every_n_steps are mutually exclusive; setting both raises at construction time. Both may be omitted, in which case validation runs once at the end of training.

  • validation_data must be re-iterable: generators/iterators are rejected because each pass restarts from the beginning.

  • ValidationConfig does not participate in hook dispatch. It is read directly by the strategy; use an AFTER_VALIDATION hook (reading ctx.validation) for summary-level logging.

field validation_data: Iterable[Batch] [Required]#

Re-iterable container (e.g. list, DataLoader, Dataset) yielding Batch instances. The strategy re-iterates this on every validation pass; one-shot generators and bare iterators are rejected at construction time.

Constraints:
  • func = <function _ensure_reiterable_validation_data at 0xeb0b2465e480>

  • json_schema_input_type = typing.Any

field validation_fn: Callable[[...], Any] | None = None#

Validation forward callable. None means use the strategy’s training_fn with the same single-model or named-model call convention.

field loss_fn: ComposedLossFunction | None = None#

Validation loss function. None means use the strategy’s loss_fn. Leaf losses are auto-normalized to a ComposedLossFunction via as_composed_loss().

field every_n_epochs: int | None = None#

Run validation after every n-th completed epoch. Mutually exclusive with every_n_steps.

Constraints:
  • ge = 1

field every_n_steps: int | None = None#

Run validation after every n-th completed optimizer step. Mutually exclusive with every_n_epochs.

Constraints:
  • ge = 1

field grad_mode: Literal['auto', 'enabled', 'disabled'] = 'auto'#

Autograd policy during validation. "auto" enables gradients when any loss component has requires_eval_grad=True and disables them when all components report False.

field set_eval: bool = True#

If True, set validation modules to eval mode and restore their original training modes afterward.

field use_ema: Literal['auto', 'always', 'never'] = 'auto'#

Whether the strategy’s inference_model slot (populated by EMA) should replace live training weights for validation.

field use_mixed_precision: Literal['auto', 'always', 'never'] = 'auto'#

Whether to reuse a registered MixedPrecisionHook autocast context for validation inference.

field batch_callback: BatchValidationCallback | None = None#

Optional user-supplied callable invoked once per validation batch with the batch, predictions, and per-batch loss output. Use it to stream per-sample diagnostics to a custom logging or storage backend. None disables per-batch callbacks. For epoch-level (summary) logging, register a hook on the AFTER_VALIDATION stage and read ctx.validation instead.

field name: str = 'validation'#

Name stored in the validation summary dictionary.

Constraints:
  • min_length = 1