Source code for peal.entrypoints.train_distilled_predictor
"""Distil a trained predictor into a smoother surrogate for counterfactuals.
Drives ``distill_predictor`` in ``peal/training/trainers.py``: the predictor
of ``--config_predictor`` is loaded together with its training and
validation dataloaders, and a second network described by
``--config_distilled_predictor`` is fitted to mimic it with
``leakysoftplus`` activations in place of ReLU, so that gradients through it
are informative. The explainers perform the same step on the fly (the
``distilled_predictor`` field of the explainer config); this script runs it
in isolation.
Invocation::
python train_distilled_predictor.py --config_predictor <predictor.yaml> \\
--config_distilled_predictor <distilled_predictor.yaml>
Both arguments are required, so the ``sys.argv[-1]`` fallback and the
commented-out ``ModelTrainer`` block are dead code. A ``<PEAL_BASE>`` prefix
in the distilled config's ``model_path`` is resolved to the project
directory; the distilled model (``model.cpl`` and ``config.yaml``) is written
there.
"""
import argparse
import sys
import os
from peal.global_utils import (
load_yaml_config,
set_random_seed,
get_project_resource_dir,
)
from peal.training.interfaces import PredictorConfig
from peal.training.trainers import get_predictor, distill_predictor
from peal.data.dataloaders import create_dataloaders_from_datasource
import torch
[docs]
def main():
"""Load both predictor configs and distil the first into the second.
Returns
-------
None
"""
parser = argparse.ArgumentParser()
parser.add_argument(
"--config_predictor",
type=str,
required=True,
help="Path to the YAML configuration file for the main predictor.",
)
parser.add_argument(
"--config_distilled_predictor",
type=str,
required=True,
help="Path to the YAML configuration file for the distilled predictor.",
)
# Add arguments from PredictorConfig class (if applicable)
# add_class_arguments(parser, PredictorConfig)
args = parser.parse_args()
if hasattr(args, "config_predictor") and hasattr(
args, "config_distilled_predictor"
):
config_predictor = args.config_predictor
distilled_predictor_config = args.config_distilled_predictor
else:
config = sys.argv[-1]
config_predictor = load_yaml_config(config_predictor, PredictorConfig)
distilled_predictor_config = load_yaml_config(
distilled_predictor_config, PredictorConfig
)
# integrate_arguments(args, config, exclude=["config"])
set_random_seed(config_predictor.seed)
predictor = get_predictor(config_predictor)
training_dataset, val_dataset, test_dataset = create_dataloaders_from_datasource(
config=config_predictor, datasource=None
)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
predictor.to(device)
base_path = distilled_predictor_config.model_path
split_path = base_path.split("/")
if split_path[0] == "<PEAL_BASE>":
base_path = os.path.join(get_project_resource_dir(), *split_path[1:])
gradient_predictor = distill_predictor(
distilled_predictor_config,
base_path,
predictor,
[training_dataset, val_dataset],
replace_with_activation="leakysoftplus",
)
# model_trainer = ModelTrainer(config)
# model_trainer.fit(
# continue_training=distilled_predictor_config.continue_training,
# is_initialized=distilled_predictor_config.is_loaded,
# )
if __name__ == "__main__":
main()