Source code for ts3.models.base
"""What a TS3 extractor is: a checkpoint in, one embedding per unit out.
The regime is an argument, never a field. ``extract.py`` asks one extractor object for the
pretrain units and then the eval units, and the two halves of the file it writes are only
comparable because the same object answered both calls. Which checkpoint answers the eval
call is the entire inductive/transductive difference, and it is settled inside
:meth:`Extractor.encode`, not by the caller.
"""
from abc import ABC, abstractmethod
from pathlib import Path
import hydra
import numpy as np
import torch
from omegaconf import DictConfig
from core.dataset import BenchmarkRegime
from core.utils.logger import Logger
def load_pretrained(
ckpt_path: Path, device: torch.device, logger: Logger, **overrides
) -> tuple[torch.nn.Module, DictConfig]:
"""Rebuild a checkpoint's model from the config it was trained with.
``overrides`` replaces entries of that config when not None: a forward pass fits more
per batch than a backward one, and the machine encoding need not be the one that
trained. They land after the model is built, so they reach what the caller reads off
the returned config (``batch_size``, ``num_workers``) and never the model itself.
"""
ckpt = torch.load(ckpt_path, weights_only=False, map_location="cpu")
cfg = DictConfig(ckpt["cfg"])
logger.info(f"Checkpoint: {ckpt_path} (epoch {ckpt.get('epoch')})")
logger.info(f"Model: {cfg.model._target_}")
model = hydra.utils.instantiate(cfg.model)
model.load_state_dict(ckpt["model_state_dict"])
for key, value in overrides.items():
if value is not None:
logger.info(f"{key}: {value} (the run used {cfg[key]})")
cfg[key] = value
return model.to(device).eval(), cfg