Exemplo n.º 1
0
  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}
Exemplo n.º 2
0
    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}
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
    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:
                summary = sess.run(self.summarize, feed_dict)
                self.train_writer.add_summary(summary, t)

        return {'t': t, 'loss': loss, 'loss_d': loss_d}
Exemplo n.º 5
0
  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
Exemplo n.º 6
0
  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()
Exemplo n.º 7
0
  def update(self, feed_dict=None):
    """Run one iteration of sampling.

    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
      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}
Exemplo n.º 8
0
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)]
Exemplo n.º 9
0
def evaluate(metrics, data, n_samples=500, output_key=None):
    """Evaluate fitted model using a set of metrics.

  A metric, or scoring rule [@winkler1994evaluating], is a function of
  observed data under the posterior predictive distribution. For
  example in supervised metrics such as classification accuracy, the
  observed data (true output) is compared to the posterior
  predictive's mean (predicted output). In unsupervised metrics such
  as log-likelihood, the probability of observing the data is
  calculated under the posterior predictive's log-density.

  Args:
    metrics: list of str or str.
      List of metrics or a single metric:
      `'binary_accuracy'`,
      `'categorical_accuracy'`,
      `'sparse_categorical_accuracy'`,
      `'log_loss'` or `'binary_crossentropy'`,
      `'categorical_crossentropy'`,
      `'sparse_categorical_crossentropy'`,
      `'hinge'`,
      `'squared_hinge'`,
      `'mse'` or `'MSE'` or `'mean_squared_error'`,
      `'mae'` or `'MAE'` or `'mean_absolute_error'`,
      `'mape'` or `'MAPE'` or `'mean_absolute_percentage_error'`,
      `'msle'` or `'MSLE'` or `'mean_squared_logarithmic_error'`,
      `'poisson'`,
      `'cosine'` or `'cosine_proximity'`,
      `'log_lik'` or `'log_likelihood'`.
    data: dict.
      Data to evaluate model with. 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.
    n_samples: int, optional.
      Number of posterior samples for making predictions, using the
      posterior predictive distribution.
    output_key: RandomVariable or tf.Tensor, optional.
      It is the key in `data` which corresponds to the model's output.

  Returns:
    list of float or float.
    A list of evaluations or a single evaluation.

  Raises:
    NotImplementedError.
    If an input metric does not match an implemented metric in Edward.

  #### Examples

  ```python
  # build posterior predictive after inference: it is
  # parameterized by a posterior sample
  x_post = ed.copy(x, {z: qz, beta: qbeta})

  # log-likelihood performance
  ed.evaluate('log_likelihood', data={x_post: x_train})

  # classification accuracy
  # here, `x_ph` is any features the model is defined with respect to,
  # and `y_post` is the posterior predictive distribution
  ed.evaluate('binary_accuracy', data={y_post: y_train, x_ph: x_train})

  # mean squared error
  ed.evaluate('mean_squared_error', data={y: y_data, x: x_data})
  ```
  """
    sess = get_session()
    if isinstance(metrics, str):
        metrics = [metrics]
    elif not isinstance(metrics, list):
        raise TypeError("metrics must have type str or list.")

    check_data(data)
    if not isinstance(n_samples, int):
        raise TypeError("n_samples must have type int.")

    if output_key is None:
        # Default output_key to the only data key that isn't a placeholder.
        keys = [
            key for key in six.iterkeys(data) if
            not isinstance(key, tf.Tensor) or "Placeholder" not in key.op.type
        ]
        if len(keys) == 1:
            output_key = keys[0]
        else:
            raise KeyError("User must specify output_key.")
    elif not isinstance(output_key, RandomVariable):
        raise TypeError("output_key must have type RandomVariable.")

    # 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
    }

    # Form true data.
    y_true = data[output_key]
    # Make predictions (if there are any supervised metrics).
    if metrics != ['log_lik'] and metrics != ['log_likelihood']:
        binary_discrete = (Bernoulli, Binomial)
        categorical_discrete = (Categorical, Multinomial, OneHotCategorical)
        if isinstance(output_key, binary_discrete + categorical_discrete):
            # Average over realizations of their probabilities, then predict
            # via argmax over probabilities.
            probs = [
                sess.run(output_key.probs, feed_dict) for _ in range(n_samples)
            ]
            probs = tf.add_n(probs) / tf.cast(n_samples, probs[0].dtype)
            if isinstance(output_key, binary_discrete):
                # make random prediction whenever probs is exactly 0.5
                random = tf.random_uniform(shape=tf.shape(probs))
                y_pred = tf.round(tf.where(tf.equal(0.5, probs), random,
                                           probs))
            else:
                y_pred = tf.argmax(probs, len(probs.shape) - 1)
        else:
            # Monte Carlo estimate the mean of the posterior predictive.
            y_pred = [
                sess.run(output_key, feed_dict) for _ in range(n_samples)
            ]
            y_pred = tf.cast(tf.add_n(y_pred), y_pred[0].dtype) / \
                tf.cast(n_samples, y_pred[0].dtype)

    # Evaluate y_true (according to y_pred if supervised) for all metrics.
    evaluations = []
    for metric in metrics:
        if metric == 'accuracy' or metric == 'crossentropy':
            # automate binary or sparse cat depending on its support
            support = sess.run(tf.reduce_max(y_true), feed_dict)
            if support <= 1:
                metric = 'binary_' + metric
            else:
                metric = 'sparse_categorical_' + metric

        if metric == 'binary_accuracy':
            evaluations += [binary_accuracy(y_true, y_pred)]
        elif metric == 'categorical_accuracy':
            evaluations += [categorical_accuracy(y_true, y_pred)]
        elif metric == 'sparse_categorical_accuracy':
            evaluations += [sparse_categorical_accuracy(y_true, y_pred)]
        elif metric == 'log_loss' or metric == 'binary_crossentropy':
            evaluations += [binary_crossentropy(y_true, y_pred)]
        elif metric == 'categorical_crossentropy':
            evaluations += [categorical_crossentropy(y_true, y_pred)]
        elif metric == 'sparse_categorical_crossentropy':
            evaluations += [sparse_categorical_crossentropy(y_true, y_pred)]
        elif metric == 'hinge':
            evaluations += [hinge(y_true, y_pred)]
        elif metric == 'squared_hinge':
            evaluations += [squared_hinge(y_true, y_pred)]
        elif (metric == 'mse' or metric == 'MSE'
              or metric == 'mean_squared_error'):
            evaluations += [mean_squared_error(y_true, y_pred)]
        elif (metric == 'mae' or metric == 'MAE'
              or metric == 'mean_absolute_error'):
            evaluations += [mean_absolute_error(y_true, y_pred)]
        elif (metric == 'mape' or metric == 'MAPE'
              or metric == 'mean_absolute_percentage_error'):
            evaluations += [mean_absolute_percentage_error(y_true, y_pred)]
        elif (metric == 'msle' or metric == 'MSLE'
              or metric == 'mean_squared_logarithmic_error'):
            evaluations += [mean_squared_logarithmic_error(y_true, y_pred)]
        elif metric == 'poisson':
            evaluations += [poisson(y_true, y_pred)]
        elif metric == 'cosine' or metric == 'cosine_proximity':
            evaluations += [cosine_proximity(y_true, y_pred)]
        elif metric == 'log_lik' or metric == 'log_likelihood':
            # Monte Carlo estimate the log-density of the posterior predictive.
            tensor = tf.reduce_mean(output_key.log_prob(y_true))
            log_pred = [sess.run(tensor, feed_dict) for _ in range(n_samples)]
            log_pred = tf.add_n(log_pred) / tf.cast(n_samples, tensor.dtype)
            evaluations += [log_pred]
        else:
            raise NotImplementedError(
                "Metric is not implemented: {}".format(metric))

    if len(evaluations) == 1:
        return sess.run(evaluations[0], feed_dict)
    else:
        return sess.run(evaluations, feed_dict)
Exemplo n.º 10
0
    def update(self, feed_dict=None):
        """Run one iteration of sampling.

    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
      acceptance rate of samples since (and including) this iteration.
    """
        sess = get_session()
        if not self.feed_dict:
            # Initialize feed for all conditionals to be the draws at step 0.
            samples = OrderedDict(self.latent_vars)
            inits = sess.run([qz.params[0] for qz in six.itervalues(samples)])
            for z, init in zip(six.iterkeys(samples), inits):
                self.feed_dict[z] = init

            for key, value in six.iteritems(self.data):
                if isinstance(key, tf.Tensor) and "Placeholder" in key.op.type:
                    self.feed_dict[key] = value
                elif isinstance(key, RandomVariable) and \
                        isinstance(value, (tf.Tensor, tf.Variable)):
                    self.feed_dict[key] = sess.run(value)

        if feed_dict is None:
            feed_dict = {}

        feed_dict.update(self.feed_dict)

        # Determine scan order.
        if self.scan_order == 'random':
            scan_order = list(six.iterkeys(self.latent_vars))
            random.shuffle(scan_order)
        else:  # list
            scan_order = self.scan_order

        # Fetch samples by iterating over complete conditional draws.
        for z in scan_order:
            if isinstance(z, RandomVariable):
                draw = sess.run(self.proposal_vars[z], feed_dict)
                feed_dict[z] = draw
                self.feed_dict[z] = draw
            else:  # list
                draws = sess.run([self.proposal_vars[zz] for zz in z],
                                 feed_dict)
                for zz, draw in zip(z, draws):
                    feed_dict[zz] = draw
                    self.feed_dict[zz] = draw

        # Assign the samples to the Empirical random variables.
        _, 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}