@classmethod
def finetune_grid_search_cv(cls, Xs, Y, *, n_splits, test_size, eval_fn=
    None, probs=False, return_all=False, **kwargs):
    """
        Performs cross validated grid search over config items defined using "GridSearchable" objects and returns either full results or
        the config object that relates to the best results. The default config contains grid searchable objects for the
        most important parameters to search over.

        It should be noted that the cv splits are not guaranteed unique, but each split is given to each set of hparams.

        :param Xs: Input text. Either [num_samples] or [sequence, num_samples] for single or multi input models respectively.
        :param Y: Targets, A list of targets, [num_samples] that correspond to each sample in Xs.
        :param n_splits: Number of CV splits to do.
        :param test_size: Int or float. If an int is given this number of samples is used to validate, if a float is
            given then that fraction of samples is used.
        :param eval_fn: An eval function that takes 2 batches of outputs and returns a float, with a max value being
            desired. An arithmetic mean must make sense for this metric.
        :param probs: If true, eval_fn is passed probability outputs from predict_proba, otherwise the output of predict is used.
        :param return_all: If True, all results are returned, if False, only the best config is returned.
        :param kwargs: Keyword arguments to pass to get_config()
        :return: default is to return the best config object. If return_all is true, it returns a list of tuples of the
            form [(config, eval_fn output), ... ]
        """
    results = []
    for _ in range(n_splits):
        res = cls.finetune_grid_search(Xs, Y, test_size=test_size, probs=
            probs, eval_fn=eval_fn, return_all=True, **kwargs)
        results.append(res)
    results = list(zip(*results))
    aggregated_results = []
    for configuration in results:
        config_common = None
        sum_res = 0
        n_res = 0
        for config, result in configuration:
            config_common = config_common or config
            assert config == config_common
            n_res += 1
            sum_res += result
        aggregated_results.append((config_common, sum_res / n_res))
    if return_all:
        return aggregated_results
    return max(aggregated_results, key=lambda x: x[1])[0]
