load_models.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. """Discover saved ensemble checkpoints and record their paths in ``state``.
  2. Training deletes each model from VRAM after saving it, so evaluation cannot reuse
  3. in-memory models. This task scans ``<work_dir>/{normal,bayesian}_models/`` for
  4. ``model_N.pt`` files and stores ordered path lists; the evaluation tasks then load
  5. one model at a time. Weights are NOT loaded here (that would defeat the memory
  6. decoupling) -- only discovered and ordered.
  7. """
  8. import pathlib as pl
  9. import re
  10. from typing import Any, Dict, List
  11. from model.factory import KIND_BAYESIAN, KIND_NORMAL
  12. from util.progress import ProgressTracker
  13. from util.ui_logger import PipelineLogger
  14. # Subdirectory (under work_dir) and state key for each model kind.
  15. _MODEL_SOURCES = {
  16. KIND_NORMAL: ("normal_models", "normal_model_paths"),
  17. KIND_BAYESIAN: ("bayesian_models", "bayesian_model_paths"),
  18. }
  19. _MODEL_FILE_RE = re.compile(r"^model_(\d+)\.pt$")
  20. def _discover_models(models_dir: pl.Path) -> List[pl.Path]:
  21. """Return ``model_N.pt`` files in ``models_dir`` sorted by N (natural order).
  22. Only the directory's top level is scanned, so intermediate checkpoints under
  23. ``intermediate_models/`` are ignored.
  24. """
  25. if not models_dir.is_dir():
  26. return []
  27. numbered: List[tuple[int, pl.Path]] = []
  28. for entry in models_dir.iterdir():
  29. if not entry.is_file():
  30. continue
  31. match = _MODEL_FILE_RE.match(entry.name)
  32. if match:
  33. numbered.append((int(match.group(1)), entry))
  34. numbered.sort(key=lambda pair: pair[0])
  35. return [path for _, path in numbered]
  36. def load_models_task(
  37. track: ProgressTracker,
  38. log: PipelineLogger,
  39. config: Dict[str, Any],
  40. state: Dict[str, Any],
  41. ) -> None:
  42. work_dir = pl.Path(config["work_dir"])
  43. track.update(total=len(_MODEL_SOURCES), advance=0)
  44. total_found = 0
  45. for kind, (subdir, state_key) in _MODEL_SOURCES.items():
  46. paths = _discover_models(work_dir / subdir)
  47. state[state_key] = paths
  48. total_found += len(paths)
  49. if paths:
  50. log.info(f"Found {len(paths)} {kind} model(s) in {subdir}/.")
  51. else:
  52. log.info(f"No {kind} models found in {subdir}/ (evaluation will skip).")
  53. track.update(advance=1)
  54. if total_found == 0:
  55. log.error(
  56. "No saved models were discovered. Train first, or point the working "
  57. "directory at an experiment that contains trained models."
  58. )