Exemplo n.º 1
0
    def samples_in_test_mode(self, total_points: int,
                             model: AbstractPriorModel):
        """
        Generate the initial points of the non-linear search in test mode. Like normal, test model draws points, by
        randomly drawing unit values from a uniform distribution between the ball_lower_limit and ball_upper_limit
        values.

        However, the log likelihood function is bypassed and all likelihoods are returned with a value -1.0e99. This
        is so that integration testing of large-scale model-fitting projects can be performed efficiently by bypassing
        sampling of points using the `log_likelihood_function`.

        Parameters
        ----------
        total_points
            The number of points in non-linear paramemter space which initial points are created for.
        model
            An object that represents possible instances of some model with a given dimensionality which is the number
            of free dimensions of the model.
        """

        unit_parameter_lists = []
        parameter_lists = []
        figure_of_merit_list = []

        point_index = 0

        while point_index < total_points:

            unit_parameter_list = model.random_unit_vector_within_limits(
                lower_limit=self.lower_limit, upper_limit=self.upper_limit)
            parameter_list = model.vector_from_unit_vector(
                unit_vector=unit_parameter_list)
            unit_parameter_lists.append(unit_parameter_list)
            parameter_lists.append(parameter_list)
            figure_of_merit_list.append(-1.0e99)
            point_index += 1

        return unit_parameter_lists, parameter_lists, figure_of_merit_list
Exemplo n.º 2
0
    def _fit(self, model: AbstractPriorModel, analysis, log_likelihood_cap=None):
        """
        Fit a model using PySwarms and the Analysis class which contains the data and returns the log likelihood from
        instances of the model, which the `NonLinearSearch` seeks to maximize.

        Parameters
        ----------
        model : ModelMapper
            The model which generates instances for different points in parameter space.
        analysis : Analysis
            Contains the data and the log likelihood function which fits an instance of the model to the data, returning
            the log likelihood the `NonLinearSearch` maximizes.

        Returns
        -------
        A result object comprising the Samples object that inclues the maximum log likelihood instance and full
        chains used by the fit.
        """

        fitness_function = self.fitness_function_from_model_and_analysis(
            model=model, analysis=analysis
        )

        if self.paths.is_object("points"):

            init_pos = self.paths.load_object("points")[-1]
            total_iterations = self.paths.load_object("total_iterations")

            self.logger.info("Existing PySwarms samples found, resuming non-linear search.")

        else:

            unit_parameter_lists, parameter_lists, log_posterior_list = self.initializer.samples_from_model(
                total_points=self.config_dict_search["n_particles"],
                model=model,
                fitness_function=fitness_function,
            )

            init_pos = np.zeros(shape=(self.config_dict_search["n_particles"], model.prior_count))

            for index, parameters in enumerate(parameter_lists):

                init_pos[index, :] = np.asarray(parameters)

            total_iterations = 0

            self.logger.info("No PySwarms samples found, beginning new non-linear search. ")

        ## TODO : Use actual limits

        vector_lower = model.vector_from_unit_vector(
            unit_vector=[1e-6] * model.prior_count,
            ignore_prior_limits=True
        )
        vector_upper = model.vector_from_unit_vector(
            unit_vector=[0.9999999] * model.prior_count,
            ignore_prior_limits=True
        )

        lower_bounds = [lower for lower in vector_lower]
        upper_bounds = [upper for upper in vector_upper]

        bounds = (np.asarray(lower_bounds), np.asarray(upper_bounds))

        self.logger.info("Running PySwarmsGlobal Optimizer...")

        while total_iterations < self.config_dict_run["iters"]:

            pso = self.sampler_from(
                model=model,
                fitness_function=fitness_function,
                bounds=bounds,
                init_pos=init_pos
            )

            iterations_remaining = self.config_dict_run["iters"] - total_iterations

            iterations = min(self.iterations_per_update, iterations_remaining)

            if iterations > 0:

                pso.optimize(objective_func=fitness_function.__call__, iters=iterations)

                total_iterations += iterations

                self.paths.save_object(
                    "total_iterations",
                    total_iterations
                )
                self.paths.save_object(
                    "points",
                    pso.pos_history
                )
                self.paths.save_object(
                    "log_posterior_list",
                    [-0.5 * cost for cost in pso.cost_history]
                )

                self.perform_update(
                    model=model, analysis=analysis, during_analysis=True
                )

                init_pos = self.paths.load_object("points")[-1]

        self.logger.info("PySwarmsGlobal complete")
Exemplo n.º 3
0
    def samples_from_model(self,
                           total_points: int,
                           model: AbstractPriorModel,
                           fitness_function,
                           use_prior_medians: bool = False):
        """
        Generate the initial points of the non-linear search, by randomly drawing unit values from a uniform
        distribution between the ball_lower_limit and ball_upper_limit values.

        Parameters
        ----------
        total_points
            The number of points in non-linear paramemter space which initial points are created for.
        model
            An object that represents possible instances of some model with a given dimensionality which is the number
            of free dimensions of the model.
        """

        if conf.instance["general"]["test"]["test_mode"]:
            return self.samples_in_test_mode(total_points=total_points,
                                             model=model)

        logger.info(
            "Generating initial samples of model, which are subject to prior limits and other constraints."
        )

        unit_parameter_lists = []
        parameter_lists = []
        figures_of_merit_list = []

        point_index = 0

        while point_index < total_points:

            if not use_prior_medians:

                unit_parameter_list = model.random_unit_vector_within_limits(
                    lower_limit=self.lower_limit, upper_limit=self.upper_limit)

                try:
                    parameter_list = model.vector_from_unit_vector(
                        unit_vector=unit_parameter_list)
                except exc.PriorLimitException:
                    continue

            else:

                unit_parameter_list = [0.5] * model.prior_count
                parameter_list = model.vector_from_unit_vector(
                    unit_vector=unit_parameter_list)

            try:
                figure_of_merit = fitness_function.figure_of_merit_from(
                    parameter_list=parameter_list)

                if np.isnan(figure_of_merit):
                    raise exc.FitException

                unit_parameter_lists.append(unit_parameter_list)
                parameter_lists.append(parameter_list)
                figures_of_merit_list.append(figure_of_merit)
                point_index += 1
            except exc.FitException:
                pass

        return unit_parameter_lists, parameter_lists, figures_of_merit_list