Example #1
0
    def tell(self, candidate: p.Parameter, value: float) -> None:
        """Provides the optimizer with the evaluation of a fitness value for a candidate.

        Parameters
        ----------
        x: np.ndarray
            point where the function was evaluated
        value: float
            value of the function

        Note
        ----
        The candidate should generally be one provided by `ask()`, but can be also
        a non-asked candidate. To create a p.Parameter instance from args and kwargs,
        you can use `optimizer.create_candidate.from_call(*args, **kwargs)`.
        """
        if not isinstance(candidate, p.Parameter):
            raise TypeError(
                "'tell' must be provided with the candidate (use optimizer.create_candidate.from_call(*args, **kwargs)) "
                "if you want to inoculate a point that as not been asked for"
            )
        candidate.freeze()  # make sure it is not modified somewhere
        # call callbacks for logging etc...
        for callback in self._callbacks.get("tell", []):
            callback(self, candidate, value)
        data = candidate.get_standardized_data(reference=self.parametrization)
        self._update_archive_and_bests(data, value)
        if candidate.uid in self._asked:
            self._internal_tell_candidate(candidate, value)
            self._asked.remove(candidate.uid)
        else:
            self._internal_tell_not_asked(candidate, value)
            self._num_tell_not_asked += 1
        self._num_tell += 1
Example #2
0
    def _internal_tell_not_asked(self, candidate: p.Parameter,
                                 loss: float) -> None:
        next_id = self.trials.new_trial_ids(1)
        new_trial = hyperopt.rand.suggest(next_id, self.domain, self.trials,
                                          self._rng.randint(2**31 - 1))
        self.trials.insert_trial_docs(new_trial)
        self.trials.refresh()
        tid = next_id[0]

        if self._transform:
            data = candidate.get_standardized_data(
                reference=self.parametrization)
            data = self._transform.forward(data)
            self.trials._dynamic_trials[tid]["misc"]["vals"] = {
                f"x_{i}": [data[i]]
                for i in range(len(data))
            }
        else:
            null_config: dict = {
                k: []
                for k in self.trials._dynamic_trials[tid]["misc"]
                ["vals"].keys()
            }
            new_vals: dict = _hp_parametrization_to_dict(candidate,
                                                         default=null_config)
            self.trials._dynamic_trials[tid]["misc"]["vals"] = new_vals

        self.trials.refresh()
        candidate._meta["trial_id"] = tid
        self._internal_tell_candidate(candidate, loss)
Example #3
0
 def _internal_tell_candidate(self, candidate: p.Parameter, value: float) -> None:
     """Returns value for a point which was "asked"
     (none asked point cannot be "tell")
     """
     x = candidate.get_standardized_data(reference=self.parametrization)
     assert self._messaging_thread is not None, 'Start by using "ask" method, instead of "tell" method'
     if not self._messaging_thread.is_alive():  # optimizer is done
         self._check_error()
         return
     messages = [m for m in self._messaging_thread.messages if m.meta.get("asked", False) and not m.done]
     messages = [m for m in messages if m.meta["uid"] == candidate.uid]
     if not messages:
         raise RuntimeError(f"No message for evaluated point {x}: {self._messaging_thread.messages}")
     messages[0].result = value  # post the value, and the thread will deal with it
Example #4
0
    def _update_archive_and_bests(self, candidate: p.Parameter,
                                  loss: tp.FloatLoss) -> None:
        x = candidate.get_standardized_data(reference=self.parametrization)
        if not isinstance(
                loss, (Real, float)
        ):  # using "float" along "Real" because mypy does not understand "Real" for now Issue #3186
            raise TypeError(
                f'"tell" method only supports float values but the passed loss was: {loss} (type: {type(loss)}.'
            )
        if np.isnan(loss) or loss == np.inf:
            warnings.warn(f"Updating fitness with {loss} value",
                          errors.BadLossWarning)
        mvalue: tp.Optional[utils.MultiValue] = None
        if x not in self.archive:
            self.archive[x] = utils.MultiValue(candidate,
                                               loss,
                                               reference=self.parametrization)
        else:
            mvalue = self.archive[x]
            mvalue.add_evaluation(loss)
            # both parameters should be non-None
            if mvalue.parameter.loss > candidate.loss:  # type: ignore
                mvalue.parameter = candidate  # keep best candidate
        # update current best records
        # this may have to be improved if we want to keep more kinds of best losss

        for name in self.current_bests:
            if mvalue is self.current_bests[name]:  # reboot
                best = min(self.archive.values(),
                           key=lambda mv, n=name: mv.get_estimation(n)
                           )  # type: ignore
                # rebuild best point may change, and which value did not track the updated value anyway
                self.current_bests[name] = best
            else:
                if self.archive[x].get_estimation(
                        name) <= self.current_bests[name].get_estimation(name):
                    self.current_bests[name] = self.archive[x]
                # deactivated checks
                # if not (np.isnan(loss) or loss == np.inf):
                #     if not self.current_bests[name].x in self.archive:
                #         bval = self.current_bests[name].get_estimation(name)
                #         avals = (min(v.get_estimation(name) for v in self.archive.values()),
                #                  max(v.get_estimation(name) for v in self.archive.values()))
                #         raise RuntimeError(f"Best value should exist in the archive at num_tell={self.num_tell})\n"
                #                            f"Best value is {bval} and archive is within range {avals} for {name}")
        if self.pruning is not None:
            self.archive = self.pruning(self.archive)
Example #5
0
 def _internal_tell_candidate(self, candidate: p.Parameter,
                              loss: tp.FloatLoss) -> None:
     """Called whenever calling :code:`tell` on a candidate that was "asked"."""
     data = candidate.get_standardized_data(reference=self.parametrization)
     self._internal_tell(data, loss)
Example #6
0
 def _internal_tell_candidate(self, candidate: p.Parameter, value: float) -> None:
     """Called whenever calling "tell" on a candidate that was "asked".
     """
     data = candidate.get_standardized_data(reference=self.parametrization)
     self._internal_tell(data, value)