特此声明:本博文为我的另一片博文 PyMC3 概率编程入门 的从博文,之前属于其中的一部分内容,但是因为该篇主博文内容较多,整体比较繁杂,阅读体验感较差,并且今后对该主博文会做更新,将其作为学习笔记。因此出于学习目的,我决定将主博文定位为入门 PyMC3 概率编程的学习脉络与框架部分,而将其中的细节于诸多从博文中展示,这样既符合模块化思维,又提升主博文的阅读体验,以防自己和观看的同学们在繁杂的内容中找不到重点。因为该篇博文是从博文,所以会和主博文有一定的联系,不过我会尽量将知识点独立地剥离出来,如果大家有什么不清楚的地方,请在评论区提出,我会尽快修改,有兴趣的同学可以移步至主博文阅读一下。
sample() 函数
通过本篇博文我们来了解一下 sample()
函数,这个函数的参数比较多,接下来对这些参数一个一个来解释,帮助大家弄清楚它们分别代表什么意思:
def sample(draws=500, step=None, init="auto", n_init=200000, start=None, trace=None,
chain_idx=0, chains=None, cores=None, tune=500, progressbar=True, model=None,
random_seed=None, discard_tuned_samples=True, compute_convergence_checks=True,
**kwargs)
-
draws:
int
类型,表示通过 MCMC 方法采样出的正式样本的数量,默认为 500,这里的正式样本是相对于预烧期样本来说的,预烧期的样本数量对应参数tune
,等下也会解释它,这里举个例子,假如将draws=5000, tune=1000
传入sample()
函数,那么对于一条 MCMC 链来说,前面 1000 个采样出来的样本不算进正式的采样样本,而后 5000 个采样出来的样本(1001 ~ 6000)才是正式采样的样本; -
step:
BlockedStep
类的子类的实例化对象类型,表示所选择的 MCMC 采样算法(step method),PyMC3 中提供了内置的采样算法,比如 NUTS、Metropolis、Slice、HamiltonianMC 和 BinaryMetropolis 等,采样算法可以由 PyMC3 自动指定也可以手动进行指定,自动指定是根据模型中的变量类型决定的,手动指定优先,可覆盖自动指定,如下为自动指定的采样算法:- 二值变量:自动指定 BinaryMetropolis 采样算法
- 离散变量:自动指定 Metropolis 采样算法
- 连续变量:自动指定 NUTS 采样算法
概念大家大概了解就行,我们来举个例子,看看怎么使用这个参数,假如现在我有
alpha
、beta
和sigma
三个参数,而我想要对我的参数alpha
使用 Slice 采样算法进行采样,那么我们可以实例化一个Slice
类的对象,然后将该实例对象传给step
,可以看到在进度条显示出模型使用 Slice 采样算法对alpha
进行采样,而因为我没有指定对beta
和sigma
使用什么采样算法,所以模型会自动默认使用 NUTS 采样算法对它们进行采样:
那假如对beta
和sigma
两个参数我也想自己指定所使用的采用算法,那我可以这样做,分别使用Slice
类、Metropolis
类 和NUTS
类实例化对象,然后将这个实例对象组成列表传给step
:
-
init:
str
类型,表示使用 NUTS 采样算法时所使用的的初始化方法,默认为 “auto” 即自动选择一个较好的初始化方法; -
n_init:
int
类型,表示初始化的迭代次数,默认为 200000,仅在init
参数为 “nuts” 或 “advi” 时有效; -
start:
dict
类型,表示 MCMC 采样时参数的初始值的字典,默认是模型自带的测试点,一般以start={'alpha':1, 'beta':2, 'theta':3}
的形式进行传参,实际上,我们很多时候都先使用find_MAP()
函数来计算参数的极大似然点估计值,然后将该点估计值作为采样时参数的初始值,关于find_MAP()
函数的具体内容大家可以参照:PyMC3 API 解读(一)—— find_MAP() 函数:
-
trace:
list
类型,表示模型在后台要跟踪的变量; -
chain_idx:
int
类型,表示 MCMC 链存储在后台的编号的起始值,默认为 0,比如说如果我的参数设置为chain_idx=1, chains=4
,那么就会产生四条独立的 MCMC 链,且它们存储在后台的编号分别为 1, 2, 3, 4,而不是 0, 1, 2, 3; -
chains:
int
类型,表示采样时生成的 MCMC 链的数量,并且这些链是相互独立的,如果被设置为 None 也就是不显式地传入参数给chains
,那么就在cores
参数和 2 之间选一个更大的数作为参数值传给chains
; -
cores:
int
类型,表示并行运行的链的数量,如果被设置为 None 也就是不显式地传入参数给cores
,那么就将当前主机的 CPU 的个数作为参数值传给cores
,不过参数值最大不超过 4; -
tune:
int
类型,表示调参过程的迭代轮数,默认为 500,其实这就是预烧期的样本的数量,所谓预烧期就是我们在产生 MCMC 链的时候,前面采样出的一部分样本可能不是平稳分布的 MCMC 链所产生的,而后面的由平稳分布的 MCMC 链产生的采样样本才是我们真正想要的,因此我们常常会丢弃预烧期的样本,不过在sample()
函数当中是否丢弃预烧期样本由参数discard_tuned_samples
决定; -
progressbar:
bool
类型,表示是否在命令行中显示程序运行时的进度条; -
model:
Model
类型,表示当前的模型,如果find_MAP()
函数是在with pm.Model()
上下文管理器中,那这个参数就不用指定,如果不在则需要指定,否则会报错; -
random_seed:
int
类型,表示设置的随机数种子; -
discard_tuned_samples:
bool
类型,表示是否丢弃预烧期样本,默认为 True,则最后返回的采样样本数不包括预烧期的样本数即丢弃预烧期的样本,以之前的例子来讲,假如将draws=5000, tune=1000
传入sample()
函数,然后将discard_tuned_samples
分别设置为 True 和 False,我们来分别观察它们的不同点:
我们可以看到它们在进度条显示的内容相差不多,那我们打印一下它们采样的结果,我们会发现,当discard_tuned_samples
设置为 True 时,最终采样出 20000 个样本,设置为 False 时,最终采样出 24000 个样本,这是因为我们一次采样过程会产生 4 条独立的 MCMC 链,所以如果丢弃tune=1000
个预烧期样本就是 5000 * 4 = 20000,而将预烧期样本保留下来就是 (5000 + 1000) * 4 = 24000:
-
compute_convergence_checks:
bool
类型,表示是否计算样本的数据统计,默认为 True; -
**kwargs:还未探究。
注:上述众多参数中使用粗体表示的是我基本探究清楚的,而未使用粗体表示的是还没有探究清楚的和还未探究的。
sample()
函数的返回值是一个 pymc3.backends.base.MultiTrace
类的对象,大家可以把它当作字典来用,如下:
关于 sample()
函数,下面也给出了它在源码中的说明和参数解释,大家可以参考一下:
def sample(draws=500, step=None, init="auto", n_init=200000, start=None, trace=None,
chain_idx=0, chains=None, cores=None, tune=500, progressbar=True, model=None,
random_seed=None, discard_tuned_samples=True, compute_convergence_checks=True,
**kwargs)
"""
Draw samples from the posterior using the given step methods.
Multiple step methods are supported via compound step methods.
Parameters
----------
draws : int
The number of samples to draw. Defaults to 500. The number of tuned samples are discarded
by default. See ``discard_tuned_samples``.
step : function or iterable of functions
A step function or collection of functions. If there are variables without step methods,
step methods for those variables will be assigned automatically. By default the NUTS step
method will be used, if appropriate to the model; this is a good default for beginning
users.
init : str
Initialization method to use for auto-assigned NUTS samplers.
* auto : Choose a default initialization method automatically.
Currently, this is ``'jitter+adapt_diag'``, but this can change in the future.
If you depend on the exact behaviour, choose an initialization method explicitly.
* adapt_diag : Start with a identity mass matrix and then adapt a diagonal based on the
variance of the tuning samples. All chains use the test value (usually the prior mean)
as starting point.
* jitter+adapt_diag : Same as ``adapt_diag``\, but add uniform jitter in [-1, 1] to the
starting point in each chain.
* advi+adapt_diag : Run ADVI and then adapt the resulting diagonal mass matrix based on the
sample variance of the tuning samples.
* advi+adapt_diag_grad : Run ADVI and then adapt the resulting diagonal mass matrix based
on the variance of the gradients during tuning. This is **experimental** and might be
removed in a future release.
* advi : Run ADVI to estimate posterior mean and diagonal mass matrix.
* advi_map: Initialize ADVI with MAP and use MAP as starting point.
* map : Use the MAP as starting point. This is discouraged.
* nuts : Run NUTS and estimate posterior mean and mass matrix from the trace.
n_init : int
Number of iterations of initializer. Only works for 'nuts' and 'ADVI'.
If 'ADVI', number of iterations, if 'nuts', number of draws.
start : dict, or array of dict
Starting point in parameter space (or partial point)
Defaults to ``trace.point(-1))`` if there is a trace provided and model.test_point if not
(defaults to empty dict). Initialization methods for NUTS (see ``init`` keyword) can
overwrite the default.
trace : backend, list, or MultiTrace
This should be a backend instance, a list of variables to track, or a MultiTrace object
with past values. If a MultiTrace object is given, it must contain samples for the chain
number ``chain``. If None or a list of variables, the NDArray backend is used.
Passing either "text" or "sqlite" is taken as a shortcut to set up the corresponding
backend (with "mcmc" used as the base name).
chain_idx : int
Chain number used to store sample in backend. If ``chains`` is greater than one, chain
numbers will start here.
chains : int
The number of chains to sample. Running independent chains is important for some
convergence statistics and can also reveal multiple modes in the posterior. If ``None``,
then set to either ``cores`` or 2, whichever is larger.
cores : int
The number of chains to run in parallel. If ``None``, set to the number of CPUs in the
system, but at most 4.
tune : int
Number of iterations to tune, defaults to 500. Samplers adjust the step sizes, scalings or
similar during tuning. Tuning samples will be drawn in addition to the number specified in
the ``draws`` argument, and will be discarded unless ``discard_tuned_samples`` is set to
False.
progressbar : bool
Whether or not to display a progress bar in the command line. The bar shows the percentage
of completion, the sampling speed in samples per second (SPS), and the estimated remaining
time until completion ("expected time of arrival"; ETA).
model : Model (optional if in ``with`` context)
random_seed : int or list of ints
A list is accepted if ``cores`` is greater than one.
discard_tuned_samples : bool
Whether to discard posterior samples of the tune interval.
compute_convergence_checks : bool, default=True
Whether to compute sampler statistics like Gelman-Rubin and ``effective_n``.
Returns
-------
trace : pymc3.backends.base.MultiTrace
A ``MultiTrace`` object that contains the samples.
"""