diff --git a/alibi/explainers/anchors/anchor_text.py b/alibi/explainers/anchors/anchor_text.py index 9a6ac971e..335711cdb 100644 --- a/alibi/explainers/anchors/anchor_text.py +++ b/alibi/explainers/anchors/anchor_text.py @@ -186,8 +186,9 @@ def __init__(self, self.model: Union['spacy.language.Language', LanguageModel] #: Language model to be used. # validate kwargs - self.perturb_opts, all_opts = self._validate_kwargs(sampling_strategy=sampling_strategy, nlp=nlp, - language_model=language_model, **kwargs) + self.perturb_opts = self._validate_kwargs( + sampling_strategy=sampling_strategy, nlp=nlp, + language_model=language_model, **kwargs) # set perturbation self.perturbation: Any = \ @@ -195,13 +196,13 @@ def __init__(self, # update metadata self.meta['params'].update(seed=seed) - self.meta['params'].update(**all_opts) + self.meta['params'].update(**self.perturb_opts) def _validate_kwargs(self, sampling_strategy: str, nlp: Optional['spacy.language.Language'] = None, language_model: Optional['LanguageModel'] = None, - **kwargs: Any) -> Tuple[dict, dict]: + **kwargs: Any) -> dict: # set sampling method sampling_strategy = sampling_strategy.strip().lower() @@ -237,7 +238,6 @@ def _validate_kwargs(self, # get default args default_args: dict = self.DEFAULTS[self.sampling_strategy] perturb_opts: dict = deepcopy(default_args) # contains only the perturbation params - all_opts = deepcopy(default_args) # contains params + some potential incorrect params # compute common keys allowed_keys = set(perturb_opts.keys()) @@ -251,8 +251,7 @@ def _validate_kwargs(self, # update defaults args and all params perturb_opts.update({key: kwargs[key] for key in common_keys}) - all_opts.update(kwargs) - return perturb_opts, all_opts + return perturb_opts def sampler(self, anchor: Tuple[int, tuple], num_samples: int, compute_labels: bool = True) -> \ Union[List[Union[np.ndarray, np.ndarray, np.ndarray, np.ndarray, float, int]], List[np.ndarray]]: diff --git a/alibi/explainers/tests/test_anchor_text.py b/alibi/explainers/tests/test_anchor_text.py index 1630fd15e..d876b5927 100644 --- a/alibi/explainers/tests/test_anchor_text.py +++ b/alibi/explainers/tests/test_anchor_text.py @@ -154,6 +154,24 @@ def test_neighbors(nlp): assert np.isclose((np.sort(similarity_score)[::-1] - similarity_score).sum(), 0.) +def test_metadata_excludes_invalid_params(nlp): + """Regression test for #459: ``meta['params']`` should record only the + validated perturbation parameters, not misspelled/invalid kwargs.""" + def predictor(x): + return np.zeros((len(x), 2)) + + explainer = AnchorText( + predictor=predictor, + sampling_strategy=AnchorText.SAMPLING_UNKNOWN, + nlp=nlp, + sample_proba=0.6, # valid perturbation parameter + not_a_real_param=123, # invalid / misspelled kwarg + ) + params = explainer.meta['params'] + assert 'not_a_real_param' not in params + assert params['sample_proba'] == 0.6 + + @pytest.mark.parametrize('lang_model', ['DistilbertBaseUncased', 'BertBaseUncased', 'RobertaBase'], indirect=True) @pytest.mark.parametrize('text, min_num', [("This is ... a sentence, with a long ?!?, lot of punctuation; test this.", 5)])