认知的概率模型(ESSLLI教程)- 第一部分译文

认知的概率模型

诺亚 古德曼,约书亚 泰拉贝尔,提摩太 奥唐纳登和Church工作组

什么是思想?我们该如何描述人们学习推导活动中的智能推理行为?我们如何才能设计出智能机器?关于思想的计算理论就希望通过假设头脑为一台计算机、脑力表征为计算机程序、思考就像运行电脑程序的计算过程来解答这些问题。

但怎样的程序呢?自然的想法是这个程序的智能行为先从传感器获得知觉、从内存中得到事实,然后再计算出结果。这样脑力思考活动就成了从输入到输出的函数调用。不过,这种输入输出对的观念将面临组合爆炸的困境:我们必须为每一个人类的智能推理活动提供一个输入输出处理程序。而另一个方法假设脑力表征为理论:一种知识的片段能满足不同场景不同推理的需要。比如,牛顿的动能守恒定律能解决无数个不同时间、不同状态、不同对象的问题。生成模型方法某种程度上把脑力表征为更像理论:他们获得更多的世界是如何运作的一般性描述,这样,思想的程序就是世界的模型,可用在许多推理场合。

通常一个生成模型描述了一个观察数据生成的过程,可以简单地说生成模型表达了世界因果关系的知识,也就是某个领域的工作模型。运用条件推理,这些模型可被用来回答很多不同的问题,这与通过对特定问题的输入输出直接映射的机械式知识表示方法截然相反。虽然这种生成模式通常描述我们认为“现实世界“如何运作,但即使用在许多实际上没有例子上生成模型也非常有用,后者一个最好的例子是在语言学,语法生成模式可以通过构造造句过程有效地描述一种语言中所有可能的句子。

可以使用确定性的生成模型来描述一个过程展开的可能方法,但由于观察的稀疏性和实际的随机性使得有许多方式方法来观察,我们该如何选择呢?概率理论提供了一种在不确定性下的推理系统,概率生成模型能够描述带有随机性的过程,而概率推理提供了为这类过程查询或推理的方法。本教程关注概率生成模型和推理方法方面的知识。

我们希望有一个形式语言能准确描述生成模型,能表达个体对世界的各种知识。这种语言普遍上应该能够表达任何(可计算)的过程。因为λ演算描述计算过程,最重要的是能捕获因果的依赖关系,尤其是λ演算不注重时间先后,而是注重事件间的相互影响,所以,我们将这门语言建立在λ演算(正如函数型语言)之上,我们还引入了随机性,构建一个随机λ演算描述条件推论。

1. 生成模型

1.1 使用λ演算、LISP、Church定义简单的生成模型

我们从λ演算以及它在LISP语言家族中的体现来开始介绍我们的形式计算模型。λ演算是由阿隆佐·邱奇在1920年代发明的形式系统。邱奇为计算的形式化引入λ演算模型,那是一种有效的计算函数的形式化方法。λ演算是一个计算的普遍模型,它被认为与其它经典计算模型等价(λ演算表现出拥有与图灵机相当的计算能力,反之亦然)。值得注意的是λ演算更有普遍性,因为它仅有两个基本操作:创建和应用函数。

1958年约翰·麦卡锡发明了LISP语言(表处理),这是一种基于λ演算的程序语言。而盖·斯蒂尔和杰拉尔德···杰···萨斯曼开发出Scheme语言,那是LISP语言的一个变种,它的语法和语义特别简单。在这个辅导材料中我们会使用Scheme标记方式来表达λ演算,Church程序语言—为了纪念阿隆佐·邱奇而这样命名—就是一种引入概率计算的普通Scheme语言。在接下来的几个章节中,我们将介绍Church的基础以及如何用它来构建生成模型。

λ演算用函数来形式化计算概念,λ演算的计算过程就是对自变量赋值后的函数计算过程。Church函数应用的看起来像这样:

(+ 1 1)

我们看到函数+被用到两个参数1上面,注意在Church语言中函数名先出现,这种表示法有时叫做波兰表示法。如果你运行上面的程序你会看到这个函数的结果。+是个确定的函数,在Church中除了Scheme基本的确定性函数,我们增加了带随机变量的基本随机函数集,这些随机基本函数被称为可交换的随机过程(XRPs),一个XRP应用的结果就是从这个XRP定义的随机变量分布的采样值。

最简单的XRP是flip函数,它返回投掷硬币(也可能是偏的)的结果,在这里我们用真假(输出为#t,#f)来表示硬币的正反两个面。

(flip)

多次运行上述程序,每次你将得到一个不同的采样值,flip两边的括号告诉Church要运行一个XRP应用,如果去掉括号的话就会返回flip这个过程对象了,过程可以说是某些函数具体应用的一个代名词。在Church中,程序每次运行就能能得到该程序所定义随机变量的一个采样值,如果运行多次就能在直方图中表示出来,你就能重构该程序所定义随机变量的概率分布。

(hist (repeat 1000 flip) “Flips”)

上面我们用的repeat过程带两个参数重复次数k和分布(本例为flip),它会返回该分布的k个采样值,我们再用hist过程显示1000个flip样本,这会大约是一个正反面的均匀分布。

本书重要的一点是flip可以从两个不同的角度来考虑,一个角度是flip取样自一个公平的硬币,也就是一个确定的概率分布的采样;另外一个角度是flip本身就有某个真与假的分布的特性。当我们考虑概率程序时常常在两个视角中来回切换,一会儿强调采样,一会儿强调分布。(在合适的约束下这种双元性是完备的:任何Church程序隐含表示了一个分布,任何分布可以用Church程序表达。)

在句法上Church由嵌套的表达式组成,简单地说一个表达式就是一个值或者括号括起来的任何东西。在一种确定性的LISP语言,如Scheme,所有表达式都能用evaluation进程计算得到一个固定的值。比如看下面稍微复杂一点的表达式:

(if (equal? 10 11)

100

‘some-symbol)

这个表达式由一个if条件和一些子表达式组成(虽然像其它函数一样有一个值,严格意义上分支表达式if不是一个函数(因为它并不计算它的所有自变量,仅仅执行最小运算)),equal?是个比较对象结构上相同的函数(与比较占用同一内存位置的同一对象相对应),它是个返回真或假的谓词,按照Church的命名习惯,谓词以?号结束。该If表达式的值是‘some-symbol,单引号告诉Church将后面跟的字符串当成文字,是符号而不是变量,不需要再求值了。在Church中符号是与字符串不同的数据类型。

(if (flip)

100

‘some-symbol)

如果将(if (equal? …)运行一千次,你总是得到相同的结果,因为它是确定了的。而另一方面Church通常情况下每次运行一个表达式能够返回一个不同的结果,所以上面的表达式每次运行都会变化,每次表达式的计算可以看成随机变量的采样,这很重要,因为正如我们下面看到那样,它意味着Church允许我们为任意的不受限制的随机变量集合定义分布。到目前为止,我们只看到了公平的投掷硬币(flip)例子,flip还有一个带权重的版本可以代表一个偏的硬币,如(flip 0.7)就是投掷一个正面权重0.7和反面权重0.3的硬币。

在程序中我们常常需要命名对象以便重复使用,这可以使用define语句,看起来如下:

(define variable-name expression)

Variable-name是个符号绑定expression的计算结果。当变量被计算时它们返回它们的绑定值。

(define some-variable ‘some-symbol)

(if (flip)

100

Some-variable)

如果你运行这个程序,你会注意到它有时会返回符号some-symbol,这是因为当flip返回假时some-variable就会被求值,因为它绑定some-symbol,所以就返回了这个值。

1.2 举例:医疗诊断中的因果模型

生成式的知识常是有因果关系的知识,下面看一个用Church表达的具有因果关系的简单医疗场景:

(define lung-cancer (flip 0.01))
(define cold (flip 0.2))
(define cough (or cold lung-cancer))

这个程序会产生一个病人的随机情况,它首先设置了病人两种疾病的基准得病率:感冒要常见而肺癌极少,而且得这两种病的机会是相互独立的,接着定义了这些病产生一个相同症状的过程:如果有感冒或肺癌或者两个病都有的话,人们会咳嗽。再下面是一个更复杂一点的例子:

(define lung-cancer (flip 0.01))
(define TB (flip 0.005))
(define cold (flip 0.2))
(define stomach-flu (flip 0.1))
(define other (flip 0.1))
(define cough (or (and cold (flip 0.5)) (and lung-cancer (flip 0.3)) (and TB (flip 0.7)) (and other (flip 0.01))))
(define fever (or (and cold (flip 0.3)) (and stomach-flu (flip 0.5)) (and TB (flip 0.1)) (and other (flip 0.01))))
(define chest-pain (or (and lung-cancer (flip 0.5)) (and TB (flip 0.5)) (and other(flip 0.01))))
(define shortness-of-breath (or (and lung-cancer (flip 0.5)) (and TB (flip 0.2)) (and other (flip 0.01))))
(list "cough" cough "fever" fever "chest-pain" chest-pain "shortness-of-breath" shortness-of-breath)

现在有四个症状和四种可能的疾病,每种疾病会有一些不同的症状,这些因果关系现在都概率化了:50%的感冒病人咳嗽,或30%的感冒病人发烧,另外还有一个“其它”疾病分类,它引起一些症状的概率很低,而由and,or,flip组成的复杂函数提供了一种既简单又富有表现力的方法来描述布尔变量之间因果关系的概率。

当你运行上述代码,它会为假设的病人产生一系列的症状,因为每种病的患病率很低,所以,最可能的结果是没有任何症状。请多试试运行上述程序。下面我们试图修改一个疾病的定义,例如用(define lung-cancer)代替(define lung-cancer (flip 0.01))来模拟病人确定有这个病的情况,试着运行几次,观察这个病的症状特点。

1.3 用lambda创建函数和分布

作为一种计算模型,λ演算的能力主要用来创建新的函数,我们可以使用lambda语句,例如创建一个将任意数字加倍的函数:

(define double (lambda (x) (+ x x)))

(double 3)

一个lambda表达式的一般形式是:

(lambda arguments body)

Lambda表达式的第一部分是函数的自变量,它是一个符号的列表告诉我们函数调用时的输入;第二部分是函数的主体,是对输入的处理部分。

我们还可以用lambda语句构建更为复杂的随机函数,下面的随机函数仅仅有时会加倍它的输入:

(define noisy-double (lambda (x) (if (flip) x (+ x x))))

(noisy-double 3)

我们可以用λ演算创建过程来操作任意的值甚至是其它的过程。下面我们定义一个twice函数,它的输入参数是一个过程,然后返回一个将原过程执行两遍的新过程:

(define double (lambda (x) (+x x)))

(define twice (lambda (f) (lambda (x) (f (f x)))))

((twice double) 3)

能创建高阶函数使得λ演算称为一种通用的计算模型。因为我们常常给函数命名, (define foo (lambda (x) …))就可简写成(define (foo x) …)(一个语法糖)。

没有自变量的lambda表达式(lambda () …)是一种形实转换程序,用它我们可以定义随机产生过程,如投掷硬币。

1.4 举例:翻转硬币

下面的程序定义了一个公平的硬币,投掷它20次看看:

(define fair-coin (lambda () (if (flip 0.5) 'h 't)))
(repeat 20 fair-coin)

还定义一个“骗人”的硬币,它有95%的几率为正面,再投掷它20次看看:

(define trick-coin (lambda () (if (flip 0.95) 'h 't)))
(repeat 20 trick-coin)

高阶函数make-coin输入一个权重输出一个函数(实际是形实转换程序)代表一个有权重的硬币。这样我们就可用make-coin定义上述的硬币或者其它的:

(define make-coin (lambda (weight) (lambda () (if (flip weight) 'h 't))))
(define fair-coin (make-coin 0.5))
(define trick-coin (make-coin 0.95))
(define bent-coin (make-coin 0.25))
(list   (pair "20 fair coin flips" (repeat 20 fair-coin))
(pair "20 trick coin flips" (repeat 20 trick-coin))
(pair "20 bent coin flips" (repeat 20 bent-coin)))

1.5 持久的随机性:mem

若我们需要建立一个拥有随机属性的对象集,比如描述一群人的眼睛的颜色:

(define (eye-color person) (uniform-draw '(blue green brown)))
(list  (eye-color 'bob)
(eye-color 'alice)
(eye-color 'bob) )

上面的过程明显是错的:鲍勃的眼睛颜色我们问一次变化一次!我们真正想要的眼睛颜色虽然是随机的但也要是不变的,我们能用另外一个Church基本词mem。mem是一个高阶函数:给它一个过程,就会返回这个过程一个有记忆的新版本。当一个随机过程有记忆的话,在它第一次被调用时才会对随机变量采样,以后再用同一变量调用它时它会返回一样的结果,也就是一个有记忆的过程在一个生成模型的运行中有一个固定的值。例如考虑比较两次flip和两次有记忆的flip的结果:

(equal? (flip) (flip))

(define mem-flip (mem flip))

(equal? (mem-flip) (mem-flip))

接下来再回到眼睛颜色的例子,我们改一下已实现每个人的眼睛颜色是随机的但每个人都有不变的眼睛颜色。

(define eye-color
  (mem
    (lambda (person) (uniform-draw '(blue green brown)))))
(list  (eye-color 'bob)
(eye-color 'alice)
(eye-color 'bob) )

这个模型叫做随机世界样式,请注意我们无需事先定义每个人的眼睛颜色,而是隐含定义了无数人的眼睛颜色的分布,当需要时才采样确定。

在传统的计算机科学中内存由于能避免重复运算常常被用作程序的优化手段,而在概率领域,如Church,我们可以看到又进了一步存储实际上已经影响了语言的表达能力。

1.6 举例:拔河的贝叶斯

想象一下拔河比赛,人们要么强壮要么弱小,比赛中可能偷懒或者不在状态。我们设定偷懒的人只用一半的力气,用力最大的队伍获胜,同时设一半的人是强壮的,每次比赛每个人有三分之一的几率偷懒。这个程序模拟运行一些队伍之间的锦标赛,请你猜猜谁强谁弱,看看程序的结果吧。

(define strength (mem (lambda (person) (if (flip) 10 5))))
(define lazy (lambda (person) (flip (/ 1 3))))
(define (total-pulling team)
  (apply +
         (map (lambda (person) (if (lazy person) (/ (strength person) 2) (strength person)))
              team)))
(define (winner team1 team2) (if (< (total-pulling team1) (total-pulling team2)) 'team2 'team1))
(list "Tournament results:"
      (winner '(alice tom) '(bob pat))
      (winner '(alice joe) '(bob pat))
      (winner '(alice tom) '(bob sue))
      (winner '(alice joe) '(bob sue))
      (winner '(tom joe) '(pat sue)))

注意strength被记忆了因为这是在每场比赛中不变的一个人的属性,但偷不偷懒是每场都变化的。每次你运行该程序就会产生一个新的随机世界:会随机决定每个人强壮还是弱小,然后在每场比赛中不变。

1.7 有用的高阶函数

在上面的例子中我们使用了些有用的工具函数。map是一个高阶函数,它将一个过程(上面用lambda创建)应用到一个表(上面是一支队伍)的每个队员。在得到每个队员力气多大后,我们需要把它们加起来,但是+运算需要应用到数字上,如(+ 1 2 3 4),而不是应用到列表上,如(+ (1 2 3 4))会出错,我们可以使用高阶函数apply,它将一个过程应用到一个列表上,就好像这个列表的每个元素就是它的变量一样。标准函数sum和product可以简单的这样定义,(apply + …)和(apply * …)。如下:

(define my-list '(3 5 2047))

(list "These numbers should all be equal:" (sum my-list) (apply + my-list) (+ 3 5 2047))

像repeat、map、apply(或sum)这些高阶函数非常有用,下面我们先定义一个实验投掷一个权重0.8的硬币10次,而后在重复这个实验1000次,最后用truelist柱形图显示结果。再试着改变权重或重复次数看看概率分布如何变化。

(define make-coin (lambda (weight) (lambda () (flip weight))))

(define coin (make-coin 0.8))

(define data (repeat 1000 (lambda () (sum (map (lambda (x) (if x 1 0)) (repeat 10 coin))))))

(truehist data "Distribution of coin flips")

转载于:https://www.cnblogs.com/limitplus/archive/2011/03/01/1967911.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值