SVI¶
- class SVI(model, guide, optim, loss, loss_and_grads=None, num_samples=0, num_steps=0, **kwargs)[source]¶
Bases:
pyro.infer.abstract_infer.TracePosterior
- 参数
model – 模型(包含 Pyro 原语的可调用对象)
guide – 导引函数(包含 Pyro 原语的可调用对象)
optim (PyroOptim) – PyTorch 优化器的包装器
loss (pyro.infer.elbo.ELBO) –
ELBO
子类的实例。Pyro 提供了三个内置损失函数:Trace_ELBO
、TraceGraph_ELBO
和TraceEnum_ELBO
。请参阅ELBO
文档了解如何实现自定义损失函数。num_samples – (已弃用) 用于蒙特卡洛后验近似的样本数量
num_steps – (已弃用) 在
run()
中执行的优化步数
Pyro 中随机变分推断的统一接口。最常用的损失函数是
loss=Trace_ELBO()
。请参阅教程 SVI 第一部分 进行讨论。- run(*args, **kwargs)[source]¶
警告
此方法已弃用,并将在未来的版本中移除。对于推断,请直接使用
step()
;对于预测,请使用Predictive
类。
ELBO¶
- class ELBOModule(model: torch.nn.modules.module.Module, guide: torch.nn.modules.module.Module, elbo: pyro.infer.elbo.ELBO)[source]¶
- class ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
object
ELBO
是通过优化证据下界进行随机变分推断的顶级接口。大多数用户不会直接与此基类
ELBO
交互;相反,他们将创建派生类的实例:Trace_ELBO
、TraceGraph_ELBO
或TraceEnum_ELBO
。注意
派生类现在通过
__call__()
为Module
类型的 (model, guide) 对提供了更符合习惯用法的 PyTorch 接口,这对于将 Pyro 的变分推断工具与Optimizer
等标准 PyTorch 接口以及 PyTorch Lightning 和 PyTorch JIT 等适用于这些接口的大量库生态系统集成非常有用model = Model() guide = pyro.infer.autoguide.AutoNormal(model) elbo_ = pyro.infer.Trace_ELBO(num_particles=10) # Fix the model/guide pair elbo = elbo_(model, guide) # perform any data-dependent initialization elbo(data) optim = torch.optim.Adam(elbo.parameters(), lr=0.001) for _ in range(100): optim.zero_grad() loss = elbo(data) loss.backward() optim.step()
请注意,在使用
PyroModule
时,Pyro 的全局参数存储可能会导致此新接口相对于标准 PyTorch 的行为出现意外。因此,强烈建议用户结合使用此接口和
pyro.settings.set(module_local_params=True)
,这将覆盖PyroModule
实例之间默认的隐式参数共享。- 参数
num_particles – 用于形成 ELBO (梯度) 估计器的粒子/样本数量。
max_plate_nesting (int) – 嵌套
pyro.plate()
上下文的最大数量的可选边界。仅在并行枚举样本点时需要此项,例如如果一个点设置了infer={"enumerate": "parallel"}
。如果省略,ELBO 可能会通过运行一次 (model, guide) 对来猜测一个有效值,但是如果模型或导引函数结构是动态的,此猜测可能不正确。vectorize_particles (bool) – 是否对 num_particles 进行 ELBO 计算的向量化。默认为 False。这要求模型和导引函数具有静态结构。
strict_enumeration_warning (bool) – 是否警告可能误用枚举,例如,仅当存在可枚举的样本点时才使用
pyro.infer.traceenum_elbo.TraceEnum_ELBO
。ignore_jit_warnings (bool) – 忽略 JIT tracer 警告的标志。当此参数为 True 时,所有
torch.jit.TracerWarning
将被忽略。默认为 False。jit_options (bool) – 可选的选项字典,用于传递给
torch.jit.trace()
,例如{"check_trace": True}
。retain_graph (bool) – 在 SVI 步骤期间是否保留 autograd 图。默认为 None (False)。
tail_adaptive_beta (float) – 指数 beta,满足
-1.0 <= beta < 0.0
,与 TraceTailAdaptive_ELBO 一起使用。
参考
[1] 概率编程中的自动化变分推断 David Wingate, Theo Weber
[2] 黑盒变分推断, Rajesh Ranganath, Sean Gerrish, David M. Blei
- class Trace_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.elbo.ELBO
基于 ELBO 的 SVI 的跟踪实现。估计器是根据参考 [1] 和 [2] 构建的。对模型或导引函数的依赖结构没有限制。当存在不可重参数化的随机变量时,梯度估计器包含部分 Rao-Blackwellization 以降低估计器的方差。Rao-Blackwellization 是部分的,因为它只使用由
plate
上下文标记的条件独立信息。有关更细粒度的 Rao-Blackwellization,请参阅TraceGraph_ELBO
。参考
- [1] 概率编程中的自动化变分推断,
David Wingate, Theo Weber
- [2] 黑盒变分推断,
Rajesh Ranganath, Sean Gerrish, David M. Blei
- loss(model, guide, *args, **kwargs)[source]¶
- 返回
返回 ELBO 的估计值
- 返回类型
使用 num_particles 个样本/粒子对 ELBO 进行评估。
- class JitTrace_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.trace_elbo.Trace_ELBO
与
Trace_ELBO
类似,但使用pyro.ops.jit.compile()
来编译loss_and_grads()
。这仅适用于有限的模型集合
模型必须具有静态结构。
模型不得依赖任何全局数据(参数存储除外)。
所有作为张量的模型输入必须通过
*args
传递。所有非张量的模型输入必须通过
**kwargs
传递,并且编译将针对每个唯一的**kwargs
触发一次。
- class TrackNonReparam[source]¶
Bases:
pyro.poutine.messenger.Messenger
跟踪不可重参数化的样本点。
参考
- 用于高效推断的概率程序的非标准解释,
David Wingate, Noah Goodman, Andreas Stuhlmüller, Jeffrey Siskind
示例
>>> import torch >>> import pyro >>> import pyro.distributions as dist >>> from pyro.infer.tracegraph_elbo import TrackNonReparam >>> from pyro.ops.provenance import get_provenance >>> from pyro.poutine import trace >>> def model(): ... probs_a = torch.tensor([0.3, 0.7]) ... probs_b = torch.tensor([[0.1, 0.9], [0.8, 0.2]]) ... probs_c = torch.tensor([[0.5, 0.5], [0.6, 0.4]]) ... a = pyro.sample("a", dist.Categorical(probs_a)) ... b = pyro.sample("b", dist.Categorical(probs_b[a])) ... pyro.sample("c", dist.Categorical(probs_c[b]), obs=torch.tensor(0)) >>> with TrackNonReparam(): ... model_tr = trace(model).get_trace() >>> model_tr.compute_log_prob() >>> print(get_provenance(model_tr.nodes["a"]["log_prob"])) frozenset({'a'}) >>> print(get_provenance(model_tr.nodes["b"]["log_prob"])) frozenset({'b', 'a'}) >>> print(get_provenance(model_tr.nodes["c"]["log_prob"])) frozenset({'b', 'a'})
- class TraceGraph_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.elbo.ELBO
基于 ELBO 的 TraceGraph 实现的 SVI。梯度估计器是根据参考 [1] 构建的,专门针对 ELBO 的情况。它支持模型和导引函数的任意依赖结构,以及用于不可重参数化随机变量的基线。记录在
Trace
中的细粒度条件依赖信息用于减少梯度估计器的方差。特别是,出处跟踪 [3] 用于查找依赖于每个不可重参数化样本点的cost
项。参考
- [1] 使用随机计算图进行梯度估计,
John Schulman, Nicolas Heess, Theophane Weber, Pieter Abbeel
- [2] 信仰网络中的神经变分推断和学习
Andriy Mnih, Karol Gregor
- [3] 用于高效推断的概率程序的非标准解释,
David Wingate, Noah Goodman, Andreas Stuhlmüller, Jeffrey Siskind
- class JitTraceGraph_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.tracegraph_elbo.TraceGraph_ELBO
与
TraceGraph_ELBO
类似,但使用torch.jit.trace()
来编译loss_and_grads()
。这仅适用于有限的模型集合
模型必须具有静态结构。
模型不得依赖任何全局数据(参数存储除外)。
所有作为张量的模型输入必须通过
*args
传递。所有非张量的模型输入必须通过
**kwargs
传递,并且编译将针对每个唯一的**kwargs
触发一次。
- class BackwardSampleMessenger(enum_trace, guide_trace)[source]¶
Bases:
pyro.poutine.messenger.Messenger
实现前向滤波 / 后向采样,用于从联合后验分布中采样。
- class TraceEnum_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.elbo.ELBO
基于 ELBO 的 SVI 的跟踪实现,支持:- 对离散样本点进行穷举枚举,以及 - 对导引函数中的任何样本点进行局部并行采样。
要在
guide
中枚举样本点,请使用infer={'enumerate': 'sequential'}
或infer={'enumerate': 'parallel'}
标记该点。要一次配置所有导引函数点,请使用config_enumerate()
。要在model
中枚举样本点,请将该点标记为infer={'enumerate': 'parallel'}
,并确保该点未出现在guide
中。这假定模型和导引函数具有受限的依赖结构:
plate
外部的变量不能依赖于该plate
内部的变量。- differentiable_loss(model, guide, *args, **kwargs)[source]¶
- 返回
ELBO 的可微分估计值
- 返回类型
- 引发
ValueError – 如果 ELBO 不可微分(例如,恒等于零)
使用
num_particles
个样本(粒子)估计可微分 ELBO。结果应该是无限可微分的(只要底层导数已实现)。
- loss_and_grads(model, guide, *args, **kwargs)[source]¶
- 返回
ELBO 的估计值
- 返回类型
使用
num_particles
个样本(粒子)估计 ELBO。对每个粒子的 ELBO 执行反向传播。
- class JitTraceEnum_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.traceenum_elbo.TraceEnum_ELBO
与
TraceEnum_ELBO
类似,但使用pyro.ops.jit.compile()
来编译loss_and_grads()
。这仅适用于有限的模型集合
模型必须具有静态结构。
模型不得依赖任何全局数据(参数存储除外)。
所有作为张量的模型输入必须通过
*args
传递。所有非张量的模型输入必须通过
**kwargs
传递,并且编译将针对每个唯一的**kwargs
触发一次。
- class TraceMeanField_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.trace_elbo.Trace_ELBO
基于 ELBO 的 SVI 的跟踪实现。这是 Pyro 中目前唯一在使用可用的解析 KL 散度时利用它们的 ELBO 估计器。
与
TraceGraph_ELBO
和Trace_ELBO
等不同,此估计器对模型和导引函数的依赖结构施加了限制。特别是,它假定导引函数具有均场结构 (mean-field structure),即它在导引函数中存在的不同潜在变量上是因子化的。它还假定导引函数中的所有潜在变量都是可重参数化的。后一个条件对于例如 Normal 分布是满足的,但对于例如 Categorical 分布则不满足。警告
如果未满足均场条件,此估计器可能会给出不正确的结果。
高级用户注意
均场条件是此估计器正确的一个充分但不必要条件。精确的条件是,对于导引函数中的每个潜在变量 z,其在模型中的父节点不能包含导引函数中作为 z 后代的任何潜在变量。这里的“在模型中的父节点”和“在导引函数中的后代”是相对于相应的(统计)依赖结构而言的。例如,如果模型和导引函数具有相同的依赖结构,则此条件总是满足的。
- class JitTraceMeanField_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.trace_mean_field_elbo.TraceMeanField_ELBO
与
TraceMeanField_ELBO
类似,但使用pyro.ops.jit.trace()
来编译loss_and_grads()
。这仅适用于有限的模型集合
模型必须具有静态结构。
模型不得依赖任何全局数据(参数存储除外)。
所有作为张量的模型输入必须通过
*args
传递。所有非张量的模型输入必须通过
**kwargs
传递,并且编译将针对每个唯一的**kwargs
触发一次。
- class TraceTailAdaptive_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.trace_elbo.Trace_ELBO
参考 [1] 中描述的,使用自适应 f-散度进行随机变分推断的接口。用户应指定 num_particles > 1 和 vectorize_particles==True。可以指定参数 tail_adaptive_beta 来修改自适应 f-散度的构建方式。详情请参阅参考文献。
请注意,此接口不支持计算变分目标本身;它只支持计算变分目标的梯度。因此,可能需要使用其他 SVI 接口(例如 RenyiELBO)来监控收敛。
请注意,此接口仅支持所有潜在变量都完全重参数化的模型。它也不支持数据子采样。
参考 [1] “变分推断与自适应尾部 f-散度”, Dilin Wang, Hao Liu, Qiang Liu, NeurIPS 2018 https://papers.nips.cc/paper/7816-variational-inference-with-tail-adaptive-f-divergence
- class RenyiELBO(alpha=0, num_particles=2, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True)[source]¶
Bases:
pyro.infer.elbo.ELBO
根据参考 [1] 实现 Renyi \(\alpha\) 散度变分推断。
为了使目标函数成为一个严格的下界,我们需要 \(\alpha \ge 0\)。然而请注意,根据参考 [1],取决于数据集,\(\alpha < 0\) 可能给出更好的结果。在特殊情况 \(\alpha = 0\) 时,目标函数是参考 [2] 中推导出的重要性加权自编码器 (important weighted autoencoder)。
注意
设置 \(\alpha < 1\) 会给出比通常的 ELBO 更好的下界。对于 \(\alpha = 1\),最好使用
Trace_ELBO
类,因为它可以帮助减少梯度估计的方差。- 参数
alpha (float) – \(\alpha\) 散度的阶数。此处 \(\alpha \neq 1\)。默认为 0。
num_particles – 用于形成目标 (梯度) 估计器的粒子/样本数量。默认为 2。
max_plate_nesting (int) – 嵌套
pyro.plate()
上下文的最大数量的边界。默认为无穷大。strict_enumeration_warning (bool) – 是否警告可能误用枚举,即,仅当存在可枚举的样本点时才使用
TraceEnum_ELBO
。
参考
- [1] Renyi 散度变分推断,
Yingzhen Li, Richard E. Turner
- [2] 重要性加权自编码器,
Yuri Burda, Roger Grosse, Ruslan Salakhutdinov
- class TraceTMC_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.elbo.ELBO
Tensor Monte Carlo [1] 的一个基于跟踪的实现,通过 Tensor Variable Elimination [2] 实现,支持: - 对模型或导引中的任何采样位置进行局部并行采样 - 对模型或导引中的任何采样位置进行穷举枚举
要进行多次采样,请将该位置标记为
infer={'enumerate': 'parallel', 'num_samples': N}
。要一次性配置模型或导引中的所有位置,请使用config_enumerate()
。要枚举或采样model
中的采样位置,请标记该位置并确保该位置不出现在guide
中。这假设模型和导引具有受限的依赖结构:
plate
之外的变量永远不能依赖于该plate
内部的变量。参考
- [1] Tensor Monte Carlo: Particle Methods for the GPU Era,
Laurence Aitchison (2018)
- [2] Tensor Variable Elimination for Plated Factor Graphs,
Fritz Obermeyer, Eli Bingham, Martin Jankowiak, Justin Chiu, Neeraj Pradhan, Alexander Rush, Noah Goodman (2019)
- differentiable_loss(model, guide, *args, **kwargs)[source]¶
- 返回
边际对数似然的可微分估计
- 返回类型
- 引发
ValueError – 如果 ELBO 不可微分(例如,恒等于零)
使用
num_particles
个样本(粒子)计算可微分的 TMC 估计。结果应该是无限可微的(只要底层导数已实现)。
重要性采样¶
- class Importance(model, guide=None, num_samples=None)[source]¶
基类:
pyro.infer.abstract_infer.TracePosterior
,pyro.infer.importance.LogWeightsMixin
- 参数
model – 定义为函数的概率模型
guide – 定义为函数的用于采样的 guide
num_samples – 从 guide 中抽取的样本数量(默认 10)
此方法通过使用 guide 作为提案分布进行重要性采样来执行后验推断。如果未提供 guide,则默认为从模型的先验进行提案。
- log_weights: Union[List[Union[float, torch.Tensor]], torch.Tensor]¶
- class LogWeightsMixin[source]¶
Bases:
object
用于从
.log_weights
属性计算分析结果的 Mixin 类。- log_weights: Union[List[Union[float, torch.Tensor]], torch.Tensor]¶
- psis_diagnostic(model, guide, *args, **kwargs)[source]¶
使用 [1] 中描述的技术计算模型/导引对的 Pareto 尾指数 k,该技术建立在 [2] 中的先前工作基础上。如果 \(0 < k < 0.5\),则导引对模型后验分布是一个很好的近似,如 [1] 中所述。如果 \(0.5 \le k \le 0.7\),导引对后验分布的近似欠佳,但在实践中可能仍然有用。如果 \(k > 0.7\),导引程序对完整后验分布的近似很差,使用时应谨慎。然而,请注意,导引可能与完整后验分布拟合不良,但仍能产生合理的模型预测。如果 \(k < 0.0\),对应于模型和导引的重要性权重似乎有上界;这对于通过 ELBO 最大化训练的导引来说是一个奇怪的结果。请参阅 [1] 以更全面地讨论尾指数 k 应如何解释。
请注意,可能需要大量样本才能准确估计 k。
请注意,我们假设模型和 guide 都已向量化且结构静态。与 Pyro 中的典型情况一样,args 和 kwargs 会传递给模型和 guide。
参考文献 [1] ‘Yes, but Did It Work?: Evaluating Variational Inference.’ Yuling Yao, Aki Vehtari, Daniel Simpson, Andrew Gelman [2] ‘Pareto Smoothed Importance Sampling.’ Aki Vehtari, Andrew Gelman, Jonah Gabry
- 参数
model (callable) – 模型程序。
guide (callable) – guide 程序。
num_particles (int) – 用于计算诊断的总共运行模型和导引的次数。默认为 1000。
max_simultaneous_particles – 从模型和 guide 中同时抽取的最大样本数量。默认为 num_particles。num_particles 必须能被 max_simultaneous_particles 整除。计算诊断。默认为 1000。
max_plate_nesting (int) – 模型/导引中嵌套
pyro.plate()
上下文的最大数量的可选边界。默认为 7。
- 返回 float
PSIS 诊断 k
重加权 Wake-Sleep¶
- class ReweightedWakeSleep(num_particles=2, insomnia=1.0, model_has_params=True, num_sleep_particles=None, vectorize_particles=True, max_plate_nesting=inf, strict_enumeration_warning=True)[source]¶
Bases:
pyro.infer.elbo.ELBO
Reweighted Wake Sleep 的实现,遵循参考文献 [1]。
注意
采样和 log_prob 评估的渐近复杂度
- 使用 wake-theta 和/或 wake-phi
从 guide 中采样 O(num_particles) 次,对模型和 guide 进行 O(num_particles) 次 log_prob 评估
- 使用 sleep-phi
从模型中采样 O(num_sleep_particles) 次,对 guide 进行 O(num_sleep_particles) 次 log_prob 评估
- 如果结合使用 1) 和 2),
从 guide 中采样 O(num_particles) 次,从模型中采样 O(num_sleep_particles) 次,对 guide 进行 O(num_particles + num_sleep_particles) 次 log_prob 评估,对模型进行 O(num_particles) 次评估
注意
这对于具有随机分支的模型特别有用,如 [2] 中所述。
注意
这返回 _两个_ 损失,一个用于模型参数 (theta),使用 iwae objective 计算;另一个用于 guide 参数 (phi),使用 csis objective 和/或自归一化重要性采样的 csis objective 计算。
注意
为了启用 sleep-phi 项的计算,guide 程序必须通过关键字参数 observations 显式传入其观测值。如果在定义期间观测值未知(例如对于摊销变分推断),可以将其默认参数设置为 observations=None,并在学习期间通过 svi.step(observations=…) 提供正确的值。
警告
暂不支持 Mini-batch 训练。
- 参数
num_particles (int) – 用于构成目标(梯度)估计器的粒子/样本数量。默认为 2。
insomnia – wake-phi 和 sleep-phi 项之间的缩放因子。默认值为 1.0 [wake-phi]
model_has_params (bool) – 指示模型是否具有可学习参数。在纯睡眠模式 [csis] 下运行时避免额外计算很有用。默认为 True。
num_sleep_particles (int) – 用于构成睡眠-phi 估计器的粒子数量。默认与 num_particles 匹配。
vectorize_particles (bool) – 是否应将跟踪矢量化以跨越 num_particles。默认为 True。
max_plate_nesting (int) – 嵌套
pyro.plate()
上下文的最大数量的边界。默认为无穷大。strict_enumeration_warning (bool) – 是否警告可能误用枚举,即,仅当存在可枚举的样本点时才使用
TraceEnum_ELBO
。
参考
- [1] Reweighted Wake-Sleep,
Jörg Bornschein, Yoshua Bengio
- [2] Revisiting Reweighted Wake-Sleep for Models with Stochastic Control Flow,
Tuan Anh Le, Adam R. Kosiorek, N. Siddharth, Yee Whye Teh, Frank Wood
序贯蒙特卡罗¶
- exception SMCFailed[source]¶
基类:
ValueError
当
SMCFilter
未能找到任何具有非零概率的假设时引发的异常。
- class SMCFilter(model, guide, num_particles, max_plate_nesting, *, ess_threshold=0.5)[source]¶
Bases:
object
SMCFilter
是通过序贯蒙特卡罗进行滤波的顶层接口。模型和导引应该是具有两个方法的对象:
.init(state, ...)
和.step(state, ...)
,旨在首先调用init()
,然后重复调用step()
。这两个方法应具有与SMCFilter
的init()
和step()
相同的方法签名,但要额外添加第一个参数state
,该参数应用于存储所有依赖于采样变量的张量。state
将是一个类似字典的对象SMCState
,具有任意键和torch.Tensor
值。模型可以读写state
,但导引只能从中读取。推断复杂度为
O(len(state) * num_time_steps)
,因此为避免马尔可夫模型中的二次复杂度,请确保state
具有固定大小。- 参数
Stein 方法¶
- class IMQSteinKernel(alpha=0.5, beta=- 0.5, bandwidth_factor=None)[source]¶
基类:
pyro.infer.svgd.SteinKernel
IMQ(逆多二次)核,用于 SVGD 推断算法 [1]。核的带宽使用 [2] 中的简单启发式方法从粒子中选择。核的形式为
\(K(x, y) = (\alpha + ||x-y||^2/h)^{\beta}\)
其中 \(\alpha\) 和 \(\beta\) 是用户指定的参数,\(h\) 是带宽。
- 参数
- 变量
bandwidth_factor (float) – 控制每次迭代缩放带宽因子的属性。
参考
[1] “Stein Points,” Wilson Ye Chen, Lester Mackey, Jackson Gorham, Francois-Xavier Briol, Chris. J. Oates. [2] “Stein Variational Gradient Descent: A General Purpose Bayesian Inference Algorithm,” Qiang Liu, Dilin Wang
- property bandwidth_factor¶
- class RBFSteinKernel(bandwidth_factor=None)[source]¶
基类:
pyro.infer.svgd.SteinKernel
用于 SVGD 推断算法的 RBF 核。核的带宽使用 [1] 中的简单启发式方法从粒子中选择。
参考
- [1] “Stein Variational Gradient Descent: A General Purpose Bayesian Inference Algorithm,”
Qiang Liu, Dilin Wang
- property bandwidth_factor¶
- class SVGD(model, kernel, optim, num_particles, max_plate_nesting, mode='univariate')[source]¶
Bases:
object
Stein Variational Gradient Descent 的基本实现,如参考文献 [1] 中所述。
- 参数
model – 模型(包含 Pyro 原语的可调用对象)。模型必须完全向量化,且只能包含连续潜在变量。
kernel – SVGD 兼容核,如
RBFSteinKernel
。optim (pyro.optim.PyroOptim) – PyTorch 优化器的包装器。
num_particles (int) – SVGD 中使用的粒子数量。
max_plate_nesting (int) – 模型中嵌套
pyro.plate()
上下文的最大数量。mode (str) – 是否使用利用 multivariate 测试函数(如 [1] 中)或 univariate 测试函数(如 [2] 中)的核化 Stein 差异。默认为 univariate。
示例用法
from pyro.infer import SVGD, RBFSteinKernel from pyro.optim import Adam kernel = RBFSteinKernel() adam = Adam({"lr": 0.1}) svgd = SVGD(model, kernel, adam, num_particles=50, max_plate_nesting=0) for step in range(500): svgd.step(model_arg1, model_arg2) final_particles = svgd.get_named_particles()
参考
- [1] “Stein Variational Gradient Descent: A General Purpose Bayesian Inference Algorithm,”
Qiang Liu, Dilin Wang
- [2] “Kernelized Complete Conditional Stein Discrepancy,”
Raghav Singhal, Saad Lahlou, Rajesh Ranganath
无似然方法¶
- class EnergyDistance(beta=1.0, prior_scale=0.0, num_particles=2, max_plate_nesting=inf)[source]¶
Bases:
object
后验预测能量距离 [1,2],可选通过先验进行贝叶斯正则化。
设 p(x,z)=p(z) p(x|z) 是模型,q(z|x) 是导引。给定数据 x 并抽取 iid 对样本 \((Z,X)\) 和 \((Z',X')\)(其中 Z 是潜在变量,X 是后验预测),
\[\begin{split}& Z \sim q(z|x); \quad X \sim p(x|Z) \\ & Z' \sim q(z|x); \quad X' \sim p(x|Z') \\ & loss = \mathbb E_X \|X-x\|^\beta - \frac 1 2 \mathbb E_{X,X'}\|X-X'\|^\beta - \lambda \mathbb E_Z \log p(Z)\end{split}\]这是一种无似然推断算法,可用于没有可处理密度函数的似然函数。\(\beta\) 能量距离是一种鲁棒的损失函数,对于任何具有有限分数矩 \(\mathbb E[\|X\|^\beta]\) 的分布都定义良好。
这需要静态的模型结构、完全重参数化的 guide 以及模型中重参数化的似然分布。模型的潜在分布可以是非重参数化的。
参考
- [1] Gabor J. Szekely, Maria L. Rizzo (2003)
Energy Statistics: A Class of Statistics Based on Distances.
- [2] Tilmann Gneiting, Adrian E. Raftery (2007)
严格适当评分规则、预测和估计。 https://www.stat.washington.edu/raftery/Research/PDF/Gneiting2007jasa.pdf
- 参数
beta (float) – [1,2] 中的指数 \(\beta\)。对于具有有限 \(\beta\) 绝对矩 \(E[\|X\|^\beta]\) 的分布,损失函数是严格适当的。因此,对于重尾分布,
beta
应该很小,例如对于Cauchy
分布,\(\beta<1\) 是严格适当的。默认为 1。必须在开区间 (0,2) 内。prior_scale (float) – 先验正则化的非负比例。只有当此值大于零时,模型参数才会被训练。如果为零(默认),则不会计算模型的对数密度(导引的对数密度永远不会计算)。
num_particles (int) – 用于构成梯度估计器的粒子/样本数量。必须至少为 2。
max_plate_nesting (int) – 嵌套
pyro.plate()
上下文最大数量的可选边界。如果省略,将通过运行一次 (model,guide) 对来猜测一个有效值。
离散推断¶
- infer_discrete(fn=None, first_available_dim=None, temperature=1, *, strict_enumeration_warning=True)[source]¶
一个 poutine,从后验中采样标记有
site["infer"]["enumerate"] = "parallel"
的离散站点,以观测值为条件。示例
@infer_discrete(first_available_dim=-1, temperature=0) @config_enumerate def viterbi_decoder(data, hidden_dim=10): transition = 0.3 / hidden_dim + 0.7 * torch.eye(hidden_dim) means = torch.arange(float(hidden_dim)) states = [0] for t in pyro.markov(range(len(data))): states.append(pyro.sample("states_{}".format(t), dist.Categorical(transition[states[-1]]))) pyro.sample("obs_{}".format(t), dist.Normal(means[states[-1]], 1.), obs=data[t]) return states # returns maximum likelihood states
- class TraceEnumSample_ELBO(num_particles=1, max_plate_nesting=inf, max_iarange_nesting=None, vectorize_particles=False, strict_enumeration_warning=True, ignore_jit_warnings=False, jit_options=None, retain_graph=None, tail_adaptive_beta=- 1.0)[source]¶
Bases:
pyro.infer.traceenum_elbo.TraceEnum_ELBO
这扩展了
TraceEnum_ELBO
,使其在 SVI 期间从离散潜在状态采样更便宜。以下是等效的,但第一个更便宜,共享了
loss
和z
的计算工作# Version 1. elbo = TraceEnumSample_ELBO(max_plate_nesting=1) loss = elbo.loss(*args, **kwargs) z = elbo.sample_saved() # Version 2. elbo = TraceEnum_ELBO(max_plate_nesting=1) loss = elbo.loss(*args, **kwargs) guide_trace = poutine.trace(guide).get_trace(*args, **kwargs) z = infer_discrete(poutine.replay(model, guide_trace), first_available_dim=-2)(*args, **kwargs)
预测工具¶
- class MHResampler(sampler: Callable, source_samples_slice: slice = slice(None, 0, None), stored_samples_slice: slice = slice(None, 0, None))[source]¶
Bases:
torch.nn.modules.module.Module
加权样本的重采样器,从由加权样本
sampler
指定的分布中生成等权样本。重采样基于 Metropolis-Hastings 算法。给定初始样本 \(x\),后续样本通过以下方式生成:
从
guide
中以概率 \(g(x')\) 采样一个新的样本候选 \(x'\)。计算接受概率 \(A(x', x) = \min\left(1, \frac{P(x')}{P(x)} \frac{g(x)}{g(x')}\right)\),其中 \(P\) 是
model
。以概率 \(A(x', x)\) 接受新的样本候选 \(x'\) 作为下一个样本,否则将当前样本 \(x\) 设置为下一个样本。
以上是 Metropolis-Hastings 算法,其中新的样本候选提议分布等于
guide
并且独立于当前样本,因此 \(g(x')=g(x' \mid x)\)。- 参数
sampler (callable) – 调用时返回
WeighedPredictiveResults
。source_samples_slice (slice) – 选择要存储的源样本(默认为 slice(0),即不存储)。
stored_samples_slice (slice) – 选择要存储的输出样本(默认为 slice(0),即不存储)。
MHResampler
的典型用例是将WeighedPredictive
生成的加权样本转换为来自目标分布的等权重样本。每次调用MHResampler
的实例时,它都会返回一组新的样本,第一次调用生成的样本分布服从guide
,随后的每次调用,样本的分布会越来越接近后验预测分布。可能需要一些实验来找出在每种情况下需要调用多少次MHResampler
的实例才能足够接近后验预测分布。示例
def model(): ... def guide(): ... def conditioned_model(): ... # Fit guide elbo = Trace_ELBO(num_particles=100, vectorize_particles=True) svi = SVI(conditioned_model, guide, optim.Adam(dict(lr=3.0)), elbo) for i in range(num_svi_steps): svi.step() # Create callable that returns weighed samples posterior_predictive = WeighedPredictive(model, guide=guide, num_samples=num_samples, parallel=parallel, return_sites=["_RETURN"]) prob = 0.95 weighed_samples = posterior_predictive(model_guide=conditioned_model) # Calculate quantile directly from weighed samples weighed_samples_quantile = weighed_quantile(weighed_samples.samples['_RETURN'], [prob], weighed_samples.log_weights)[0] resampler = MHResampler(posterior_predictive) num_mh_steps = 10 for mh_step_count in range(num_mh_steps): resampled_weighed_samples = resampler(model_guide=conditioned_model) # Calculate quantile from resampled weighed samples (samples are equally weighed) resampled_weighed_samples_quantile = quantile(resampled_weighed_samples.samples[`_RETURN`], [prob])[0] # Quantiles calculated using both methods should be identical assert_close(weighed_samples_quantile, resampled_weighed_samples_quantile, rtol=0.01)
采样器行为说明
如果
guide
完美地跟踪model
,则此采样器将不做任何事情,因为接受概率 \(A(x', x)\) 将始终为一。此外,如果导引是近似可分离的,即 \(g(z_A, z_B) \approx g_A(z_A) g_B(z_B)\),其中 \(g_A(z_A)\) 完美地跟踪
model
而 \(g_B(z_B)\) 较差地跟踪model
,则使用MHResampler
采样的样本计算得到的 \(z_A\) 分位数将比使用weighed_quantile
计算得到的 \(z_A\) 分位数具有更低的方差,因为使用weighed_quantile
计算的有效样本量会因为 \(g_B(z_B)\) 较差地跟踪model
而较低,而使用MHResampler
时,\(g_B(z_B)\) 较差地跟踪model
对 \(z_A\) 样本的有效样本量影响微乎其微。
- forward(*args, **kwargs)[source]¶
执行单次重采样步骤。返回
WeighedPredictiveResults
- class Predictive(model, posterior_samples=None, guide=None, num_samples=None, return_sites=(), parallel=False)[source]¶
Bases:
torch.nn.modules.module.Module
用于构建预测分布的实验类。通过在后验样本 posterior_samples 的潜在样本上以条件方式运行 model 来获得预测分布。如果提供了 guide,则也会返回所有潜在站点的后验样本。
警告
Predictive
类的接口是实验性的,将来可能会更改。- 参数
model – 包含 Pyro 原语的 Python 可调用对象。
posterior_samples (dict) – 后验样本字典。
guide (callable) – 用于获取不在 posterior_samples 中的站点后验样本的可选 guide。
num_samples (int) – 从预测分布中抽取的样本数量。如果
posterior_samples
非空,则此参数无效,此时使用posterior_samples
中样本的领先维度大小。return_sites (list, tuple, or set) – 要返回的位置;默认情况下,仅返回 posterior_samples 中不存在的采样位置。
parallel (bool) – 通过在现有模型中最外层包装一个 plate messenger 来并行进行预测。请注意,这要求模型通过
plate
正确标注所有批量维度。默认为 False。
- call(*args, **kwargs)[source]¶
调用
forward()
并返回导引的参数值作为 tuple 而非 dict 的方法,这是 JIT 跟踪的要求。与forward()
不同,此方法可以被torch.jit.trace_module()
跟踪。警告
此方法被
Module
内部使用。用户应改用__call__()
,如Predictive(model)(*args, **kwargs)
。
- forward(*args, **kwargs)[source]¶
返回预测分布的样本字典。默认情况下,仅返回 posterior_samples 中不包含的采样位置。这可以通过修改此
Predictive
实例的 return_sites 关键字参数来更改。注意
此方法由
Module
内部使用。用户应改用__call__()
,如Predictive(model)(*args, **kwargs)
。- 参数
args – 模型参数。
kwargs – 模型关键字参数。
- class WeighedPredictive(model, posterior_samples=None, guide=None, num_samples=None, return_sites=(), parallel=False)[source]¶
基类:
pyro.infer.predictive.Predictive
用于构建加权预测分布的类,其初始化接口与
Predictive
相同。方法 .forward 和 .call 可以带有一个额外的关键字参数
model_guide
,它是用于创建和优化导引的模型(如果未提供,model_guide
默认为self.model
),并且它们同时返回样本和对数权重。权重计算为
model_guide
对数概率与导引对数概率之间的每个样本差距(必须始终提供导引)。典型用例基于
model
\(p(x,z)=p(x|z)p(z)\) 和已经根据观测值 \(p(X_{obs},z)\) 与模型拟合的guide
\(q(z)\),两者都在WeighedPredictive
初始化时提供(与Predictive
的做法相同)。调用WeighedPredictive
的实例时,我们将给定观测值 \(p(X_{obs},z)\) 的模型作为关键字参数model_guide
提供。结果输出将是Predictive
返回的通常样本 \(p(x|z)q(z)\),以及每个样本的权重 \(p(X_{obs},z)/q(z)\)。样本和权重可以输入到weighed_quantile
中,以获得结果分布的真实分位数。注意,如果样本位置 \(y\) 是在观测值和导引采样的潜在变量之后采样的,则
model
可以更复杂,包含未被观测且不属于导引的样本位置 \(y\),例如 \(p(x,y,z)=p(y|x,z)p(x|z)p(z)\),其中乘积中的每个元素代表一组pyro.sample
语句。- call(*args, **kwargs)[source]¶
方法 .call 向后兼容
Predictive
中的同名方法,但可以带有一个额外的关键字参数 model_guide,它是用于创建和优化导引的模型。返回
WeighedPredictiveResults
,它具有属性.samples
和每个样本的权重.log_weights
。
- forward(*args, **kwargs)[source]¶
方法 .forward 向后兼容
Predictive
中的同名方法,但可以带有一个额外的关键字参数 model_guide,它是用于创建和优化导引的模型。返回
WeighedPredictiveResults
,它具有属性.samples
和每个样本的权重.log_weights
。
- class WeighedPredictiveResults(samples: Union[dict, tuple], log_weights: torch.Tensor, guide_log_prob: torch.Tensor, model_log_prob: torch.Tensor)[source]¶
基类:
pyro.infer.importance.LogWeightsMixin
,pyro.infer.util.CloneMixin
WeighedPredictive
实例调用的返回值。- guide_log_prob: torch.Tensor¶
- log_weights: torch.Tensor¶
- model_log_prob: torch.Tensor¶
- class EmpiricalMarginal(trace_posterior, sites=None, validate_args=None)[source]¶
基类:
pyro.distributions.distribution.Distribution
,Callable
TracePosterior
模型中单个位置(或多个位置,如果它们形状相同)的边际分布。- 参数
trace_posterior (TracePosterior) – 表示 Monte Carlo 后验的
TracePosterior
实例。sites (list) – 需要为其生成边际分布的可选位置列表。
- class Marginals(trace_posterior, sites=None, validate_args=None)[source]¶
Bases:
object
保存
TracePosterior
模型中一个或多个位置的边际分布。这是一个方便的容器类,可以由TracePosterior
子类扩展,例如用于实现诊断。- 参数
trace_posterior (TracePosterior) – 表示 Monte Carlo 后验的 TracePosterior 实例。
sites (list) – 需要为其生成边际分布的可选位置列表。
- property empirical¶
位置名称及其对应的
EmpiricalMarginal
分布的字典。- 类型
OrderedDict
- class TracePosterior(num_chains=1)[source]¶
Bases:
object
抽象的 TracePosterior 对象,后验推断算法继承自此对象。运行时,从近似后验中收集一组执行轨迹。此对象旨在供其他需要访问已收集执行轨迹的实用类(如 EmpiricalMarginal)使用。
- information_criterion(pointwise=False)[source]¶
计算模型的信息准则。当前,仅返回“广泛适用/渡边-赤池信息准则”(WAIC)以及相应的有效参数数量。
参考
[1] 实用贝叶斯模型评估:使用留一法交叉验证和WAIC,Aki Vehtari, Andrew Gelman, 和 Jonah Gabry
- 参数
pointwise (bool) – 一个标志,用于决定是否获取向量化的 WAIC。当
pointwise=False
时,返回总和。- 返回
一个包含 WAIC 及其有效参数数量值的字典。
- 返回类型
OrderedDict
- class TracePredictive(model, posterior, num_samples, keep_sites=None)[source]¶
Bases:
pyro.infer.abstract_infer.TracePosterior
警告
此类已被弃用,并将在未来的版本中移除。请改用
Predictive
类。给定来自近似后验的模型执行轨迹,生成并保存来自后验预测分布的轨迹。这是通过将潜在站点限制为从模型执行轨迹中随机采样的参数值,然后向前运行模型来生成包含新的响应 (“_RETURN”) 站点的轨迹来实现的。 :param model: 包含 Pyro 原语的任意 Python 可调用对象。 :param TracePosterior posterior: 持有来自模型近似后验的样本的 TracePosterior 实例。 :param int num_samples: 要生成的样本数量。 :param keep_sites: 应从后验分布中采样的站点(默认:全部)