pytorch pyro 贝叶斯神经网络 bnn beyesean neure network svi ​定制SVI目标和培训循环,变更推理

本文主要是介绍pytorch pyro 贝叶斯神经网络 bnn beyesean neure network svi ​定制SVI目标和培训循环,变更推理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

定制SVI目标和培训循环¶

Pyro支持各种基于优化的贝叶斯推理方法,包括Trace_ELBO作为SVI(随机变分推理)的基本实现。参见文件(documents的简写)有关各种SVI实现和SVI教程的更多信息I, 二,以及罗马数字3了解SVI的背景。

在本教程中,我们将展示高级用户如何修改和/或增加变分目标(或者:损失函数)以及由Pyro提供的训练步骤实现,以支持特殊的用例。

  1. 基本SVI用法

    1. 较低层次的模式

  2. 示例:自定义正则化

  3. 示例:调整损失

  4. 例如:贝塔VAE

  5. 示例:混合优化器

  6. 示例:自定义ELBO

  7. 示例:KL退火

基本SVI用法¶

我们首先回顾一下SVI烟火中的物体。我们假设用户已经定义了一个model和一个guide。然后,用户创建一个优化器和一个SVI对象:

optimizer = pyro.optim.Adam({"lr": 0.001, "betas": (0.90, 0.999)})
svi = pyro.infer.SVI(model, guide, optimizer, loss=pyro.infer.Trace_ELBO())

然后可以通过调用svi.step(...)。对…的争论step()然后被传递给modelguide.

较低层次的模式¶

上述模式的好处在于,它允许Pyro为我们处理各种细节,例如:

  • pyro.optim.Adam动态创建一个新的torch.optim.Adam每当遇到新参数时优化器

  • SVI.step()渐变步骤之间的零渐变

如果我们想要更多的控制,我们可以直接操纵各种可微损失方法ELBO班级。例如,这个优化循环:

svi = pyro.infer.SVI(model, guide, optimizer, loss=pyro.infer.Trace_ELBO())
for i in range(n_iter):loss = svi.step(X_train, y_train)

相当于这个低级模式:

loss_fn = lambda model, guide: pyro.infer.Trace_ELBO().differentiable_loss(model, guide, X_train, y_train)
with pyro.poutine.trace(param_only=True) as param_capture:loss = loss_fn(model, guide)
params = set(site["value"].unconstrained()for site in param_capture.trace.nodes.values())
optimizer = torch.optim.Adam(params, lr=0.001, betas=(0.90, 0.999))
for i in range(n_iter):# compute lossloss = loss_fn(model, guide)loss.backward()# take a step and zero the parameter gradientsoptimizer.step()optimizer.zero_grad()

示例:自定义正则化¶

假设我们想在SVI损失中加入一个定制的正则项。使用上面的使用模式,这很容易做到。首先我们定义正则项:

def my_custom_L2_regularizer(my_parameters):reg_loss = 0.0for param in my_parameters:reg_loss = reg_loss + param.pow(2.0).sum()return reg_loss

那么我们唯一需要做的改变就是:

- loss = loss_fn(model, guide)
+ loss = loss_fn(model, guide) + my_custom_L2_regularizer(my_parameters)

示例:剪裁渐变¶

对于一些模型,损耗梯度可能在训练期间爆炸,导致溢出和NaN价值观。防止这种情况的一种方法是使用渐变剪辑。中的优化器pyro.optim拿一本可选的字典clip_args这允许将梯度范数或梯度值剪切到给定的界限内。

要更改上面的基本示例:

- optimizer = pyro.optim.Adam({"lr": 0.001, "betas": (0.90, 0.999)})
+ optimizer = pyro.optim.Adam({"lr": 0.001, "betas": (0.90, 0.999)}, {"clip_norm": 10.0})

还可以通过修改上述低级模式来手动实现梯度裁剪的其他变体。

示例:调整损失¶

根据优化算法,损失的规模可能重要,也可能无关紧要。假设我们想在对损失函数进行微分之前,根据数据点的数量对其进行缩放。这很容易做到:

- loss = loss_fn(model, guide)
+ loss = loss_fn(model, guide) / N_data

请注意,在SVI的情况下,损失函数中的每一项都是来自模型或指南的对数概率,同样的效果可以通过使用poutine.scale。例如,我们可以使用poutine.scale装饰器缩放模型和指南:

@poutine.scale(scale=1.0/N_data)
def model(...):pass@poutine.scale(scale=1.0/N_data)
def guide(...):pass

例如:贝塔VAE¶

我们也可以使用poutine.scale以构建非标准的ELBO变分目标,其中,例如,KL散度相对于期望的对数似然性被不同地缩放。特别是对于βVAE,KL散度用一个因子来缩放beta:

def model(data, beta=0.5):z_loc, z_scale = ...with pyro.poutine.scale(scale=beta)z = pyro.sample("z", dist.Normal(z_loc, z_scale))pyro.sample("obs", dist.Bernoulli(...), obs=data)def guide(data, beta=0.5):with pyro.poutine.scale(scale=beta)z_loc, z_scale = ...z = pyro.sample("z", dist.Normal(z_loc, z_scale))

有了这种模型的选择,并引导对应于潜在变量的测井密度z来构建变分目标

svi = pyro.infer.SVI(model, guide, optimizer, loss=pyro.infer.Trace_ELBO())

将被缩放一倍beta,导致KL发散,其同样由beta.

示例:混合优化器¶

中的各种优化器pyro.optim允许用户在每个参数的基础上指定优化设置(如学习率)。但是如果我们要对不同的参数使用不同的优化算法呢?我们可以使用Pyro的MultiOptimizer(见下文),但我们也可以实现同样的事情,如果我们直接操纵differentiable_loss:

adam = torch.optim.Adam(adam_parameters, {"lr": 0.001, "betas": (0.90, 0.999)})
sgd = torch.optim.SGD(sgd_parameters, {"lr": 0.0001})
loss_fn = pyro.infer.Trace_ELBO().differentiable_loss
# compute loss
loss = loss_fn(model, guide)
loss.backward()
# take a step and zero the parameter gradients
adam.step()
sgd.step()
adam.zero_grad()
sgd.zero_grad()

为了完整起见,我们还展示了如何使用多重优化器,这使我们能够结合多个烟火优化。请注意,由于MultiOptimizer使用torch.autograd.grad引擎盖下(而不是torch.Tensor.backward()),它的界面略有不同;特别是step()方法也将参数作为输入。

def model():pyro.param('a', ...)pyro.param('b', ...)...adam = pyro.optim.Adam({'lr': 0.1})
sgd = pyro.optim.SGD({'lr': 0.01})
optim = MixedMultiOptimizer([(['a'], adam), (['b'], sgd)])
with pyro.poutine.trace(param_only=True) as param_capture:loss = elbo.differentiable_loss(model, guide)
params = {'a': pyro.param('a'), 'b': pyro.param('b')}
optim.step(loss, params)

示例:自定义ELBO¶

在前三个例子中,我们绕过了创建SVI对象提供的可微分损失函数ELBO实施。我们可以做的另一件事是创造定制ELBO实现,并将它们传递到SVI机械。例如,简化版本的Trace_ELBO损失函数可能如下所示:

# note that simple_elbo takes a model, a guide, and their respective arguments as inputs
def simple_elbo(model, guide, *args, **kwargs):# run the guide and trace its executionguide_trace = poutine.trace(guide).get_trace(*args, **kwargs)# run the model and replay it against the samples from the guidemodel_trace = poutine.trace(poutine.replay(model, trace=guide_trace)).get_trace(*args, **kwargs)# construct the elbo loss functionreturn -1*(model_trace.log_prob_sum() - guide_trace.log_prob_sum())svi = SVI(model, guide, optim, loss=simple_elbo)

请注意,这基本上就是elbo实施于“迷你烟火”看起来像。

示例:KL退火¶

在……里深度马尔可夫模型教程ELBO变分目标在训练期间被修改。特别地,潜在随机变量之间的各种KL-散度项相对于观察数据的对数概率按比例缩小(即退火)。在本教程中,这是通过使用poutine.scale。我们可以通过定义一个定制的损失函数来完成同样的事情。后一种选择并不是一种非常优雅的模式,但是我们还是包含了它,以显示我们所拥有的灵活性。

def simple_elbo_kl_annealing(model, guide, *args, **kwargs):# get the annealing factor and latents to anneal from the keyword# arguments passed to the model and guideannealing_factor = kwargs.pop('annealing_factor', 1.0)latents_to_anneal = kwargs.pop('latents_to_anneal', [])# run the guide and replay the model against the guideguide_trace = poutine.trace(guide).get_trace(*args, **kwargs)model_trace = poutine.trace(poutine.replay(model, trace=guide_trace)).get_trace(*args, **kwargs)elbo = 0.0# loop through all the sample sites in the model and guide trace and# construct the loss; note that we scale all the log probabilities of# samples sites in `latents_to_anneal` by the factor `annealing_factor`for site in model_trace.values():if site["type"] == "sample":factor = annealing_factor if site["name"] in latents_to_anneal else 1.0elbo = elbo + factor * site["fn"].log_prob(site["value"]).sum()for site in guide_trace.values():if site["type"] == "sample":factor = annealing_factor if site["name"] in latents_to_anneal else 1.0elbo = elbo - factor * site["fn"].log_prob(site["value"]).sum()return -elbosvi = SVI(model, guide, optim, loss=simple_elbo_kl_annealing)
svi.step(other_args, annealing_factor=0.2, latents_to_anneal=["my_latent"])

以前的然后

Customizing SVI objectives and training loops¶

Pyro provides support for various optimization-based approaches to Bayesian inference, with Trace_ELBO serving as the basic implementation of SVI (stochastic variational inference). See the docs for more information on the various SVI implementations and SVI tutorials I, II, and III for background on SVI.

In this tutorial we show how advanced users can modify and/or augment the variational objectives (alternatively: loss functions) and the training step implementation provided by Pyro to support special use cases.

  1. Basic SVI Usage

    1. A Lower Level Pattern

  2. Example: Custom Regularizer

  3. Example: Scaling the Loss

  4. Example: Beta VAE

  5. Example: Mixing Optimizers

  6. Example: Custom ELBO

  7. Example: KL Annealing

Basic SVI Usage¶

We first review the basic usage pattern of SVI objects in Pyro. We assume that the user has defined a model and a guide. The user then creates an optimizer and an SVI object:

optimizer = pyro.optim.Adam({"lr": 0.001, "betas": (0.90, 0.999)})
svi = pyro.infer.SVI(model, guide, optimizer, loss=pyro.infer.Trace_ELBO())

Gradient steps can then be taken with a call to svi.step(...). The arguments to step() are then passed to model and guide.

A Lower-Level Pattern¶

The nice thing about the above pattern is that it allows Pyro to take care of various details for us, for example:

  • pyro.optim.Adam dynamically creates a new torch.optim.Adam optimizer whenever a new parameter is encountered

  • SVI.step() zeros gradients between gradient steps

If we want more control, we can directly manipulate the differentiable loss method of the various ELBO classes. For example, this optimization loop:

svi = pyro.infer.SVI(model, guide, optimizer, loss=pyro.infer.Trace_ELBO())
for i in range(n_iter):loss = svi.step(X_train, y_train)

is equivalent to this low-level pattern:

loss_fn = lambda model, guide: pyro.infer.Trace_ELBO().differentiable_loss(model, guide, X_train, y_train)
with pyro.poutine.trace(param_only=True) as param_capture:loss = loss_fn(model, guide)
params = set(site["value"].unconstrained()for site in param_capture.trace.nodes.values())
optimizer = torch.optim.Adam(params, lr=0.001, betas=(0.90, 0.999))
for i in range(n_iter):# compute lossloss = loss_fn(model, guide)loss.backward()# take a step and zero the parameter gradientsoptimizer.step()optimizer.zero_grad()

Example: Custom Regularizer¶

Suppose we want to add a custom regularization term to the SVI loss. Using the above usage pattern, this is easy to do. First we define our regularizer:

def my_custom_L2_regularizer(my_parameters):reg_loss = 0.0for param in my_parameters:reg_loss = reg_loss + param.pow(2.0).sum()return reg_loss

Then the only change we need to make is:

- loss = loss_fn(model, guide)
+ loss = loss_fn(model, guide) + my_custom_L2_regularizer(my_parameters)

Example: Clipping Gradients¶

For some models the loss gradient can explode during training, leading to overflow and NaN values. One way to protect against this is with gradient clipping. The optimizers in pyro.optim take an optional dictionary of clip_args which allows clipping either the gradient norm or the gradient value to fall within the given limit.

To change the basic example above:

- optimizer = pyro.optim.Adam({"lr": 0.001, "betas": (0.90, 0.999)})
+ optimizer = pyro.optim.Adam({"lr": 0.001, "betas": (0.90, 0.999)}, {"clip_norm": 10.0})

Further variants of gradient clipping can also be implemented manually by modifying the low-level pattern described above.

Example: Scaling the Loss¶

Depending on the optimization algorithm, the scale of the loss may or not matter. Suppose we want to scale our loss function by the number of datapoints before we differentiate it. This is easily done:

- loss = loss_fn(model, guide)
+ loss = loss_fn(model, guide) / N_data

Note that in the case of SVI, where each term in the loss function is a log probability from the model or guide, this same effect can be achieved using poutine.scale. For example we can use the poutine.scale decorator to scale both the model and guide:

@poutine.scale(scale=1.0/N_data)
def model(...):pass@poutine.scale(scale=1.0/N_data)
def guide(...):pass

Example: Beta VAE¶

We can also use poutine.scale to construct non-standard ELBO variational objectives in which, for example, the KL divergence is scaled differently relative to the expected log likelihood. In particular for the Beta VAE the KL divergence is scaled by a factor beta:

def model(data, beta=0.5):z_loc, z_scale = ...with pyro.poutine.scale(scale=beta)z = pyro.sample("z", dist.Normal(z_loc, z_scale))pyro.sample("obs", dist.Bernoulli(...), obs=data)def guide(data, beta=0.5):with pyro.poutine.scale(scale=beta)z_loc, z_scale = ...z = pyro.sample("z", dist.Normal(z_loc, z_scale))

With this choice of model and guide the log densities corresponding to the latent variable z that enter into constructing the variational objective via

svi = pyro.infer.SVI(model, guide, optimizer, loss=pyro.infer.Trace_ELBO())

will be scaled by a factor of beta, resulting in a KL divergence that is likewise scaled by beta.

Example: Mixing Optimizers¶

The various optimizers in pyro.optim allow the user to specify optimization settings (e.g. learning rates) on a per-parameter basis. But what if we want to use different optimization algorithms for different parameters? We can do this using Pyro’s MultiOptimizer (see below), but we can also achieve the same thing if we directly manipulate differentiable_loss:

adam = torch.optim.Adam(adam_parameters, {"lr": 0.001, "betas": (0.90, 0.999)})
sgd = torch.optim.SGD(sgd_parameters, {"lr": 0.0001})
loss_fn = pyro.infer.Trace_ELBO().differentiable_loss
# compute loss
loss = loss_fn(model, guide)
loss.backward()
# take a step and zero the parameter gradients
adam.step()
sgd.step()
adam.zero_grad()
sgd.zero_grad()

For completeness, we also show how we can do the same thing using MultiOptimizer, which allows us to combine multiple Pyro optimizers. Note that since MultiOptimizer uses torch.autograd.grad under the hood (instead of torch.Tensor.backward()), it has a slightly different interface; in particular the step() method also takes parameters as inputs.

def model():pyro.param('a', ...)pyro.param('b', ...)...adam = pyro.optim.Adam({'lr': 0.1})
sgd = pyro.optim.SGD({'lr': 0.01})
optim = MixedMultiOptimizer([(['a'], adam), (['b'], sgd)])
with pyro.poutine.trace(param_only=True) as param_capture:loss = elbo.differentiable_loss(model, guide)
params = {'a': pyro.param('a'), 'b': pyro.param('b')}
optim.step(loss, params)

Example: Custom ELBO¶

In the previous three examples we bypassed creating a SVI object and directly manipulated the differentiable loss function provided by an ELBO implementation. Another thing we can do is create custom ELBO implementations and pass those into the SVI machinery. For example, a simplified version of a Trace_ELBO loss function might look as follows:

# note that simple_elbo takes a model, a guide, and their respective arguments as inputs
def simple_elbo(model, guide, *args, **kwargs):# run the guide and trace its executionguide_trace = poutine.trace(guide).get_trace(*args, **kwargs)# run the model and replay it against the samples from the guidemodel_trace = poutine.trace(poutine.replay(model, trace=guide_trace)).get_trace(*args, **kwargs)# construct the elbo loss functionreturn -1*(model_trace.log_prob_sum() - guide_trace.log_prob_sum())svi = SVI(model, guide, optim, loss=simple_elbo)

Note that this is basically what the elbo implementation in “mini-pyro” looks like.

Example: KL Annealing¶

In the Deep Markov Model Tutorial the ELBO variational objective is modified during training. In particular the various KL-divergence terms between latent random variables are scaled downward (i.e. annealed) relative to the log probabilities of the observed data. In the tutorial this is accomplished using poutine.scale. We can accomplish the same thing by defining a custom loss function. This latter option is not a very elegant pattern but we include it anyway to show the flexibility we have at our disposal.

def simple_elbo_kl_annealing(model, guide, *args, **kwargs):# get the annealing factor and latents to anneal from the keyword# arguments passed to the model and guideannealing_factor = kwargs.pop('annealing_factor', 1.0)latents_to_anneal = kwargs.pop('latents_to_anneal', [])# run the guide and replay the model against the guideguide_trace = poutine.trace(guide).get_trace(*args, **kwargs)model_trace = poutine.trace(poutine.replay(model, trace=guide_trace)).get_trace(*args, **kwargs)elbo = 0.0# loop through all the sample sites in the model and guide trace and# construct the loss; note that we scale all the log probabilities of# samples sites in `latents_to_anneal` by the factor `annealing_factor`for site in model_trace.values():if site["type"] == "sample":factor = annealing_factor if site["name"] in latents_to_anneal else 1.0elbo = elbo + factor * site["fn"].log_prob(site["value"]).sum()for site in guide_trace.values():if site["type"] == "sample":factor = annealing_factor if site["name"] in latents_to_anneal else 1.0elbo = elbo - factor * site["fn"].log_prob(site["value"]).sum()return -elbosvi = SVI(model, guide, optim, loss=simple_elbo_kl_annealing)
svi.step(other_args, annealing_factor=0.2, latents_to_anneal=["my_latent"])

这篇关于pytorch pyro 贝叶斯神经网络 bnn beyesean neure network svi ​定制SVI目标和培训循环,变更推理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1135268

相关文章

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

poj3750约瑟夫环,循环队列

Description 有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。 Input 第一行输入小孩的人数N(N<=64) 接下来每行输入一个小孩的名字(人名不超过15个字符) 最后一行输入W,S (W < N),用

内卷时代无人机培训机构如何做大做强

在当今社会,随着科技的飞速发展,“内卷”一词频繁被提及,反映了各行业竞争日益激烈的现象。对于无人机培训行业而言,如何在这样的时代背景下脱颖而出,实现做大做强的目标,成为每个培训机构必须深思的问题。以下是从八个关键方面提出的策略,旨在帮助无人机培训机构在内卷时代中稳步前行。 1. 精准定位市场需求 深入研究市场:通过市场调研,了解无人机行业的最新趋势、政策导向及未来发展方向。 明确目标

PDFQFZ高效定制:印章位置、大小随心所欲

前言 在科技编织的快节奏时代,我们不仅追求速度,更追求质量,让每一分努力都转化为生活的甜蜜果实——正是在这样的背景下,一款名为PDFQFZ-PDF的实用软件应运而生,它以其独特的功能和高效的处理能力,在PDF文档处理领域脱颖而出。 它的开发,源自于对现代办公效率提升的迫切需求。在数字化办公日益普及的今天,PDF作为一种跨平台、不易被篡改的文档格式,被广泛应用于合同签署、报告提交、证书打印等各个

[数据集][目标检测]血细胞检测数据集VOC+YOLO格式2757张4类别

数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2757 标注数量(xml文件个数):2757 标注数量(txt文件个数):2757 标注类别数:4 标注类别名称:["Platelets","RBC","WBC","sickle cell"] 每个类别标注的框数:

校验码:奇偶校验,CRC循环冗余校验,海明校验码

文章目录 奇偶校验码CRC循环冗余校验码海明校验码 奇偶校验码 码距:任何一种编码都由许多码字构成,任意两个码字之间最少变化的二进制位数就称为数据检验码的码距。 奇偶校验码的编码方法是:由若干位有效信息(如一个字节),再加上一个二进制位(校验位)组成校验码。 奇校验:整个校验码中1的个数为奇数 偶校验:整个校验码中1的个数为偶数 奇偶校验,可检测1位(奇数位)的错误,不可纠错。