def _draw_fantasy_values()

in syne_tune/optimizer/schedulers/searchers/bayesopt/models/gpiss_model.py [0:0]


    def _draw_fantasy_values(
            self, state: TuningJobState) -> TuningJobState:
        """
        Note: Fantasized target values are not de-normalized, because they
        are used internally only (see `prepare_data` with
        `do_fantasizing=True`).

        :param state: State with pending evaluations without fantasies
        :return: Copy of `state`, where `pending_evaluations` contains
            fantasized target values

        """
        assert self.num_fantasy_samples > 0
        # Fantasies are drawn in sequential chunks, one trial with pending
        # evaluations at a time.
        data_nopending, data_pending = prepare_data_with_pending(
            state=state,
            configspace_ext=self._configspace_ext,
            active_metric=self.active_metric,
            normalize_targets=self.normalize_targets)
        if not data_nopending['configs']:
            # It can happen that all trials with observed data also have
            # pending evaluations. This is possible only at the very start,
            # as long as no trial has been stopped or paused.
            # In this case, we find the trial with the largest number of
            # observed targets and remove its pending evaluations, so
            # `data_nopending` gets one entry. It is not possible to compute
            # a posterior state without any data, so handling this case
            # correctly would be very tedious).
            assert data_pending['configs'], \
                "State is empty, cannot do posterior inference:\n" +\
                str(state)
            names = ('configs', 'targets', 'trial_ids')
            elem = {k: data_pending[k].pop(0) for k in names}
            for k, v in elem.items():
                data_nopending[k] = [v]
            k = 'features'
            all_features = data_pending[k]
            data_nopending[k] = all_features[0].reshape((1, -1))
            data_pending[k] = all_features[1:, :]
            logger.info(
                "All trials currently have pending evaluations. In order to "
                "sample fantasy targets, I'll remove pending evaluations "
                f"from trial_id {elem['trial_ids']} (which has "
                f"{elem['targets'].size} observations)")
        # Start with posterior state, conditioned on data from trials without
        # pending evaluations
        self._gpmodel.recompute_states(data_nopending)
        poster_state_nopending = self._gpmodel.states[0]
        # Loop over trials with pending evaluations: For each trial, we sample
        # fantasy targets given observed ones, then update `poster_state` by
        # conditioning on both. This ensures we obtain a joint sample (the
        # ordering of trials does not matter). For the application here, we
        # do not need the final `poster_state`.
        all_fantasy_targets = []
        for sample_it in range(self.num_fantasy_samples):
            fantasy_targets, _ = poster_state_nopending.sample_and_update_for_pending(
                data_pending, sample_all_nonobserved=False,
                random_state=self._gpmodel.random_state)
            for pos, fantasies in enumerate(fantasy_targets):
                if sample_it == 0:
                    all_fantasy_targets.append([fantasies])
                else:
                    all_fantasy_targets[pos].append(fantasies)
        # Convert into `FantasizedPendingEvaluation`
        r_min = self._configspace_ext.resource_attr_range[0]
        pending_evaluations_with_fantasies = []
        for trial_id, targets, fantasies in zip(
                data_pending['trial_ids'], data_pending['targets'],
                all_fantasy_targets):
            n_observed = targets.size
            n_pending = fantasies[0].size
            start = r_min + n_observed
            resources = list(range(start, start + n_pending))
            fantasy_matrix = np.hstack(v.reshape((-1, 1)) for v in fantasies)
            assert fantasy_matrix.shape == (n_pending, self.num_fantasy_samples)
            for resource, fantasy in zip(resources, fantasy_matrix):
                pending_evaluations_with_fantasies.append(
                    FantasizedPendingEvaluation(
                        trial_id=trial_id,
                        fantasies={self.active_metric: fantasy},
                        resource=resource))
        # Return new state, with `pending_evaluations` replaced
        return TuningJobState(
            hp_ranges=state.hp_ranges,
            config_for_trial=state.config_for_trial,
            trials_evaluations=state.trials_evaluations,
            failed_trials=state.failed_trials,
            pending_evaluations=pending_evaluations_with_fantasies)