Skip to content

Commit 2b820d8

Browse files
authored
Merge pull request #1631 from pymc-devs/edward_interface
Adopt Edward wrapper
2 parents 6d90dee + 73cbcec commit 2b820d8

File tree

5 files changed

+117
-0
lines changed

5 files changed

+117
-0
lines changed

pymc3/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from .blocking import *
44
from .distributions import *
5+
from .external import *
56
from .math import logsumexp, logit, invlogit
67
from .model import *
78
from .stats import *
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python
2+
"""A simple coin flipping example. Inspired by Stan's toy example. Copied and modified
3+
from Edward code base (https://github.com/blei-lab/edward).
4+
5+
The model is written in PyMC3.
6+
"""
7+
from __future__ import absolute_import
8+
from __future__ import division
9+
from __future__ import print_function
10+
11+
import edward as ed
12+
import numpy as np
13+
import pymc3 as pm
14+
import theano
15+
import tensorflow as tf
16+
17+
from edward.models import Beta
18+
from pymc3.external.edward import EdwardModel
19+
20+
x_obs = theano.shared(np.zeros(1))
21+
with pm.Model() as pm_model:
22+
p = pm.Beta('p', 1, 1, transform=None)
23+
x = pm.Bernoulli('x', p, observed=x_obs)
24+
25+
ed.set_seed(42)
26+
model = EdwardModel(pm_model)
27+
28+
data = {x_obs: np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 1])}
29+
30+
qp_a = tf.nn.softplus(tf.Variable(tf.random_normal([])))
31+
qp_b = tf.nn.softplus(tf.Variable(tf.random_normal([])))
32+
qp = Beta(a=qp_a, b=qp_b)
33+
34+
inference = ed.KLqp({'p': qp}, data, model)
35+
inference.run(n_iter=500)

pymc3/external/__init__.py

Whitespace-only changes.

pymc3/external/edward.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""
2+
Copied and modified from Edward code base (https://github.com/blei-lab/edward) following
3+
deprecation of external package wrappers by Edward.
4+
"""
5+
6+
from __future__ import absolute_import
7+
from __future__ import division
8+
from __future__ import print_function
9+
10+
import numpy as np
11+
import six
12+
import tensorflow as tf
13+
14+
class EdwardModel(object):
15+
"""Model wrapper for models written in PyMC3 to be fit using Edward.
16+
"""
17+
def __init__(self, model):
18+
"""
19+
Parameters
20+
----------
21+
model : pymc3.Model
22+
The probability model, written with Theano shared
23+
variables to form any observations and with
24+
`transform=None` for any latent variables. The Theano
25+
shared variables are set during inference, and all latent
26+
variables live on their original (constrained) space.
27+
"""
28+
29+
self.model = model
30+
self.n_vars = None
31+
32+
def log_prob(self, xs, zs):
33+
"""
34+
Parameters
35+
----------
36+
xs : dict of str to tf.Tensor
37+
Data dictionary. Each key is a data structure used in the
38+
model (Theano shared variable), and its value is the
39+
corresponding realization (tf.Tensor).
40+
zs : dict of str to tf.Tensor
41+
Latent variable dictionary. Each key names a latent variable
42+
used in the model (str), and its value is the corresponding
43+
realization (tf.Tensor).
44+
45+
Returns
46+
-------
47+
tf.Tensor
48+
Scalar, the log joint density log p(xs, zs).
49+
50+
Notes
51+
-----
52+
It wraps around a Python function. The Python function takes
53+
inputs of type np.ndarray and outputs a np.ndarray.
54+
"""
55+
# Store keys so that ``_py_log_prob_args`` knows how each
56+
# value corresponds to a key.
57+
self.xs_keys = list(six.iterkeys(xs))
58+
self.zs_keys = list(six.iterkeys(zs))
59+
60+
# Pass in all tensors as a flattened list for tf.py_func().
61+
inputs = [tf.convert_to_tensor(x) for x in six.itervalues(xs)]
62+
inputs += [tf.convert_to_tensor(z) for z in six.itervalues(zs)]
63+
64+
return tf.py_func(self._py_log_prob_args, inputs, [tf.float32])[0]
65+
66+
def _py_log_prob_args(self, *args):
67+
xs_values = args[:len(self.xs_keys)]
68+
zs_values = args[len(self.xs_keys):]
69+
70+
# Set data placeholders in PyMC3 model (Theano shared
71+
# variable) to their realizations (NumPy array).
72+
for key, value in zip(self.xs_keys, xs_values):
73+
key.set_value(value)
74+
75+
# Calculate model's log density using a dictionary of latent
76+
# variables.
77+
z = {key: value for key, value in zip(self.zs_keys, zs_values)}
78+
lp = self.model.fastlogp(z)
79+
return lp.astype(np.float32)
80+

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@
5555
classifiers=classifiers,
5656
install_requires=install_reqs,
5757
tests_require=test_reqs,
58+
extras_require={'edward': ['edward>=1.1.6']},
5859
test_suite='nose.collector')

0 commit comments

Comments
 (0)