Source code for peal.explainers.explainer_factory
"""Factory that resolves an explainer specification into an ``ExplainerInterface``.
Explainers produce the counterfactual (or other) explanations that PEAL's
teachers judge and its adaptors learn from. ``get_explainer`` maps the legacy
counterfactual ``explainer_type`` names (``SCE``, ``ACE``, ``TIME``,
``DAEdistill``) onto ``CounterfactualExplainer`` and otherwise looks the type up
among the ``ExplainerInterface`` subclasses found under ``peal/explainers``.
"""
import torch
import os
from typing import Union
from peal.explainers.counterfactual_explainer import CounterfactualExplainer
from peal.explainers.interfaces import (
ExplainerInterface,
)
from peal.registry import lookup
from peal.global_utils import (
load_yaml_config,
get_project_resource_dir,
)
[docs]
def get_explainer(
explainer: Union[ExplainerInterface, str, dict],
device: Union[str, torch.device] = "cuda",
predictor_datasets=None,
**kwargs,
) -> ExplainerInterface:
"""Return an explainer built from an instance, a yaml path or a config dict.
Parameters
----------
explainer : ExplainerInterface or str or dict
A ready explainer (returned unchanged), a yaml path or a dict-like
config. The config's ``explainer_type`` selects the class: the values
``SCE``, ``ACE``, ``TIME`` and ``DAEdistill`` all instantiate
``CounterfactualExplainer(explainer_config=..., **kwargs)``; any other
value must be the class name of an ``ExplainerInterface`` subclass
discovered under ``peal/explainers``, which is then called as
``cls(config=..., device=..., predictor_dataset=predictor_datasets,
**kwargs)``.
device : str or torch.device, optional
Device handed to non-counterfactual explainers. Default ``"cuda"``.
predictor_datasets : optional
Dataset(s) of the predictor, forwarded as ``predictor_dataset``.
**kwargs
Extra constructor arguments forwarded to the explainer class.
Returns
-------
ExplainerInterface
The resolved explainer.
Raises
------
peal.registry.UnknownComponentError
If the config's ``explainer_type`` matches neither the legacy names nor
a registered or discoverable subclass.
"""
if not isinstance(explainer, ExplainerInterface):
explainer_config = load_yaml_config(explainer)
explainer_type = getattr(explainer_config, "explainer_type", None)
if explainer_type in ["SCE", "ACE", "TIME", "DAEdistill"]:
explainer_out = CounterfactualExplainer(
explainer_config=explainer_config, **kwargs
)
else:
explainer_class = lookup(
"explainers",
explainer_type,
base_class=ExplainerInterface,
scan_dir=os.path.join(get_project_resource_dir(), "peal", "explainers"),
)
explainer_out = explainer_class(
config=explainer_config,
device=device,
predictor_dataset=predictor_datasets,
**kwargs,
)
else:
explainer_out = explainer
return explainer_out