In Edward, models were typically written inline by composing random variables. In Edward2, the recommended pattern is to write models as functions.
In this functional pattern:
- Function Inputs: Represent what the probabilistic program conditions on (the $x$ in $p(y|x)$).
- Function Outputs: Represent what the probabilistic program is over (the $y$ in $p(y|x)$).
Best Practice: Always provide a name argument to all random variables (e.g., ed.Gamma(..., name="w2")). This ensures cleaner names in the computational graph and facilitates model manipulation.
def deep_exponential_family(data_size, feature_size, units, shape):
"""A multi-layered topic model over a documents-by-terms matrix."""
w2 = ed.Gamma(0.1, 0.3, sample_shape=[units[2], units[1]], name="w2")
w1 = ed.Gamma(0.1, 0.3, sample_shape=[units[1], units[0]], name="w1")
w0 = ed.Gamma(0.1, 0.3, sample_shape=[units[0], feature_size], name="w0")
z2 = ed.Gamma(0.1, 0.1, sample_shape=[data_size, units[2]], name="z2")
z1 = ed.Gamma(shape, shape / tf.matmul(z2, w2), name="z1")
z0 = ed.Gamma(shape, shape / tf.matmul(z1, w1), name="z0")
x = ed.Poisson(tf.matmul(z0, w0), name="x")
return x