首页
Preview

从理论到实践:使用Python实现贝叶斯神经网络

我拥有物理学硕士学位,并在航空航天工程研究领域工作。

物理学和工程学是两门不同的科学,它们共同追求理解自然和对其进行建模的能力。

物理学家的方法更加理论化。物理学家观察世界,并试图以最准确的方式对其进行建模。物理学家建模的现实是不完美的,有近似值,但一旦我们考虑到这些不完美,现实变得整洁、完美和优美。

工程师的方法则更加实际。工程师意识到物理学家模型的所有限制,并试图使实验室中的经验尽可能顺利。工程师可能会做出更加粗略的近似(例如π=3),但其近似值实际上更有效。

这种工程师实际方法和物理学家优美和理论方法之间的区别可以通过 Gordon Lindsay Glegg 的以下引言概括:

“一个科学家可以发现一个新星,但他不能制造一个。他必须向工程师请教。”

在研究人员的日常生活中,它就像这样运作。物理学家是具有特定现象理论的人。工程师是一位科学家,可以设置实验并查看理论是否成立。

现实情况是,当我从物理学家转向工程师时,我经常被问到以下问题:

“好的,你的模型似乎有效...但它有多健壮?”

这是一个典型的工程师问题。

当你拥有一个物理模型时,在给定某些条件的情况下,该模型在理论上是完美的。

然而,在进行实验时,存在一定程度的误差,你必须能够正确估计它。

在我们正在进行的具体示例中,我们如何估计理论输出和实验结果之间的能量差异?

两个选项:

A. 如果模型是确定性的,你可以通过某个delta(例如将确定性规则应用于输入的嘈杂版本)更改初始条件。

B. 如果模型是概率性的,则对于某些给定的输入,可以从输出中提取一些统计信息(例如平均值、标准差、不确定性边界...)

现在让我们进入机器学习的语言。在这种情况下:

A. 如果机器学习模型是确定性的,我们可以通过打乱训练和验证集来测试其健壮性。

B. 如果机器学习模型是概率性的,则对于某些给定的输入,可以从输出中提取一些统计信息(例如平均值、标准差、不确定性边界...)

现在,假设我们想要使用的模型是神经网络。第一个问题是:你需要神经网络吗?如果答案是肯定的,那么你必须使用它(不用说)。问题是:

“你的机器学习模型是否健壮?”

神经网络的原始定义是“纯确定性的”。我们可以打乱训练、验证和测试集,但我们需要考虑到神经网络可能需要很长时间才能训练,如果我们想进行多次测试(例如CV=10,000),那么你可能需要等待一段时间。

我们需要考虑的另一件事是,神经网络使用一种称为梯度下降的算法进行优化。这个想法是,我们从参数空间中的一个点开始,如其名称所示,沿着损失的负梯度指示的方向“下降”。这理想情况下会带我们到一个全局最小值(剧透:实际上它从来不是全局的)。

对于一个不现实的简单1D损失函数,理想情况如下:

在这种情况下,如果我们改变起始点,我们仍然会收敛到唯一的全局最小值。

更现实的情况是这样的:

因此,如果我们从不同的起始点重新启动训练算法,我们会收敛到不同的局部最小值。

因此,如果我们从点1或点3开始,我们会到达比起始点2更低的点。

损失函数可能充满局部最小值,因此找到真正的全局最小值可能是一项艰巨的任务。我们可以做的另一件事是从不同的起始点重新启动训练并比较损失函数值。使用这种方法我们仍有同样的问题:我们只能这样做很多次。

有一种更健壮、严谨和优雅的方法可以以概率方式使用神经网络的相同计算能力,它被称为贝叶斯神经网络。在本文中,我们将学习:

  • 贝叶斯神经网络背后的思想
  • 贝叶斯神经网络的数学公式
  • 使用Python(更具体地说是Pytorch)实现贝叶斯神经网络
  • 如何使用贝叶斯神经网络解决回归问题

让我们开始吧!

1. 什么是贝叶斯神经网络?

正如我们之前所说,贝叶斯神经网络的思想是为典型神经网络添加概率“感觉”。我们该如何做到这一点呢?

在了解贝叶斯神经网络之前,我们可能应该回顾一下贝叶斯定理的一些知识。

一个非常有效的看待贝叶斯定理的方法是:

“贝叶斯定理是一种数学定理,它解释了为什么如果世界上所有的汽车都是蓝色的,那么我的汽车也必须是蓝色的,但仅仅因为我的汽车是蓝色的并不意味着世界上所有的汽车都是蓝色的。”

在数学术语中,给定事件“A”和“B”,在事件“B”发生的情况下,事件“A”发生的概率如下:

图片来自作者

而在事件“A”发生的情况下,事件“B”发生的概率如下:

图片来自作者

将第一个和最后一个表达式联系起来的方程式如下:

图片来自作者

懂了吗?太好了。现在,假设你有你的神经网络模型。这个神经网络不过是一组将给定输入转换为期望输出的参数。

一个前馈神经网络(最简单的深度学习结构)通过将输入乘以参数矩阵来处理输入。然后,一个非线性激活函数(这是神经网络真正的力量)被逐个应用于这个矩阵乘积的结果。结果是下一层的输入,其中应用相同的过程。

我们现在将模型的参数集称为w。现在我们可以问自己这个棘手的问题。

假设我有一个数据集D,它是一组输入x_i和输出y_i的对,例如,一个动物的第i个图像和第i个标签(猫或狗):

图片来自作者

那么,给定某个数据集D,有一组参数的概率是多少呢?

你可能需要阅读这个问题3或4遍才能理解它,但是思路在那里。如果你有一定的输入输出映射,在极端的确定性情况下,只有一个集合的参数能够处理输入并给出期望输出。在概率上,将有一个更有可能的概率参数集,而不是另一个。

因此,我们感兴趣的是这个量。

图片来自作者

现在,这三件事很酷:

  1. 当你考虑到分布的平均值时,你仍然可以将其视为标准的神经网络模型。例如:

图片来自作者

而方程式的左侧表示计算的平均输出,右侧表示所有可能的参数结果集(N)的平均值,概率分布提供每个结果的权重。

  1. 虽然**p(w|D)**显然是一个谜,但是p(D|w)是我们总是可以处理的。如果我们对巨大的N使用上述方程式,就没有必要进行机器学习。你可以简单地说:“在给定某个神经网络的情况下,尝试所有可能的模型,并使用上述方程式权衡所有可能的结果。”

  2. 当我们得到p时,我们不仅得到了一个机器学习模型;我们实际上得到了无限的机器学习模型。这意味着我们可以从你的预测中提取一些不确定性边界和统计信息。结果不仅是“10.23”,而是更像“10.23,可能误差为0.50”。

我希望我已经激起了你的兴趣。让我们进入下一章吧。

2. 一些数学

如果你已经了解了贝叶斯神经网络的思想,或者已经了解了它们背后的数学,那么可以跳过本章。如果你需要参考,可以参考以下文章。(深度学习用户的贝叶斯神经网络入门教程

现在,所有这些似乎都很酷,但我认为,如果你是一个机器学习用户,你会有这样的想法:

“我怎么能够优化这样一个奇怪的东西?”

简短的回答是,“通过最大化:

图片来自作者但我认为这并不是显而易见的。

在这种情况下,优化原则是找到分布p(w|D)的最佳估计。我们将称这个分布为q,并希望有一个衡量两个分布函数之间距离的指标。

我们将使用的度量标准称为Kullback-Leibler散度。

作者提供的图片

一些有趣的事实:

  • 对于两个相等的分布它为0
  • 如果两个分布的分母趋近于零而分子仍然为非零,则它为无穷大。
  • 它是非对称的

现在,你看到的损失函数是Kullback-Leibler散度的代理数量,它被称为证据下界(ELBO)

权重q的分布被认为是一个具有均值mu和方差sigma2的正态分布:

作者提供的图片

因此,优化是关于确定该分布的最佳mu和sigma值。

作者提供的图片

在实际的PyTorch实现中,还将均值的均方误差与目标添加到我们的L(mu,sigma)中。

3. Pyt(orch)hon实现

使用PyTorch在Python中实现贝叶斯神经网络非常简单,这要归功于一个名为torchbnn的库。

安装它非常容易:

pip install torchbnn

正如我们将看到的那样,我们将构建与标准Tor神经网络非常相似的东西:

model = nn.Sequential(
    bnn.BayesLinear(prior_mu=0, prior_sigma=0.1, in_features=1, out_features=1000),
    nn.ReLU(),
    bnn.BayesLinear(prior_mu=0, prior_sigma=0.1, in_features=1000, out_features=1),
)

实际上,有一个库可以将你的torch模型转换为其贝叶斯代理:

transform_model(model, nn.Conv2d, bnn.BayesConv2d, 
                args={"prior_mu":0, "prior_sigma":0.1, "in_channels" : ".in_channels",
                      "out_channels" : ".out_channels", "kernel_size" : ".kernel_size",
                      "stride" : ".stride", "padding" : ".padding", "bias":".bias"
                     }, 
                attrs={"weight_mu" : ".weight"})

但让我们做一个实际的,详细的例子:

4. 实际的回归任务

第一件事是导入一些库:

之后,我们将制作我们非常简单的双维数据集:

因此,给定我们的1D输入x(范围从-2到2),我们希望找到我们的y。

Clean_target是我们的实际生成器,而target是我们的嘈杂数据生成器。

现在,我们将定义我们的贝叶斯前馈神经网络:

正如我们所看到的,它是一个具有贝叶斯层的两层前馈神经网络。这将允许我们拥有概率输出

现在,我们将定义我们的均方误差损失和剩余的Kullback-Leibler散度:

这两个损失将在我们的优化步骤中使用:

使用了2000个epoch。

让我们定义我们的测试集:

现在,model类输出的结果是概率的。这意味着如果我们运行我们的模型10000次,我们将获得10000个稍微不同的值。对于从-2到2的每个数据点,我们将得到平均值和标准差,

并且我们将绘制我们的置信区间。

5. 总结

在本文中,我们看到了如何构建一个结合了神经网络的能力并仍然保持对我们的预测的概率方法的机器学习模型。

为了做到这一点,我们可以构建所谓的贝叶斯神经网络这个想法不是优化神经网络的损失,而是无限神经网络的损失。换句话说,我们正在优化给定数据集的模型参数的概率分布。

我们使用包含度量标准称为Kullback-Leibler散度的损失函数来实现这一点。这用于计算两个分布之间的距离。

优化我们的损失函数后,我们能够使用概率模型。这意味着如果我们将此模型重复两次,我们将获得两个不同的结果,如果我们将其重复10k次,我们将能够提取我们的结果的强大统计分布。

我们使用torch和一个名为torchbnn的库实现了这一点。我们构建了我们的简单回归任务,并使用两层前馈神经网络解决了它。

译自:https://towardsdatascience.com/from-theory-to-practice-with-bayesian-neural-network-using-python-9262b611b825

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
alivne
复杂的问题简单化

评论(0)

添加评论