예제 #1
0
def select_new_region_of_interest(
    factorial_importance_analysis: pd.DataFrame,
    space: Space,
    threshold: float,
    n_levels: int,
) -> Tuple[Space, dict]:
    """Select new region of interest and frozen parameter values based on factorial analysis.

    Parameters
    ----------
    factorial_importance_analysis: dict
        Marginal variance ratios on best levels of the factorial performance analysis.
        Should have format {'dim-name': <marginal variance ratio>, ...}
    space: ``orion.algo.space.Space``
        Space object representing the current region of interest.
    threshold: float
        Threshold of marginal variance ratio below which we should freeze a dimension.

    """

    frozen_param_values = {}
    new_space = Space()
    for key, dim in space.items():
        dim_importance_analysis = factorial_importance_analysis[
            factorial_importance_analysis["param"] == key]
        if float(dim_importance_analysis["importance"]) < threshold:
            frozen_param_values[key] = sum(dim.interval()) / 2.0
        else:
            level = int(dim_importance_analysis["best_level"])
            low, high = dim.interval()
            intervals = (high - low) / n_levels
            new_low = low + intervals * (level - 1)
            new_space.register(Real(dim.name, "uniform", new_low, intervals))

    return new_space, frozen_param_values
예제 #2
0
    def test_order(self):
        """Test that the same space built twice will have the same ordering."""
        space1 = Space()
        space1.register(Integer('yolo1', 'uniform', -3, 6, shape=(2, )))
        space1.register(Integer('yolo2', 'uniform', -3, 6, shape=(2, )))
        space1.register(Real('yolo3', 'norm', 0.9))
        space1.register(Categorical('yolo4', ('asdfa', 2)))

        space2 = Space()
        space2.register(Integer('yolo1', 'uniform', -3, 6, shape=(2, )))
        space2.register(Real('yolo3', 'norm', 0.9))
        space2.register(Categorical('yolo4', ('asdfa', 2)))
        space2.register(Integer('yolo2', 'uniform', -3, 6, shape=(2, )))

        assert list(space1) == list(space1.keys())
        assert list(space2) == list(space2.keys())
        assert list(space1.values()) == list(space2.values())
        assert list(space1.items()) == list(space2.items())
        assert list(space1.keys()) == list(space2.keys())
        assert list(space1.values()) == list(space2.values())
        assert list(space1.items()) == list(space2.items())
예제 #3
0
    def test_order(self):
        """Test that the same space built twice will have the same ordering."""
        space1 = Space()
        space1.register(Integer("yolo1", "uniform", -3, 6, shape=(2,)))
        space1.register(Integer("yolo2", "uniform", -3, 6, shape=(2,)))
        space1.register(Real("yolo3", "norm", 0.9))
        space1.register(Categorical("yolo4", ("asdfa", 2)))

        space2 = Space()
        space2.register(Integer("yolo1", "uniform", -3, 6, shape=(2,)))
        space2.register(Real("yolo3", "norm", 0.9))
        space2.register(Categorical("yolo4", ("asdfa", 2)))
        space2.register(Integer("yolo2", "uniform", -3, 6, shape=(2,)))

        assert list(space1) == list(space1.keys())
        assert list(space2) == list(space2.keys())
        assert list(space1.values()) == list(space2.values())
        assert list(space1.items()) == list(space2.items())
        assert list(space1.keys()) == list(space2.keys())
        assert list(space1.values()) == list(space2.values())
        assert list(space1.items()) == list(space2.items())
예제 #4
0
def orion_space_to_hebo_space(space: Space) -> DesignSpace:
    """Get the HEBO-equivalent space for the `Space` `space`.

    Parameters
    ----------
    :param space: `Space` instance.

    Returns
    -------
    a `DesignSpace` from the `hebo` package.

    Raises
    ------
    NotImplementedError
        If there is an unsupported dimension or prior type in `space`.
    """
    specs = []

    ds = DesignSpace()
    name: str
    dimension: Dimension
    for name, dimension in space.items():
        spec: dict[str, Any] = {"name": name}
        prior_name = dimension.prior_name
        bounds = dimension.interval()
        if dimension.shape:
            raise NotImplementedError(
                f"HEBO algorithm doesn't support dimension {dimension} since it has a shape."
            )
        if dimension.type == "fidelity":
            # Ignore that dimension: Don't include it in the space for Hebo to optimize.
            continue

        # BUG: https://github.com/Epistimio/orion/issues/800
        bounds = tuple(b.item() if isinstance(b, np.ndarray) else b for b in bounds)

        if prior_name == "choices":
            categories = [str(b) for b in bounds]
            spec.update(type="cat", categories=categories)
        elif prior_name == "uniform":
            spec.update(type="num", lb=bounds[0], ub=bounds[1])
        elif prior_name == "reciprocal":
            spec.update(type="pow", lb=bounds[0], ub=bounds[1])
        elif prior_name == "int_uniform":
            spec.update(type="int", lb=bounds[0], ub=bounds[1])
        elif prior_name == "int_reciprocal":
            spec.update(type="pow_int", lb=bounds[0], ub=bounds[1])
        else:
            raise NotImplementedError(prior_name, dimension)
        specs.append(spec)
    ds.parse(specs)
    return ds
예제 #5
0
def to_ng_space(orion_space: Space) -> Instrumentation:
    """Convert an orion space to a nevergrad space."""
    if IMPORT_ERROR:
        raise IMPORT_ERROR
    converted_dimensions: dict[str, Parameter] = {}
    for name, dim in orion_space.items():
        try:
            converted_dimensions[name] = registry[dim.type,
                                                  dim.prior_name](dim)
        except KeyError as exc:
            raise RuntimeError(
                f"Dimension with type and prior: {exc.args[0]} cannot be converted to nevergrad."
            ) from exc

    return ng.p.Instrumentation(**converted_dimensions)
예제 #6
0
def generate_olh_samples(space: Space, n_levels: int, strength: int,
                         index: int, rng: RandomState) -> Tuple[np.array, int]:
    """
    Generates samples from an orthogonal Latin hypercube (OLH)

    Parameters
    ----------
    space: `orion.core.worker.Space`
        Parameter space
    n_levels: int
        Number of levels
    strength: {1,2}
        Strength parameter for an orthogonal Latin hypercube
    rng: None or ``numpy.random.RandomState``
        Random number generator

    Returns
    -------
    (numpy.array, int) A tuple of the samples array from the normalized parameter space,
        and the n_levels parameter, which may be changed to suit the OLH requirements.
    """

    dimensions = len(space.items())
    if not _is_prime(n_levels):
        n_levels = _find_n_levels(dimensions)
        logger.warning(
            """WARNING: n_levels specified is not a prime number.
            Changing n_levels to %d""",
            n_levels,
        )
    elif n_levels < dimensions - 1:
        n_levels = _find_n_levels(dimensions)
        logger.warning(
            """WARNING: n_levels specified is less than the number of hyperparameters
            minus 1. Changing n_levels to %d""",
            n_levels,
        )
    n_rows = n_levels**strength
    logger.debug("MOFA: setting number of trials in this iteration to %d",
                 n_rows * index)
    all_samples = []
    for _ in range(index):
        lhc = LatinHypercube(d=dimensions, strength=strength, seed=rng)
        samples = lhc.random(n_rows).tolist()
        all_samples.extend(samples)

    return np.array(all_samples), n_levels
예제 #7
0
    def build_grid(space: Space,
                   n_values: dict[str, int],
                   max_trials: int = 10000):
        """Build a grid of trials

        Parameters
        ----------
        n_values: int or dict
            Dictionary specifying number of trials for each dimension independently
            (name, n_values). For categorical dimensions, n_values will not be used, and all
            categories will be used to build the grid.
        max_trials: int
            Maximum number of trials for the grid. If n_values lead to more trials than max_trials,
            the n_values will be adjusted down. Will raise ValueError if it is impossible to build
            a grid smaller than max_trials (for instance if choices are too large).

        """
        adjust = 0
        n_trials = float("inf")
        coordinates: list[list] = []

        while n_trials > max_trials:
            coordinates = []
            capped_values = []
            for name, dim in space.items():
                capped_value = max(n_values[name] - adjust, 1)
                capped_values.append(capped_value)
                coordinates.append(list(grid(dim, capped_value)))

            if all(value <= 1 for value in capped_values):
                raise ValueError(
                    f"Cannot build a grid smaller than {max_trials}. "
                    "Try reducing the number of choices in categorical dimensions."
                )

            n_trials = numpy.prod(
                [len(dim_values) for dim_values in coordinates])
            # TODO: Use binary search instead of incrementing by one.
            adjust += 1

        if adjust > 1:
            log.warning(
                f"`n_values` reduced by {adjust-1} to limit number of trials below {max_trials}."
            )

        return list(itertools.product(*coordinates))