Performs Black Box Variational Inference

        Parameters
        ----------
        posterior : method
            Hands bbvi_fit a posterior object

        optimizer : string
            Stochastic optimizer: one of RMSProp or ADAM.

        iterations: int
            How many iterations for BBVI

        map_start : boolean
            Whether to start values from a MAP estimate (if False, uses default starting values)

        Returns
        ----------
        BBVIResults object

def _bbvi_fit(self, posterior, optimizer='RMSProp', iterations=1000, 
        map_start=True, batch_size=12, mini_batch=None, learning_rate=0.001, 
        record_elbo=False, quiet_progress=False, **kwargs):
        """ Performs Black Box Variational Inference

        Parameters
        ----------
        posterior : method
            Hands bbvi_fit a posterior object

        optimizer : string
            Stochastic optimizer: one of RMSProp or ADAM.

        iterations: int
            How many iterations for BBVI

        map_start : boolean
            Whether to start values from a MAP estimate (if False, uses default starting values)

        Returns
        ----------
        BBVIResults object
        """

        # Starting values
        phi = self.latent_variables.get_z_starting_values()
        phi = kwargs.get('start',phi).copy() # If user supplied

        if self.model_type not in ['GPNARX','GPR','GP','GASRank'] and map_start is True and mini_batch is None:
            p = optimize.minimize(posterior, phi, method='L-BFGS-B') # PML starting values
            start_loc = 0.8*p.x + 0.2*phi
        else:
            start_loc = phi
        start_ses = None

        # Starting values for approximate distribution
        for i in range(len(self.latent_variables.z_list)):
            approx_dist = self.latent_variables.z_list[i].q
            if isinstance(approx_dist, Normal):
                if start_ses is None:
                    self.latent_variables.z_list[i].q.mu0 = start_loc[i]
                    self.latent_variables.z_list[i].q.sigma0 = np.exp(-3.0)
                else:
                    self.latent_variables.z_list[i].q.mu0 = start_loc[i]
                    self.latent_variables.z_list[i].q.sigma0 = start_ses[i]

        q_list = [k.q for k in self.latent_variables.z_list]

        if mini_batch is None:
            bbvi_obj = BBVI(posterior, q_list, batch_size, optimizer, iterations, learning_rate, record_elbo, quiet_progress)
        else:
            bbvi_obj = BBVIM(posterior, self.neg_logposterior, q_list, mini_batch, optimizer, iterations, learning_rate, mini_batch, record_elbo, quiet_progress)
        
        q, q_z, q_ses, elbo_records = bbvi_obj.run()
        self.latent_variables.set_z_values(q_z,'BBVI',np.exp(q_ses),None)

        for k in range(len(self.latent_variables.z_list)):
            self.latent_variables.z_list[k].q = q[k]

        self.latent_variables.estimation_method = 'BBVI'

        theta, Y, scores, states, states_var, X_names = self._categorize_model_output(q_z)

        # Change this in future
        try:
            latent_variables_store = self.latent_variables.copy()
        except:
            latent_variables_store = self.latent_variables

        return BBVIResults(data_name=self.data_name, X_names=X_names, model_name=self.model_name,
            model_type=self.model_type, latent_variables=latent_variables_store, data=Y, index=self.index,
            multivariate_model=self.multivariate_model, objective_object=self.neg_logposterior, 
            method='BBVI', ses=q_ses, signal=theta, scores=scores, elbo_records=elbo_records,
            z_hide=self._z_hide, max_lag=self.max_lag, states=states, states_var=states_var)