| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- """Construction and loading of ensemble models for evaluation.
- Training saves each member's ``state_dict`` to ``model_N.pt``. Evaluation must
- rebuild an identically-structured module before ``load_state_dict``. For Bayesian
- members this means applying the DNN->BNN conversion (with the same prior params
- used at training time) *before* loading weights, otherwise the parameter names
- won't match.
- """
- import pathlib as pl
- from typing import Any, Dict
- import torch
- from torch import nn
- from model.cnn import CNN3D
- from model.dnn_mod import DEFAULT_BNN_PRIOR_PARAMETERS, dnn_to_bnn_mod
- # Model-kind strings (mirror evaluation.schema.MODEL_KIND_*). Kept here too so
- # model/ has no dependency on the evaluation package.
- KIND_NORMAL = "normal"
- KIND_BAYESIAN = "bayesian"
- def build_model(config: Dict[str, Any], kind: str) -> CNN3D:
- """Build an (untrained) CNN3D of the requested kind on CPU.
- For ``kind == "bayesian"`` the conv/linear layers are converted to their
- Bayesian counterparts using :data:`DEFAULT_BNN_PRIOR_PARAMETERS`.
- """
- data_cfg = config["data"]
- train_cfg = config["training"]
- model = CNN3D(
- image_channels=data_cfg["image_channels"],
- clin_data_channels=data_cfg["clin_data_channels"],
- num_classes=data_cfg["num_classes"],
- droprate=train_cfg["droprate"],
- ).float()
- if kind == KIND_BAYESIAN:
- dnn_to_bnn_mod(model, DEFAULT_BNN_PRIOR_PARAMETERS)
- elif kind != KIND_NORMAL:
- raise ValueError(f"Unknown model kind {kind!r}; expected 'normal'/'bayesian'.")
- return model
- def load_model(
- path: pl.Path,
- kind: str,
- config: Dict[str, Any],
- device: str,
- ) -> nn.Module:
- """Rebuild a model of ``kind`` and load ``path``'s weights onto ``device``.
- The returned model is in ``eval()`` mode. Bayesian models remain stochastic
- in eval mode (their reparameterization layers sample every forward pass),
- which is exactly what Monte-Carlo evaluation relies on.
- """
- model = build_model(config, kind)
- state_dict = torch.load(path, map_location="cpu")
- model.load_state_dict(state_dict)
- model.to(device)
- model.eval()
- return model
|