def __init__(
        self,
        generative_model: nn.Module,
        tokenizer: PreTrainedTokenizer,
        embedding_reduction_model: Optional = None,
        clustering_models: Optional[List] = None,
        scoring_fn: Optional[
            Callable[[torch.Tensor, torch.Tensor, int], torch.Tensor]
        ] = None,
        seed: int = 0,
    ):
        """
        A hallucination multicalibrator class.
        Given some context (e.g. a question), some text (e.g. one or multiple answers) and some scoring function,
        it multicalibrates the probability that the text is a hallucination or not based on a supervised calibration
        dataset.
        Under the hood, the method constructs model-based low-dimensional embeddings of the initial contexts plus texts,
        it clusters them to provide meaningful (possibly overlapping) groups,
        it computes the scores for each text,
        and it finally calibrates the scores on each subset formed by the intersection of each group and each level set
        of the score function.

        Parameters
        ----------
        generative_model: nn.Module
            A generative model.
        tokenizer: PreTrainedTokenizer
            A tokenizer.
        embedding_reduction_model: Optional
            An embedding reduction model.
        clustering_models: Optional[List]
            A list of clustering models.
        scoring_fn: Optional[Callable[[torch.Tensor, torch.Tensor, int], torch.Tensor]]
            A scoring function.
        """
        self.generative_model = generative_model
        self.tokenizer = tokenizer
        if self.tokenizer.pad_token is None:
            self.tokenizer.pad_token = self.tokenizer.eos_token
            logging.info("`tokenizer.pad_token` is None. Set to `tokenizer.eos_token`.")
        self.embedding_reduction_model = embedding_reduction_model or umap.UMAP(
            n_neighbors=100, n_components=100
        )
        self.scoring_fn = scoring_fn or inv_perplexity
        self.clustering_models = clustering_models or [
            GaussianMixture(n_components=i) for i in range(2, 21)
        ]
        self.grouping_model = None
        self.multicalibrator = None
        self._quantiles = None
        self.rng = np.random.default_rng(seed)

        A hallucination multicalibrator class.
        Given some context (e.g. a question), some text (e.g. one or multiple answers) and some scoring function,
        it multicalibrates the probability that the text is a hallucination or not based on a supervised calibration
        dataset.
        Under the hood, the method constructs model-based low-dimensional embeddings of the initial contexts plus texts,
        it clusters them to provide meaningful (possibly overlapping) groups,
        it computes the scores for each text,
        and it finally calibrates the scores on each subset formed by the intersection of each group and each level set
        of the score function.

        Parameters
        ----------
        generative_model: nn.Module
            A generative model.
        tokenizer: PreTrainedTokenizer
            A tokenizer.
        embedding_reduction_model: Optional
            An embedding reduction model.
        clustering_models: Optional[List]
            A list of clustering models.
        scoring_fn: Optional[Callable[[torch.Tensor, torch.Tensor, int], torch.Tensor]]
            A scoring function.
        
fortuna/hallucination/base.py