def get_next_population(self, prev_response):
        """
        Returns a new generation for a given experiment.
        :param prev_response: the previous generation, *with* evaluation metrics for each Candidate
        :return: a new generation, as a PopulationResponse object
        """
        # Prepare a request for next generation
        request_params = {
            'version': self.version,
            'experiment_id': self.experiment_id
        }
        request = ParseDict(request_params, PopulationRequest())
        request.config = self.experiment_params_as_bytes
        if prev_response:
            request.evaluated_population_response.CopyFrom(prev_response)

        # Ask for next generation
        response = self._next_population_with_retry(request)
        return response
    def request_base_model(self):
        # Update the request to query for 1 Keras model
        params = copy.deepcopy(self.experiment_params)
        params["evolution"] = {"population_size": 1}
        params["LEAF"]["representation"] = "KerasNN"

        # Prepare a request for next generation
        request_params = {
            'version': self.version,
            'experiment_id': self.experiment_id
        }
        request = ParseDict(request_params, PopulationRequest())
        request.config = self.extension_packaging.to_extension_bytes(params)

        # Ask for the base model
        response = self._next_population_with_retry(request)

        # Convert the received bytes to a Keras model
        model_bytes = response.population[0].interpretation
        model_file = io.BytesIO(model_bytes)
        keras_model = load_model(model_file)

        # return the base model
        return keras_model