概率编程实战(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-23 06:09:25

点击下载

作者:[美]Avi Pfeffer(艾维·费弗)

出版社:人民邮电出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

概率编程实战

概率编程实战试读:

前言

概率编程是一个激动人心的新领域,正在快速地引起人们的兴趣,从学术领域进入程序员的世界中。本质上,概率编程是创建概率推理模型的新方法,这种模型用来根据观测预测或者推理未知的事物。概率推理很久以来都是机器学习的核心方法之一,在机器学习中,使用了概率模型来描述从经验中得到的知识。在概率编程之前,概率推理系统局限于包含贝叶斯网络等简单、固定结构的模型。而概率编程提供了编程语言的全部能力以表现模型,使概率推理系统摆脱了这些桎梏。这正如从电路转向高级编程语言。

我从青少年时代用BASIC语言开发一个足球模拟程序时就致力于概率编程,只是当时还没认识到。这个模拟程序使用“GOTO 1730 + RANDOM * 5”这样的指令表示随机的事件顺序。经过精心的调校,模拟程序已经很逼真,足以让我娱乐数个小时。当然,在随后的岁月中,概率编程已经逐渐成熟,不再只是包含随机目标的GOTO语句了。

1997年,我和Daphne Koller、David McAllester合作编撰了第一篇关于概率编程的论文。这篇论文引入了一种类似Lisp的概率语言,但是主要的创新是根据关于输出的证据,推理程序可能特征的一种算法。这一创新不仅提供了运行程序以获得可能执行方式的手段,还反向论证和推理了产生观测结果的原因,从而使概率语言超越了典型的概率模拟语言。

21世纪初,我开发了第一种基于函数式编程的通用概率编程系统IBAL。IBAL有很强的表达能力并包含新型推理算法,但是几年之后,我逐渐对其局限性感到不满,主要是难以与数据交互、与应用程序集成。这些局限性促使我在2009年开始开发新的概率编程系统,我将其定名为Figaro。Figaro以实用性作为首要目标,同时并没有牺牲概率编程能力。这导致了将Figaro作为Scala程序库的设计决策,该决策使得概率编程模型更容易与Java虚拟机应用集成。同时,Figaro具备了我所知的概率编程系统中最广泛的表现特征和推理算法。Figaro现在是一个开源GitHub项目,最新版本号为3.3。

概率编程可能是一种难以掌握的技术,因为它需要多种技能,其中主要的是编写概率模型和编写程序的能力。对于许多程序员来说,编写程序很自然,但是概率建模有些神秘。本书的目的是揭开概率建模的神秘面纱,告诉您如何在创建概率模型时高效编程,帮助您有效地使用概率编程系统。本书假定读者在机器学习或者概率推理上没有任何背景。函数式编程和Scala的经验有所帮助,但是要使用本书并不一定要成为Scala的奇才,Scala专业知识也可能因为阅读本书而增长。

阅读本书之后,您应该可以在没有机器学习博士学位的情况下,为许多应用程序设计概率模型,从数据中获得有意义的信息。如果您是某个领域的专家,本书能够帮助您表达脑海中或者纸面上的模型,使它们可以运算,实现对不同概率的计算和分析。如果您是一位数据科学家,本书可以帮助您开发比其他工具更丰富、更详细和更精确的模型。如果您是软件工程师或者架构师,正寻求在系统中加入不确定情形下的推理能力,本书不仅能够帮助您构建处理不确定性的模型,还能将这些模型集成到应用程序中。不管因为何种原因选择本书,我都希望您能够喜欢它,并从中得益。序

1814年,皮埃尔•西蒙•拉普拉斯写道,“在很大程度上,人生最重要的问题就是概率问题。”此后过了100多年,回答这些问题(这一格言依然正确)的唯一方法是用笔和纸分析每个问题,得到结果的公式,手工填入数字以求得公式值。计算机的出现对这一情况并没有很大的改变,只是能够为包含更多数字的更复杂公式求值,纸笔分析也变得更加雄心勃勃,往往用纸数百页。

概率问题的分析需要构思概率模型,这种模型以某种方式规划概率空间,为其指定数值化概率。过去,概率模型用自然语言文本和半正式的数学标记法的组合写下。从模型中,经过进一步数学处理得出计算答案的公式或者算法。这些阶段都十分费时费力、容易出错,而且存在特定于具体问题的难点,使概率理论的适用性受到了严重的限制。尽管拉普拉斯在多年前就已提出,但是这个生活中最重要的问题仍然没有答案。

解决上述问题的第一个重要进步是定义概率模型所用的形式语言的发展,例如贝叶斯网络和马尔科夫网络。形式语言具有定义正确表达式的精确语法,以及定义每种正确表达式含义的精确语义(即每个表达式表示哪种概率模型)。因此,用机器可理解的形式描述概率模型,开发一个算法计算任何可表达概率模型结果都成为可能。

在前面的叙述中,美中不足的是:可表达概率模型的缺乏。实际上,贝叶斯和马尔科夫网络等形式语言表达能力相当有限。从某种意义上说,它们只是布尔电路的概率模拟。为了对这一局限性的含义有所了解,我们考虑一个问题:编写大型公司所用的工资单软件。在Java等高级编程语言中,这可能涉及数万行代码。现在,想象一下将许多逻辑门电路连接起来完成相同的功能。这样的任务似乎完全无法完成。这样的电路规模、复杂度和清晰性都无法想象,因为电路缺乏捕捉问题结构的表达能力。

1997年,本书作者Avi Pfeffer(当时还是个学生)和他的导师Daphne Koller以及协作者David McAllester发表了一篇关于概率编程语言(PPL)的原创论文,提供了将概率理论与高级编程语言联系起来的关键思路。这一思路是通过引入随机元素使程序成为概率模型,并将程序的意义定义为每个可能执行路径的概率。这一思路以高效的方式结合了数学的两个最重要分支,我们接下来将要开始探索由此产生的新可能性。

本书使用Figaro语言阐述这些概念及其应用,逐步引领读者理解上述思路。书中避开了不必要的数学知识,集中于详细构思、认真解释的实例,适合于拥有典型编程背景的读者。通读本书还有一个副产品:读者能够比以往更轻松地熟练掌握贝叶斯推理和统计学的原理及技术。最重要的是,读者将学习建模技能,这是任何科学家或者工程师的最关键技能之一。Figaro和其他PPL使人们可以直接、快速、精确地表现这种技能。

本书是将概率编程从开发它的实验室中转移到真实世界的重要步骤。从某种程度上说,PPL系统的能力无疑还难以应对这种挑战,那些研究实验室也将停止工作。另一方面,本书的读者一定能找出应用Figaro的创新方法,它与各种新问题的相关性也绝非作者所能想象的。Stuart Russell加州大学伯克利分校计算机科学教授致谢

本书的创作经过了许多年:从关于概率编程的第一个思路,到IBAL和Figaro系统的创建,再到构思、编写并与Manning出版社一起完善。在这段时间里,许多人贡献了自己的力量,使本书得以面世。

本书的出版很大程度上归功于我在Charles River Analytics的团队的努力:Joe Gorman、Scott Harrison、Michael Howard、Lee Kellogg、Alison O’Connor、Mike Reposa、Brian Ruttenberg和Glenn Takata。还要感谢Scott Neal Reilly从一开始就支持Figaro。

在人工智能和机器学习方面,给我最大教益的是我的导师和合作者Daphne Koller。Stuart Russell为我提供了学习人工智能的第一个机会,在整个职业生涯中鼓励我,并成为最新的合作者和本书的序言撰写者。Mike Stonebraker在其Postgres项目中为我提供了第一个研究机会,在他的小组中工作时,我学到了许多关于系统构建的知识。Alon Halevy曾邀请我和他在AT&T实验室中一起度过一个夏季,我在那里第一次和David McAllester讨论关于概率编程的问题,成果就是和Daphne合作编写的Lisp概率论文。当这些思路刚刚萌芽时,我总是和我的合作者和同事Lise Getoor一起探讨。

我深深感谢Alex Ihler,他慷慨地贡献自己的专业知识,认真阅读本书以审核技术上的准确性。过去几年中,在所有与推理相关的事情上,Alex总是极好的意见反馈者。

在不同的发展阶段,还有其他许多人提供了意见,包括Ravishankar Rajagopalan、Shabeesh Balan、Chris Heneghan、Clemens Baader、Cristofer Weber、Earl Bingham、Giuseppe de Marco、Jaume Valls、Javier Guerra Giraldez、Kostas Passadis、Luca Campobasso、Lucas Gallindo、Mark Elston、Mark Miller、Nitin Gode、Odisseyas Pentakolos、Peter Rabinovitch、 Phillip Bradford、Stephen Wakely、Taposh Dutta Roy和Unnikrishnan Kumar。

感谢Manning Publications的许多出色员工对本书出版的帮助。特别要感谢编辑Dan Maharry使这本书远远超过了我自己完成的质量,还要感谢Frank Pohlmann鼓励我编写本书,并且帮助我准备写作过程。

感谢空军研究实验室(AFRL)和国防部高级研究计划署(DARPA)对本书所描述的先进机器学习概率编程(PPAML)项目中某些工作的投资。特别要感谢几位DARPA项目经理,Bob Kohout、Tony Falcone、Kathleen Fisher和Suresh Jagannathan,他们对概率编程深信不疑并致力于实现它。

最后,如果没有家人的爱和支持,本书也不可能出版。感谢我的妻子Debby Gelber和孩子们(Dina、Nomi和Ruti),你们都是了不起的人。永远感谢我的母亲Claire Pfeffer用自己的爱养育了我。谨以本书献给你们。关于本书

不管商业、科学、军事上还是日常生活中,许多决策都涉及不确定情况下的判断。当不同的因素将您引向不同方向,如何知道最应该注意的是哪个方面?概率模型可以表达关于您所处情况的所有相关信息。概率推理使用这些模型确定对决策影响最大的变量的概率。您可以使用概率推理预测最可能发生的情况:您的产品能否在目标价格上取得成功;患者对特定疗法的反应是否良好;您的候选人如果采用某种立场,能否赢得选举?您还可以使用概率推理推导出所发生情况的可能原因:如果产品失败,是不是因为价格太高?

概率推理也是机器学习的主要方法之一。您在概率模型中编码关于所在领域的初始信念,如用户对市场产品的一般反应。然后,提供训练数据(可能与特定产品的用户反应有关),更新信念以获得新模型。现在,可以使用新模型预测未来的结果,如规划中的产品是否成功,或者推导出观测结果的可能原因,如新产品失败的原因。

过去,概率推理使用专用语言表示概率模型。近年来,我们意识到可以使用常规的编程语言,这造就了概率编程。概率编程有三大好处。首先,在构建模型时,可以从编程语言的所有特征中获益,如丰富的数据结构和控制流。其次,概率模型很容易与其他应用程序集成。第三,可以从用于论证模型的通用推理算法中获益。

本书的目标是提供在日常活动中使用概率编程的知识。特别是:

如何构建概率模型并以概率程序表达。

概率推理的工作原理以及如何以各种推理算法实现。

如何使用Figaro概率编程系统构建实用的概率程序。

Figaro以Scala程序库的形式实现。和Scala一样,Figaro结合了函数式和面向对象编程风格。这对于不了解函数编程的人来说很有用。本书不使用高级函数式编程概念,所以您应该能在对此了解有限的情况下理解。同样,对Scala有所了解是有益的。尽管本书中常常会解释Scala的结构,但不是Scala的简介。同样,本书通常不使用Scala较为难懂的功能,所以略有涉猎就应该足够了。路线图

本书的第1部分简介概率编程和Figaro。第1章首先解释概率编程的定义及其实用性,然后简单介绍Figaro。第2章是Figaro的使用教程,帮助您很快地了解概率程序的编写。第3章提供了一个完整的概率编程应用——一个垃圾邮件过滤器,包括论证给定电子邮件是常规邮件还是垃圾邮件的组件,以及从训练数据学习概率模型的组件。第3章的目标是在详细介绍建模技术之前,提供各种技术相互融合的全貌。

第2部分介绍概率程序的构建。第4章包含有关概率模型和概率程序的基本材料,这对理解它们,真正了解创建概率程序时需要做什么很重要。第5章提供了两种作为概率编程核心的建模框架——贝叶斯网络和马尔科夫网络。第6~8章描述了一组用于构建更高级程序的实用编程技术。第6章讨论使用Scala和Figaro集合组织涉及许多同类变量的程序的方法。第7章讨论面向对象编程,这种方法对于概率编程和常规程序同样有益。第8章介绍建模动态系统。动态系统是状态随时间推移而变化的系统,是这一章深入介绍的概率推理极其常见和重要的应用。

第3部分向您传授关于概率推理算法的知识。理解推理对于有效使用概率编程很重要,这样您就可以使用适合于任务的算法,对合适的方式配置,以支持有效推理的方式表达模型。第3部分在传授算法理论和使用这些算法的实践技巧之间达成了平衡。第9章是基础,介绍了捕捉概率推理中使用的主要思路的3条原则。第10章和第11章描述了两个主要的推理算法家族。第10章描述因子分解算法,包括对因子及其工作原理的介绍,以及变量消除和置信传播算法。第11章介绍抽样算法,特别关注重要性抽样和马尔科夫链蒙特卡洛算法。第10章和第11章专注于计算感兴趣的变量概率的基本查询,而第12章介绍如何使用因子分解和抽样算法计算其他查询,如多变量联合概率、变量最大可能值和观测证据的概率。最后,第13章讨论两个高级而重要的推理任务:监视随时变化的动态系统,从数据中学习概率模型的数值参数。

每章都有一组练习,涵盖了从简单计算、编程任务到开放思维练习的范围。

本书还包括两个附录。附录A是Figaro的安装指南。附录B是其他概率编程系统的概况。关于代码和练习

本书的代码以等宽字体显示,以便和正文分开。许多代码清单中含有代码注释,强调了重要的概念。在某些情况下,清单之后有链接到解释的编号项目。

本书包含许多代码示例,其中大部分可以从本书网站www.manning.com/books/practical-probabilistic-programming 的在线代码库中找到。该网站还包含部分练习答案。关于作者

Avi Pfeffer是概率编程的先驱,从一开始就活跃于这个领域。Avi是Figaro的首席设计者和开发者。在Charles River Analytics,Avi参与了Figaro在多个问题上的应用,包括恶意软件分析、汽车健康监控、气象模型建立和工程系统评估。

在闲暇时,Avi是一位歌手、作曲家和音乐制作人。他和妻子及三个孩子在马萨诸塞州坎布里奇生活。作者在线

购买本书就可以免费访问Manning Publications运营的一个私有网络论坛,在那里可以评论本书,提出技术问题,讨论书中的练习,从作者和社区那里得到帮助。在www.manning.com/books/practical-probabilistic-programming 可以访问和订阅该论坛。这个页面提供了关于注册后如何访问论坛、论坛提供的帮助类型以及行为准则的信息。

Manning对读者的承诺是,提供读者之间和读者与作者之间有意义对话的途径。我们不能承诺作者的参与度,他们对论坛的贡献完全是自愿(无偿)的。我们建议读者向作者提出挑战性的问题,以免他们失去兴趣!

只要本书仍在销售中,作者在线论坛和过去讨论的存档都可以在Manning网站上访问。关于封面

本书封面上的插图题为“威尼斯人”。这幅插图取自一本法国旅游图书——J. G. St. Saveur于1796年出版的《旅游百科全书》。当时,旅游消遣还是相当新颖的现象,这样的旅游指南很受欢迎,它向旅游者和空谈旅游家介绍了法国和海外其他地区的风土人情。《旅游百科全书》中丰富的插图生动地讲述了200年前世界各个城市和地区的独特个性。当时,在两个距离仅为几十英里的地区,人们的穿着就足以独特地反映所属地区。这本旅游指南展示了当时与其他历史时代(除了快节奏的现在)的孤立感和距离感。

当时的着装规范已经变化,各个地区的多样化也逐渐消失。现在,往往难以分辨不同大陆的居民。从乐观的角度看,我们用文化和视觉上的多样性换来了更多彩的个人生活——或者更丰富、有趣的知识和技术生活。

Manning通过复活这本旅游指南中的插图,用两个世纪前丰富多彩的地域性差别赞美计算机行业的创造性和乐趣。第1部分概率编程和Figaro简介

什么是概率编程?它有什么用处?如何使用它?这些问题是第1部分的主题。第1章介绍概率编程的基本思路。首先介绍概率推理系统的概念,说明概率编程如何将传统的概率推理系统概念和编程语言技术相结合。

在本书中,您将使用Figaro概率编程系统。第1章简要介绍Figaro,第2章提供所有Figaro主要概念的简单教程,帮助您快速开始编写概率程序。第3章介绍一个完整的概率编程应用程序,为您提供实际应用程序组合的全貌。虽然这一章接近全书的开头,因此您从一开始就一窥全局,但是在阅读本书的更多章节,已经学习到更深入的概念时,仍值得不时复习。第1章概率编程简介本章介绍如下内容:● 什么是概率编程?● 为什么应该关心概率编程?为什么我的老板应该关心概率编程?● 概率编程的工作原理是什么?● Figaro——概率编程所用的系统● 使用和不使用概率编程的情况下,概率应用程序编写的对比

在本章中,您将学习如何使用概率推理系统的两个主要组成部分(概率模型和推理算法)做出日常决策,还将了解现代概率编程语言是如何比Java或Python等通用语言更轻松地创建这种推理系统的。本章还将介绍Figaro,这是本书自始至终使用的基于Scala的概率编程语言。1.1 什么是概率编程

概率编程是一种系统创建方法,它所创建的系统能够帮助我们在面对不确定性时做出决策。许多日常决策涉及在确定无法直接观测的相关因素时的判断能力。历史上,帮助在不确定性下做出决策的方法之一是使用概率推理系统。概率推理将我们对某种情况的认识和概率法则结合起来,确定无法观测的决策关键因素。直到最近,概率推理系统的范围仍然有限,难以应用到许多现实情况中。概率编程是一种新方法,它使概率推理系统更容易构建,适用范围更广。

要理解概率编程,首先要观察不确定性条件下的决策过程和涉及的主观判断。然后,您将了解概率推理是如何帮助您做出决策的。您将注意到概率推理系统所能进行的3种推理,也就能理解概率编程,以及通过编程语言的能力用概率编程构建概率推理系统的方法。1.1.1 我们如何做出主观判断

在现实世界中,我们所关心的问题很少有非此即彼的答案。例如,如果您打算启动一个新产品,想要知道它的销路如何。您可能认为它将取得成功,因为您相信它设计精良,市场调查也表明有需求,但是无法确定。您的竞争者可能推出更好的产品,或者您的产品可能有市场不能容许的致命缺陷,经济也可能突然衰退。如果要求百分之百的确定,就无法做出是否投放该产品的决策(见图1-1)。图1-1 去年所有人都喜爱我的产品,但是明年会怎么样呢?

概率语言有助于做出此类决策。在投放某个产品时,可以使用类似产品的先期经验估算产品的成功概率。然后,用这一概率帮助决定是否继续推进并投放该产品。您可能不仅关心产品能否成功,还关心它能带来多少收入,或者失败将导致多大的损失。您可以使用不同结果的概率做出更明智的决策。

概率论思想可以帮助您做出艰难的决策和判断,但是,您该怎么做呢?一般原则在下面列出。

事实:主观判断基于知识+逻辑。

您对感兴趣的问题有某些知识。例如,您对产品有深入的了解,可能进行了一些市场调查以找出客户的需求。您还可能有关于竞争对手的情报和经济预测。同时,逻辑帮助您运用知识获得问题的答案。

您需要一种规格化知识的方法,还需要运用知识得出问题答案的逻辑。概率编程提供了规格化知识和回答问题的逻辑。在我描述概率编程系统概念之前,我将描述概率推理系统的一般概念,这种系统提供了规格化知识和提供逻辑的基本手段。1.1.2 概率推理系统帮助决策

概率推理是使用您的领域模型做出不确定条件下决策的一种方法。举个足球界的例子。假定统计显示9%的角球造成进球。您的任务是预测某次角球的结果。攻方的中锋身高6英尺4英寸(约1.93米),以头球能力著称。守方正选门将刚刚受伤,被第一次出场的替补门将换下。除此之外,咆哮的大风使长传难以控制。那么,如何计算进球的概率?

图1-2展示了使用概率推理系统找出答案的途径。您在一个角球模型中编码关于角球和所有相关因素的知识。然后,提供特定角球的证据,也就是中锋个子很高、守门员缺乏经验以及强风。您告诉该系统,希望知道这次角球是否进球。推理算法返回答案——有20%的概率进球。图1-2 概率推理系统预测角球结果的方法关键定义

一般知识——不考虑特定情况细节时,对领域相关情况的概括了解。

概率模型——用定量的概率术语编码的领域一般知识。

证据——关于特定情况的具体信息。

查询——您希望知道的情况属性。

推理——概率模型根据证据回答查询的过程。

在概率推理中,您创建一个模型,以定量的概率术语捕捉领域的所有相关一般知识。在我们的例子中,这个模型可能是对角球情况和影响结果的所有球员相关特征及条件的描述。然后,对于某个特定情况,您将该模型应用于所拥有的具体信息,得出结论。这些具体信息称为证据。在本例中,证据是中锋身材高大,守门员缺乏经验,风力很大。所得出的结论可以帮助您决策——例如,您是否应该在下一场比赛中更换不同的守门员。结论本身以概率的方式描述,比如守门员的不同技能水平的概率。

模型、您所提供的信息和查询答案之间的关系由数学上的概率法则定义。根据证据,运用模型回答查询的过程称作概率推理或者简单地称作推理。幸运的是,计算机算法已经有了很大的发展,能够为您完成这些数学题,自动进行所有必要的计算。这些算法被称作推理算法。

图1-3总结了您所学到的知识。图1-3 概率推理系统的基本组成部分

简言之,我们刚刚讨论的是概率推理系统的组成,以及与之互动的方式。但是,如何利用这样的系统?它如何帮助您决策?下一小节描述了概率推理系统所能执行的3类推理。1.1.3 概率推理系统有3种方式推理

概率推理系统很灵活。它们可以根据任何方面的证据,回答关于情况其他特征的查询。在实践中,概率推理系统执行3类推理。● 预测未来的事件。在图1-2中您已经看到此类推理,根据当前情

况预测是否进球。您的证据通常包括关于当前情况的信息,如中

锋身高、守门员的经验和风力。● 推断事件的根源。快进10秒。高个中锋刚刚头球射门,从守门

员身下入网,取得一分。根据这一证据,您对这位新手守门员有

何想法?您能否得出结论,她的技能不足?图1-4说明如何使用

概率推理系统回答这个问题。该模型是您之前用于预测是否进球

的同一个角球模型(这是概率推理的一个实用属性:用于预测未

来结果的模型同样可以在事后推断结果的根源)。使用的证据和

以前一样,并结合了角球得分这一事实。查询是守门员的技能水

平,答案提供了不同技能水平的概率。图1-4 改变查询和证据,系统现在可以推断出进球的原因● 想想看,第一种推理模式描述了前向推理,根据对当前情况的了

解预测未来的事件,而第二种推理模式描述了后向推理,根据当

前结果推断过去的条件。在构建概率模型时,模型本身通常遵循

自然的时间顺序。一名球员踢角球,风作用于球,中锋跃起头球,

守门员做出扑救。但是推理可以向前和向后进行。这是概率推理

的关键特征之一,我在本书中将反复重申这一点:推理的方向不

一定遵循模型的方向。● 从过去的事件中学习,更好地预测未来的事件。现在,再快进

10分钟。同一球队又获得一次角球机会。所有情况与前面类似

——高中锋、缺乏经验的守门员,但是现在风力减弱了。使用

概率推理,可以利用前一次角球发生的情况,帮助您预测下一次

角球的结果。图1-5说明了这一点。证据包括上一次的所有证据(注明其来自上一次)以及当前情况的新信息。在回答这次角球

能否进球时,推理算法首先推断导致第一次进球的条件,例如中

锋和守门员的技能水平。然后,它利用这些更新的属性做出关于

新情况的决策。图1-5 通过将上一次角球的结果考虑在内,概率推理系统可以在下一次角球时做出更好的预测

这些类型的查询能够帮助您做出许多层次上的决策。● 您可以根据有无额外防守队员进球的概率,决定是否用一名防守

队员替换进攻队员。● 可以根据对守门员技能的评估,决定下一次合同谈判时向他提出

的工资数额。● 可以利用了解到的守门员相关情况,帮助预测下一场比赛的结

果,决定是否使用同一名守门员。

学习更好的模型

上述3种推理模式提供了特定情况、给定证据下的推理手段,利用概率推理系统,还可以从过去的情况中学习,改善您的一般知识。在第三种推理模式中,您了解到如何从特定的过去经验学习,更好地预测未来的情况。另一种从过去的经验中学习的方法是改善模型本身。特别是在拥有许多过去的经验可以吸取时(如许多次角球),您可能希望学习一个新模型,以表示角球通常发生情况的一般知识。如图1-6所示,这可以通过一个学习算法实现。与推理算法有些不同,学习算法的目标是产生新的模型而不是回答查询。学习算法从原始模型入手,根据经验更新之,产生新的模型。新模型可以用于回答未来的问题。可以推测,使用新模型产生的答案应该比原始模型更明智。图1-6 可以使用学习算法,以一组经验为基础学习新的模型。然后,这个新模型可以用于未来的推断概率推理系统与精确的预测和任何机器学习系统一样,概率推理系统得到的数据越多,预测就越精确。预测的质量取决于两个因素:原始模型精确反映现实情况的程度和您所提供的数据量。一般来说,提供的数据越多,原始模型就越不重要,这是因为新模型是原始模型和数据所包含信息之间的一个平衡。如果您的数据很少,原始模型占据统治地位,所以它的质量必须很高才能得出准确的预测。如果您拥有许多数据,数据将占据统治地位,新模型倾向于忘掉不那么重要的原始模型。例如,如果您从整个足球赛季中学习,应该能够准确地学习到影响角球的因素。如果只有一场比赛的数据,就需要首先对精确预测比赛所需的因素有出色的想法。概率推理系统将很好地利用给定的模型和可用数据,尽可能精确地做出预测。

现在,您已经了解了概率推理的概念。那么,什么是概率编程?1.1.4 概率编程系统:用编程语言表达的概率推理系统

每个概率推理系统都使用某种表示语言表达其概率模型。表示语言有许多种,您可能已经听说了其中一些,如贝叶斯网络(也称作置信网络)和隐含马尔科夫模型。表示语言控制系统可处理的模型以及模型的情况。语言所能表示的一组模型称作语言的表达能力。对于实际应用,您肯定希望表达能力尽可能强。

简单地说,概率编程系统是以编程语言作为表示语言的概率推理系统。我所说的编程语言是指具有编程语言所有预期特征(如变量、丰富的数据类型、控制流、函数等)的语言。正如您将要看到的,概率编程语言可以表达极其广泛的概率模型,超越传统的概率推理框架。概率编程语言有极强的表达能力。

图1-7说明了概率编程系统与概率推理系统的关系。可以将该图与图1-3比较,以凸显两种系统之间的差别。主要的变化是,模型以编程语言编写的程序表达,而不使用贝叶斯网络等数学结构。由于这种变化,证据、查询和答案都应用到程序中的变量。证据可能指定程序变量的特定值,查询询问程序变量的值,答案是不同查询变量值的概率。此外,概率编程系统通常带有一套推理算法。这些算法适用于以该语言编写的程序。图1-7 概率编程系统是使用编程语言表示概率模型的概率推理系统

尽管存在许多类概率编程系统(参见附录B),本书的重点是函数式的图灵完备系统。函数式意味着它们基于函数式编程,但是不要被它吓住——使用函数式概率编程系统并不需要知道λ函数(lambda)等概念。这一切只意味着,函数式编程提供了这些语言表示概率模型的理论基础。同时,图灵完备是一句行话,表示编程语言可以编写任何能在数字计算机上完成的计算。如果某一运算可以在数字计算机上完成,就可以由任何图灵完备语言实现。您所熟悉的大部分编程语言,如C、Java和Python,都是图灵完备的。因为概率编程语言构建于图灵完备编程语言基础上,它们可以构建的模型类型极其灵活。关键定义

表示语言——用于编码关于模型领域知识的语言。

表达能力——表示语言编码模型中不同类型知识的能力。

图灵完备——能够表示可在数字计算机完成的任何计算的语言。

概率编程语言——使用图灵完备编程语言表示知识的概率表示语言。

附录B论述了除本书使用的Figaro之外的一些概率编程系统。这些系统大部分都使用图灵完备语言。有一些系统(包括BUGS和Dimple)没有使用图灵完备语言,但是它们对目标应用很实用。本书主要关注图灵完备概率编程语言的能力。

将概率模型表示为程序

但是,编程语言如何成为概率建模语言?如何将概率模型表示为程序?我将在这里提出回答这一问题的一些线索,将更深入的讨论放在稍后的章节,那时您已经对概率程序有所了解。

编程语言的核心思路之一是执行。您执行一个程序以产生输出。概率程序也类似,但是它可以有许多执行路径,每个路径产生不同的输出。在程序中随机选择执行路径,每个随机的选择有许多可能的结果,程序编码每种结果的概率。因此,概率程序可以视为随机执行以产生输出的一个程序。

图1-8说明了上述概念。在图中,概率编程系统包含了一个角球程序。这个程序描述生成角球结果的随机过程,它取得一些输入;在我们的例子中,这些输入是中锋的身高、守门员的经验和风力。根据这些输入,程序随机执行以生成输出。每次随机执行产生特定的输出。因为每个随机选择都有多种可能结果,存在许多可能的执行路径,造成不同的输出。任何给定输出(如进球)可能由多个执行路径产生。

让我们来看看,这种程序如何定义概率模型。从一系列随机选择形成的任何特定执行路径都有特定的结果。每个随机选择都有发生的概率。如果将这些概率相乘,就可以得到执行路径的概率。这样,程序定义了每个执行路径的概率。想象一下,如果将该程序运行许多次,生成任何给定执行路径的次数比例等于其概率。输出的概率就是产生该输出的程序运行次数比例。在图1-8中,1/4的运行产生进球的结果,所以进球概率为1/4。图1-8 概率程序定义按照输入随机生成输出的过程注意:您可能疑惑于为什么图1-8中的块标签为“随机执行”而不是其他插图中的推理算法。图1-8展示了概率程序的含义——定义一个随机执行过程,而不是使用概率编程系统的方式——使用推理算法根据证据回答查询。所以,尽管上述插图的结构类似,但是表达了不同的概念。事实上,随机执行形成了某些推理算法的基础,但是许多算法并不基于简单的随机执行。

利用概率编程决策

使用概率编程预测未来很容易理解。只要随机多次执行程序,使用当前已知的信息作为输入,并观察每个输出的出现次数。在图1-8的角球示例中,多次执行该程序,以高中锋、缺乏经验的守门员和强风作为输入。因为1/4的运行得出进球的结果,您可以认定在这些输入条件下,进球概率为25%。

但是,概率编程的魔法在于,它还可以用于1.3.1小节中描述的各类概率推理。概率编程不仅可用于预测未来,还可以推断导致特定结果的事实;您可以“展开”程序,发现结果的根源,还可以在某种情况下应用程序,从结果中学习,在未来使用学习到的信息做出更好的决策。可以使用概率编程做出所有通过概率思想得到的决策。

概率编程是如何工作的?当人们意识到,在较简单的表示语言(如贝叶斯网络)上有效的推理算法可以扩展到程序上时,概率编程就变得实用了。本书的第3部分介绍实现这一扩展的各种推理算法。幸运的是,概率编程系统自带一些内建的推理算法,这些算法可以自动地应用到您的程序中。您所需要做的是以概率程序的形式提供领域知识并指明证据,系统负责推断和学习。

在本书中,您将学习通过概率编程进行概率推理。首先,您将学习概率模型的概念以及使用它得出结论的方法。您还将学习一些从简单组件构成的模型中得出那些结论所需进行的操作。您将学习各种建模技术,以及使用概率编程实现它们的方法,还将了解概率推理算法的工作原理,以便有效地设计和使用自己的模型。在阅读完本书之后,您将能够自信地使用概率编程得出有益的结论,帮助您在面对不确定性时做出决策。1.2 为什么使用概率编程

概率推理是机器学习的基础技术之一。Google、Amazon和Microsoft等公司使用它理解可用数据。概率推理已经用于各种各样的应用程序,如预测股价、推荐电影、诊断计算机和检测网络入侵。许多应用都使用了本书中将要学习的技术。

前一小节中,有两个引人注目的要点。● 概率推理可用于预测未来、推断过去,以及从过去的事实中学习

更好地预测未来。● 概率编程是使用图灵完备编程语言作为表示语言的概率推理。

将上面两个要点结合起来,可以得到如下表示。

事实:概率推理+图灵完备=概率编程

概率编程的动机是将两个本身就很强大的概念结合起来,结果是使用计算机辅助不确定性下决策的更简单、更灵活方法。1.2.1 更好的概率推理

大部分现有概率表示语言在所能表示的系统丰富性上都很有限。有些相对简单的语言(如贝叶斯网络)假定固定的变量集,其灵活性不足,不能建立变量本身可能变化的领域模型。近年来,已经有一些具有更高灵活性的先进语言开发出来。其中一些语言(如BUGS)还提供了编程语言的特征,包括循环和数组,但是没有达到图灵完备。BUGS等语言的成功说明了更丰富、结构更严整的表示方式的必要性。但是,向成熟的图灵完备语言转移,为概率推理开拓了一个新领域。现在,可以建立具有许多交互实体及事件的长期运行过程的模型。

我们再次考虑足球的例子,但是这次想象一下,您的工作是体育分析,希望为一支球队做出人员配备决策的建议。您可以使用积累的统计数字做出决策,但是统计数字不能捕捉积累它们时所处的背景。您可以建立赛季的细致模型,实现粒度更细、情境感知的分析。这要求建立许多相关事件以及相互作用的球员和球队的模型。如果没有完整的编程语言所提供的数据结构和控制流,构建这种模型是难以想象的。

现在,让我们再次思考产品投放的例子,从综合的角度观察业务决策过程。产品投放不是孤立事件,而是经过市场分析、研究和开发的过程,各个过程的结果都有不确定性。产品投放的结果取决于所有阶段,以及市场中其他产品的分析。全面的分析还需要关注竞争对手对您的产品的反应,以及他们可能提出的新产品。这一问题很困难,因为您必须对竞争产品做出推测。甚至有一些竞争对手尚不为人所知。在这个例子中,产品是复杂过程产生的数据结构。同样,用完整的编程语言创建模型很有益处。

不过,概率编程的好处之一是,可以使用更简单的概率推理框架。概率编程系统可以表示广泛的现有框架,以及这些框架所不能表示的系统。本书将传授许多使用概率编程的此类框架。所以,在概率编程的学习中,您还能够精通许多当今常用的概率推理框架。1.2.2 更好的模拟语言

图灵完备的概率建模语言已经存在。它们常常被称作模拟语言。我们知道,使用编程语言模拟足球赛季等复杂过程是可能的。在这种情境下,我使用模拟语言这一术语描述能够表示复杂过程随机执行的语言。正如概率程序,这些模拟随机执行,以产生不同输出。模拟和概率推理一样应用广泛,涵盖了从军事计划到组件设计以及公共卫生及体育比赛预测等范围。确实,精密模拟的广泛使用说明了对丰富概率建模语言的需求。

但是,概率程序远不仅是模拟。使用模拟,您只能完成概率程序的一项功能:预测未来。无法用它推断观测结果的根源。而且,尽管可以不断地用已知的当前信息更新模拟,但是很难包含必须推断的未知信息。因此,从过去经验中学习以改善未来预测和分析的能力很有限。不能将模拟用于机器学习。

概率程序就像不仅可以运行,而且可以分析的模拟一样。开发概率编程的关键要点是,推理算法既可用于较简单的建模框架,也可用于模拟。因此,您有能力编写一个模拟并在其基础上执行推理,以创建概率模型。

最后一点,概率推理系统已经出现了一段时间,Hugin、Netica和BayesiaLab等软件提供了贝叶斯网络系统。但是概率编程更有表现力的表示语言很新颖,我们刚刚开始发现其强大的应用。老实说,我不能告诉您概率编程已经用于大量现有应用,但是有一些重要的应用。Microsoft已经能够使用概率编程,确定在线游戏玩家的真正技能水平。加州大学伯克利分校的Stuart Russell编写了一个程序,通过识别表明核爆炸的地震活动,帮助联合国《全面禁止核试验条约》的实施。麻省理工学院(MIT)的Josh Tenenbaum和斯坦福大学的Noah Goodman已经创建了建立人类识别模型的概率程序,并在试验中取得了很大的成功。在Charles River Analytics,我们已经使用概率编程推断恶意软件实例的组件并确定它们的演变。但是,我相信这些应用仅仅是个开始。将会有越来越多的人用概率编程系统做出所在领域的决策。阅读本书,您也有机会成为这一新技术的尝鲜者。1.3 Figaro简介:一种概率编程语言

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

Figaro是从2009年开始开发的一个开源软件,在GitHub上维护。它以Scala库的形式实现。图1-9说明Figaro如何使用Scala实现概率编程系统。该图详细说明了图1-7,后者描述了概率编程系统的主要组成部分。让我们从概率模型开始,在Figaro中,该模型由任意数量的数据结构(称作“元素”)组成。每个元素代表在您的情境中可取任意数量值的一个变量。这些数据结构用Scala实现,您可以用这些数据结构编写Scala程序创建模型。可以通过关于元素值的信息提供证据,也可以指定希望在查询中了解的元素。至于推理算法,您可以选择一个Figaro内建推理算法并应用到模型上,根据证据回答您的查询。推理算法以Scala实现,其调用就是一个Scala函数调用。推理结果是查询元素不同值的概率。图1-9 Figaro使用Scala提供概率编程系统的方法

Figaro内嵌于Scala提供了一些重大优势。其中一些来自内嵌于通用宿主语言相对于独立概率语言的优势。其他优势则是因为Scala的良好特性。下面是在通用宿主语言中内嵌概率编程语言的好处。● 证据可以用宿主语言的程序得出。例如,您可以编写一个程序读

取一个数据文件,以某种方式处理其中的值,并将其作为证据提

供给Figaro模型。在独立语言中,这一任务要难得多。● 类似地,您可以在一个程序中使用Figaro提供的答案。例如,如

果您有一个供足球队经理使用的程序,该程序可以取得进球概

率,向经理提出建议。● 可以在概率程序中嵌入通用代码。例如,假设您有一个模拟头球

在空中飞行轨迹的物理模型,可以在Figaro元素中加入这个模型。● 可以使用通用编程技术构建Figaro模型。例如,您可能有一个映

射,包含对应于球队中所有球员的Figaro元素,并根据情况中涉

及的球员选择对应的元素。

下面是选择Scala作为内嵌概率编程系统的宿主语言的一些理由。● Scala是一个函数式编程语言,因此Figaro也能得到函数式编程

的好处。正如我在第2部分中所说明的,函数式编程对概率编程

有帮助,许多模型可以自然地以函数式风格编写。● Scala是面向对象的,其优点之一是既是函数式语言,又具有面

向对象的特征。Figaro也是面向对象的。正如第2部分中将要说

明的,面向对象是表达概率编程中多种设计模式的有用手段。

最后,Figaro还有嵌入Scala之外的一些优势,包括:● Figaro能够表示极其广泛的概率模型。Figaro元素的值可以为任

何类型,包括布尔型、整数、双精度数、数组、树、图等。这些

元素之间的关系可以由任何函数定义。● Figaro提供了使用其条件和约束规定证据的丰富框架。● Figaro有多种多样的推理算法。● Figaro能够表示和推理随时间变化的动态模型。● Figaro能够在其模型中包含明确决策,并支持最优决策的推断。

由于多种原因,Figaro是学习概率编程的出色语言。● Figaro以Scala库的形式实现,可以用于Java和Scala程序,很容

易与应用程序集成。● 由于以程序库而非独立语言的形式实现,Figaro提供了宿主编程

语言的全部功能,可以用来构建模型。Scala是高级的现代化语

言,具有许多有用的程序组织功能,使用Figaro时可以自动获得

这些好处。● 从所提供算法的范围来看,Figaro 堪称全能。

本书强调使用的技术和实用的示例。只要有可能,我都会解释建模的一般原则,并描述在Figaro中的实现方法。不管您最终使用哪一种概率编程系统,这对您都将大有裨益。并不是所有系统都能轻松地实现本书中的所有技术。例如,现有的面向对象概率编程系统很少。但是有了好的基础,您就可以找出用所选语言表达需求的方法。使用Scala因为Figaro是一个Scala库,需要Scala的知识才能使用Figaro。本书是关于概率编程的,所以在本书中不教授Scala的知识。Scala的出色学习资源很多,比如Twitter的Scala School(http://twitter.github.io/scala_school)。但是为了防止您对Scala不自信,我在本书中对代码中使用的Scala功能加以说明。即使您还不了解Scala,也能够跟上本书的进度。从概率编程和Figaro中获益并不要求您是一位Scala奇才,在本书中也避免使用一些较为高级和晦涩的特性。但是,增强Scala技能有助于成为更好的Figaro程序员。您甚至会发现,阅读本书也可以提高Scala的技能。Figaro与Java的对比:构建简单的概率编程系统

为了说明概率编程和Figaro的好处,我将展示以两种方式编写的简单概率应用。首先,我说明用Java(您可能对它很熟悉)编写这种应用的方法。然后,我将展示用Figaro编写的Scala应用。尽管Scala相对Java有一定的优势,但是这不是我要指出的主要差别。关键的思路是,Figaro提供了表示概率模型和用这些模型进行推理的能力,如果没有概率编程,这些能力就不存在。

我们的小应用将作为Figaro的“Hello,World”示例。想象一下,有个人早上起床,查看天气是否晴朗,并根据天气发出问候。每天发出连续两天的问候。而且,第二天的天气取决于第一天:如果第一天是晴天,第二天就更可能是晴天。这些陈述可以由表1-1中的数字量化。表1-1 量化“你好,世界”示例的概率今天的天气晴天0.2不是晴天0.8今天的问候语“Hello, world!”0.6如果今天是晴天“Howdy, universe!”0.4“Hello, world!”0.2如果今天不是晴天“ Oh no, not again”0.8明天的天气晴天0.8如果今天是晴天不是晴天0.2晴天0.05如果今天不是晴天不是晴天0.95明天的问候语“Hello, world!”0.6如果明天是晴天“Howdy, universe!”0.4“Hello, world!”0.2如果明天不是晴天“Oh no, not again”0.8

下面几章将明确解释这些数字的含义。现在,我们直观地认为今天是晴天的概率为0.2,也就是说,今天有20%的可能放晴。同样,如果明天是晴天,明天的问候语为“Hello, world!”的概率为0.6,也就是说问候语为“Hello, world!”有60%的可能性,“Howdy, universe!”的可能性为40%。

我们为自己设定了用这个模型执行3种推理任务的目标。在1.1.3小节中您已经知道,用概率模型能够进行3类推理:预测未来,推断导致观测结果的过去事件,从过去事件中学习以更好地预测未来。您将用我们的简单模型完成这三种任务。具体任务如下。

1.预测今天的问候语。

2.如果观测发现今天的问候语是“Hello, world!”,推断今天是不是晴天。

3.从今天对问候语是“Hello, world!”这一观测值的学习,预测明天的问候语。

下面是用Java完成这些任务的方法。程序清单1-1 用Java实现的Hello World 程序class HelloWorldJava { ◁——● //定义问候语 static String greeting1 = "Hello, world!"; static String greeting2 = "Howdy, universe!"; static String greeting3 = "Oh no, not again"; static Double pSunnyToday = 0.2; ◁——● //指定模型的数值参数 static Double pNotSunnyToday = 0.8; static Double pSunnyTomorrowIfSunnyToday = 0.8; static Double pNotSunnyTomorrowIfSunnyToday = 0.2; static Double pSunnyTomorrowIfNotSunnyToday = 0.05; static Double pNotSunnyTomorrowIfNotSunnyToday = 0.95; static Double pGreeting1TodayIfSunnyToday = 0.6; static Double pGreeting2TodayIfSunnyToday = 0.4; static Double pGreeting1TodayIfNotSunnyToday = 0.2; static Double pGreeting3TodayIfNotSunnyToday = 0.8; static Double pGreeting1TomorrowIfSunnyTomorrow = 0.6; static Double pGreeting2TomorrowIfSunnyTomorrow = 0.4; static Double pGreeting1TomorrowIfNotSunnyTomorrow = 0.2; static Double pGreeting3TomorrowIfNotSunnyTomorrow = 0.8; static void predict() { ◁——● //用概率推理规则预测今天的问候语 Double pGreeting1Today = pSunnyToday * pGreeting1TodayIfSunnyToday + pNotSunnyToday * pGreeting1TodayIfNotSunnyToday; System.out.println("Today's greeting is " + greeting1 + "with probability " + pGreeting1Today + "."); } static void infer() { ◁——● //按照今天的问候语是“Hello, world!”这一观测值,运用概率推理原则推断今天的天气 Double pSunnyTodayAndGreeting1Today = pSunnyToday * pGreeting1TodayIfSunnyToday; Double pNotSunnyTodayAndGreeting1Today = pNotSunnyToday * pGreeting1TodayIfNotSunnyToday; Double pSunnyTodayGivenGreeting1Today = pSunnyTodayAndGreeting1Today / (pSunnyTodayAndGreeting1Today + pNotSunnyTodayAndGreeting1Today); System.out.println("If today's greeting is " + greeting1 + ", today's weather is sunny with probability " + pSunnyTodayGivenGreeting1Today + "."); } static void learnAndPredict() { ◁——● //从今天问候语是“Hello, world!”的观测中学习,运用概率推理原则预测明天的问候语 Double pSunnyTodayAndGreeting1Today = pSunnyToday * pGreeting1TodayIfSunnyToday; Double pNotSunnyTodayAndGreeting1Today = pNotSunnyToday * pGreeting1TodayIfNotSunnyToday; Double pSunnyTodayGivenGreeting1Today = pSunnyTodayAndGreeting1Today / (pSunnyTodayAndGreeting1Today + pNotSunnyTodayAndGreeting1Today); Double pNotSunnyTodayGivenGreeting1Today = 1 - pSunnyTodayGivenGreeting1Today; Double pSunnyTomorrowGivenGreeting1Today = pSunnyTodayGivenGreeting1Today * pSunnyTomorrowIfSunnyToday + pNotSunnyTodayGivenGreeting1Today * pSunnyTomorrowIfNotSunnyToday; Double pNotSunnyTomorrowGivenGreeting1Today = 1 - pSunnyTomorrowGivenGreeting1Today; Double pGreeting1TomorrowGivenGreeting1Today = pSunnyTomorrowGivenGreeting1Today * pGreeting1TomorrowIfSunnyTomorrow + pNotSunnyTomorrowGivenGreeting1Today * pGreeting1TomorrowIfNotSunnyTomorrow; System.out.println("If today's greeting is " + greeting1 + ", tomorrow's greeting will be " + greeting1 + " with probability " + pGreeting1TomorrowGivenGreeting1Today); } public static void main(String[] args) { ◁——● //执行所有任务的主方法 predict(); infer(); learnAndPredict(); } }

在此,我不对使用推理规则进行计算的方法做出描述。上述代码使用了3条推理规则:链式法则、全概率公式和贝叶斯法则。这些规则将在第9章中详细解释。现在,我们指出这段代码的两个主要问题。● 无法定义建模所用的规则

模型定义包含在一个变量名与双精度值的列表中。当我在本节的

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载