def run(self):
        """
        The core BBVI routine - draws Monte Carlo gradients and uses a stochastic optimizer.
        """

        # Initialization assumptions
        z = self.draw_normal_initial()
        gradient = self.cv_gradient_initial(z)
        gradient[np.isnan(gradient)] = 0
        variance = np.power(gradient, 2)       
        final_parameters = self.current_parameters()
        final_samples = 1

        # Create optimizer
        if self.optimizer == 'ADAM':
            self.optim = ADAM(final_parameters, variance, self.learning_rate, 0.9, 0.999)
        elif self.optimizer == 'RMSProp':
            self.optim = RMSProp(final_parameters, variance, self.learning_rate, 0.99)

        # Record elbo
        if self.record_elbo is True:
            elbo_records = np.zeros(self.iterations)
        else:
            elbo_records = None

        for i in range(self.iterations):
            x = self.draw_normal()
            gradient = self.cv_gradient(x)
            gradient[np.isnan(gradient)] = 0
            self.change_parameters(self.optim.update(gradient))

            if self.printer is True:
                self.print_progress(i, self.optim.parameters[::2])

            # Construct final parameters using final 10% of samples
            if i > self.iterations-round(self.iterations/10):
                final_samples += 1
                final_parameters = final_parameters+self.optim.parameters

            if self.record_elbo is True:
                elbo_records[i] = self.get_elbo(self.optim.parameters[::2])

        final_parameters = final_parameters/float(final_samples)
        self.change_parameters(final_parameters)
        final_means = np.array([final_parameters[el] for el in range(len(final_parameters)) if el%2==0])
        final_ses = np.array([final_parameters[el] for el in range(len(final_parameters)) if el%2!=0])
        if not self.quiet_progress:
            print("")
            print("Final model ELBO is " + str(-self.full_neg_posterior(final_means)-self.create_normal_logq(final_means)))
        return self.q, final_means, final_ses, elbo_records
The core BBVI routine - draws Monte Carlo gradients and uses a stochastic optimizer.