Skip to content

Commit 968fc01

Browse files
Merge pull request #61 from brandonwillard/add-basic-docs
Add some high-level documentation
2 parents 1f4e0f0 + 3925b91 commit 968fc01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+10117
-209
lines changed

Makefile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: help venv conda docker docstyle format style black test lint check coverage
1+
.PHONY: help venv conda docker docstyle format style black test lint check coverage docs
22
.DEFAULT_GOAL = help
33

44
PYTHON = python
@@ -63,6 +63,15 @@ test: # Test code using pytest.
6363
coverage: test
6464
diff-cover coverage.xml --compare-branch=master --fail-under=100
6565

66+
docs:
67+
# latesttag=$(git describe --tags `git rev-list --tags --max-count=1`)
68+
# echo checking out ${latesttag}
69+
# git checkout ${latesttag}
70+
pushd docs && \
71+
make html && \
72+
ghp-import -n -p -r upstream -b gh-pages build/html && \
73+
popd
74+
6675
lint: docstyle format style # Lint code using pydocstyle, black and pylint.
6776

6877
check: lint test coverage # Both lint and test code. Runs `make lint` followed by `make test`.

README.md

Lines changed: 13 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,29 @@
33
[![Build Status](https://travis-ci.org/pymc-devs/symbolic-pymc.svg?branch=master)](https://travis-ci.org/pymc-devs/symbolic-pymc) [![Coverage Status](https://coveralls.io/repos/github/pymc-devs/symbolic-pymc/badge.svg?branch=master)](https://coveralls.io/github/pymc-devs/symbolic-pymc?branch=master)
44

55

6-
Symbolic PyMC provides tools for the symbolic manipulation of [PyMC](https://github.com/pymc-devs) models and their underlying computational graphs. It enables graph manipulations in the relational DSL [miniKanren](http://minikanren.org/)—via the [`kanren`](https://github.com/logpy/logpy) package—by way of meta classes and S-expression forms of a graph.
6+
[Symbolic PyMC](https://pymc-devs.github.io/symbolic-pymc) provides tools for the symbolic manipulation of [PyMC](https://github.com/pymc-devs) models and their underlying computational graphs in [Theano](https://github.com/Theano/Theano) and [TensorFlow](https://github.com/tensorflow/tensorflow). It enables graph manipulations in the relational DSL [miniKanren](http://minikanren.org/)—via the [`kanren`](https://github.com/logpy/logpy) package—by way of meta classes and S-expression forms of a graph.
77

8-
This work stems from a series of articles starting [here](https://brandonwillard.github.io/a-role-for-symbolic-computation-in-the-general-estimation-of-statistical-models.html).
8+
This work stems from a series of articles starting [here](https://brandonwillard.github.io/a-role-for-symbolic-computation-in-the-general-estimation-of-statistical-models.html). Documentation and examples for Symbolic PyMC are available [here](https://pymc-devs.github.io/symbolic-pymc).
99

1010
*This package is currently in alpha, so expect large-scale changes at any time!*
1111

1212
## Features
1313

1414
### General
1515

16+
* Support for [Theano](https://github.com/Theano/Theano) and [TensorFlow](https://github.com/tensorflow/tensorflow) graphs
17+
- [Unification and reification](https://github.com/mrocklin/unification) for all components of a graph
18+
- A more robust Theano `Op` for representing random variables
19+
- Conversion of PyMC3 models into sample-able Theano graphs representing all random variable inter-dependencies
20+
- A Theano LaTeX pretty printer that displays shape information and distributions in mathematical notation
21+
- Simple text-based TensorFlow graph print-outs
1622
* Full [miniKanren](http://minikanren.org/) integration for relational graph/model manipulation.
1723
- Perform simple and robust "search and replace" over arbitrary graphs (e.g. Python builtin collections, AST, tensor algebra graphs, etc.)
18-
- Create and compose relations with explicit high-level statistical/mathematical meaning and functionality, such as "`X` is a normal scale mixture with mixing distribution `Y`", and automatically "solve" for components (i.e. `X` and `Y`) that satisfy a relation.
19-
- Apply non-trivial conditions—as relations—to produce sophisticated graph manipulations (e.g. search for normal scale mixtures and scale a term in the mixing distribution).
20-
- Integrate standard Python operations into relations (e.g. use a symbolic math library to compute an inverse-Laplace transform to determine if a distribution is a scale mixture—and find its mixing distribution).
21-
* Convert graphs to an S-expression-like tuple-based form and perform manipulations at the syntax level.
22-
* Pre-built example relations for symbolic closed-form posteriors and standard statistical model reformulations.
23-
24-
### [Theano](https://github.com/Theano/Theano)
25-
26-
* A more robust Theano `Op` for representing random variables
27-
* Conversion of PyMC3 models into sample-able Theano graphs representing all random variable inter-dependencies
28-
* A LaTeX pretty printer that displays shape information and distributions in mathematical notation
29-
30-
### [TensorFlow](https://github.com/tensorflow/tensorflow)
31-
32-
* TensorFlow graph support
33-
* [In progress] PyMC4 model conversion
24+
- Create and compose relations with explicit high-level statistical/mathematical meaning and functionality, such as "`X` is a normal scale mixture with mixing distribution `Y`", and automatically "solve" for components (i.e. `X` and `Y`) that satisfy a relation
25+
- Apply non-trivial conditions—as relations—to produce sophisticated graph manipulations (e.g. search for normal scale mixtures and scale a term in the mixing distribution)
26+
- Integrate standard Python operations into relations (e.g. use a symbolic math library to compute an inverse-Laplace transform to determine if a distribution is a scale mixture—and find its mixing distribution)
27+
* Convert graphs to an S-expression-like tuple-based form and perform manipulations at the syntax level
28+
* Pre-built example relations for graph traversal, fixed-points, symbolic closed-form posteriors, and standard statistical model reformulations
3429

3530
## Installation
3631

@@ -39,193 +34,3 @@ The package name is `symbolic_pymc` and it can be installed with `pip` directly
3934
$ pip install git+https://github.com/pymc-devs/symbolic-pymc
4035
```
4136
or after cloning the repo (and then installing with `pip`).
42-
43-
## Examples
44-
### Compute Symbolic Closed-form Posteriors
45-
46-
```python
47-
import numpy as np
48-
49-
import theano
50-
import theano.tensor as tt
51-
52-
import pymc3 as pm
53-
54-
from functools import partial
55-
56-
from unification import var
57-
58-
from kanren import run
59-
from kanren.graph import reduceo, walko
60-
61-
from symbolic_pymc.theano.printing import tt_pprint
62-
from symbolic_pymc.theano.pymc3 import model_graph
63-
64-
from symbolic_pymc.relations.theano.conjugates import conjugate
65-
66-
theano.config.cxx = ''
67-
theano.config.compute_test_value = 'ignore'
68-
69-
a_tt = tt.vector('a')
70-
R_tt = tt.matrix('R')
71-
F_t_tt = tt.matrix('F')
72-
V_tt = tt.matrix('V')
73-
74-
a_tt.tag.test_value = np.r_[1., 0.]
75-
R_tt.tag.test_value = np.diag([10., 10.])
76-
F_t_tt.tag.test_value = np.c_[-2., 1.]
77-
V_tt.tag.test_value = np.diag([0.5])
78-
79-
y_tt = tt.as_tensor_variable(np.r_[-3.])
80-
y_tt.name = 'y'
81-
82-
with pm.Model() as model:
83-
84-
# A normal prior
85-
beta_rv = pm.MvNormal('beta', a_tt, R_tt, shape=(2,))
86-
87-
# An observed random variable using the prior as a regression parameter
88-
E_y_rv = F_t_tt.dot(beta_rv)
89-
Y_rv = pm.MvNormal('Y', E_y_rv, V_tt, observed=y_tt)
90-
91-
# Create a graph for the model
92-
fgraph = model_graph(model, output_vars=[Y_rv])
93-
94-
95-
def conjugate_graph(graph):
96-
"""Apply conjugate relations throughout a graph."""
97-
98-
def fixedp_conjugate_applyo(x, y):
99-
return reduceo(partial(walko, conjugate), x, y)
100-
101-
expr_graph, = run(1, var('q'),
102-
fixedp_conjugate_applyo(graph, var('q')))
103-
104-
fgraph_opt = expr_graph.eval_obj
105-
fgraph_opt_tt = fgraph_opt.reify()
106-
return fgraph_opt_tt
107-
108-
109-
fgraph_conj = conjugate_graph(fgraph.outputs[0])
110-
```
111-
112-
Before:
113-
```python
114-
>>> print(tt_pprint(fgraph))
115-
F in R**(N^F_0 x N^F_1), a in R**(N^a_0), R in R**(N^R_0 x N^R_1)
116-
V in R**(N^V_0 x N^V_1)
117-
beta ~ N(a, R) in R**(N^beta_0), Y ~ N((F * beta), V) in R**(N^Y_0)
118-
Y = [-3.]
119-
```
120-
121-
After:
122-
```python
123-
>>> print(tt_pprint(fgraph_conj))
124-
a in R**(N^a_0), R in R**(N^R_0 x N^R_1), F in R**(N^F_0 x N^F_1)
125-
c in R**(N^c_0 x N^c_1), d in R**(N^d_0 x N^d_1)
126-
V in R**(N^V_0 x N^V_1), e in R**(N^e_0 x N^e_1)
127-
b ~ N((a + (((R * F.T) * c) * ([-3.] - (F * a)))), (R - ((((R * F.T) * d) * (V + (F * (R * F.T)))) * ((R * F.T) * e).T))) in R**(N^b_0)
128-
b
129-
```
130-
131-
### Automatic Re-centering and Re-scaling
132-
133-
We can automate the PyMC3 model recentering and rescaling in ["Why hierarchical models are awesome, tricky, and Bayesian"](https://twiecki.io/blog/2017/02/08/bayesian-hierchical-non-centered/) and improve sample chain quality:
134-
135-
```python
136-
import numpy as np
137-
import pandas as pd
138-
139-
import pymc3 as pm
140-
141-
import theano
142-
import theano.tensor as tt
143-
144-
from functools import partial
145-
146-
from unification import var
147-
148-
from kanren import run
149-
from kanren.graph import reduceo
150-
151-
from symbolic_pymc.theano.meta import mt
152-
from symbolic_pymc.theano.pymc3 import model_graph, graph_model
153-
from symbolic_pymc.theano.utils import canonicalize
154-
155-
from symbolic_pymc.relations.theano import non_obs_walko
156-
from symbolic_pymc.relations.theano.distributions import scale_loc_transform
157-
158-
159-
tt.config.compute_test_value = 'ignore'
160-
161-
data = pd.read_csv('https://github.com/pymc-devs/pymc3/raw/master/pymc3/examples/data/radon.csv')
162-
data['log_radon'] = data['log_radon'].astype(theano.config.floatX)
163-
county_names = data.county.unique()
164-
county_idx = data.county_code.values
165-
166-
n_counties = len(data.county.unique())
167-
168-
with pm.Model() as model_centered:
169-
mu_a = pm.Normal('mu_a', mu=0., sd=100**2)
170-
sigma_a = pm.HalfCauchy('sigma_a', 5)
171-
mu_b = pm.Normal('mu_b', mu=0., sd=100**2)
172-
sigma_b = pm.HalfCauchy('sigma_b', 5)
173-
a = pm.Normal('a', mu=mu_a, sd=sigma_a, shape=n_counties)
174-
b = pm.Normal('b', mu=mu_b, sd=sigma_b, shape=n_counties)
175-
eps = pm.HalfCauchy('eps', 5)
176-
radon_est = a[county_idx] + b[county_idx] * data.floor.values
177-
radon_like = pm.Normal('radon_like', mu=radon_est, sd=eps,
178-
observed=data.log_radon)
179-
180-
# Convert the PyMC3 graph into a symbolic-pymc graph
181-
fgraph = model_graph(model_centered)
182-
# Perform a set of standard algebraic simplifications
183-
fgraph = canonicalize(fgraph, in_place=False)
184-
185-
186-
def reparam_graph(graph):
187-
"""Apply re-parameterization relations throughout a graph."""
188-
189-
graph_mt = mt(graph)
190-
191-
def scale_loc_fixedp_walko(x, y):
192-
return reduceo(partial(non_obs_walko, scale_loc_transform), x, y)
193-
194-
expr_graph = run(0, var('q'),
195-
# Apply our transforms to unobserved RVs only
196-
scale_loc_fixedp_walko(graph_mt, var('q')))
197-
198-
expr_graph = expr_graph[0]
199-
opt_graph_tt = expr_graph.reify()
200-
201-
# PyMC3 needs names for each RV
202-
opt_graph_tt.owner.inputs[1].name = 'Y_new'
203-
204-
return opt_graph_tt
205-
206-
207-
fgraph_reparam = reparam_graph(fgraph.outputs[0])
208-
209-
# Convert the symbolic-pymc graph into a PyMC3 graph so that we can sample it
210-
model_recentered = graph_model(fgraph_reparam)
211-
212-
np.random.seed(123)
213-
214-
with model_centered:
215-
centered_trace = pm.sample(draws=5000, tune=1000, cores=4)[1000:]
216-
217-
with model_recentered:
218-
recentered_trace = pm.sample(draws=5000, tune=1000, cores=4)[1000:]
219-
```
220-
221-
Before:
222-
```python
223-
>>> pm.traceplot(centered_trace, varnames=['sigma_b'])
224-
```
225-
![](images/centered_trace.png)
226-
227-
After:
228-
```python
229-
>>> pm.traceplot(recentered_trace, varnames=['sigma_b'])
230-
```
231-
![](images/recentered_trace.png)

docs/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line, and also
5+
# from the environment for the first two.
6+
SPHINXOPTS ?=
7+
SPHINXBUILD ?= sphinx-build
8+
SOURCEDIR = source
9+
BUILDDIR = build
10+
11+
# Put it first so that "make" without argument is like "make help".
12+
help:
13+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14+
15+
.PHONY: help Makefile
16+
17+
# Catch-all target: route all unknown targets to Sphinx using the new
18+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19+
%: Makefile
20+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

0 commit comments

Comments
 (0)