コード例 #1
0
    def test_simple_network(self):
        # From https://en.wikipedia.org/wiki/Bayesian_network#Example
        def model():
            raining = yield Root(tfd.Bernoulli(probs=0.2, dtype=tf.int32))
            sprinkler_prob = [0.4, 0.01]
            sprinkler_prob = tf.gather(sprinkler_prob, raining)
            sprinkler = yield tfd.Bernoulli(probs=sprinkler_prob,
                                            dtype=tf.int32)
            grass_wet_prob = [[0.0, 0.8], [0.9, 0.99]]
            grass_wet_prob = tf.gather_nd(grass_wet_prob,
                                          _stack(sprinkler, raining))
            grass_wet = yield tfd.Bernoulli(probs=grass_wet_prob,
                                            dtype=tf.int32)

        d = marginalize.MarginalizableJointDistributionCoroutine(model)
        # We want to know the probability that it was raining
        # and we want to marginalize over the state of the sprinkler.
        observations = [
            'tabulate',  # We want to know the probability it rained.
            'marginalize',  # We don't know the sprinkler state.
            1
        ]  # We observed a wet lawn.
        p = tf.exp(d.marginalized_log_prob(observations))
        p = p / tf.reduce_sum(p)
        self.assertAllClose(p[1], 0.357688)
コード例 #2
0
    def test_hmm(self):
        n_steps = 4
        infer_step = 2

        observations = [-1.0, 0.0, 1.0, 2.0]

        initial_prob = tf.constant([0.6, 0.4], dtype=tf.float32)
        transition_matrix = tf.constant([[0.6, 0.4], [0.3, 0.7]],
                                        dtype=tf.float32)
        observation_locs = tf.constant([0.0, 1.0], dtype=tf.float32)
        observation_scale = tf.constant(0.5, dtype=tf.float32)

        dist1 = tfd.HiddenMarkovModel(tfd.Categorical(probs=initial_prob),
                                      tfd.Categorical(probs=transition_matrix),
                                      tfd.Normal(loc=observation_locs,
                                                 scale=observation_scale),
                                      num_steps=n_steps)

        p = dist1.posterior_marginals(
            observations).probs_parameter()[infer_step]

        def model():
            i = yield Root(tfd.Categorical(probs=initial_prob, dtype=tf.int32))
            z = yield tfd.Normal(loc=tf.gather(observation_locs, i),
                                 scale=observation_scale)

            for t in range(n_steps - 1):
                i = yield tfd.Categorical(probs=tf.gather(
                    transition_matrix, i),
                                          dtype=tf.int32)
                yield tfd.Normal(loc=tf.gather(observation_locs, i),
                                 scale=observation_scale)

        dist2 = marginalize.MarginalizableJointDistributionCoroutine(model)
        full_observations = list(
            itertools.chain(*zip([
                'tabulate' if i == infer_step else 'marginalize'
                for i in range(n_steps)
            ], observations)))
        q = tf.exp(dist2.marginalized_log_prob(full_observations))
        q = q / tf.reduce_sum(q)

        self.assertAllClose(p, q)
コード例 #3
0
    def test_basics(self):
        probs = np.random.rand(20)

        def model():
            i = yield Root(tfd.Categorical(probs=probs, dtype=tf.int32))
            j = yield Root(tfd.Categorical(probs=probs, dtype=tf.int32))
            k = yield Root(tfd.Categorical(probs=probs, dtype=tf.int32))

        dist = marginalize.MarginalizableJointDistributionCoroutine(model)

        p = tf.exp(
            dist.marginalized_log_prob(['tabulate', 'tabulate', 'tabulate']))
        self.assertEqual(p.shape, [20, 20, 20])
        self.assertAllClose(tf.reduce_sum(p), 1.0)

        s = tf.exp(
            dist.marginalized_log_prob(
                ['marginalize', 'marginalize', 'marginalize']))
        self.assertAllClose(s, 1.0)
コード例 #4
0
    def test_marginalized_gradient(self):
        n = 10

        mu1 = tf.Variable(3.)
        mu2 = tf.Variable(3.)

        def model():
            change_year = yield Root(tfd.Categorical(probs=tf.ones(n) / n))
            for year in range(n):
                post_change_year = tf.cast(year >= change_year, dtype=tf.int32)
                mu = tf.gather([mu1, mu2], post_change_year)
                accidents = yield tfd.Poisson(mu)

        counts = np.ones([n], dtype=np.float32)
        dist = marginalize.MarginalizableJointDistributionCoroutine(model)
        obs = ['marginalize'] + list(counts)
        with tf.GradientTape() as tape:
            loss = -dist.marginalized_log_prob(obs)
        grad = tape.gradient(loss, [mu1, mu2])
        self.assertLen(grad, 2)
        self.assertAllNotNone(grad)
コード例 #5
0
  def test_sample_distribution(self):
    probs = np.random.rand(4) + 0.001
    probs = probs / np.sum(probs)

    def model():
      i = yield Root(
          tfd.Sample(
              tfd.Categorical(probs=probs, dtype=tf.int32), sample_shape=[2]))
      # Note use of scalar `sample_shape` to test expansion of shape
      # to vector.
      j = yield tfd.Sample(
          tfd.Categorical(probs=probs, dtype=tf.int32), sample_shape=2)

    dist = marginalize.MarginalizableJointDistributionCoroutine(model)

    ptt = tf.exp(dist.marginalized_log_prob(['tabulate', 'tabulate']))
    ptm = tf.exp(dist.marginalized_log_prob(['tabulate', 'marginalize']))
    pmt = tf.exp(dist.marginalized_log_prob(['marginalize', 'tabulate']))
    pmm = tf.exp(dist.marginalized_log_prob(['marginalize', 'marginalize']))
    self.assertEqual(ptt.shape, [4, 4, 4, 4])
    self.assertEqual(ptm.shape, [4, 4])
    self.assertEqual(pmt.shape, [4, 4])
    self.assertEqual(pmm.shape, [])
コード例 #6
0
    def test_markov_chain_stationary(self):
        n_steps = 52
        initial_prob = tf.constant([0.6, 0.4], dtype=tf.float64)
        transition_matrix = tf.constant([[0.6, 0.4], [0.3, 0.7]],
                                        dtype=tf.float64)

        def model():
            i = yield Root(tfd.Categorical(probs=initial_prob, dtype=tf.int32))

            for t in range(n_steps - 1):
                i = yield tfd.Categorical(probs=tf.gather(
                    transition_matrix, i),
                                          dtype=tf.int32)

            yield tfd.Deterministic(i)

        dist = marginalize.MarginalizableJointDistributionCoroutine(model)
        # Compute probability of ending in state 1 by marginalizing out
        # all intermediate states.
        # Limiting distribution as `n_steps` -> infinity is exactly 4/7.
        observations = n_steps * ['marginalize'] + [1]
        p = tf.exp(
            dist.marginalized_log_prob(observations, internal_type=tf.float64))
        self.assertAllClose(p, 4. / 7.)
コード例 #7
0
    def test_particle_tree(self):
        # m particles are born at the same random location on an n x n grid.
        # They independently take `n_steps` steps of a random walk going N, S,
        # E or W at each step. At the end we observe their positions subject
        # to Gaussian noise. Computes posterior distribution for the birthplace.

        n = 16
        m = 3
        n_steps = 16

        def model():
            # Shared birthplace
            x_start = yield Root(
                tfd.Categorical(probs=tf.ones(n) / n, dtype=tf.int32))
            y_start = yield tfd.Categorical(probs=tf.ones(n) / n,
                                            dtype=tf.int32)

            x = m * [x_start]
            y = m * [y_start]

            for t in range(n_steps):
                for i in range(m):
                    # Construct PDF for next step in walk
                    # Start with PDF for all mass on current point.
                    ox = tf.one_hot(x[i], n)
                    oy = tf.one_hot(y[i], n)
                    o = ox[..., :, None] * oy[..., None, :]

                    # Deliberate choice of non-centered distribution as
                    # reduced symmetry lends itself to better testing.
                    p = (0.1 * tf.roll(o, shift=[0, -1], axis=[-2, -1]) +
                         0.2 * tf.roll(o, shift=[0, 1], axis=[-2, -1]) +
                         0.3 * tf.roll(o, shift=[-1, 0], axis=[-2, -1]) +
                         0.4 * tf.roll(o, shift=[1, 0], axis=[-2, -1]))

                    # Reshape just last two dimensions.
                    p = tf.reshape(p, _cat(p.shape[:-2], [-1]))
                    xy = yield tfd.Categorical(probs=p, dtype=tf.int32)
                    x[i] = xy // n
                    y[i] = xy % n

            # 2 * m noisy 2D observations at end
            for i in range(m):
                yield tfd.Normal(tf.cast(x[i], dtype=tf.float32), scale=2.0)
                yield tfd.Normal(tf.cast(y[i], dtype=tf.float32), scale=2.0)

        d = marginalize.MarginalizableJointDistributionCoroutine(model)
        final_observations = [0.0, 0.0, 4.0, 4.0, 0.0, 4.0]
        observations = (
            ['tabulate', 'tabulate'] +
            n_steps * ['marginalize', 'marginalize', 'marginalize'] +
            final_observations)
        # Using `method='logeinsumexp' here creates a large intermediate
        # that impacts performance. Because we are only setting
        # `STEPS == 16` the probabilities involved aren't small enough
        # to result in underflow.
        p = tf.exp(d.marginalized_log_prob(observations, method='einsum'))
        q = _tree_example(n, n_steps)

        # Note that while p and q should be close in value there is a large
        # difference in computation time. I would expect the p
        # to be slower by a factor of around `n_steps/log2(n_steps)` (because
        # `numpy` compute matrix powers by repeated squaring) but it seems
        # to be even slower. This likely means future versions of
        # `marginalized_log_prob` will run faster when the elimination
        # order chosen by `tf.einsum` closer matches `_tree_example` above.
        self.assertAllClose(p, q)