1814 年,皮埃尔•西蒙•拉普拉斯写道“在很大程度上,人生最重要的问题就是概率问题。”然而漫长的概率理论研究却是一波三折,直到概率编程的出现使其取得了重要的进步。
“明天可能下雨吗?”“这个球他能踢进吗?”“他抛的硬币会是正面还是反面?”……我们每天都身处在无数的概率事件中,不同的结果可能会带来完全相反的影响,这是完全有趣的经历,仔细一想,是不是就不会觉得人生是如此枯燥?人们对于概率的研究或许也是出于这种对人生无限可能性的探究,虽然这并不简单。
19 世纪人们回答概率问题的唯一方法是用笔和纸分析每个问题,得到结果的公式,手工填入数字以求得公式值。计算机的出现对这一情况并没有很大的改变,只是能够为包含更多数字的更复杂公式求值,纸笔分析也变得更加雄心勃勃,往往用纸数百页。
概率问题的分析需要构思概率模型,这种模型以某种方式规划概率空间,为其指定数值化概率。过去,概率模型用自然语言文本和半正式的数学标记法的组合写下。从模型中,经过进一步数学处理得出计算答案的公式或者算法。这些阶段都十分费时费力、容易出错,而且存在特定于具体问题的难点,使概率理论的适用性受到了严重的限制。尽管拉普拉斯在多年前就已提出,但是这个生活中最重要的问题仍然没有答案。
解决上述问题的第一个重要进步是定义概率模型所用的形式语言的发展,例如贝叶斯网络和马尔科夫网络。形式语言具有定义正确表达式的精确语法,以及定义每种正确表达式含义的精确语义(即每个表达式表示哪种概率模型)。因此,用机器可理解的形式描述概率模型,开发一个算法计算任何可表达概率模型结果都成为可能。
在前面的叙述中,美中不足的是:可表达概率模型的缺乏。实际上,贝叶斯和马尔科夫网络等形式语言表达能力相当有限。从某种意义上说,它们只是布尔电路的概率模拟。为了对这一局限性的含义有所了解,我们考虑一个问题:编写大型公司所用的工资单软件。在Java等高级编程语言中,这可能涉及数万行代码。现在,想象一下将许多逻辑门电路连接起来完成相同的功能。这样的任务似乎完全无法完成。这样的电路规模、复杂度和清晰性都无法想象,因为电路缺乏捕捉问题结构的表达能力。
1997 年,Avi Pfeffer(当时还是个学生)和他的导师Daphne Koller以及协作者David McAllester发表了一篇关于概率编程语言(PPL)的原创论文,提供了将概率理论与高级编程语言联系起来的关键思路。这一思路是通过引入随机元素使程序成为概率模型,并将程序的意义定义为每个可能执行路径的概率。这一思路以高效的方式结合了数学的两个最重要分支,我们接下来将要开始探索由此产生的新可能性。
概率编程是一种系统创建方法,它所创建的系统能够帮助我们在面对不确定性时做出决策。许多日常决策涉及在确定无法直接观测的相关因素时的判断能力。历史上,帮助在不确定性下做出决策的方法之一是使用概率推理系统。概率推理将我们对某种情况的认识和概率法则结合起来,确定无法观测的决策关键因素。直到最近,概率推理系统的范围仍然有限,难以应用到许多现实情况中。概率编程是一种新方法,它使概率推理系统更容易构建,适用范围更广。
要理解概率编程,首先要观察不确定性条件下的决策过程和涉及的主观判断。然后,您将了解概率推理是如何帮助您做出决策的。您将注意到概率推理系统所能进行的 3 种推理,也就能理解概率编程,以及通过编程语言的能力用概率编程构建概率推理系统的方法。
在现实世界中,我们所关心的问题很少有非此即彼的答案。例如,如果您打算启动一个新产品,想要知道它的销路如何。您可能认为它将取得成功,因为您相信它设计精良,市场调查也表明有需求,但是无法确定。您的竞争者可能推出更好的产品,或者您的产品可能有市场不能容许的致命缺陷,经济也可能突然衰退。如果要求百分之百的确定,就无法做出是否投放该产品的决策(见图 1 )。
图1 去年所有人都喜爱我的产品,但是明年会怎么样呢?
概率语言有助于做出此类决策。在投放某个产品时,可以使用类似产品的先期经验估算产品的成功概率。然后,用这一概率帮助决定是否继续推进并投放该产品。您可能不仅关心产品能否成功,还关心它能带来多少收入,或者失败将导致多大的损失。您可以使用不同结果的概率做出更明智的决策。
概率论思想可以帮助您做出艰难的决策和判断,但是,您该怎么做呢?一般原则在下面列出。
事实:主观判断基于知识+逻辑。
您对感兴趣的问题有某些知识。例如,您对产品有深入的了解,可能进行了一些市场调查以找出客户的需求。您还可能有关于竞争对手的情报和经济预测。同时,逻辑帮助您运用知识获得问题的答案。
您需要一种规格化知识的方法,还需要运用知识得出问题答案的逻辑。概率编程提供了规格化知识和回答问题的逻辑。在我描述概率编程系统概念之前,我将描述概率推理系统的一般概念,这种系统提供了规格化知识和提供逻辑的基本手段。
概率推理是使用您的领域模型做出不确定条件下决策的一种方法。举个足球界的例子。假定统计显示 9% 的角球造成进球。您的任务是预测某次角球的结果。攻方的中锋身高 6 英尺 4 英寸(约 1.93 米),以头球能力著称。守方正选门将刚刚受伤,被第一次出场的替补门将换下。除此之外,咆哮的大风使长传难以控制。那么,如何计算进球的概率?
图 2 展示了使用概率推理系统找出答案的途径。您在一个角球模型中编码关于角球和所有相关因素的知识。然后,提供特定角球的证据,也就是中锋个子很高、守门员缺乏经验以及强风。您告诉该系统,希望知道这次角球是否进球。推理算法返回答案——有 20% 的概率进球。
图2 概率推理系统预测角球结果的方法
关键定义
一般知识——不考虑特定情况细节时,对领域相关情况的概括了解。
概率模型——用定量的概率术语编码的领域一般知识。
证据——关于特定情况的具体信息。
查询——您希望知道的情况属性。
推理——概率模型根据证据回答查询的过程。
在概率推理中,您创建一个模型,以定量的概率术语捕捉领域的所有相关一般知识。在我们的例子中,这个模型可能是对角球情况和影响结果的所有球员相关特征及条件的描述。然后,对于某个特定情况,您将该模型应用于所拥有的具体信息,得出结论。这些具体信息称为证据。在本例中,证据是中锋身材高大,守门员缺乏经验,风力很大。所得出的结论可以帮助您决策——例如,您是否应该在下一场比赛中更换不同的守门员。结论本身以概率的方式描述,比如守门员的不同技能水平的概率。
模型、您所提供的信息和查询答案之间的关系由数学上的概率法则定义。根据证据,运用模型回答查询的过程称作概率推理或者简单地称作推理。幸运的是,计算机算法已经有了很大的发展,能够为您完成这些数学题,自动进行所有必要的计算。这些算法被称作推理算法。
图 3 总结了您所学到的知识。
图3 概率推理系统的基本组成部分
简言之,我们刚刚讨论的是概率推理系统的组成,以及与之互动的方式。但是,如何利用这样的系统?它如何帮助您决策?下面描述了概率推理系统所能执行的 3 类推理。
概率推理系统很灵活。它们可以根据任何方面的证据,回答关于情况其他特征的查询。在实践中,概率推理系统执行 3 类推理。
-
预测未来的事件。在图 2 中您已经看到此类推理,根据当前情况预测是否进球。您的证据通常包括关于当前情况的信息,如中锋身高、守门员的经验和风力。
-
推断事件的根源。快进 10 秒。高个中锋刚刚头球射门,从守门员身下入网,取得一分。根据这一证据,您对这位新手守门员有何想法?您能否得出结论,她的技能不足?图 4 说明如何使用概率推理系统回答这个问题。该模型是您之前用于预测是否进球的同一个角球模型(这是概率推理的一个实用属性:用于预测未来结果的模型同样可以在事后推断结果的根源)。使用的证据和以前一样,并结合了角球得分这一事实。查询是守门员的技能水平,答案提供了不同技能水平的概率。
图4 改变查询和证据,系统现在可以推断出进球的原因
想想看,第一种推理模式描述了前向推理,根据对当前情况的了解预测未来的事件,而第二种推理模式描述了后向推理,根据当前结果推断过去的条件。在构建概率模型时,模型本身通常遵循自然的时间顺序。一名球员踢角球,风作用于球,中锋跃起头球,守门员做出扑救。但是推理可以向前和向后进行。这是概率推理的关键特征之一,我在本书中将反复重申这一点:推理的方向不一定遵循模型的方向。
-
从过去的事件中学习,更好地预测未来的事件。现在,再快进 10 分钟。同一球队又获得一次角球机会。所有情况与前面类似——高中锋、缺乏经验的守门员,但是现在风力减弱了。使用概率推理,可以利用前一次角球发生的情况,帮助您预测下一次角球的结果。图 5 说明了这一点。证据包括上一次的所有证据(注明其来自上一次)以及当前情况的新信息。在回答这次角球能否进球时,推理算法首先推断导致第一次进球的条件,例如中锋和守门员的技能水平。然后,它利用这些更新的属性做出关于新情况的决策。
图5 通过将上一次角球的结果考虑在内,概率推理系统可以在下一次角球时做出更好的预测
这些类型的查询能够帮助您做出许多层次上的决策。
-
您可以根据有无额外防守队员进球的概率,决定是否用一名防守队员替换进攻队员。
-
可以根据对守门员技能的评估,决定下一次合同谈判时向他提出的工资数额。
-
可以利用了解到的守门员相关情况,帮助预测下一场比赛的结果,决定是否使用同一名守门员。
学习更好的模型
上述 3 种推理模式提供了特定情况、给定证据下的推理手段,利用概率推理系统,还可以从过去的情况中学习,改善您的一般知识。在第三种推理模式中,您了解到如何从特定的过去经验学习,更好地预测未来的情况。另一种从过去的经验中学习的方法是改善模型本身。特别是在拥有许多过去的经验可以吸取时(如许多次角球),您可能希望学习一个新模型,以表示角球通常发生情况的一般知识。如图 6 所示,这可以通过一个学习算法实现。与推理算法有些不同,学习算法的目标是产生新的模型而不是回答查询。学习算法从原始模型入手,根据经验更新之,产生新的模型。新模型可以用于回答未来的问题。可以推测,使用新模型产生的答案应该比原始模型更明智。
图6 可以使用学习算法,以一组经验为基础学习新的模型。然后,这个新模型可以用于未来的推断
概率推理系统与精确的预测
和任何机器学习系统一样,概率推理系统得到的数据越多,预测就越精确。预测的质量取决于两个因素:原始模型精确反映现实情况的程度和您所提供的数据量。一般来说,提供的数据越多,原始模型就越不重要,这是因为新模型是原始模型和数据所包含信息之间的一个平衡。如果您的数据很少,原始模型占据统治地位,所以它的质量必须很高才能得出准确的预测。如果您拥有许多数据,数据将占据统治地位,新模型倾向于忘掉不那么重要的原始模型。例如,如果您从整个足球赛季中学习,应该能够准确地学习到影响角球的因素。如果只有一场比赛的数据,就需要首先对精确预测比赛所需的因素有出色的想法。概率推理系统将很好地利用给定的模型和可用数据,尽可能精确地做出预测。
现在,您已经了解了概率推理的概念。那么,什么是概率编程?
每个概率推理系统都使用某种表示语言表达其概率模型。表示语言有许多种,您可能已经听说了其中一些,如贝叶斯网络(也称作置信网络)和隐含马尔科夫模型。表示语言控制系统可处理的模型以及模型的情况。语言所能表示的一组模型称作语言的表达能力。对于实际应用,您肯定希望表达能力尽可能强。
简单地说,概率编程系统是以编程语言作为表示语言的概率推理系统。我所说的编程语言是指具有编程语言所有预期特征(如变量、丰富的数据类型、控制流、函数等)的语言。正如您将要看到的,概率编程语言可以表达极其广泛的概率模型,超越传统的概率推理框架。概率编程语言有极强的表达能力。
图 7 说明了概率编程系统与概率推理系统的关系。可以将该图与图 3 比较,以凸显两种系统之间的差别。主要的变化是,模型以编程语言编写的程序表达,而不使用贝叶斯网络等数学结构。由于这种变化,证据、查询和答案都应用到程序中的变量。证据可能指定程序变量的特定值,查询询问程序变量的值,答案是不同查询变量值的概率。此外,概率编程系统通常带有一套推理算法。这些算法适用于以该语言编写的程序。
图7 概率编程系统是使用编程语言表示概率模型的概率推理系统
尽管存在许多类概率编程系统,本文的重点是函数式的图灵完备系统。函数式意味着它们基于函数式编程,但是不要被它吓住——使用函数式概率编程系统并不需要知道λ函数(lambda)等概念。这一切只意味着,函数式编程提供了这些语言表示概率模型的理论基础。同时,图灵完备是一句行话,表示编程语言可以编写任何能在数字计算机上完成的计算。如果某一运算可以在数字计算机上完成,就可以由任何图灵完备语言实现。您所熟悉的大部分编程语言,如C、Java和Python,都是图灵完备的。因为概率编程语言构建于图灵完备编程语言基础上,它们可以构建的模型类型极其灵活。
关键定义
表示语言——用于编码关于模型领域知识的语言。
表达能力——表示语言编码模型中不同类型知识的能力。
图灵完备——能够表示可在数字计算机完成的任何计算的语言。
概率编程语言——使用图灵完备编程语言表示知识的概率表示语言。
将概率模型表示为程序
但是,编程语言如何成为概率建模语言?如何将概率模型表示为程序?我将在这里提出回答这一问题的一些线索。
编程语言的核心思路之一是执行。您执行一个程序以产生输出。概率程序也类似,但是它可以有许多执行路径,每个路径产生不同的输出。在程序中随机选择执行路径,每个随机的选择有许多可能的结果,程序编码每种结果的概率。因此,概率程序可以视为随机执行以产生输出的一个程序。
图 8 说明了上述概念。在图中,概率编程系统包含了一个角球程序。这个程序描述生成角球结果的随机过程,它取得一些输入;在我们的例子中,这些输入是中锋的身高、守门员的经验和风力。根据这些输入,程序随机执行以生成输出。每次随机执行产生特定的输出。因为每个随机选择都有多种可能结果,存在许多可能的执行路径,造成不同的输出。任何给定输出(如进球)可能由多个执行路径产生。
让我们来看看,这种程序如何定义概率模型。从一系列随机选择形成的任何特定执行路径都有特定的结果。每个随机选择都有发生的概率。如果将这些概率相乘,就可以得到执行路径的概率。这样,程序定义了每个执行路径的概率。想象一下,如果将该程序运行许多次,生成任何给定执行路径的次数比例等于其概率。输出的概率就是产生该输出的程序运行次数比例。在图 8 中,1/4 的运行产生进球的结果,所以进球概率为 1/4。
图8 概率程序定义按照输入随机生成输出的过程
您可能疑惑于为什么图 8 中的块标签为“随机执行”而不是其他插图中的推理算法。图 8 展示了概率程序的含义——定义一个随机执行过程,而不是使用概率编程系统的方式——使用推理算法根据证据回答查询。所以,尽管上述插图的结构类似,但是表达了不同的概念。事实上,随机执行形成了某些推理算法的基础,但是许多算法并不基于简单的随机执行。
利用概率编程决策
使用概率编程预测未来很容易理解。只要随机多次执行程序,使用当前已知的信息作为输入,并观察每个输出的出现次数。在图 8 的角球示例中,多次执行该程序,以高中锋、缺乏经验的守门员和强风作为输入。因为 1/4 的运行得出进球的结果,您可以认定在这些输入条件下,进球概率为 25%。
概率编程不仅可用于预测未来,还可以推断导致特定结果的事实;您可以“展开”程序,发现结果的根源,还可以在某种情况下应用程序,从结果中学习,在未来使用学习到的信息做出更好的决策。可以使用概率编程做出所有通过概率思想得到的决策。
概率编程是如何工作的?当人们意识到,在较简单的表示语言(如贝叶斯网络)上有效的推理算法可以扩展到程序上时,概率编程就变得实用了。幸运的是,概率编程系统自带一些内建的推理算法,这些算法可以自动地应用到您的程序中。您所需要做的是以概率程序的形式提供领域知识并指明证据,系统负责推断和学习。
概率推理是机器学习的基础技术之一。Google、Amazon和Microsoft等公司使用它理解可用数据。概率推理已经用于各种各样的应用程序,如预测股价、推荐电影、诊断计算机和检测网络入侵。
前一小节中,有两个引人注目的要点。
-
概率推理可用于预测未来、推断过去,以及从过去的事实中学习更好地预测未来。
-
概率编程是使用图灵完备编程语言作为表示语言的概率推理。
将上面两个要点结合起来,可以得到如下表示。
事实:概率推理+图灵完备=概率编程
概率编程的动机是将两个本身就很强大的概念结合起来,结果是使用计算机辅助不确定性下决策的更简单、更灵活方法。
大部分现有概率表示语言在所能表示的系统丰富性上都很有限。有些相对简单的语言(如贝叶斯网络)假定固定的变量集,其灵活性不足,不能建立变量本身可能变化的领域模型。近年来,已经有一些具有更高灵活性的先进语言开发出来。其中一些语言(如BUGS)还提供了编程语言的特征,包括循环和数组,但是没有达到图灵完备。BUGS等语言的成功说明了更丰富、结构更严整的表示方式的必要性。但是,向成熟的图灵完备语言转移,为概率推理开拓了一个新领域。现在,可以建立具有许多交互实体及事件的长期运行过程的模型。
我们再次考虑足球的例子,但是这次想象一下,您的工作是体育分析,希望为一支球队做出人员配备决策的建议。您可以使用积累的统计数字做出决策,但是统计数字不能捕捉积累它们时所处的背景。您可以建立赛季的细致模型,实现粒度更细、情境感知的分析。这要求建立许多相关事件以及相互作用的球员和球队的模型。如果没有完整的编程语言所提供的数据结构和控制流,构建这种模型是难以想象的。
现在,让我们再次思考产品投放的例子,从综合的角度观察业务决策过程。产品投放不是孤立事件,而是经过市场分析、研究和开发的过程,各个过程的结果都有不确定性。产品投放的结果取决于所有阶段,以及市场中其他产品的分析。全面的分析还需要关注竞争对手对您的产品的反应,以及他们可能提出的新产品。这一问题很困难,因为您必须对竞争产品做出推测。甚至有一些竞争对手尚不为人所知。在这个例子中,产品是复杂过程产生的数据结构。同样,用完整的编程语言创建模型很有益处。
不过,概率编程的好处之一是,可以使用更简单的概率推理框架。概率编程系统可以表示广泛的现有框架,以及这些框架所不能表示的系统。
图灵完备的概率建模语言已经存在。它们常常被称作模拟语言。我们知道,使用编程语言模拟足球赛季等复杂过程是可能的。在这种情境下,我使用模拟语言这一术语描述能够表示复杂过程随机执行的语言。正如概率程序,这些模拟随机执行,以产生不同输出。模拟和概率推理一样应用广泛,涵盖了从军事计划到组件设计以及公共卫生及体育比赛预测等范围。确实,精密模拟的广泛使用说明了对丰富概率建模语言的需求。
但是,概率程序远不仅是模拟。使用模拟,您只能完成概率程序的一项功能:预测未来。无法用它推断观测结果的根源。而且,尽管可以不断地用已知的当前信息更新模拟,但是很难包含必须推断的未知信息。因此,从过去经验中学习以改善未来预测和分析的能力很有限。不能将模拟用于机器学习。
概率程序就像不仅可以运行,而且可以分析的模拟一样。开发概率编程的关键要点是,推理算法既可用于较简单的建模框架,也可用于模拟。因此,您有能力编写一个模拟并在其基础上执行推理,以创建概率模型。
最后一点,概率推理系统已经出现了一段时间,Hugin、Netica和BayesiaLab等软件提供了贝叶斯网络系统。但是概率编程更有表现力的表示语言很新颖,我们刚刚开始发现其强大的应用。老实说,我不能告诉您概率编程已经用于大量现有应用,但是有一些重要的应用。Microsoft已经能够使用概率编程,确定在线游戏玩家的真正技能水平。加州大学伯克利分校的Stuart Russell编写了一个程序,通过识别表明核爆炸的地震活动,帮助联合国《全面禁止核试验条约》的实施。麻省理工学院(MIT)的Josh Tenenbaum和斯坦福大学的Noah Goodman已经创建了建立人类识别模型的概率程序,并在试验中取得了很大的成功。在Charles River Analytics,我们已经使用概率编程推断恶意软件实例的组件并确定它们的演变。但是,我相信这些应用仅仅是个开始。将会有越来越多的人用概率编程系统做出所在领域的决策。
(本文节选自【美】Avi Pfeffer(艾维·费弗)作品《概率编程实战》)