def deterministics_callback(q_samples): st = flow.SamplingState.from_values( q_samples, observed_values=self.state.observed_values) _, st = flow.evaluate_model_transformed(self.model, state=st) for transformed_name in st.transformed_values: untransformed_name = NameParts.from_name( transformed_name).full_untransformed_name st.deterministics[ untransformed_name] = st.untransformed_values.pop( untransformed_name) return st.deterministics
def deterministics_callback(*values, **kwargs): if kwargs and values: raise TypeError("Either list state should be passed or a dict one") elif values: kwargs = dict(zip(unobserved_keys, values)) st = flow.SamplingState.from_values(kwargs, observed_values=observed_var) _, st = flow.evaluate_model_transformed(model, state=st) for transformed_name in st.transformed_values: untransformed_name = NameParts.from_name(transformed_name).full_untransformed_name st.deterministics[untransformed_name] = st.untransformed_values.pop(untransformed_name) return st.deterministics.values()
def sample(self, n): """Generate samples from posterior distribution.""" q_samples = dict(zip(self.unobserved_keys, self.approx.sample(n))) # TODO - Account for deterministics as well. # For all transformed_variables, apply inverse of bijector to sampled values to match support in constraint space. _, st = flow.evaluate_model(self.model) for transformed_name in self.state.transformed_values: untransformed_name = NameParts.from_name( transformed_name).full_untransformed_name transform = st.distributions[untransformed_name].transform if transform.JacobianPreference == JacobianPreference.Forward: q_samples[untransformed_name] = transform.forward( q_samples[transformed_name]) else: q_samples[untransformed_name] = transform.inverse( q_samples[transformed_name]) # Add a new axis so as n_chains=1 for InferenceData: handles shape issues trace = {k: v.numpy()[np.newaxis] for k, v in q_samples.items()} trace = az.from_dict(trace, observed_data=self.state.observed_values) return trace
def __call__(self, *args, name=_no_name_provided, keep_auxiliary=None, keep_return=None, **kwargs): """ Evaluate the model. Model evaluation usually comes with :code:`yield` keyword, see Examples below Parameters ---------- name : str The desired name for the model, by default, it is inferred from the model declaration context, but can be used just once keep_auxiliary : bool Whether to override the default variable for `keep_auxiliary` keep_return: bool Whether to override the default variable for `keep_return` args : tuple positional conditioners for generative process kwargs : dict keyword conditioners for the generative process Returns ------- Model The conditioned generative process, for which we can obtain generator (generative process) with :code:`iter` Examples -------- >>> import pymc4 as pm >>> from pymc4 import distributions as dist >>> @pm.model # keep_return is True by default ... def nested_model(cond): ... norm = yield dist.Normal("n", cond, 1) ... return norm >>> @pm.model ... def main_model(): ... norm = yield dist.Normal("n", 0, 1) ... result = yield nested_model(norm, name="a") ... return result >>> ret, state = pm.evaluate_model(main_model()) >>> print(sorted(state.untransformed_values)) ['main_model', 'main_model/a', 'main_model/a/n', 'main_model/n'] Setting :code`keep_return=False` for the nested model we can remove ``'main_model/a'`` from output state >>> @pm.model ... def main_model(): ... norm = yield dist.Normal("n", 0, 1) ... result = yield nested_model(norm, name="a", keep_return=False) ... return result >>> ret, state = pm.evaluate_model(main_model()) >>> print(sorted(state.untransformed_values)) ['main_model', 'main_model/a/n', 'main_model/n'] We can also observe some variables setting :code:`observed=True` in a distribution >>> @pm.model # keep_return is True by default ... def main_model(): ... norm = yield dist.Normal("n", 0, 1, observed=0.) ... result = yield nested_model(norm, name="a") ... return result >>> ret, state = pm.evaluate_model(main_model()) >>> print(sorted(state.untransformed_values)) ['main_model', 'main_model/a', 'main_model/a/n'] >>> print(sorted(state.observed_values)) ['main_model/n'] """ genfn = functools.partial(self.template, *args, **kwargs) name = get_name(self.name, self.template, name) if name is not None and not NameParts.is_valid_untransformed_name( name): # throw an informative message to fix a name raise ValueError(NameParts.UNTRANSFORMED_NAME_ERROR_MESSAGE) if keep_auxiliary is None: keep_auxiliary = self.keep_auxiliary if keep_return is None: keep_return = self.keep_return return Model(genfn, name=name, keep_auxiliary=keep_auxiliary, keep_return=keep_return)