《树莓派开发实战(第2版)》——2.6 使用条件和约束指定证据

2.6 使用条件和约束指定证据

现在,我已经相当详细地介绍了构建模型的方法。使用Figaro时,您的很大一部分精力将花在创建模型上。但是不要忽略证据的指定。Figaro提供了3种说明证据的机制:观测值,条件和约束。

2.6.1 观测值

您已经看到使用观测值指定证据的方法。在Hello World程序中已经提供了一个例子,使用如下的语句:

greetingToday.observe("Hello, world!")```
一般来说,observe是元素上定义的一个方法,以元素的某个可能取值作为参数。它的效果是规定该元素必须采用该值。元素采用不同值的任何随机执行都被排除。这个观测值对相关元素的概率有影响。例如,在Hello World程序中,您可以看到声明这个观测值使sunnyToday更可能为true,因为根据该模型,今天是晴天比不是晴天更可能造成“Hello, world!”的问候语。

您还看到了关联观测值的另一种方法:

greetingToday.unobserve()`
上述语句删除greetingToday上的观测值(如果有的话),这样就不会排除任何随机执行。结果是,关于greetingToday的证据不影响其他元素的概率。

2.6.2 条件

observe指定元素的特定值。如果您知道元素值的某些相关情况,但是不确定该值,该怎么办?Figaro允许将任何预测作为证据。这称作条件。条件指定一个布尔函数,该函数为真某个值才可能出现。例如:

val sunnyDaysInMonth = Binomial(30, 0.2)
println(VariableElimination.probability(sunnyDaysInMonth, 5)  ◁——●  //打印0.172279182850003
sunnyDaysInMonth.setCondition((i: Int) => i > 8)              ◁——●  //晴天超过8天的证据
println(VariableElimination.probability(sunnyDaysInMonth, 5)  ◁——●  //打印0,因为5个晴天与证据不符```
观察证据并用它推断其他变量的概率是概率推理的核心。例如,通过观察当月的晴天数量,可以推断某人是否可能拥有好心情。使用来自2.5节的例子:

val sunnyDaysInMonth = Binomial(30, 0.2)
val monthQuality = Apply(sunnyDaysInMonth,
(i: Int) => if (i > 10) "good"; else if (i > 5) "average"; else "poor")
val goodMood = Chain(monthQuality, (s: String) =>

 if (s == "good") Flip(0.9)
 else if (s == "average") Flip(0.6)
 else Flip(0.1))

println(VariableElimination.probability(goodMood, true))
// prints 0.3939286578054374 with no evidence`
设定条件,规定sunnyDaysInMonth的值必须大于8。然后,可以看到它对goodMood的影响:

sunnyDaysInMonth.setCondition((i: Int) => i > 8)
println(VariableElimination.probability(goodMood, true))
// prints 0.6597344078195809```
好心情的概率明显上升,因为您排除了晴天数量少于8的“坏”月份。

Figaro允许指定某个元素满足的多个条件。这通过使用addCondition方法实现,该方法向元素的现有条件中增添一个条件。增添条件的结果是元素值必须同时满足新条件和现有条件。

sunnyDaysInMonth.addCondition((i: Int) => i % 3 == 2)`
上述语句说明,除了大于8之外,sunnyDaysInMonth的值还必须比3的倍数大2。这就排除了9和10等可能值,所以,最小的可能值为11。当然,当您查询好心情的概率时,可以看到它再次上升:

println(VariableElimination.probability(goodMood, true))
// prints 0.9```
可以用removeConditions删除某个元素上的所有条件:

sunnyDaysInMonth.removeConditions()
println(VariableElimination.probability(goodMood, true))
// prints 0.3939286578054374 again`
顺便说一句,观测值只是条件的一个特例,要求某个元素取单一特定值。下面总结与条件相关的方法。

setCondition是元素上的一个方法,以一个预测作为参数。预测必须是从元素值类型到布尔类型的函数。setCondition方法使这个预测成为元素上的唯一条件,删除现有条件和观测值。
addCondition也是元素上的方法,以预测作为参数,预测必须是从元素值类型到布尔类型的函数。addCondition在现有条件和观测值之上添加这个预测。
removeConditions是元素上的方法,删除元素的所有条件和观测值。

2.6.3 约束

约束提供了规定元素相关情况的更通用手段,它通常有两个目的:(1)作为指定“软”证据的手段;(2)作为提供模型中元素间附加关系的手段。

用作软证据的约束

假定您有关于元素的某种证据,但是不是很确定。例如,您认为我看上去脾气暴躁,但是从外表无法得知我的情绪。所以您不指定goodMood为false这样的硬证据,而是指定软证据:goodMood为false的可能性大于true的可能性。

这可以使用约束实现。约束是一个从元素值到Double类型值的函数。虽然Figaro没有强制规定,但是约束在这个函数值始终在0和1(含)之间时工作得最好。例如,为了表示我的情绪似乎暴躁但是不确定的证据,您可以为goodMood添加一个约束,当goodMood为true时生成值0.5,在goodMood为false时生成1.0:

goodMood.addConstraint((b: Boolean) => if (b) 0.5; else 1.0)```
这个软约束可以这样解读:在其他条件不变的情况下,goodMood为true的可能性只有false的一半,因为0.5是1.0的一半。第4章将讨论这方面的数学运算,简而言之,某个元素值的概率乘以该值的约束结果。所以,在这个例子中,true的概率乘以0.5,false的概率乘以1.0。这样做之后,概率加总不一定等于1,所以将被按比例调整,使之加起来等于1。如果没有这个证据,我认为goodMood为true和false的可能性相同,所以它们的概率均为0.5。看到这个证据之后,首先将两个概率乘以约束结果,得出true的概率为0.25,false的概率为0.5,这两个数加起来不为1,经过比例调整,最后的答案是goodMood为true的概率是1/3,为false的概率是2/3。

条件和约束之间的不同是,在条件中,声明某些状态是不可能的(概率为0)。相比之下,约束改变不同状态的概率,但是除非结果为0,否则不会使某个状态变为不可能。条件有时候称作硬条件,因为它们设置了可能状态不能违反的规则,而约束被称作软约束。

回到示例程序,在添加这个约束之后查询goodMood,将看到概率因为这个软证据而下降,但是不像设置“我很暴躁”的硬证据那样为0:

println(VariableElimination.probability(goodMood, true))
// prints 0.24527469450215497`
约束提供了和条件类似的一组方法。

setConstraint是元素上的一个方法,以预测作为参数。预测必须是从元素值类型到Double类型值的函数。setConstraint方法使该预测成为元素上的唯一约束。
addConstraint也是元素上的一个方法,以预测作为参数,该参数必须是从元素值类型到Double类型值的函数。addConstraint方法在任何现有约束上添加这个预测。
removeConstraints是元素上的一个方法,从元素中删除所有约束。
条件和约束是相互独立的,所以设置条件或者删除所有条件不会删除任何现有约束,反之亦然。

作为连接元素的约束

约束有一种强大的用途。假定您认为两个元素的值相关,但是无法在元素定义中捕捉。例如,假设您的垒球队胜率为40%,每场比赛可以通过Flip(0.4)定义。再假设您认为自己的球队有连续性,所以相邻的比赛可能有相同的结果。您可以添加对相邻比赛的约束以捕捉这一信念,这个约束说明相邻比赛得到相同值的可能性大于得到不同值的可能性。用如下的代码可以实现上述模型。我介绍的是3场比赛的代码。但是可以用数组和for循环将其推广到任何数量的比赛。

首先,定义3场比赛的结果:

val result1 = Flip(0.4)
val result2 = Flip(0.4)
val result3 = Flip(0.4)```
现在,为了表示发生的情况,创建一个allWins元素,当所有结果都为真时,其值为true:

val allWins = Apply(result1, result2, result3,
(w1: Boolean, w2: Boolean, w3: Boolean) => w1 && w2 && w3)`
我们来看看添加任何约束之前所有比赛全胜的概率:

println(VariableElimination.probability(allWins, true))
// prints 0.064000000000000002```
现在添加约束。您将定义一个makeStreaky函数,取得两个比赛结果并对其添加连续性约束:

def makeStreaky(r1: Element[Boolean], r2: Element[Boolean]) {
val pair = Apply(r1, r2, (b1: Boolean, b2: Boolean) => (b1, b2))

 pair.setConstraint((bb: (Boolean, Boolean)) =>
if (bb._1 == bb._2) 1.0; else 0.5

)}`
这个函数以两个Boolean元素为参数,这两个参数表示两场比赛的结果。因为约束只能应用到一个元素,您希望使用约束创建两个元素之间的关系,所以首先将两个元素打包成单一元素,该元素的值是一个二元组。这通过Apply(r1, r2, (b1: Boolean, b2: Boolean) => (b1, b2))实现。现在,您有了一个值为两场比赛结果配对的元素。然后,设置该配对的约束为一个函数,该函数取一对Boolean变量bb,如果bb._1 ==bb._2(配对的第一部分和第二部分相等)则返回1,否则返回0.5。这个约束说明,在其他条件不变时,两场比赛结果相同的概率两倍于不同的概率。

现在,您可以使相邻两场比赛的结果保持延续性,并查询所有比赛全胜的概率:

makeStreaky(result1, result2)
makeStreaky(result2, result3)
println(VariableElimination.probability(allWins, true))
// prints 0.11034482758620691```
可以看到,概率因为球队的连续性而明显上升。

注意:

了解概率图模型的人将会注意到,使用本节中阐述的约束使Figaro能够描述无方向模型,如马尔科夫网络。
时间: 2024-09-20 11:54:53

《树莓派开发实战(第2版)》——2.6 使用条件和约束指定证据的相关文章

《树莓派开发实战(第2版)》——导读

前言 树莓派开发实战(第2版)自从2011年诞生以来,树莓派已经成为基于Linux的低成本电脑和嵌入式计算平台这两个领域中的重要角色.同时,也受到了教育工作者和业余爱好者们的一致好评. 自从本书第1版问世以来,树莓派的销售量已超过了几百万台,同时还出现了许多新型号的树莓派.某些型号,比如B+.A+和B+型树莓派2等,还对该设备的规范进行了改进,出现了具有4核处理器的树莓派2和树莓派计算模块,即可以把树莓派作为一个插件式电路板用作更大系统的零部件. 针对出现的各种新型树莓派以及Raspbian操作

《树莓派开发实战(第2版)》——第2章 网络连接

第2章 网络连接 树莓派开发实战(第2版) 2.0 引言 树莓派在设计之初,便是要连接到互联网的.互联网通信是它的关键功能之一,这给其他各种用途铺平了道路,例如家庭自动化.Web服务.网络监控等. 树莓派既可以使用以太网线缆(这种情况至少要求是B型树莓派)联网,也可以使用USB Wi-Fi无线网卡连接网络.树莓派一旦连接到互联网上面,就意味着你可以通过其他计算机来远程连接树莓派.这对于本身难以接近,或者没有连接键盘.鼠标和显示器的树莓派来说,是非常有用的. 接下来,本章将详细介绍树莓派连接互联网

《树莓派开发实战(第2版)》——1.3 Figaro简介:一种概率编程语言

1.3 Figaro简介:一种概率编程语言 在本书中,您将使用一种称为Figaro的概率编程系统.(我用莫扎特的歌剧<费加罗的婚礼>中的角色为其命名.我喜爱莫扎特,并在该剧于波士顿的一次演出中饰演巴尔托洛医生.)本书的主要目标是教授概率编程的原则,在本书中学到的技术应该可以在其他概率编程系统上沿用.附录B简单描述了现有的一些系统.但是,本书还有第二个目标--帮助您获得创建使用概率程序的亲身体验,并提供可以立即使用的工具.因此,许多例子都用Figaro代码实现. Figaro是从2009年开始开

《树莓派开发实战(第2版)》——2.1 连接有线网络

2.1 连接有线网络 面临问题 你想通过有线网络将树莓派连接到互联网. 解决方案 首先,如果你的树莓派的型号为A.A+或Zero的话,那么它们自身并没有提供RJ45以太网接口.这种情况下,最好使用USB无线网卡来连接互联网(见2.5节). 如果你的树莓派是B型的,可以将以太网电缆插入RJ45接口,同时将线缆另一端接入家用路由器后方的空闲接口中即可.图2-1展示的是一款老版的树莓派1,它的网络LED就在音频接口旁边.对于树莓派2来说,这些LED位于以太网接口自身内部. 树莓派一旦连接到网络上面,它

《树莓派开发实战(第2版)》——1.10 优化性能

1.10 优化性能 面临问题你感觉自己的树莓派运行得太慢了,所以,想通过超频来提速. 解决方案如果你使用的是4核处理器的树莓派2的话,你不会有太慢的感觉.但是,如果你使用的是单核心处理器的老版树莓派的话,感觉就像是老牛拉破车. 为了提高树莓派的运行速度,你可以使用超频方法. 当然,这会使树莓派的耗电量有所增加,同时也会使它变得更热(参考后面的讨论). 这里使用的超频方法称为动态超频,因为它会自动检测树莓派的温度,并且一旦温度过高,时钟频率就会自动下调. 为了给树莓派超频,可以在终端输入下列命令来

《树莓派开发实战(第2版)》——2.5 配置无线网络连接

2.5 配置无线网络连接 面临问题你想通过USB无线网卡将树莓派连接到互联网上. 解决方案如果你的Raspbian是最新版本的话,那么配置Wi-Fi的任务将易如反掌.你只需插入USB Wi-Fi无线网卡,然后在屏幕右上方单击Network图标即可(见图2-3).之后,你会看到一个无线网络清单.你选择网络后,系统将提示你输入Pre Shared Key,即密码. 输入密码,稍等片刻,Network图标就会变为标准的Wi-Fi标志,说明无线网络已经连接成功. 如果你使用的是老版的Raspbian的话

《树莓派开发实战(第2版)》——1.3 选择电源

1.3 选择电源 面临问题 你需要为树莓派选择电源. 解决方案 树莓派对电源的基本电气规格的要求为提供5V稳压直流电. 至于电源在电流大小方面的要求,这要取决于树莓派的具体型号以及其连接的外围设备.你最好采用一款能够轻松驱动树莓派的电源,因此电流一般不宜小于700mA.如果你在同一个卖家那里购买树莓派和电源的话,他通常能够告诉你某款电源是否与你的树莓派相匹配. 如果你打算使用无线上网卡或其他大功率的USB外设的话,那么最好选用能够提供1.5A甚至2A电流的电源. 此外需要注意的是,那些非常廉价的

《树莓派开发实战(第2版)》——2.6 使用控制台线联网

2.6 使用控制台线联网 面临问题 虽然没有网络连接可用,但是,你仍然希望能够从另一台计算机远程访问树莓派. 解决方案 使用控制台线来连接树莓派. 如果你打算以无外设的方式来使用树莓派的话,即不用键盘.鼠标或显示器,那么控制台线将是不二之选.控制台线的外观如图2-5所示,可以从Adafruit(https://www.adafruit.com/ )网站购买. 控制台线的连接方式如下. 1.将红色(5V)导线连接到GPIO接口左边缘上的5V引脚. 2.将黑色(GND)导线连接至上面用到的5V引脚左

《树莓派开发实战(第2版)》——1.2 为什么使用概率编程

1.2 为什么使用概率编程 概率推理是机器学习的基础技术之一.Google.Amazon和Microsoft等公司使用它理解可用数据.概率推理已经用于各种各样的应用程序,如预测股价.推荐电影.诊断计算机和检测网络入侵.许多应用都使用了本书中将要学习的技术. 前一小节中,有两个引人注目的要点. 概率推理可用于预测未来.推断过去,以及从过去的事实中学习更好地预测未来. 概率编程是使用图灵完备编程语言作为表示语言的概率推理. 将上面两个要点结合起来,可以得到如下表示. 事实:概率推理+图灵完备=概率编