예제 #1
0
def load(name, version=None, mode="r"):
    """Load experiment from database

    An experiment view provides all reading operations of standard experiment but prevents the
    modification of the experiment and its trials.

    Parameters
    ----------
    name: str
        Name of the experiment to build
    version: int, optional
        Version to select. If None, last version will be selected. If version given is larger than
        largest version available, the largest version will be selected.
    mode: str, optional
        The access rights of the experiment on the database.
        'r': read access only
        'w': can read and write to database
        Default is 'r'

    """
    assert mode in set("rw")

    log.debug(
        f"Loading experiment {name} (version={version}) from database in mode `{mode}`"
    )
    db_config = fetch_config_from_db(name, version)

    if not db_config:
        message = (
            "No experiment with given name '%s' and version '%s' inside database, "
            "no view can be created." % (name, version if version else "*")
        )
        raise NoConfigurationError(message)

    db_config.setdefault("version", 1)

    return create_experiment(mode=mode, **db_config)
예제 #2
0
def build(name, version=None, branching=None, **config):
    """Build an experiment object

    If new, `space` argument must be provided, else all arguments are fetched from the database
    based on (name, version). If any argument given does not match the corresponding ones in the
    database for given (name, version), than the version is incremented and the experiment will be a
    child of the previous version.

    Parameters
    ----------
    name: str
        Name of the experiment to build
    version: int, optional
        Version to select. If None, last version will be selected. If version given is larger than
        largest version available, the largest version will be selected.
    branch_from: str, optional
        Name of the experiment to branch from. The new experiment will have access to all trials
        from the parent experiment it has been branched from.
    space: dict, optional
        Optimization space of the algorithm. Should have the form `dict(name='<prior>(args)')`.
    algorithms: str or dict, optional
        Algorithm used for optimization.
    strategy: str or dict, optional
        Parallel strategy to use to parallelize the algorithm.
    max_trials: int, optional
        Maximum number or trials before the experiment is considered done.
    storage: dict, optional
        Configuration of the storage backend.
    branching: dict, optional
        Arguments to control the branching.

        branch_from: str, optional
            Name of the experiment to branch from.
        manual_resolution: bool, optional
            Starts the prompt to resolve manually the conflicts. Defaults to False.
        non_monitored_arguments: list of str, optional
            Will ignore these arguments while looking for differences. Defaults to [].
        ignore_code_changes: bool, optional
            Will ignore code changes while looking for differences. Defaults to False.
        algorithm_change: bool, optional
            Whether to automatically solve the algorithm conflict (change of algo config).
            Defaults to True.
        code_change_type: str, optional
            How to resolve code change automatically. Must be one of 'noeffect', 'unsure' or
            'break'.  Defaults to 'break'.
        cli_change_type: str, optional
            How to resolve cli change automatically. Must be one of 'noeffect', 'unsure' or 'break'.
            Defaults to 'break'.
        config_change_type: str, optional
            How to resolve config change automatically. Must be one of 'noeffect', 'unsure' or
            'break'.  Defaults to 'break'.

    """
    config = copy.deepcopy(config)
    for key, value in list(config.items()):
        if key.startswith('_') or value is None:
            config.pop(key)

    if 'strategy' in config:
        config['producer'] = {'strategy': config.pop('strategy')}

    if branching is None:
        branching = {}

    if branching.get('branch_from'):
        branching.setdefault('branch_to', name)
        name = branching['branch_from']

    db_config = fetch_config_from_db(name, version)

    new_config = config
    config = resolve_config.merge_configs(db_config, config)

    metadata = resolve_config.fetch_metadata(config.get('user'),
                                             config.get('user_args'))

    config = resolve_config.merge_configs(db_config, config,
                                          {'metadata': metadata})

    # TODO: Find a better solution
    if isinstance(config.get('algorithms'),
                  dict) and len(config['algorithms']) > 1:
        config['algorithms'] = new_config['algorithms']

    config.setdefault('name', name)
    config.setdefault('version', version)

    if 'space' not in config:
        raise NoConfigurationError(
            'Experiment {} does not exist in DB and space was not defined.'.
            format(name))

    if len(config['space']) == 0:
        raise NoConfigurationError(
            "No prior found. Please include at least one.")

    experiment = create_experiment(**copy.deepcopy(config))
    if experiment.id is None:
        try:
            _register_experiment(experiment)
        except DuplicateKeyError:
            experiment = build(branching=branching, **config)

        return experiment

    conflicts = _get_conflicts(experiment, branching)
    must_branch = len(conflicts.get()) > 1 or branching.get('branch_to')
    if must_branch:
        branched_experiment = _branch_experiment(experiment, conflicts,
                                                 version, branching)
        try:
            _register_experiment(branched_experiment)
        except DuplicateKeyError as e:
            raise RaceCondition(
                'There was a race condition during branching.') from e

        return branched_experiment

    _update_experiment(experiment)
    return experiment
예제 #3
0
def build(name, version=None, branching=None, **config):
    """Build an experiment object

    If new, ``space`` argument must be provided, else all arguments are fetched from the database
    based on (name, version). If any argument given does not match the corresponding ones in the
    database for given (name, version), than the version is incremented and the experiment will be a
    child of the previous version.

    Parameters
    ----------
    name: str
        Name of the experiment to build
    version: int, optional
        Version to select. If None, last version will be selected. If version given is larger than
        largest version available, the largest version will be selected.
    space: dict, optional
        Optimization space of the algorithm. Should have the form ``dict(name='<prior>(args)')``.
    algorithms: str or dict, optional
        Algorithm used for optimization.
    strategy: str or dict, optional
        Deprecated and will be remove in v0.4. It should now be set in algorithm configuration
        directly if it supports it.
    max_trials: int, optional
        Maximum number of trials before the experiment is considered done.
    max_broken: int, optional
        Number of broken trials for the experiment to be considered broken.
    storage: dict, optional
        Configuration of the storage backend.

    branching: dict, optional
        Arguments to control the branching.

        branch_from: str, optional
            Name of the experiment to branch from.
        manual_resolution: bool, optional
            Starts the prompt to resolve manually the conflicts. Defaults to False.
        non_monitored_arguments: list of str, optional
            Will ignore these arguments while looking for differences. Defaults to [].
        ignore_code_changes: bool, optional
            Will ignore code changes while looking for differences. Defaults to False.
        algorithm_change: bool, optional
            Whether to automatically solve the algorithm conflict (change of algo config).
            Defaults to True.
        orion_version_change: bool, optional
            Whether to automatically solve the orion version conflict.
            Defaults to True.
        code_change_type: str, optional
            How to resolve code change automatically. Must be one of 'noeffect', 'unsure' or
            'break'.  Defaults to 'break'.
        cli_change_type: str, optional
            How to resolve cli change automatically. Must be one of 'noeffect', 'unsure' or 'break'.
            Defaults to 'break'.
        config_change_type: str, optional
            How to resolve config change automatically. Must be one of 'noeffect', 'unsure' or
            'break'.  Defaults to 'break'.

    """
    log.debug(f"Building experiment {name} with {version}")
    log.debug("    Passed experiment config:\n%s", pprint.pformat(config))
    log.debug("    Branching config:\n%s", pprint.pformat(branching))

    name, config, branching = clean_config(name, config, branching)

    config = consolidate_config(name, version, config)

    if "space" not in config:
        raise NoConfigurationError(
            "Experiment {} does not exist in DB and space was not defined.".
            format(name))

    if len(config["space"]) == 0:
        raise NoConfigurationError(
            "No prior found. Please include at least one.")

    experiment = create_experiment(mode="x", **copy.deepcopy(config))
    if experiment.id is None:
        log.debug(
            "Experiment not found in DB. Now attempting registration in DB.")
        try:
            _register_experiment(experiment)
            log.debug("Experiment successfully registered in DB.")
        except DuplicateKeyError:
            log.debug(
                "Experiment registration failed. This is likely due to a race condition. "
                "Now rolling back and re-attempting building it.")
            experiment = build(branching=branching, **config)

        return experiment

    log.debug(
        f"Experiment {config['name']}-v{config['version']} already existed.")

    conflicts = _get_conflicts(experiment, branching)
    must_branch = len(conflicts.get()) > 1 or branching.get("branch_to")

    if must_branch and branching.get("enable", orion.core.config.evc.enable):
        return _attempt_branching(conflicts, experiment, version, branching)
    elif must_branch:
        log.warning(
            "Running experiment in a different state:\n%s",
            _get_branching_status_string(conflicts, branching),
        )

    log.debug("No branching required.")

    _update_experiment(experiment)
    return experiment
예제 #4
0
def get_or_create_benchmark(
    name, algorithms=None, targets=None, storage=None, debug=False
):
    """
    Create or get a benchmark object.

    Parameters
    ----------
    name: str
        Name of the benchmark
    algorithms: list, optional
        Algorithms used for benchmark, each algorithm can be a string or dict.
    targets: list, optional
        Targets for the benchmark, each target will be a dict with two keys.

        assess: list
            Assessment objects
        task: list
            Task objects
    storage: dict, optional
        Configuration of the storage backend.
    debug: bool, optional
        If using in debug mode, the storage config is overrided with legacy:EphemeralDB.
        Defaults to False.

    Returns
    -------
    An instance of `orion.benchmark.Benchmark`
    """
    setup_storage(storage=storage, debug=debug)

    # fetch benchmark from db
    db_config = _fetch_benchmark(name)

    benchmark_id = None
    input_configure = None

    if db_config:
        if algorithms or targets:
            input_benchmark = Benchmark(name, algorithms, targets)
            input_configure = input_benchmark.configuration
        benchmark_id, algorithms, targets = _resolve_db_config(db_config)

    if not algorithms or not targets:
        raise NoConfigurationError(
            "Benchmark {} does not exist in DB, "
            "algorithms and targets space was not defined.".format(name)
        )

    benchmark = _create_benchmark(name, algorithms, targets)

    if input_configure and input_benchmark.configuration != benchmark.configuration:
        logger.warn(
            "Benchmark with same name is found but has different configuration, "
            "which will be used for this creation.\n{}".format(benchmark.configuration)
        )

    if benchmark_id is None:
        logger.debug("Benchmark not found in DB. Now attempting registration in DB.")
        try:
            _register_benchmark(benchmark)
            logger.debug("Benchmark successfully registered in DB.")
        except DuplicateKeyError:
            logger.info(
                "Benchmark registration failed. This is likely due to a race condition. "
                "Now rolling back and re-attempting building it."
            )
            get_or_create_benchmark(name, algorithms, targets, storage, debug)

    return benchmark