def stochastic_node_mean_symbolic(approx: pm.MeanField, node, size=100, more_replacements=None, shape=None, dtype=None): """Symbolic mean of a given PyMC3 stochastic node with respect to a given variational posterior approximation. Args: approx: an instance of PyMC3 approximation node: stochastic node size: the number of samples to use for calculating the mean more_replacements: (optional) an ordered dictionary of node replacements to be applied to the computational graph before sampling shape: (optional) shape of the node dtype: (optional) dtype of the node Raises: ValueError: If `node.tag.test_value` is not present and `shape` and `dtype` are not provided Returns: Symbolic approximate mean of the stochastic node """ assert size > 0 if shape is not None and dtype is not None: cum_sum = tt.zeros(shape, dtype) elif hasattr(node.tag, 'test_value') and node.tag.test_value is not None: cum_sum = tt.zeros(node.tag.test_value.shape, node.tag.test_value.dtype) else: raise ValueError( "Can not determine the shape of the node to be sampled") if more_replacements is not None: node = th.clone(node, more_replacements, strict=False) posterior_samples = approx.random(size) node = approx.to_flat_input(node) def add_sample_to_cum_sum(posterior_sample, _cum_sum): new_sample = th.clone(node, {approx.input: posterior_sample}, strict=False) return _cum_sum + tt.patternbroadcast(new_sample, _cum_sum.broadcastable) outputs, _ = th.scan(add_sample_to_cum_sum, sequences=[posterior_samples], outputs_info=[cum_sum], n_steps=size) return outputs[-1] / size
def stochastic_node_mean_symbolic(approx: pm.MeanField, node, size=100, more_replacements=None, shape=None, dtype=None): """Symbolic mean of a given PyMC3 stochastic node with respect to a given variational posterior approximation. Args: approx: an instance of PyMC3 approximation node: stochastic node size: the number of samples to use for calculating the mean more_replacements: (optional) an ordered dictionary of node replacements to be applied to the computational graph before sampling shape: (optional) shape of the node dtype: (optional) dtype of the node Raises: ValueError: If `node.tag.test_value` is not present and `shape` and `dtype` are not provided Returns: Symbolic approximate mean of the stochastic node """ assert size > 0 if shape is not None and dtype is not None: cum_sum = tt.zeros(shape, dtype) elif hasattr(node.tag, 'test_value') and node.tag.test_value is not None: cum_sum = tt.zeros(node.tag.test_value.shape, node.tag.test_value.dtype) else: raise ValueError("Can not determine the shape of the node to be sampled") if more_replacements is not None: node = th.clone(node, more_replacements, strict=False) posterior_samples = approx.random(size) node = approx.to_flat_input(node) def add_sample_to_cum_sum(posterior_sample, _cum_sum): new_sample = th.clone(node, {approx.input: posterior_sample}, strict=False) return _cum_sum + tt.patternbroadcast(new_sample, _cum_sum.broadcastable) outputs, _ = th.scan(add_sample_to_cum_sum, sequences=[posterior_samples], outputs_info=[cum_sum], n_steps=size) return outputs[-1] / size
def get_sampling_generator_for_model_approximation(model_approx: pm.MeanField, model_var_name: str, num_samples: int = 250) -> Generator: """Get a generator that returns samples of a precomputed model approximation for a specific variable in that model Args: model_approx: an instance of PyMC3 meanfield approximation model_var_name: a stochastic node in the model num_samples: number of samples to draw Returns: A generator that will yield `num_samples` samples from an approximation to a posterior """ return (model_approx.sample()[model_var_name] for _ in range(num_samples))
def get_sampling_generator_for_model_approximation(model_approx: pm.MeanField, node, num_samples: int = 20) -> Generator: """Get a generator that returns samples of a precomputed model approximation for a specific variable in that model Args: model_approx: an instance of PyMC3 mean-field approximation node: a stochastic node in the model num_samples: number of samples to draw Returns: A generator that will yield `num_samples` samples from an approximation to a posterior """ sample = model_approx.sample_node(node, size=1)[0] return (sample.eval() for _ in range(num_samples))