def __init__( self, draws=2000, start=None, model=None, random_seed=None, threshold=0.5, ): """ Parameters ---------- draws: int The number of samples to draw from the posterior (i.e. last stage). And also the number of independent chains. Defaults to 2000. start: dict, or array of dict Starting point in parameter space. It should be a list of dict with length `chains`. When None (default) the starting point is sampled from the prior distribution. model: Model (optional if in ``with`` context)). random_seed: int Value used to initialize the random number generator. threshold: float Determines the change of beta from stage to stage, i.e.indirectly the number of stages, the higher the value of `threshold` the higher the number of stages. Defaults to 0.5. It should be between 0 and 1. """ self.draws = draws self.start = start if threshold < 0 or threshold > 1: raise ValueError( f"Threshold value {threshold} must be between 0 and 1") self.threshold = threshold self.model = model self.rng = np.random.default_rng(seed=random_seed) self.model = modelcontext(model) self.variables = inputvars(self.model.value_vars) self.var_info = {} self.tempered_posterior = None self.prior_logp = None self.likelihood_logp = None self.tempered_posterior_logp = None self.prior_logp_func = None self.likelihood_logp_func = None self.log_marginal_likelihood = 0 self.beta = 0 self.iteration = 0 self.resampling_indexes = None self.weights = np.ones(self.draws) / self.draws
def __init__(self, vars=None, prior_cov=None, prior_chol=None, model=None, **kwargs): self.model = modelcontext(model) chol = get_chol(prior_cov, prior_chol) self.prior_chol = at.as_tensor_variable(chol) if vars is None: vars = self.model.cont_vars else: vars = [self.model.rvs_to_values.get(var, var) for var in vars] vars = inputvars(vars) super().__init__(vars, [self.model.compile_logp()], **kwargs)
def __init__(self, vars=None, w=1.0, tune=True, model=None, iter_limit=np.inf, **kwargs): self.model = modelcontext(model) self.w = w self.tune = tune self.n_tunes = 0.0 self.iter_limit = iter_limit if vars is None: vars = self.model.cont_vars else: vars = [self.model.rvs_to_values.get(var, var) for var in vars] vars = inputvars(vars) super().__init__(vars, [self.model.compile_logp()], **kwargs)
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 find_MAP(start=None, vars=None, method="L-BFGS-B", return_raw=False, include_transformed=True, progressbar=True, maxeval=5000, model=None, *args, seed: Optional[int] = None, **kwargs): """Finds the local maximum a posteriori point given a model. `find_MAP` should not be used to initialize the NUTS sampler. Simply call ``pymc.sample()`` and it will automatically initialize NUTS in a better way. Parameters ---------- start: `dict` of parameter values (Defaults to `model.initial_point`) vars: list List of variables to optimize and set to optimum (Defaults to all continuous). method: string or callable Optimization algorithm (Defaults to 'L-BFGS-B' unless discrete variables are specified in `vars`, then `Powell` which will perform better). For instructions on use of a callable, refer to SciPy's documentation of `optimize.minimize`. return_raw: bool Whether to return the full output of scipy.optimize.minimize (Defaults to `False`) include_transformed: bool, optional defaults to True Flag for reporting automatically transformed variables in addition to original variables. progressbar: bool, optional defaults to True Whether or not to display a progress bar in the command line. maxeval: int, optional, defaults to 5000 The maximum number of times the posterior distribution is evaluated. model: Model (optional if in `with` context) *args, **kwargs Extra args passed to scipy.optimize.minimize Notes ----- Older code examples used `find_MAP` to initialize the NUTS sampler, but this is not an effective way of choosing starting values for sampling. As a result, we have greatly enhanced the initialization of NUTS and wrapped it inside ``pymc.sample()`` and you should thus avoid this method. """ model = modelcontext(model) if vars is None: vars = model.cont_vars if not vars: raise ValueError("Model has no unobserved continuous variables.") vars = inputvars(vars) disc_vars = list(typefilter(vars, discrete_types)) allinmodel(vars, model) ipfn = make_initial_point_fn( model=model, jitter_rvs={}, return_transformed=True, overrides=start, ) if seed is None: seed = model.rng_seeder.randint(2**30, dtype=np.int64) start = ipfn(seed) model.check_start_vals(start) x0 = DictToArrayBijection.map(start) # TODO: If the mapping is fixed, we can simply create graphs for the # mapping and avoid all this bijection overhead def logp_func(x): return DictToArrayBijection.mapf(model.fastlogp_nojac)(RaveledVars( x, x0.point_map_info)) try: # This might be needed for calls to `dlogp_func` # start_map_info = tuple((v.name, v.shape, v.dtype) for v in vars) def dlogp_func(x): return DictToArrayBijection.mapf(model.fastdlogp_nojac(vars))( RaveledVars(x, x0.point_map_info)) compute_gradient = True except (AttributeError, NotImplementedError, tg.NullTypeGradError): compute_gradient = False if disc_vars or not compute_gradient: pm._log.warning( "Warning: gradient not available." + "(E.g. vars contains discrete variables). MAP " + "estimates may not be accurate for the default " + "parameters. Defaulting to non-gradient minimization " + "'Powell'.") method = "Powell" if compute_gradient: cost_func = CostFuncWrapper(maxeval, progressbar, logp_func, dlogp_func) else: cost_func = CostFuncWrapper(maxeval, progressbar, logp_func) try: opt_result = minimize(cost_func, x0.data, method=method, jac=compute_gradient, *args, **kwargs) mx0 = opt_result["x"] # r -> opt_result except (KeyboardInterrupt, StopIteration) as e: mx0, opt_result = cost_func.previous_x, None if isinstance(e, StopIteration): pm._log.info(e) finally: last_v = cost_func.n_eval if progressbar: assert isinstance(cost_func.progress, ProgressBar) cost_func.progress.total = last_v cost_func.progress.update(last_v) print(file=sys.stdout) mx0 = RaveledVars(mx0, x0.point_map_info) vars = get_default_varnames(model.unobserved_value_vars, include_transformed) mx = { var.name: value for var, value in zip( vars, model.fastfn(vars)(DictToArrayBijection.rmap(mx0))) } if return_raw: return mx, opt_result else: return mx
def __init__(self, vars=None, num_particles=40, max_stages=100, batch="auto", model=None): _log.warning("BART is experimental. Use with caution.") model = modelcontext(model) initial_values = model.recompute_initial_point() value_bart = inputvars(vars)[0] self.bart = model.values_to_rvs[value_bart].owner.op self.X = self.bart.X self.Y = self.bart.Y self.missing_data = np.any(np.isnan(self.X)) self.m = self.bart.m self.alpha = self.bart.alpha self.k = self.bart.k self.alpha_vec = self.bart.split_prior if self.alpha_vec is None: self.alpha_vec = np.ones(self.X.shape[1]) self.init_mean = self.Y.mean() # if data is binary Y_unique = np.unique(self.Y) if Y_unique.size == 2 and np.all(Y_unique == [0, 1]): self.mu_std = 6 / (self.k * self.m ** 0.5) # maybe we need to check for count data else: self.mu_std = (2 * self.Y.std()) / (self.k * self.m ** 0.5) self.num_observations = self.X.shape[0] self.num_variates = self.X.shape[1] self.available_predictors = list(range(self.num_variates)) self.sum_trees = np.full_like(self.Y, self.init_mean).astype(aesara.config.floatX) self.a_tree = Tree.init_tree( leaf_node_value=self.init_mean / self.m, idx_data_points=np.arange(self.num_observations, dtype="int32"), ) self.mean = fast_mean() self.normal = NormalSampler() self.prior_prob_leaf_node = compute_prior_probability(self.alpha) self.ssv = SampleSplittingVariable(self.alpha_vec) self.tune = True if batch == "auto": batch = max(1, int(self.m * 0.1)) self.batch = (batch, batch) else: if isinstance(batch, (tuple, list)): self.batch = batch else: self.batch = (batch, batch) self.log_num_particles = np.log(num_particles) self.indices = list(range(2, num_particles)) self.len_indices = len(self.indices) self.max_stages = max_stages shared = make_shared_replacements(initial_values, vars, model) self.likelihood_logp = logp(initial_values, [model.datalogpt], vars, shared) self.all_particles = [] for i in range(self.m): self.a_tree.leaf_node_value = self.init_mean / self.m p = ParticleTree(self.a_tree) self.all_particles.append(p) self.all_trees = np.array([p.tree for p in self.all_particles]) super().__init__(vars, shared)