Source code for pimm.engines.hooks.eval.final_tester

"""Final evaluation hook."""

import os

import torch

from pimm.engines.hooks.builder import HOOKS
from pimm.utils.checkpoints import checkpoint_model_state_dict
from pimm.engines.hooks.default import HookBase
from pimm.observability import structured_logger as sl


[docs] @HOOKS.register_module() class FinalEvaluator(HookBase): """Run the configured tester once after training, usually on model_best. On ``after_train`` (and only when ``cfg.evaluate`` is true), builds the tester named by ``cfg.test.type`` from the ``TESTERS`` registry and runs its full ``test()`` pass. By default it loads ``model_best.pth`` (the best checkpoint selected during training) into the tester before testing; set ``test_last=True`` to instead test the in-memory ``model_last`` weights. This hook computes no metric of its own and does not set the checkpoint-selection ``comm_info`` keys — it delegates all metric computation to the tester. Registered as ``FinalEvaluator`` (use as ``type`` in a ``hooks=[...]`` entry). Args: test_last (bool): Test the current ``model_last`` weights instead of loading ``model_best.pth``. Defaults to ``False``. Note: Runs exactly once, after training exits. When ``test_last`` is ``False`` the best checkpoint is loaded with ``strict=True``, so the tester model architecture must match the saved state dict. Example: Add to ``cfg.hooks``; once in ``after_train`` it runs the configured tester on the best checkpoint: .. code-block:: python hooks = [dict(type="FinalEvaluator", test_last=False)] # → after training, builds cfg.test.type from the TESTERS registry, # loads <save_path>/model/model_best.pth (strict=True) into it, and # runs tester.test(); computes no metric of its own """ def __init__(self, test_last=False): """Select whether final evaluation uses model_last instead of model_best.""" self.test_last = test_last
[docs] @sl.log_trace_span("evaluation.final") def after_train(self): """Build the tester and execute final evaluation after training exits.""" if not self.trainer.cfg.get("evaluate", True): self.trainer.logger.info("Skipping final evaluation (evaluate=False)") return sl.add_step_tag("evaluation") # Import lazily to avoid pimm.engines.test importing hooks while hooks # are still being registered. from pimm.engines.test import TESTERS self.trainer.logger.info( ">>>>>>>>>>>>>>>> Start Final Evaluation >>>>>>>>>>>>>>>>" ) torch.cuda.empty_cache() cfg = self.trainer.cfg tester = TESTERS.build( dict(type=cfg.test.type, cfg=cfg, model=self.trainer.model) ) if self.test_last: self.trainer.logger.info("=> Testing on model_last ...") else: self.trainer.logger.info("=> Testing on model_best ...") best_path = os.path.join( self.trainer.cfg.save_path, "model", "model_best.pth" ) checkpoint = torch.load(best_path) state_dict = checkpoint_model_state_dict(checkpoint) tester.model.load_state_dict(state_dict, strict=True) tester.test()