tfp.mcmc.SliceSampler

Class SliceSampler

Runs one step of the slice sampler using a hit and run approach.

Inherits From: TransitionKernel

Defined in python/mcmc/slice_sampler_kernel.py.

Slice Sampling is a Markov Chain Monte Carlo (MCMC) algorithm based, as stated by [Neal (2003)][1], on the observation that "...one can sample from a distribution by sampling uniformly from the region under the plot of its density function. A Markov chain that converges to this uniform distribution can be constructed by alternately uniform sampling in the vertical direction with uniform sampling from the horizontal slice defined by the current vertical position, or more generally, with some update that leaves the uniform distribution over this slice invariant". Mathematical details and derivations can be found in [Neal (2003)][1]. The one dimensional slice sampler is extended to n-dimensions through use of a hit-and-run approach: choose a random direction in n-dimensional space and take a step, as determined by the one-dimensional slice sampling algorithm, along that direction [Belisle at al. 1993][2].

The one_step function can update multiple chains in parallel. It assumes that all leftmost dimensions of current_state index independent chain states (and are therefore updated independently). The output of target_log_prob_fn(*current_state) should sum log-probabilities across all event dimensions. Slices along the rightmost dimensions may have different target distributions; for example, current_state[0, :] could have a different target distribution from current_state[1, :]. These semantics are governed by target_log_prob_fn(*current_state). (The number of independent chains is tf.size(target_log_prob_fn(*current_state)).)

Note that the sampler only supports states where all components have a common dtype.

Examples:

Simple chain with warm-up.

In this example we sample from a standard univariate normal distribution using slice sampling.

  import tensorflow as tf
  import tensorflow_probability as tfp
  import numpy as np

  tfd = tfp.distributions

  dtype = np.float32

  target = tfd.Normal(loc=dtype(0), scale=dtype(1))

  samples, _ = tfp.mcmc.sample_chain(
      num_results=1000,
      current_state=dtype(1),
      kernel=tfp.mcmc.SliceSampler(
          target.log_prob,
          step_size=1.0,
          max_doublings=5,
          seed=1234),
      num_burnin_steps=500,
      parallel_iterations=1)  # For determinism.

  sample_mean = tf.reduce_mean(samples, axis=0)
  sample_std = tf.sqrt(
    tf.reduce_mean(tf.squared_difference(samples, sample_mean),
                   axis=0))

  with tf.Session() as sess:
    [sample_mean, sample_std] = sess.run([sample_mean, sample_std])

  print "Sample mean: ", sample_mean
  print "Sample Std: ", sample_std

Sample from a Two Dimensional Normal.

In the following example we sample from a two dimensional Normal distribution using slice sampling.

  import tensorflow as tf
  import tensorflow_probability as tfp
  import numpy as np

  tfd = tfp.distributions

  dtype = np.float32
  true_mean = dtype([0, 0])
  true_cov = dtype([[1, 0.5], [0.5, 1]])
  num_results = 500
  num_chains = 50

  # Target distribution is defined through the Cholesky decomposition
  chol = tf.linalg.cholesky(true_cov)
  target = tfd.MultivariateNormalTriL(loc=true_mean, scale_tril=chol)

  # Assume that the state is passed as a list of 1-d tensors `x` and `y`.
  # Then the target log-density is defined as follows:
  def target_log_prob(x, y):
    # Stack the input tensors together
    z = tf.stack([x, y], axis=-1) - true_mean
    return target.log_prob(z)

  # Initial state of the chain
  init_state = [np.ones([num_chains, 1], dtype=dtype),
                np.ones([num_chains, 1], dtype=dtype)]

  # Run Slice Samper for `num_results` iterations for `num_chains`
  # independent chains:
  [x, y], _ = tfp.mcmc.sample_chain(
      num_results=num_results,
      current_state=init_state,
      kernel=tfp.mcmc.SliceSampler(
          target_log_prob_fn=target_log_prob,
          step_size=1.0,
          max_doublings=5,
          seed=47),
      num_burnin_steps=200,
      num_steps_between_results=1,
      parallel_iterations=1)

  states = tf.stack([x, y], axis=-1)
  sample_mean = tf.reduce_mean(states, axis=[0, 1])
  z = states - sample_mean
  sample_cov = tf.reduce_mean(tf.matmul(z, z, transpose_a=True),
                              axis=[0, 1])

  with tf.Session() as sess:
    [sample_mean, sample_cov] = sess.run([
        sample_mean, sample_cov])

  print "sample_mean: ", sample_mean
  print "sample_cov: ", sample_cov

References

[1]: Radford M. Neal. Slice Sampling. The Annals of Statistics. 2003, Vol 31, No. 3 , 705-767. https://projecteuclid.org/download/pdf_1/euclid.aos/1056562461

[2]: C.J.P. Belisle, H.E. Romeijn, R.L. Smith. Hit-and-run algorithms for generating multivariate distributions. Math. Oper. Res., 18(1993), 225-266. https://www.jstor.org/stable/3690278?seq=1#page_scan_tab_contents

__init__

__init__(
    target_log_prob_fn,
    step_size,
    max_doublings,
    seed=None,
    name=None
)

Initializes this transition kernel.

Args:

  • target_log_prob_fn: Python callable which takes an argument like current_state (or *current_state if it is a list) and returns its (possibly unnormalized) log-density under the target distribution.
  • step_size: Scalar or tf.Tensor with same dtype as and shape compatible with x_initial. The size of the initial interval.
  • max_doublings: Scalar positive int32 tf.Tensor. The maximum number of doublings to consider.
  • seed: Python integer to seed the random number generator.
  • name: Python str name prefixed to Ops created by this function. Default value: None (i.e., 'slice_sampler_kernel').

Returns:

  • next_state: Tensor or Python list of Tensors representing the state(s) of the Markov chain(s) at each result step. Has same shape as current_state.
  • kernel_results: collections.namedtuple of internal calculations used to advance the chain.

Properties

is_calibrated

Returns True if Markov chain converges to specified distribution.

TransitionKernels which are "uncalibrated" are often calibrated by composing them with the tfp.mcmc.MetropolisHastings TransitionKernel.

max_doublings

name

parameters

Returns dict of __init__ arguments and their values.

seed

step_size

target_log_prob_fn

Methods

bootstrap_results

bootstrap_results(init_state)

Returns an object with the same type as returned by one_step(...)[1].

Args:

  • init_state: Tensor or Python list of Tensors representing the initial state(s) of the Markov chain(s).

Returns:

  • kernel_results: A (possibly nested) tuple, namedtuple or list of Tensors representing internal calculations made within this function.

one_step

one_step(
    current_state,
    previous_kernel_results
)

Runs one iteration of Slice Sampler.

Args:

  • current_state: Tensor or Python list of Tensors representing the current state(s) of the Markov chain(s). The first r dimensions index independent chains, r = tf.rank(target_log_prob_fn(*current_state)).
  • previous_kernel_results: collections.namedtuple containing Tensors representing values from previous calls to this function (or from the bootstrap_results function.)

Returns:

  • next_state: Tensor or Python list of Tensors representing the state(s) of the Markov chain(s) after taking exactly one step. Has same type and shape as current_state.
  • kernel_results: collections.namedtuple of internal calculations used to advance the chain.

Raises:

  • ValueError: if there isn't one step_size or a list with same length as current_state.
  • TypeError: if not target_log_prob.dtype.is_floating.