def find_hessian(point, vars=None, model=None): """ Returns Hessian of logp at the point passed. Parameters ---------- model: Model (optional if in `with` context) point: dict vars: list Variables for which Hessian is to be calculated. """ model = modelcontext(model) H = model.fastd2logp(vars) return H(Point(point, filter_model_vars=True, model=model))
def find_hessian_diag(point, vars=None, model=None): """ Returns Hessian of logp at the point passed. Parameters ---------- model: Model (optional if in `with` context) point: dict vars: list Variables for which Hessian is to be calculated. """ model = modelcontext(model) H = model.compile_fn(hessian_diag(model.logpt(), vars)) return H(Point(point, model=model))
def _initialize_kernel(self): """Create variables and logp function necessary to run kernel This method should not be overwritten. If needed, use `setup_kernel` instead. """ # Create dictionary that stores original variables shape and size initial_point = self.model.recompute_initial_point( seed=self.rng.integers(2**30)) for v in self.variables: self.var_info[v.name] = (initial_point[v.name].shape, initial_point[v.name].size) # Create particles bijection map if self.start: init_rnd = self.start else: init_rnd = self.initialize_population() population = [] for i in range(self.draws): point = Point( {v.name: init_rnd[v.name][i] for v in self.variables}, model=self.model) population.append(DictToArrayBijection.map(point).data) self.tempered_posterior = np.array(floatX(population)) # Initialize prior and likelihood log probabilities shared = make_shared_replacements(initial_point, self.variables, self.model) self.prior_logp_func = _logp_forw(initial_point, [self.model.varlogpt], self.variables, shared) self.likelihood_logp_func = _logp_forw(initial_point, [self.model.datalogpt], self.variables, shared) priors = [ self.prior_logp_func(sample) for sample in self.tempered_posterior ] likelihoods = [ self.likelihood_logp_func(sample) for sample in self.tempered_posterior ] self.prior_logp = np.array(priors).squeeze() self.likelihood_logp = np.array(likelihoods).squeeze()
def test_missing_data(self): # Originally from a case described in #3122 X = np.random.binomial(1, 0.5, 10) X[0] = -1 # masked a single value X = np.ma.masked_values(X, value=-1) with pm.Model() as m: x1 = pm.Uniform("x1", 0.0, 1.0) x2 = pm.Bernoulli("x2", x1, observed=X) gf = m.logp_dlogp_function() gf._extra_are_set = True assert m["x2_missing"].type == gf._extra_vars_shared["x2_missing"].type pnt = m.test_point.copy() del pnt["x2_missing"] res = [gf(DictToArrayBijection.map(Point(pnt, model=m))) for i in range(5)] assert reduce(lambda x, y: np.array_equal(x, y) and y, res) is not False
def fixed_hessian(point, vars=None, model=None): """ Returns a fixed Hessian for any chain location. Parameters ---------- model: Model (optional if in `with` context) point: dict vars: list Variables for which Hessian is to be calculated. """ model = modelcontext(model) if vars is None: vars = model.cont_vars vars = inputvars(vars) point = Point(point, model=model) rval = np.ones(DictToArrayBijection.map(point).size) / 10 return rval
def __init__( self, vars=None, scaling=None, step_scale=0.25, is_cov=False, model=None, blocked=True, potential=None, dtype=None, Emax=1000, target_accept=0.8, gamma=0.05, k=0.75, t0=10, adapt_step_size=True, step_rand=None, **aesara_kwargs ): """Set up Hamiltonian samplers with common structures. Parameters ---------- vars: list, default=None List of Aesara variables. If None, all continuous RVs from the model are included. scaling: array_like, ndim={1,2} Scaling for momentum distribution. 1d arrays interpreted matrix diagonal. step_scale: float, default=0.25 Size of steps to take, automatically scaled down by 1/n**(1/4), where n is the dimensionality of the parameter space is_cov: bool, default=False Treat scaling as a covariance matrix/vector if True, else treat it as a precision matrix/vector model: pymc.Model blocked: bool, default=True potential: Potential, optional An object that represents the Hamiltonian with methods `velocity`, `energy`, and `random` methods. **aesara_kwargs: passed to Aesara functions """ self._model = modelcontext(model) if vars is None: vars = self._model.cont_vars else: vars = [self._model.rvs_to_values.get(var, var) for var in vars] super().__init__(vars, blocked=blocked, model=self._model, dtype=dtype, **aesara_kwargs) self.adapt_step_size = adapt_step_size self.Emax = Emax self.iter_count = 0 # We're using the initial/test point to determine the (initial) step # size. # XXX: If the dimensions of these terms change, the step size # dimension-scaling should change as well, no? test_point = self._model.initial_point nuts_vars = [test_point[v.name] for v in vars] size = sum(v.size for v in nuts_vars) self.step_size = step_scale / (size ** 0.25) self.step_adapt = step_sizes.DualAverageAdaptation( self.step_size, target_accept, gamma, k, t0 ) self.target_accept = target_accept self.tune = True if scaling is None and potential is None: mean = floatX(np.zeros(size)) var = floatX(np.ones(size)) potential = QuadPotentialDiagAdapt(size, mean, var, 10) if isinstance(scaling, dict): point = Point(scaling, model=self._model) scaling = guess_scaling(point, model=self._model, vars=vars) if scaling is not None and potential is not None: raise ValueError("Can not specify both potential and scaling.") if potential is not None: self.potential = potential else: self.potential = quad_potential(scaling, is_cov) self.integrator = integration.CpuLeapfrogIntegrator(self.potential, self._logp_dlogp_func) self._step_rand = step_rand self._warnings = [] self._samples_after_tune = 0 self._num_divs_sample = 0
def __call__(self, q0: RaveledVars) -> RaveledVars: """Returns proposed sample given the current sample in dictionary form (q0_dict).""" # Logging is reduced to avoid extensive console output # during multiple recursive calls of subsample() _log = logging.getLogger("pymc") _log.setLevel(logging.ERROR) # Convert current sample from RaveledVars -> # dict before feeding to subsample. q0_dict = DictToArrayBijection.rmap(q0) with self.model_below: # Check if the tuning flag has been set to False # in which case tuning is stopped. The flag is set # to False (by MLDA's astep) when the burn-in # iterations of the highest-level MLDA sampler run out. # The change propagates to all levels. if self.tune: # Subsample in tuning mode trace = subsample( draws=0, step=self.step_method_below, start=q0_dict, tune=self.subsampling_rate, ) else: # Subsample in normal mode without tuning # If DEMetropolisZMLDA is the base sampler a flag is raised to # make sure that history is edited after tuning ends if self.tuning_end_trigger: if isinstance(self.step_method_below, DEMetropolisZMLDA): self.step_method_below.tuning_end_trigger = True self.tuning_end_trigger = False trace = subsample( draws=self.subsampling_rate, step=self.step_method_below, start=q0_dict, tune=0, ) # set logging back to normal _log.setLevel(logging.NOTSET) # return sample with index self.subchain_selection from the generated # sequence of length self.subsampling_rate. The index is set within # MLDA's astep() function q_dict = trace.point(self.subchain_selection) # Make sure output dict is ordered the same way as the input dict. q_dict = Point( {key: q_dict[key] for key in q0_dict.keys()}, model=self.model_below, filter_model_vars=True, ) return DictToArrayBijection.map(q_dict)