def __init__(self, latent_vars, data=None, discriminator=None, global_vars=None): """Create an inference algorithm. Args: discriminator: function. Function (with parameters). Unlike `GANInference`, it is interpreted as a ratio estimator rather than a discriminator. It takes three arguments: a data dict, local latent variable dict, and global latent variable dict. As with GAN discriminators, it can take a batch of data points and local variables, of size $M$, and output a vector of length $M$. global_vars: dict of RandomVariable to RandomVariable. Identifying which variables in `latent_vars` are global variables, shared across data points. These will not be encompassed in the ratio estimation problem, and will be estimated with tractable variational approximations. """ if not callable(discriminator): raise TypeError("discriminator must be a callable function.") self.discriminator = discriminator if global_vars is None: global_vars = {} check_latent_vars(global_vars) self.global_vars = global_vars # call grandparent's method; avoid parent (GANInference) super(GANInference, self).__init__(latent_vars, data)
def __init__(self, latent_vars, proposal_vars, data=None, inverse_temperatures=np.logspace(0, -2, 5), exchange_freq=0.1): """Create an inference algorithm. Args: proposal_vars: dict of RandomVariable to RandomVariable. Collection of random variables to perform inference on; each is binded to a proposal distribution $g(z' \mid z)$. inverse_temperatures: list of inverse temperature. exchange_freq: frequency of exchanging replica. """ check_latent_vars(proposal_vars) self.proposal_vars = proposal_vars self.n_replica = len(inverse_temperatures) if inverse_temperatures[0] != 1: raise ValueError("inverse_temperatures[0] must be 1.") self.inverse_temperatures = [tf.convert_to_tensor(inverse_temperature, dtype=list(latent_vars.values())[0].dtype) for inverse_temperature in inverse_temperatures] # Make replica. self.replica_vars = [] for inverse_temperature in self.inverse_temperatures: self.replica_vars.append({z: Empirical(params=tf.Variable(tf.zeros( qz.params.shape, dtype=latent_vars[z].dtype))) for z, qz in six.iteritems(latent_vars)}) self.exchange_freq = exchange_freq super(ReplicaExchangeMC, self).__init__(latent_vars, data)
def __init__(self, latent_vars, proposal_vars=None, data=None): """ Parameters ---------- proposal_vars : dict of RandomVariable to RandomVariable, optional Collection of random variables to perform inference on; each is binded to its complete conditionals which Gibbs cycles draws on. If not specified, default is to use ``ed.complete_conditional``. Examples -------- >>> x_data = np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 1]) >>> >>> p = Beta(1.0, 1.0) >>> x = Bernoulli(p=p, sample_shape=10) >>> >>> qp = Empirical(tf.Variable(tf.zeros(500))) >>> inference = ed.Gibbs({p: qp}, data={x: x_data}) """ if proposal_vars is None: proposal_vars = { z: complete_conditional(z) for z in six.iterkeys(latent_vars) } else: check_latent_vars(proposal_vars) self.proposal_vars = proposal_vars super(Gibbs, self).__init__(latent_vars, data)
def __init__(self, latent_vars, proposal_vars, data=None, inverse_temperatures=np.logspace(0, -2, 5), exchange_freq=0.1): """Create an inference algorithm. Args: proposal_vars: dict of RandomVariable to RandomVariable. Collection of random variables to perform inference on; each is binded to a proposal distribution $g(z' \mid z)$. inverse_temperatures: list of inverse temperature. exchange_freq: frequency of exchanging replica. """ check_latent_vars(proposal_vars) self.proposal_vars = proposal_vars super(ReplicaExchangeMC, self).__init__(latent_vars, data) self.n_replica = len(inverse_temperatures) if inverse_temperatures[0] != 1: raise ValueError("inverse_temperatures[0] must be 1.") self.inverse_temperatures = tf.cast(inverse_temperatures, dtype=list(self.latent_vars)[0].dtype) # Make replica. self.replica_vars = [] for i in range(self.n_replica): self.replica_vars.append({z: Empirical(params=tf.Variable(tf.zeros( qz.params.shape, dtype=self.latent_vars[z].dtype))) for z, qz in six.iteritems(self.latent_vars)}) self.exchange_freq = exchange_freq
def __init__(self, latent_vars=None, data=None): """Initialization. Parameters ---------- latent_vars : dict, optional Collection of latent variables (of type ``RandomVariable`` or ``tf.Tensor``) to perform inference on. Each random variable is binded to another random variable; the latter will infer the former conditional on data. data : dict, optional Data dictionary which binds observed variables (of type ``RandomVariable`` or ``tf.Tensor``) to their realizations (of type ``tf.Tensor``). It can also bind placeholders (of type ``tf.Tensor``) used in the model to their realizations; and prior latent variables (of type ``RandomVariable``) to posterior latent variables (of type ``RandomVariable``). Examples -------- >>> mu = Normal(loc=tf.constant(0.0), scale=tf.constant(1.0)) >>> x = Normal(loc=tf.ones(50) * mu, scale=tf.constant(1.0)) >>> >>> qmu_loc = tf.Variable(tf.random_normal([])) >>> qmu_scale = tf.nn.softplus(tf.Variable(tf.random_normal([]))) >>> qmu = Normal(loc=qmu_loc, scale=qmu_scale) >>> >>> inference = ed.Inference({mu: qmu}, data={x: tf.zeros(50)}) """ sess = get_session() if latent_vars is None: latent_vars = {} if data is None: data = {} check_latent_vars(latent_vars) self.latent_vars = latent_vars check_data(data) self.data = {} for key, value in six.iteritems(data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: self.data[key] = value elif isinstance(key, (RandomVariable, tf.Tensor)): if isinstance(value, (RandomVariable, tf.Tensor)): self.data[key] = value elif isinstance( value, (float, list, int, np.ndarray, np.number, str)): # If value is a Python type, store it in the graph. # Assign its placeholder with the key's data type. with tf.variable_scope("data"): ph = tf.placeholder(key.dtype, np.shape(value)) var = tf.Variable(ph, trainable=False, collections=[]) sess.run(var.initializer, {ph: value}) self.data[key] = var
def __init__(self, latent_vars, proposal_vars, data=None): """Create an inference algorithm. Args: proposal_vars: dict of RandomVariable to RandomVariable. Collection of random variables to perform inference on; each is binded to a proposal distribution $g(z' \mid z)$. """ check_latent_vars(proposal_vars) self.proposal_vars = proposal_vars super(MetropolisHastings, self).__init__(latent_vars, data)
def __init__(self, latent_vars, proposal_vars, data=None): """Create an inference algorithm. Args: proposal_vars: dict of RandomVariable to RandomVariable. Collection of random variables to perform inference on; each is binded to a proposal distribution $g(z' \mid z)$. """ check_latent_vars(proposal_vars) self.proposal_vars = proposal_vars super(MetropolisHastings, self).__init__(latent_vars, data)
def __init__(self, latent_vars, data=None, discriminator=None, global_vars=None): """ Parameters ---------- discriminator : function Function (with parameters). Unlike ``GANInference``, it is interpreted as a ratio estimator rather than a discriminator. It takes three arguments: a data dict, local latent variable dict, and global latent variable dict. As with GAN discriminators, it can take a batch of data points and local variables, of size :math:`M`, and output a vector of length :math:`M`. global_vars : dict of RandomVariable to RandomVariable, optional Identifying which variables in ``latent_vars`` are global variables, shared across data points. These will not be encompassed in the ratio estimation problem, and will be estimated with tractable variational approximations. Notes ----- Unlike ``GANInference``, ``discriminator`` takes dict's as input, and must subset to the appropriate values through lexical scoping from the previously defined model and latent variables. This is necessary as the discriminator can take an arbitrary set of data, latent, and global variables. Note the type for ``discriminator``'s output changes when one passes in the ``scale`` argument to ``initialize()``. + If ``scale`` has at most one item, then ``discriminator`` outputs a tensor whose multiplication with that element is broadcastable. (For example, the output is a tensor and the single scale factor is a scalar.) + If ``scale`` has more than one item, then in order to scale its corresponding output, ``discriminator`` must output a dictionary of same size and keys as ``scale``. """ if not callable(discriminator): raise TypeError("discriminator must be a callable function.") self.discriminator = discriminator if global_vars is None: global_vars = {} check_latent_vars(global_vars) self.global_vars = global_vars # call grandparent's method; avoid parent (GANInference) super(GANInference, self).__init__(latent_vars, data)
def __init__(self, latent_vars, proposal_vars=None, data=None): """Create an inference algorithm. Args: proposal_vars: dict of RandomVariable to RandomVariable, optional. Collection of random variables to perform inference on; each is binded to its complete conditionals which Gibbs cycles draws on. If not specified, default is to use `ed.complete_conditional`. """ if proposal_vars is None: proposal_vars = {z: complete_conditional(z) for z in six.iterkeys(latent_vars)} else: check_latent_vars(proposal_vars) self.proposal_vars = proposal_vars super(Gibbs, self).__init__(latent_vars, data)
def __init__(self, latent_vars=None, data=None): """Create an inference algorithm. Args: latent_vars: dict, optional. Collection of latent variables (of type `RandomVariable` or `tf.Tensor`) to perform inference on. Each random variable is binded to another random variable; the latter will infer the former conditional on data. data: dict, optional. Data dictionary which binds observed variables (of type `RandomVariable` or `tf.Tensor`) to their realizations (of type `tf.Tensor`). It can also bind placeholders (of type `tf.Tensor`) used in the model to their realizations; and prior latent variables (of type `RandomVariable`) to posterior latent variables (of type `RandomVariable`). """ sess = get_session() if latent_vars is None: latent_vars = {} if data is None: data = {} check_latent_vars(latent_vars) self.latent_vars = latent_vars check_data(data) self.data = {} for key, value in six.iteritems(data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: self.data[key] = value elif isinstance(key, (RandomVariable, tf.Tensor)): if isinstance(value, (RandomVariable, tf.Tensor)): self.data[key] = value elif isinstance( value, (float, list, int, np.ndarray, np.number, str)): # If value is a Python type, store it in the graph. # Assign its placeholder with the key's data type. with tf.variable_scope(None, default_name="data"): ph = tf.placeholder(key.dtype, np.shape(value)) var = tf.Variable(ph, trainable=False, collections=[]) sess.run(var.initializer, {ph: value}) self.data[key] = var
def __init__(self, latent_vars=None, data=None): """Create an inference algorithm. Args: latent_vars: dict, optional. Collection of latent variables (of type `RandomVariable` or `tf.Tensor`) to perform inference on. Each random variable is binded to another random variable; the latter will infer the former conditional on data. data: dict, optional. Data dictionary which binds observed variables (of type `RandomVariable` or `tf.Tensor`) to their realizations (of type `tf.Tensor`). It can also bind placeholders (of type `tf.Tensor`) used in the model to their realizations; and prior latent variables (of type `RandomVariable`) to posterior latent variables (of type `RandomVariable`). """ sess = get_session() if latent_vars is None: latent_vars = {} if data is None: data = {} check_latent_vars(latent_vars) self.latent_vars = latent_vars check_data(data) self.data = {} for key, value in six.iteritems(data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: self.data[key] = value elif isinstance(key, (RandomVariable, tf.Tensor)): if isinstance(value, (RandomVariable, tf.Tensor)): self.data[key] = value elif isinstance(value, (float, list, int, np.ndarray, np.number, str)): # If value is a Python type, store it in the graph. # Assign its placeholder with the key's data type. with tf.variable_scope("data"): ph = tf.placeholder(key.dtype, np.shape(value)) var = tf.Variable(ph, trainable=False, collections=[]) sess.run(var.initializer, {ph: value}) self.data[key] = var
def __init__(self, latent_vars, proposal_vars, data=None): """ Parameters ---------- proposal_vars : dict of RandomVariable to RandomVariable Collection of random variables to perform inference on; each is binded to a proposal distribution :math:`g(z' \mid z)`. Examples -------- >>> z = Normal(mu=0.0, sigma=1.0) >>> x = Normal(mu=tf.ones(10) * z, sigma=1.0) >>> >>> qz = Empirical(tf.Variable(tf.zeros(500))) >>> proposal_z = Normal(mu=z, sigma=0.5) >>> data = {x: np.array([0.0] * 10, dtype=np.float32)} >>> inference = ed.MetropolisHastings({z: qz}, {z: proposal_z}, data) """ check_latent_vars(proposal_vars) self.proposal_vars = proposal_vars super(MetropolisHastings, self).__init__(latent_vars, data)
def test(self): with self.test_session(): mu = Normal(0.0, 1.0) qmu = Normal(tf.Variable(0.0), tf.constant(1.0)) qmu_vec = Normal(tf.constant([0.0]), tf.constant([1.0])) check_latent_vars({mu: qmu}) check_latent_vars({mu: tf.constant(0.0)}) check_latent_vars({tf.constant(0.0): qmu}) self.assertRaises(TypeError, check_latent_vars, {mu: '5'}) self.assertRaises(TypeError, check_latent_vars, {mu: qmu_vec})
def ppc(T, data, latent_vars=None, n_samples=100): """Posterior predictive check (Rubin, 1984; Meng, 1994; Gelman, Meng, and Stern, 1996). PPC's form an empirical distribution for the predictive discrepancy, $p(T\mid x) = \int p(T(x^{\\text{rep}})\mid z) p(z\mid x) dz$ by drawing replicated data sets $x^{\\text{rep}}$ and calculating $T(x^{\\text{rep}})$ for each data set. Then it compares it to $T(x)$. If `data` is inputted with the prior predictive distribution, then it is a prior predictive check (Box, 1980). Args: T: function. Discrepancy function, which takes a dictionary of data and dictionary of latent variables as input and outputs a `tf.Tensor`. data: dict. Data to compare to. It binds observed variables (of type `RandomVariable` or `tf.Tensor`) to their realizations (of type `tf.Tensor`). It can also bind placeholders (of type `tf.Tensor`) used in the model to their realizations. latent_vars: dict, optional. Collection of random variables (of type `RandomVariable` or `tf.Tensor`) binded to their inferred posterior. This argument is used when the discrepancy is a function of latent variables. n_samples: int, optional. Number of replicated data sets. Returns: list of np.ndarray. List containing the reference distribution, which is a NumPy array with `n_samples` elements, $(T(x^{{\\text{rep}},1}, z^{1}), ..., T(x^{\\text{rep,nsamples}}, z^{\\text{nsamples}}))$ and the realized discrepancy, which is a NumPy array with `n_samples` elements, $(T(x, z^{1}), ..., T(x, z^{\\text{nsamples}})).$ #### Examples ```python # build posterior predictive after inference: # it is parameterized by a posterior sample x_post = ed.copy(x, {z: qz, beta: qbeta}) # posterior predictive check # T is a user-defined function of data, T(data) T = lambda xs, zs: tf.reduce_mean(xs[x_post]) ed.ppc(T, data={x_post: x_train}) # in general T is a discrepancy function of the data (both response and # covariates) and latent variables, T(data, latent_vars) T = lambda xs, zs: tf.reduce_mean(zs[z]) ed.ppc(T, data={y_post: y_train, x_ph: x_train}, latent_vars={z: qz, beta: qbeta}) # prior predictive check # run ppc on original x ed.ppc(T, data={x: x_train}) ``` """ sess = get_session() if not callable(T): raise TypeError("T must be a callable function.") check_data(data) if latent_vars is None: latent_vars = {} check_latent_vars(latent_vars) if not isinstance(n_samples, int): raise TypeError("n_samples must have type int.") # Build replicated latent variables. zrep = {key: tf.convert_to_tensor(value) for key, value in six.iteritems(latent_vars)} # Build replicated data. xrep = {x: (x.value() if isinstance(x, RandomVariable) else obs) for x, obs in six.iteritems(data)} # Create feed_dict for data placeholders that the model conditions # on; it is necessary for all session runs. feed_dict = {key: value for key, value in six.iteritems(data) if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type} # Calculate discrepancy over many replicated data sets and latent # variables. Trep = T(xrep, zrep) Tobs = T(data, zrep) Treps = [] Ts = [] for _ in range(n_samples): # Take a forward pass (session run) to get new samples for # each calculation of the discrepancy. # Alternatively, we could unroll the graph by registering this # operation `n_samples` times, each for different parent nodes # representing `xrep` and `zrep`. But it's expensive. Treps += [sess.run(Trep, feed_dict)] Ts += [sess.run(Tobs, feed_dict)] return [np.stack(Treps), np.stack(Ts)]
def ppc(T, data, latent_vars=None, n_samples=100): """Posterior predictive check [@rubin1984bayesianly; @meng1994posterior; @gelman1996posterior]. PPC's form an empirical distribution for the predictive discrepancy, $p(T\mid x) = \int p(T(x^{\\text{rep}})\mid z) p(z\mid x) dz$ by drawing replicated data sets $x^{\\text{rep}}$ and calculating $T(x^{\\text{rep}})$ for each data set. Then it compares it to $T(x)$. If `data` is inputted with the prior predictive distribution, then it is a prior predictive check [@box1980sampling]. Args: T: function. Discrepancy function, which takes a dictionary of data and dictionary of latent variables as input and outputs a `tf.Tensor`. data: dict. Data to compare to. It binds observed variables (of type `RandomVariable` or `tf.Tensor`) to their realizations (of type `tf.Tensor`). It can also bind placeholders (of type `tf.Tensor`) used in the model to their realizations. latent_vars: dict, optional. Collection of random variables (of type `RandomVariable` or `tf.Tensor`) binded to their inferred posterior. This argument is used when the discrepancy is a function of latent variables. n_samples: int, optional. Number of replicated data sets. Returns: list of np.ndarray. List containing the reference distribution, which is a NumPy array with `n_samples` elements, $(T(x^{{\\text{rep}},1}, z^{1}), ..., T(x^{\\text{rep,nsamples}}, z^{\\text{nsamples}}))$ and the realized discrepancy, which is a NumPy array with `n_samples` elements, $(T(x, z^{1}), ..., T(x, z^{\\text{nsamples}})).$ #### Examples ```python # build posterior predictive after inference: # it is parameterized by a posterior sample x_post = ed.copy(x, {z: qz, beta: qbeta}) # posterior predictive check # T is a user-defined function of data, T(data) T = lambda xs, zs: tf.reduce_mean(xs[x_post]) ed.ppc(T, data={x_post: x_train}) # in general T is a discrepancy function of the data (both response and # covariates) and latent variables, T(data, latent_vars) T = lambda xs, zs: tf.reduce_mean(zs[z]) ed.ppc(T, data={y_post: y_train, x_ph: x_train}, latent_vars={z: qz, beta: qbeta}) # prior predictive check # run ppc on original x ed.ppc(T, data={x: x_train}) ``` """ sess = get_session() if not callable(T): raise TypeError("T must be a callable function.") check_data(data) if latent_vars is None: latent_vars = {} check_latent_vars(latent_vars) if not isinstance(n_samples, int): raise TypeError("n_samples must have type int.") # Build replicated latent variables. zrep = { key: tf.convert_to_tensor(value) for key, value in six.iteritems(latent_vars) } # Build replicated data. xrep = { x: (x.value() if isinstance(x, RandomVariable) else obs) for x, obs in six.iteritems(data) } # Create feed_dict for data placeholders that the model conditions # on; it is necessary for all session runs. feed_dict = { key: value for key, value in six.iteritems(data) if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type } # Calculate discrepancy over many replicated data sets and latent # variables. Trep = T(xrep, zrep) Tobs = T(data, zrep) Treps = [] Ts = [] for _ in range(n_samples): # Take a forward pass (session run) to get new samples for # each calculation of the discrepancy. # Alternatively, we could unroll the graph by registering this # operation `n_samples` times, each for different parent nodes # representing `xrep` and `zrep`. But it's expensive. Treps += [sess.run(Trep, feed_dict)] Ts += [sess.run(Tobs, feed_dict)] return [np.stack(Treps), np.stack(Ts)]