def __init__(self, layers=None): get_session() if layers is None: self.layers = [] self.shape = [] self.n_vars = 0 self.n_params = 0 self.is_differentiable = True self.is_multivariate = [] self.is_reparameterized = True self.is_normal = True self.is_entropy = True else: self.layers = layers self.shape = [layer.shape for layer in self.layers] self.n_vars = sum([layer.n_vars for layer in self.layers]) self.n_params = sum([layer.n_params for layer in self.layers]) self.is_differentiable = all([layer.is_differentiable for layer in self.layers]) self.is_multivariate = [layer.is_multivariate for layer in self.layers] self.is_reparameterized = all([layer.is_reparameterized for layer in self.layers]) self.is_normal = all([isinstance(layer, Normal) for layer in self.layers]) self.is_entropy = all(['entropy' in layer.__class__.__dict__ for layer in self.layers])
def __init__(self, layers=[]): get_session() self.layers = layers if layers == []: self.num_factors = 0 self.num_vars = 0 self.num_params = 0 self.is_reparam = True self.is_normal = True self.is_entropy = True self.sample_tensor = [] else: self.num_factors = sum( [layer.num_factors for layer in self.layers]) self.num_vars = sum([layer.num_vars for layer in self.layers]) self.num_params = sum([layer.num_params for layer in self.layers]) self.is_reparam = all([ 'reparam' in layer.__class__.__dict__ for layer in self.layers ]) self.is_normal = all( [isinstance(layer, Normal) for layer in self.layers]) self.is_entropy = all([ 'entropy' in layer.__class__.__dict__ for layer in self.layers ]) self.sample_tensor = [layer.sample_tensor for layer in self.layers]
def __init__(self, layers=None): get_session() if layers is None: self.layers = [] self.shape = [] self.num_vars = 0 self.num_params = 0 self.is_reparam = True self.is_normal = True self.is_entropy = True self.sample_tensor = [] self.is_multivariate = [] else: self.layers = layers self.shape = [layer.shape for layer in self.layers] self.num_vars = sum([layer.num_vars for layer in self.layers]) self.num_params = sum([layer.num_params for layer in self.layers]) self.is_reparam = all(['reparam' in layer.__class__.__dict__ for layer in self.layers]) self.is_normal = all([isinstance(layer, Normal) for layer in self.layers]) self.is_entropy = all(['entropy' in layer.__class__.__dict__ for layer in self.layers]) self.sample_tensor = [layer.sample_tensor for layer in self.layers] self.is_multivariate = [layer.is_multivariate for layer in self.layers]
def __init__(self, layers=None): get_session() if layers is None: self.layers = [] self.shape = [] self.n_vars = 0 self.n_params = 0 self.is_differentiable = True self.is_multivariate = [] self.is_reparameterized = True self.is_normal = True self.is_entropy = True else: self.layers = layers self.shape = [layer.shape for layer in self.layers] self.n_vars = sum([layer.n_vars for layer in self.layers]) self.n_params = sum([layer.n_params for layer in self.layers]) self.is_differentiable = all( [layer.is_differentiable for layer in self.layers]) self.is_multivariate = [ layer.is_multivariate for layer in self.layers ] self.is_reparameterized = all( [layer.is_reparameterized for layer in self.layers]) self.is_normal = all( [isinstance(layer, Normal) for layer in self.layers]) self.is_entropy = all([ 'entropy' in layer.__class__.__dict__ for layer in self.layers ])
def finalize(self): get_session() x = self.data.sample(self.n_data) # uses mini-batch z, _ = self.variational.sample() var_list = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='variational') inv_cov = hessian(self.model.log_prob(x, z), var_list) print("Precision matrix:") print(inv_cov.eval())
def finalize(self): """Function to call after convergence. Computes the Hessian at the mode. """ get_session() x = self.data.sample(self.n_data) # uses mini-batch z = self.variational.sample() var_list = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='variational') inv_cov = hessian(self.model.log_prob(x, z), var_list) print("Precision matrix:") print(inv_cov.eval())
def __init__(self, model, data=Data()): """Initialization. Calls ``util.get_session()`` Parameters ---------- model : ed.Model probability model data : ed.Data, optional observed data """ self.model = model self.data = data get_session()
def update(self, feed_dict=None): """Run one iteration of inference. Parameters ---------- feed_dict : dict, optional Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. Returns ------- dict Dictionary of algorithm-specific information. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor): feed_dict[key] = value sess = get_session() t = sess.run(self.increment_t) if self.debug: sess.run(self.op_check) if self.logging and self.n_print != 0: if t == 1 or t % self.n_print == 0: summary = sess.run(self.summarize, feed_dict) self.train_writer.add_summary(summary, t) return {'t': t}
def print_params(self): sess = get_session() m, s = sess.run([self.m, self.s]) print("mean:") print(m) print("std dev:") print(s)
def print_params(self): sess = get_session() a, b = sess.run([self.a, self.b]) print("shape:") print(a) print("scale:") print(b)
def update(self, feed_dict=None): """Run one iteration of optimization. Args: feed_dict: dict, optional. Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. Returns: dict. Dictionary of algorithm-specific information. In this case, the loss function value after one iteration. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: feed_dict[key] = value sess = get_session() _, t, loss = sess.run([self.train, self.increment_t, self.loss], feed_dict) if self.debug: sess.run(self.op_check, feed_dict) if self.logging and self.n_print != 0: if t == 1 or t % self.n_print == 0: summary = sess.run(self.summarize, feed_dict) self.train_writer.add_summary(summary, t) return {'t': t, 'loss': loss}
def update(self, feed_dict=None): """Run one iteration of inference. Any derived class of `Inference` **must** implement this method. Args: feed_dict: dict, optional. Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. Returns: dict. Dictionary of algorithm-specific information. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: feed_dict[key] = value sess = get_session() t = sess.run(self.increment_t) if self.debug: sess.run(self.op_check, feed_dict) if self.logging and self.n_print != 0: if t == 1 or t % self.n_print == 0: summary = sess.run(self.summarize, feed_dict) self.train_writer.add_summary(summary, t) return {'t': t}
def update(self, feed_dict=None): """Run one iteration of sampling for Monte Carlo. Parameters ---------- feed_dict : dict, optional Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. Returns ------- dict Dictionary of algorithm-specific information. In this case, the acceptance rate of samples since (and including) this iteration. Notes ----- We run the increment of t separately from other ops. Whether the others op run with the t before incrementing or after incrementing depends on which is run faster in the TensorFlow graph. Running it separately forces a consistent behavior. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor): feed_dict[key] = value sess = get_session() _, accept_rate = sess.run([self.train, self.n_accept_over_t], feed_dict) t = sess.run(self.increment_t) return {'t': t, 'accept_rate': accept_rate}
def update(self, feed_dict=None): """Run one iteration of optimizer for variational inference. Parameters ---------- feed_dict : dict, optional Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. Returns ------- dict Dictionary of algorithm-specific information. In this case, the loss function value after one iteration. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor): feed_dict[key] = value sess = get_session() _, t, loss = sess.run([self.train, self.increment_t, self.loss], feed_dict) return {'t': t, 'loss': loss}
def update(self, feed_dict=None): """Run one iteration of optimization. Args: feed_dict: dict, optional. Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. Returns: dict. Dictionary of algorithm-specific information. In this case, the loss function value after one iteration. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: feed_dict[key] = value sess = get_session() _, t, loss = sess.run([self.train, self.increment_t, self.loss], feed_dict) if self.debug: sess.run(self.op_check, feed_dict) if self.logging and self.n_print != 0: if t == 1 or t % self.n_print == 0: if self.summarize is not None: summary = sess.run(self.summarize, feed_dict) self.train_writer.add_summary(summary, t) return {'t': t, 'loss': loss}
def __init__(self, model, data=None): """Initialization. Parameters ---------- model : ed.Model probability model data : dict, optional Data dictionary. For TensorFlow, Python, and Stan models, the key type is a string; for PyMC3, the key type is a Theano shared variable. For TensorFlow, Python, and PyMC3 models, the value type is a NumPy array or TensorFlow tensor; for Stan, the value type is the type according to the Stan program's data block. Notes ----- If ``data`` is not passed in, the dictionary is empty. Three options are available for batch training: 1. internally if user passes in data as a dictionary of NumPy arrays; 2. externally if user passes in data as a dictionary of TensorFlow placeholders (and manually feeds them); 3. externally if user passes in data as TensorFlow tensors which are the outputs of data readers. """ sess = get_session() self.model = model if data is None: data = {} if isinstance(model, StanModel): # Stan models do no support data subsampling because they # take arbitrary data structure types in the data block # and not just NumPy arrays (this makes it unamenable to # TensorFlow placeholders). Therefore fix the data # dictionary ``self.data`` at compile time to ``data``. self.data = data else: self.data = {} for key, value in six.iteritems(data): if isinstance(value, tf.Tensor): # If ``data`` has TensorFlow placeholders, the user # must manually feed them at each step of # inference. # If ``data`` has tensors that are the output of # data readers, then batch training operates # according to the reader. self.data[key] = value elif isinstance(value, np.ndarray): # If ``data`` has NumPy arrays, store the data # in the computational graph. placeholder = tf.placeholder(tf.float32, value.shape) var = tf.Variable(placeholder, trainable=False, collections=[]) self.data[key] = var sess.run(var.initializer, {placeholder: value}) else: raise NotImplementedError()
def update(self, feed_dict=None, variables=None): """Run one iteration of optimization. Parameters ---------- feed_dict : dict, optional Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. variables : str, optional Which set of variables to update. Either "Disc" or "Gen". Default is both. Returns ------- dict Dictionary of algorithm-specific information. In this case, the iteration number and generative and discriminative losses. Notes ----- The outputted iteration number is the total number of calls to ``update``. Each update may include updating only a subset of parameters. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor): if "Placeholder" in key.op.type: feed_dict[key] = value sess = get_session() if variables is None: _, _, t, loss, loss_d = sess.run([ self.train, self.train_d, self.increment_t, self.loss, self.loss_d ], feed_dict) elif variables == "Gen": _, t, loss = sess.run([self.train, self.increment_t, self.loss], feed_dict) loss_d = 0.0 elif variables == "Disc": _, t, loss_d = sess.run( [self.train_d, self.increment_t, self.loss_d], feed_dict) loss = 0.0 else: raise NotImplementedError() if self.debug: sess.run(self.op_check) if self.logging and self.n_print != 0: if t == 1 or t % self.n_print == 0: if self.summarize is not None: summary = sess.run(self.summarize, feed_dict) self.train_writer.add_summary(summary, t) return {'t': t, 'loss': loss, 'loss_d': loss_d}
def __str__(self): try: sess = get_session() mu, chol = sess.run([self.distribution.mu, self.distribution.chol]) return "mu: \n" + mu.__str__() + "\n" + \ "chol: \n" + chol.__str__() except: return super(MultivariateNormalCholesky, self).__str__()
def update(self, feed_dict=None, variables=None): info_dict = super(WGANInference, self).update(feed_dict, variables) sess = get_session() if self.clip_op is not None and variables in (None, "Disc"): sess.run(self.clip_op) return info_dict
def update(self, feed_dict=None, variables=None): info_dict = super(WGANInference, self).update(feed_dict, variables) sess = get_session() if variables is None or variables == "Disc": sess.run(self.clip_d) return info_dict
def __str__(self): try: sess = get_session() n, alpha = sess.run([self.distribution.n, self.distribution.alpha]) return "n: \n" + n.__str__() + "\n" + \ "alpha: \n" + alpha.__str__() except: return super(DirichletMultinomial, self).__str__()
def __str__(self): try: sess = get_session() a, b = sess.run([self.distribution.a, self.distribution.b]) return "a: \n" + a.__str__() + "\n" + \ "b: \n" + b.__str__() except: return super(Beta, self).__str__()
def sample(self, size=1): """x ~ p(x | params)""" sess = get_session() a, b = sess.run([self.alpha, self.beta]) x = np.zeros((size, self.num_vars)) for d in range(self.num_vars): x[:, d] = invgamma.rvs(a[d], b[d], size=size) return x
def sample(self, size=1): """z ~ q(z | lambda)""" sess = get_session() a, b = sess.run([self.a, self.b]) z = np.zeros((size, self.num_vars)) for d in range(self.num_vars): z[:, d] = invgamma.rvs(a[d], b[d], size=size) return z
def __str__(self): try: sess = get_session() loc, scale = sess.run( [self.distribution.loc, self.distribution.scale]) return "loc: \n" + loc.__str__() + "\n" + \ "scale: \n" + scale.__str__() except: return super(Laplace, self).__str__()
def __str__(self): try: sess = get_session() mu, diag_stdev = sess.run( [self.distribution.mu, self.distribution.diag_stdev]) return "mu: \n" + mu.__str__() + "\n" + \ "diag_stdev: \n" + diag_stdev.__str__() except: return super(MultivariateNormalDiag, self).__str__()
def __str__(self): try: sess = get_session() alpha, beta = sess.run( [self.distribution.alpha, self.distribution.beta]) return "alpha: \n" + alpha.__str__() + "\n" + \ "beta: \n" + beta.__str__() except: return super(InverseGamma, self).__str__()
def __str__(self): try: sess = get_session() mu, sigma = sess.run( [self.distribution.mu, self.distribution.sigma]) return "mu: \n" + mu.__str__() + "\n" + \ "sigma: \n" + sigma.__str__() except: return super(Normal, self).__str__()
def update(self, feed_dict=None, variables=None): """Run one iteration of optimization. Args: feed_dict: dict, optional. Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. variables: str, optional. Which set of variables to update. Either "Disc" or "Gen". Default is both. Returns: dict. Dictionary of algorithm-specific information. In this case, the iteration number and generative and discriminative losses. #### Notes The outputted iteration number is the total number of calls to `update`. Each update may include updating only a subset of parameters. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: feed_dict[key] = value sess = get_session() if variables is None: _, _, t, loss, loss_d = sess.run( [self.train, self.train_d, self.increment_t, self.loss, self.loss_d], feed_dict) elif variables == "Gen": _, t, loss = sess.run( [self.train, self.increment_t, self.loss], feed_dict) loss_d = 0.0 elif variables == "Disc": _, t, loss_d = sess.run( [self.train_d, self.increment_t, self.loss_d], feed_dict) loss = 0.0 else: raise NotImplementedError("variables must be None, 'Gen', or 'Disc'.") if self.debug: sess.run(self.op_check, feed_dict) if self.logging and self.n_print != 0: if t == 1 or t % self.n_print == 0: if self.summarize is not None: summary = sess.run(self.summarize, feed_dict) self.train_writer.add_summary(summary, t) return {'t': t, 'loss': loss, 'loss_d': loss_d}
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 update(self): """Run one iteration of optimizer for variational inference. Returns ------- loss : double Loss function values after one iteration. """ sess = get_session() _, loss = sess.run([self.train, self.loss]) return loss
def update(self): """Runs one iteration of KLpq minimization. Returns ------- loss : double KLpq loss function value after one iteration. """ sess = get_session() feed_dict = self.variational.np_dict(self.zs) _, loss = sess.run([self.train, self.loss], feed_dict) return loss
def __str__(self): try: sess = get_session() df, mu, sigma = sess.run([ self.distribution.df, self.distribution.mu, self.distribution.sigma ]) return "df: \n" + df.__str__() + "\n" + \ "mu: \n" + mu.__str__() + "\n" + \ "sigma: \n" + sigma.__str__() except: return super(StudentT, self).__str__()
def __init__(self, layers=[]): get_session() self.layers = layers if layers == []: self.num_factors = 0 self.num_vars = 0 self.num_params = 0 self.is_reparam = True self.is_normal = True self.is_entropy = True self.sample_tensor = [] else: self.num_factors = sum([layer.num_factors for layer in self.layers]) self.num_vars = sum([layer.num_vars for layer in self.layers]) self.num_params = sum([layer.num_params for layer in self.layers]) self.is_reparam = all(['reparam' in layer.__class__.__dict__ for layer in self.layers]) self.is_normal = all([isinstance(layer, Normal) for layer in self.layers]) self.is_entropy = all(['entropy' in layer.__class__.__dict__ for layer in self.layers]) self.sample_tensor = [layer.sample_tensor for layer in self.layers]
def __init__(self, shape=1): """Initialize. Parameters ---------- shape : int, list, or tuple, optional Shape of random variable(s). If ``is_multivariate=True``, then the inner-most (right-most) dimension indicates the dimension of the multivariate random variable. Otherwise, all dimensions are conceptually the same. """ get_session() if isinstance(shape, int): shape = (shape, ) elif isinstance(shape, list): shape = tuple(shape) self.shape = shape self.num_vars = np.prod(self.shape) self.num_params = None self.sample_tensor = False self.is_multivariate = False
def __init__(self, shape=1): """Initialize. Parameters ---------- shape : int, list, or tuple, optional Shape of random variable(s). If ``is_multivariate=True``, then the inner-most (right-most) dimension indicates the multivariate dimension. Otherwise, all dimensions are conceptually the same. """ get_session() if isinstance(shape, int): shape = (shape, ) elif isinstance(shape, list): shape = tuple(shape) self.shape = shape self.n_vars = np.prod(self.shape) self.n_params = None self.is_differentiable = False self.is_multivariate = False self.is_reparameterized = False
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 update(self, feed_dict=None): """Run one iteration of sampling for Monte Carlo. Parameters ---------- feed_dict : dict, optional Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. Returns ------- dict Dictionary of algorithm-specific information. In this case, the acceptance rate of samples since (and including) this iteration. Notes ----- We run the increment of ``t`` separately from other ops. Whether the others op run with the ``t`` before incrementing or after incrementing depends on which is run faster in the TensorFlow graph. Running it separately forces a consistent behavior. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor): feed_dict[key] = value sess = get_session() _, accept_rate = sess.run([self.train, self.n_accept_over_t], feed_dict) t = sess.run(self.increment_t) if self.debug: sess.run(self.op_check) if self.logging and self.n_print != 0: if t == 1 or t % self.n_print == 0: summary = sess.run(self.summarize, feed_dict) self.train_writer.add_summary(summary, t) return {'t': t, 'accept_rate': accept_rate}
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 update(self, feed_dict=None): """Run one iteration of sampling. Args: feed_dict: dict. Feed dictionary for a TensorFlow session run. It is used to feed placeholders that are not fed during initialization. Returns: dict. Dictionary of algorithm-specific information. In this case, the acceptance rate of samples since (and including) this iteration. #### Notes We run the increment of `t` separately from other ops. Whether the others op run with the `t` before incrementing or after incrementing depends on which is run faster in the TensorFlow graph. Running it separately forces a consistent behavior. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: feed_dict[key] = value sess = get_session() _, accept_rate = sess.run([self.train, self.n_accept_over_t], feed_dict) t = sess.run(self.increment_t) if self.debug: sess.run(self.op_check, feed_dict) if self.logging and self.n_print != 0: if t == 1 or t % self.n_print == 0: summary = sess.run(self.summarize, feed_dict) self.train_writer.add_summary(summary, t) return {'t': t, 'accept_rate': accept_rate}
def finalize(self, feed_dict=None): """Function to call after convergence. Computes the Hessian at the mode. Args: feed_dict: dict, optional. Feed dictionary for a TensorFlow session run during evaluation of Hessian. It is used to feed placeholders that are not fed during initialization. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: feed_dict[key] = value sess = get_session() sess.run(self.finalize_ops, feed_dict) super(Laplace, self).finalize()
def finalize(self, feed_dict=None): """Function to call after convergence. Computes the Hessian at the mode. Parameters ---------- feed_dict : dict, optional Feed dictionary for a TensorFlow session run during evaluation of Hessian. It is used to feed placeholders that are not fed during initialization. """ if feed_dict is None: feed_dict = {} for key, value in six.iteritems(self.data): if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type: feed_dict[key] = value var_list = list(six.itervalues(self.latent_vars)) hessians = tf.hessians(self.loss, var_list) assign_ops = [] for z, hessian in zip(six.iterkeys(self.latent_vars), hessians): qz = self.latent_vars_normal[z] sigma_var = get_variables(qz.sigma)[0] if isinstance(qz, MultivariateNormalCholesky): sigma = tf.matrix_inverse(tf.cholesky(hessian)) elif isinstance(qz, MultivariateNormalDiag): sigma = 1.0 / tf.diag_part(hessian) else: # qz is MultivariateNormalFull sigma = tf.matrix_inverse(hessian) assign_ops.append(sigma_var.assign(sigma)) sess = get_session() sess.run(assign_ops, feed_dict) self.latent_vars = self.latent_vars_normal.copy() del self.latent_vars_normal super(Laplace, self).finalize()
def eval_model(Xx, Yy, nom, probabilities=None, dataset=None, qw=None, qb=None): if probabilities is None: ans = get_y_preds(Xx, Yy, qvars=[qw, qb], n_samples=10000) zw, zb = [np.mean(an, axis=0) for an in ans] probabilities = sigmoid(Xx.dot(zw) + zb) ins = pd.DataFrame(probabilities, columns=['prob']) ins['target'] = Yy ins['guess'] = ins['prob'].round().clip(0, 1) print(nom, '\n------') print('acc:', (ins['target'] == ins['guess']).mean()) print('sk.logloss:', log_loss(ins['target'], ins['prob'])) sess = get_session() print('ed.logloss (corrected):', sess.run( binary_crossentropy(ins['target'], -np.log(1 / ins['prob'] - 1)))) print('ed.logloss (current):', sess.run(binary_crossentropy(ins['target'], ins['prob']))) if dataset is not None: if nom == 'ins': eras = dataset.training_data['era'] else: eras = dataset.prediction_data['era'] big_ins = pd.concat([pd.DataFrame(Xx), eras, ins], axis=1).dropna() consist = 0 for x in big_ins.era.unique(): lil_ins = big_ins[big_ins.era == x] lloss = log_loss(lil_ins['target'], lil_ins['prob']) print(x.replace("era", "regime"), '(%s) :' % str(float(len(lil_ins)) / len(big_ins))[:5], (lil_ins['target'] == lil_ins['guess']).mean(), lloss) if lloss < -np.log(.5): consist += 1 print('consistency:', float(consist) / len(big_ins.era.unique())) print('') return ins
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 __init__(self, num_factors=1): get_session() self.num_factors = num_factors self.num_vars = None self.num_params = None self.sample_tensor = False
def ppc(T, data, latent_vars=None, model_wrapper=None, n_samples=100): """Posterior predictive check (Rubin, 1984; Meng, 1994; Gelman, Meng, and Stern, 1996). If ``latent_vars`` is inputted as ``None``, then it is a prior predictive check (Box, 1980). PPC's form an empirical distribution for the predictive discrepancy, .. math:: p(T) = \int p(T(x^{rep}) | z) p(z | x) dz by drawing replicated data sets xrep and calculating :math:`T(x^{rep})` for each data set. Then it compares it to :math:`T(x)`. Parameters ---------- 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``) 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 of str to RandomVariable, optional Collection of random variables binded to their inferred posterior. It is an optional argument, necessary for when the discrepancy is a function of latent variables. model_wrapper : ed.Model, optional An optional wrapper for the probability model. It must have a ``sample_likelihood`` method. If ``latent_vars`` is not specified, it must also have a ``sample_prior`` method, as ``ppc`` will default to a prior predictive check. ``data`` is also changed. For TensorFlow, Python, and Stan models, the key type is a string; for PyMC3, the key type is a Theano shared variable. For TensorFlow, Python, and PyMC3 models, the value type is a NumPy array or TensorFlow placeholder; for Stan, the value type is the type according to the Stan program's data block. n_samples : int, optional Number of replicated data sets. Returns ------- list of np.ndarray List containing the reference distribution, which is a NumPy array of size elements, .. math:: (T(x^{rep,1}, z^{1}), ..., T(x^{rep,size}, z^{size})) and the realized discrepancy, which is a NumPy array of size elements, .. math:: (T(x, z^{1}), ..., T(x, z^{size})). Examples -------- >>> # build posterior predictive after inference: it is >>> # parameterized by posterior means >>> x_post = copy(x, {z: qz.mean(), beta: qbeta.mean()}) >>> >>> # posterior predictive check >>> # T is a user-defined function of data, T(data) >>> T = lambda xs, zs: tf.reduce_mean(xs[x_post]) >>> 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']) >>> ppc(T, data={y_post: y_train, x_ph: x_train}, ... latent_vars={'z': qz, 'beta': qbeta}) >>> >>> # prior predictive check >>> # running ppc on original x >>> ppc(T, data={x: x_train}) """ sess = get_session() # Sample to get replicated data sets and latent variables. if model_wrapper is None: if latent_vars is None: zrep = None else: zrep = {key: value.value() for key, value in six.iteritems(latent_vars)} xrep = {} for x, obs in six.iteritems(data): if isinstance(x, RandomVariable): # Replace observed data with replicated data. xrep[x] = x.value() else: xrep[x] = obs else: if latent_vars is None: zrep = model_wrapper.sample_prior() else: zrep = {key: value.value() for key, value in six.iteritems(latent_vars)} xrep = model_wrapper.sample_likelihood(zrep) # Create feed_dict for data placeholders that the model conditions # on; it is necessary for all session runs. feed_dict = {x: obs for x, obs in six.iteritems(data) if not isinstance(x, RandomVariable) and not isinstance(x, str)} # Calculate discrepancy over many replicated data sets and latent # variables. Trep = T(xrep, zrep) Tobs = T(data, zrep) Treps = [] Ts = [] for s in range(n_samples): # Take a forward pass (session run) to get new samples for # each calculation of the discrepancy. # Note that alternatively we can unroll the graph by registering # this operation ``n_samples`` times, each for different parent # nodes representing ``xrep`` and ``zrep``. Treps += [sess.run(Trep, feed_dict)] Ts += [sess.run(Tobs, feed_dict)] return [np.stack(Treps), np.stack(Ts)]
def ppc(model, variational=None, data=None, T=None, size=100): """Posterior predictive check. (Rubin, 1984; Meng, 1994; Gelman, Meng, and Stern, 1996) If no posterior approximation is provided through ``variational``, then we default to a prior predictive check (Box, 1980). PPC's form an empirical distribution for the predictive discrepancy, .. math:: p(T) = \int p(T(yrep) | z) p(z | y) dz by drawing replicated data sets yrep and calculating :math:`T(yrep)` for each data set. Then it compares it to :math:`T(y)`. Parameters ---------- model : ed.Model class object that implements the ``sample_likelihood`` method variational : ed.Variational, optional latent variable distribution q(z) to sample from. It is an approximation to the posterior, e.g., a variational approximation or an empirical distribution from MCMC samples. If not specified, samples will be obtained from the model through the ``sample_prior`` method. data : dict, optional Observed data to compare to. If not specified, will return only the reference distribution with an assumed replicated data set size of 1. For TensorFlow, Python, and Stan models, the key type is a string; for PyMC3, the key type is a Theano shared variable. For TensorFlow, Python, and PyMC3 models, the value type is a NumPy array or TensorFlow placeholder; for Stan, the value type is the type according to the Stan program's data block. T : function, optional Discrepancy function, which takes a data dictionary and list of latent variables as input and outputs a tf.Tensor. Default is the identity function. size : int, optional number of replicated data sets Returns ------- list List containing the reference distribution, which is a Numpy vector of size elements, .. math:: (T(yrep^{1}, z^{1}), ..., T(yrep^{size}, z^{size})) and the realized discrepancy, which is a NumPy vector of size elements, .. math:: (T(y, z^{1}), ..., T(y, z^{size})). If the discrepancy function is not specified, then the list contains the full data distribution where each element is a data set (dictionary). """ sess = get_session() if data is None: N = 1 y = {} else: # Assume all values have the same data set size. N = get_dims(list(six.itervalues(data))[0])[0] y = data # 1. Sample from posterior (or prior). # We must fetch zs out of the session because sample_likelihood() # may require a SciPy-based sampler. if variational is not None: zs = variational.sample(size=size) # This is to avoid fetching, e.g., a placeholder x with the # dictionary {x: np.array()}. TensorFlow will raise an error. if isinstance(zs, list): zs = [tf.identity(zs_elem) for zs_elem in zs] else: zs = tf.identity(zs) zs = sess.run(zs) else: zs = model.sample_prior(size=size) zs = zs.eval() # 2. Sample from likelihood. yreps = model.sample_likelihood(zs, size=N) # 3. Calculate discrepancy. if T is None: if y is None: return yreps else: return [yreps, y] Tyreps = [] Tys = [] for yrep, z in zip(yreps, tf.unpack(zs)): Tyreps += [T(yrep, z)] if y is not None: Tys += [T(y, z)] if y is None: return sess.run(tf.pack(Tyreps)) else: return sess.run([tf.pack(Tyreps), tf.pack(Tys)])
def evaluate(metrics, model, variational, data, y_true=None): """Evaluate fitted model using a set of metrics. Parameters ---------- metrics : list or str List of metrics or a single metric. model : ed.Model Probability model p(x, z) variational : ed.Variational Variational approximation to the posterior p(z | x) data : dict Data dictionary to evaluate model with. For TensorFlow, Python, and Stan models, the key type is a string; for PyMC3, the key type is a Theano shared variable. For TensorFlow, Python, and PyMC3 models, the value type is a NumPy array or TensorFlow placeholder; for Stan, the value type is the type according to the Stan program's data block. y_true : np.ndarray or tf.Tensor True values to compare to in supervised learning tasks. Returns ------- list or float A list of evaluations or a single evaluation. Raises ------ NotImplementedError If an input metric does not match an implemented metric in Edward. """ sess = get_session() # Monte Carlo estimate the mean of the posterior predictive: # 1. Sample a batch of latent variables from posterior n_minibatch = 100 zs = variational.sample(size=n_minibatch) # 2. Make predictions, averaging over each sample of latent variables y_pred = model.predict(data, zs) # Evaluate y_pred according to y_true for all metrics. evaluations = [] if isinstance(metrics, str): metrics = [metrics] for metric in metrics: if metric == 'accuracy' or metric == 'crossentropy': # automate binary or sparse cat depending on max(y_true) support = tf.reduce_max(y_true).eval() if support <= 1: metric = 'binary_' + metric else: metric = 'sparse_categorical_' + metric if metric == 'binary_accuracy': evaluations += [sess.run(binary_accuracy(y_true, y_pred))] elif metric == 'categorical_accuracy': evaluations += [sess.run(categorical_accuracy(y_true, y_pred))] elif metric == 'sparse_categorical_accuracy': evaluations += [sess.run(sparse_categorical_accuracy(y_true, y_pred))] elif metric == 'log_loss' or metric == 'binary_crossentropy': evaluations += [sess.run(binary_crossentropy(y_true, y_pred))] elif metric == 'categorical_crossentropy': evaluations += [sess.run(categorical_crossentropy(y_true, y_pred))] elif metric == 'sparse_categorical_crossentropy': evaluations += [sess.run(sparse_categorical_crossentropy(y_true, y_pred))] elif metric == 'hinge': evaluations += [sess.run(hinge(y_true, y_pred))] elif metric == 'squared_hinge': evaluations += [sess.run(squared_hinge(y_true, y_pred))] elif metric == 'mse' or metric == 'MSE' or \ metric == 'mean_squared_error': evaluations += [sess.run(mean_squared_error(y_true, y_pred))] elif metric == 'mae' or metric == 'MAE' or \ metric == 'mean_absolute_error': evaluations += [sess.run(mean_absolute_error(y_true, y_pred))] elif metric == 'mape' or metric == 'MAPE' or \ metric == 'mean_absolute_percentage_error': evaluations += [sess.run(mean_absolute_percentage_error(y_true, y_pred))] elif metric == 'msle' or metric == 'MSLE' or \ metric == 'mean_squared_logarithmic_error': evaluations += [sess.run(mean_squared_logarithmic_error(y_true, y_pred))] elif metric == 'poisson': evaluations += [sess.run(poisson(y_true, y_pred))] elif metric == 'cosine' or metric == 'cosine_proximity': evaluations += [sess.run(cosine_proximity(y_true, y_pred))] elif metric == 'log_lik' or metric == 'log_likelihood': evaluations += [sess.run(y_pred)] else: raise NotImplementedError() if len(evaluations) == 1: return evaluations[0] else: return evaluations
def __str__(self): sess = get_session() a, b = sess.run([self.alpha, self.beta]) return "shape: \n" + a.__str__() + "\n" + \ "scale: \n" + b.__str__()
def sample(self, size=1): sess = get_session() a, b = sess.run([self.alpha, self.beta]) return invgamma.rvs(a, b, size=size)
def __str__(self): sess = get_session() m, s = sess.run([self.loc, self.scale]) return "mean: \n" + m.__str__() + "\n" + \ "std dev: \n" + s.__str__()