Skip to content

Commit 2dfd78c

Browse files
committed
refine docs, add dev-docs
1 parent f0f2e58 commit 2dfd78c

File tree

5 files changed

+333
-100
lines changed

5 files changed

+333
-100
lines changed

pymc3/variational/approximations.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ def __init_group__(self, group):
414414
)
415415
if not isinstance(formula, flows.Formula):
416416
formula = flows.Formula(formula)
417-
if self.islocal:
417+
if self.local:
418418
bs = -1
419419
elif self.batched:
420420
bs = self.bdim
@@ -500,7 +500,7 @@ def symbolic_random(self):
500500

501501
@node_property
502502
def bdim(self):
503-
if not self.islocal:
503+
if not self.local:
504504
return super(NormalizingFlowGroup, self).bdim
505505
else:
506506
return next(iter(self.user_params[0].values())).shape[0]
@@ -533,11 +533,11 @@ def sample_approx(approx, draws=100, include_transformed=True):
533533
# single group shortcuts exported to user
534534
class SingleGroupApproximation(Approximation):
535535
"""Base class for Single Group Approximation"""
536-
group_class = None
536+
_group_class = None
537537

538538
def __init__(self, *args, **kwargs):
539539
local_rv = kwargs.get('local_rv')
540-
groups = [self.group_class(None, *args, **kwargs)]
540+
groups = [self._group_class(None, *args, **kwargs)]
541541
if local_rv is not None:
542542
groups.extend([Group([v], params=p, local=True, model=kwargs.get('model'))
543543
for v, p in local_rv.items()])
@@ -549,17 +549,17 @@ def __getattr__(self, item):
549549

550550
class MeanField(SingleGroupApproximation):
551551
"""Single Group Mean Field Approximation"""
552-
group_class = MeanFieldGroup
552+
_group_class = MeanFieldGroup
553553

554554

555555
class FullRank(SingleGroupApproximation):
556556
"""Single Group Full Rank Approximation"""
557-
group_class = FullRankGroup
557+
_group_class = FullRankGroup
558558

559559

560560
class Empirical(SingleGroupApproximation):
561561
"""Single Group Full Rank Approximation"""
562-
group_class = EmpiricalGroup
562+
_group_class = EmpiricalGroup
563563

564564
def __init__(self, trace=None, size=None, **kwargs):
565565
if kwargs.get('local_rv', None) is not None:
@@ -569,7 +569,7 @@ def __init__(self, trace=None, size=None, **kwargs):
569569

570570
class NormalizingFlow(SingleGroupApproximation):
571571
"""Single Group Normalizing Flow Approximation"""
572-
group_class = NormalizingFlowGroup
572+
_group_class = NormalizingFlowGroup
573573

574574
def __init__(self, flow=NormalizingFlowGroup.default_flow, *args, **kwargs):
575575
kwargs['flow'] = flow

pymc3/variational/flows.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def flow_for_short_name(cls, name):
129129
return cls.__name_registry[name.lower()]
130130

131131
def __init__(self, z0=None, dim=None, jitter=.001, batch_size=None, local=False):
132-
self.islocal = local
132+
self.local = local
133133
self.batch_size = batch_size
134134
self.__jitter = jitter
135135
if isinstance(z0, AbstractFlow):
@@ -155,7 +155,7 @@ def add_param(self, user=None, name=None, ref=0., dtype='floatX'):
155155
spec = self.__param_spec__[name]
156156
shape = tuple(eval(s, {'d': self.dim}) for s in spec)
157157
if user is None:
158-
if self.islocal:
158+
if self.local:
159159
raise opvi.LocalGroupError('Need parameters for local group flow')
160160
if self.batched:
161161
if self.batch_size is None:
@@ -168,7 +168,7 @@ def add_param(self, user=None, name=None, ref=0., dtype='floatX'):
168168

169169
else:
170170
if self.batched:
171-
if self.islocal or self.batch_size is None:
171+
if self.local or self.batch_size is None:
172172
shape = (-1,) + shape
173173
else:
174174
shape = (self.batch_size,) + shape

pymc3/variational/inference.py

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@
3232

3333

3434
class Inference(object):
35-
R"""
36-
Base class for Variational Inference
35+
R"""**Base class for Variational Inference**
3736
3837
Communicates Operator, Approximation and Test Function to build Objective Function
3938
@@ -87,8 +86,7 @@ def run_profiling(self, n=1000, score=None, **kwargs):
8786

8887
def fit(self, n=10000, score=None, callbacks=None, progressbar=True,
8988
**kwargs):
90-
"""
91-
Performs Operator Variational Inference
89+
"""Perform Operator Variational Inference
9290
9391
Parameters
9492
----------
@@ -100,8 +98,29 @@ def fit(self, n=10000, score=None, callbacks=None, progressbar=True,
10098
calls provided functions after each iteration step
10199
progressbar : bool
102100
whether to show progressbar or not
103-
kwargs : kwargs
104-
additional kwargs for :func:`ObjectiveFunction.step_function`
101+
102+
Other Parameters
103+
----------------
104+
obj_n_mc : `int`
105+
Number of monte carlo samples used for approximation of objective gradients
106+
tf_n_mc : `int`
107+
Number of monte carlo samples used for approximation of test function gradients
108+
obj_optimizer : function (grads, params) -> updates
109+
Optimizer that is used for objective params
110+
test_optimizer : function (grads, params) -> updates
111+
Optimizer that is used for test function params
112+
more_obj_params : `list`
113+
Add custom params for objective optimizer
114+
more_tf_params : `list`
115+
Add custom params for test function optimizer
116+
more_updates : `dict`
117+
Add custom updates to resulting updates
118+
total_grad_norm_constraint : `float`
119+
Bounds gradient norm, prevents exploding gradient problem
120+
fn_kwargs : `dict`
121+
Add kwargs to theano.function (e.g. `{'profile': True}`)
122+
more_replacements : `dict`
123+
Apply custom replacements before calculating gradients
105124
106125
Returns
107126
-------
@@ -198,7 +217,8 @@ def _infmean(input_array):
198217
score=True)
199218

200219
def refine(self, n, progressbar=True):
201-
"""Refine the solution using the last compiled step function"""
220+
"""Refine the solution using the last compiled step function
221+
"""
202222
if self.state is None:
203223
raise TypeError('Need to call `.fit` first')
204224
i, step, callbacks, score = self.state
@@ -211,19 +231,22 @@ def refine(self, n, progressbar=True):
211231

212232

213233
class KLqp(Inference):
214-
"""General approach to fit Approximations that define :math:`logq`
215-
by maximizing ELBO (Evidence Lower BOund).
234+
"""**Kullback Leibler Divergence Inference**
235+
236+
General approach to fit Approximations that define :math:`logq`
237+
by maximizing ELBO (Evidence Lower Bound).
216238
217239
Parameters
218240
----------
219241
approx : :class:`Approximation`
242+
Approximation to fit, it is required to have `logQ`
220243
"""
221244
def __init__(self, approx):
222245
super(KLqp, self).__init__(KL, approx, None)
223246

224247

225248
class ADVI(KLqp):
226-
R"""Automatic Differentiation Variational Inference (ADVI)
249+
R"""**Automatic Differentiation Variational Inference (ADVI)**
227250
228251
This class implements the meanfield ADVI, where the variational
229252
posterior distribution is assumed to be spherical Gaussian without
@@ -341,7 +364,7 @@ class ADVI(KLqp):
341364
Parameters
342365
----------
343366
local_rv : dict[var->tuple]
344-
mapping {model_variable -> local_variable (:math:`\mu`, :math:`\rho`)}
367+
mapping {model_variable -> approx params}
345368
Local Vars are used for Autoencoding Variational Bayes
346369
See (AEVB; Kingma and Welling, 2014) for details
347370
model : :class:`pymc3.Model`
@@ -371,12 +394,12 @@ def __init__(self, *args, **kwargs):
371394

372395

373396
class FullRankADVI(KLqp):
374-
R"""Full Rank Automatic Differentiation Variational Inference (ADVI)
397+
R"""**Full Rank Automatic Differentiation Variational Inference (ADVI)**
375398
376399
Parameters
377400
----------
378401
local_rv : dict[var->tuple]
379-
mapping {model_variable -> local_variable (:math:`\mu`, :math:`\rho`)}
402+
mapping {model_variable -> approx params}
380403
Local Vars are used for Autoencoding Variational Bayes
381404
See (AEVB; Kingma and Welling, 2014) for details
382405
model : :class:`pymc3.Model`
@@ -406,7 +429,9 @@ def __init__(self, *args, **kwargs):
406429

407430

408431
class ImplicitGradient(Inference):
409-
"""Implicit Gradient for Variational Inference
432+
"""**Implicit Gradient for Variational Inference**
433+
434+
**not suggested to use**
410435
411436
An approach to fit arbitrary approximation by computing kernel based gradient
412437
By default RBF kernel is used for gradient estimation. Default estimator is
@@ -424,7 +449,7 @@ def __init__(self, approx, estimator=KSD, kernel=test_functions.rbf, **kwargs):
424449

425450

426451
class SVGD(ImplicitGradient):
427-
R"""Stein Variational Gradient Descent
452+
R"""**Stein Variational Gradient Descent**
428453
429454
This inference is based on Kernelized Stein Discrepancy
430455
it's main idea is to move initial noisy particles so that
@@ -433,9 +458,9 @@ class SVGD(ImplicitGradient):
433458
Algorithm is outlined below
434459
435460
*Input:* A target distribution with density function :math:`p(x)`
436-
and a set of initial particles :math:`{x^0_i}^n_{i=1}`
461+
and a set of initial particles :math:`\{x^0_i\}^n_{i=1}`
437462
438-
*Output:* A set of particles :math:`{x_i}^n_{i=1}` that approximates the target distribution.
463+
*Output:* A set of particles :math:`\{x^{*}_i\}^n_{i=1}` that approximates the target distribution.
439464
440465
.. math::
441466
@@ -490,7 +515,9 @@ def __init__(self, n_particles=100, jitter=1, model=None, start=None,
490515

491516

492517
class ASVGD(ImplicitGradient):
493-
R"""Amortized Stein Variational Gradient Descent
518+
R"""**Amortized Stein Variational Gradient Descent**
519+
520+
**not suggested to use**
494521
495522
This inference is based on Kernelized Stein Discrepancy
496523
it's main idea is to move initial noisy particles so that
@@ -585,7 +612,7 @@ def run_profiling(self, n=1000, score=None, obj_n_mc=500, **kwargs):
585612

586613

587614
class NFVI(KLqp):
588-
R"""Normalizing Flow based :class:`KLqp` inference
615+
R"""**Normalizing Flow based :class:`KLqp` inference**
589616
590617
Normalizing flow is a series of invertible transformations on initial distribution.
591618
@@ -648,15 +675,14 @@ def fit(n=10000, local_rv=None, method='advi', model=None,
648675
n : `int`
649676
number of iterations
650677
local_rv : dict[var->tuple]
651-
mapping {model_variable -> local_variable (:math:`\mu`, :math:`\rho`)}
678+
mapping {model_variable -> approx params}
652679
Local Vars are used for Autoencoding Variational Bayes
653680
See (AEVB; Kingma and Welling, 2014) for details
654681
method : str or :class:`Inference`
655682
string name is case insensitive in:
656683
657684
- 'advi' for ADVI
658685
- 'fullrank_advi' for FullRankADVI
659-
- 'advi->fullrank_advi' for fitting ADVI first and then FullRankADVI
660686
- 'svgd' for Stein Variational Gradient Descent
661687
- 'asvgd' for Amortized Stein Variational Gradient Descent
662688
- 'nfvi' for Normalizing Flow with default `scale-loc` flow
@@ -671,8 +697,35 @@ def fit(n=10000, local_rv=None, method='advi', model=None,
671697
additional kwargs passed to :class:`Inference`
672698
start : `Point`
673699
starting point for inference
674-
kwargs : kwargs
675-
additional kwargs for :func:`Inference.fit`
700+
701+
Other Parameters
702+
----------------
703+
score : bool
704+
evaluate loss on each iteration or not
705+
callbacks : list[function : (Approximation, losses, i) -> None]
706+
calls provided functions after each iteration step
707+
progressbar : bool
708+
whether to show progressbar or not
709+
obj_n_mc : `int`
710+
Number of monte carlo samples used for approximation of objective gradients
711+
tf_n_mc : `int`
712+
Number of monte carlo samples used for approximation of test function gradients
713+
obj_optimizer : function (grads, params) -> updates
714+
Optimizer that is used for objective params
715+
test_optimizer : function (grads, params) -> updates
716+
Optimizer that is used for test function params
717+
more_obj_params : `list`
718+
Add custom params for objective optimizer
719+
more_tf_params : `list`
720+
Add custom params for test function optimizer
721+
more_updates : `dict`
722+
Add custom updates to resulting updates
723+
total_grad_norm_constraint : `float`
724+
Bounds gradient norm, prevents exploding gradient problem
725+
fn_kwargs : `dict`
726+
Add kwargs to theano.function (e.g. `{'profile': True}`)
727+
more_replacements : `dict`
728+
Apply custom replacements before calculating gradients
676729
677730
Returns
678731
-------

pymc3/variational/operators.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@
1212

1313

1414
class KL(Operator):
15-
"""
16-
Operator based on Kullback Leibler Divergence
15+
R"""**Operator based on Kullback Leibler Divergence**
1716
1817
.. math::
1918
20-
KL[q(v)||p(v)] = \int q(v)\log\\frac{q(v)}{p(v)}dv
19+
KL[q(v)||p(v)] = \int q(v)\log\frac{q(v)}{p(v)}dv
2120
"""
21+
2222
def apply(self, f):
2323
return self.logq_norm - self.logp_norm
2424

2525
# SVGD Implementation
2626

2727

2828
class KSDObjective(ObjectiveFunction):
29-
"""Helper class for construction loss and updates for variational inference
29+
R"""Helper class for construction loss and updates for variational inference
3030
3131
Parameters
3232
----------
@@ -59,8 +59,7 @@ def __call__(self, nmc, **kwargs):
5959

6060

6161
class KSD(Operator):
62-
R"""
63-
Operator based on Kernelized Stein Discrepancy
62+
R"""**Operator based on Kernelized Stein Discrepancy**
6463
6564
Input: A target distribution with density function :math:`p(x)`
6665
and a set of initial particles :math:`\{x^0_i\}^n_{i=1}`
@@ -74,8 +73,8 @@ class KSD(Operator):
7473
7574
Parameters
7675
----------
77-
approx : :class:`Empirical`
78-
Empirical Approximation used for inference
76+
approx : :class:`Approximation`
77+
Approximation used for inference
7978
8079
References
8180
----------

0 commit comments

Comments
 (0)