Beispiel #1
0
 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
Beispiel #2
0
 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()
Beispiel #3
0
    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
Beispiel #4
0
    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)