天天看點

《樹莓派開發實戰(第2版)》——2.2 建立模型和運作推理:重回Hello World

本節書摘來異步社群《機率程式設計實戰》一書中的第2章,第2.2節,作者:【美】avi pfeffer(艾維·費弗),更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

您已經概要了解了figaro概念,接下來看看它們是如何融合在一起的。您将回顧第1章的hello world示例,特别注意圖2-2中的所有概念是如何出現在這個例子中的。您将關注如何從原子和複合元素中構模組化型,觀測證據,提出查詢,運作推理算法,得到答案。

本章的代碼可以兩種方式運作。一種是使用scala控制台,逐行輸入語句并獲得即時響應。為此,進入本書項目根目錄practicalprobprog/examples并輸入sbt console,将會看到scala提示符。然後輸入每行代碼,檢視響應。

第二種方式是通常的方法:編寫一個包含main方法的程式,該方法包含想要執行的代碼。在本章中,我不提供将代碼轉換為可運作程式的模闆,隻提供與figaro相關的代碼。我将確定指出您需要導入的内容及将其導入的位置。

首先,您将建構最簡單的figaro模型。這個模型包含一個原子元素。構模組化型之前,必須導入必要的figaro結構:

val sunnytoday = flip(0.2)<code>`</code>

圖2-3解釋了這一行代碼。搞清楚哪一部分是scala,哪一部分是figaro,是很重要的。在這行代碼中,建立了一個名為sunnytoday的變量,并指派flip(0.2)。scala值flip(0.2)是一個figaro元素,表示true值機率為0.2、false值機率為0.8的一個随機過程。元素是表示随機産生一個值的過程的資料結構。随機過程可能産生任意數量的結果。每個可能結果被稱為過程的一個值。是以,flip(0.2)是可能取值為布爾值true及false的元素。總結起來就是,您有了一個包含scala值的scala變量。該scala值是figaro元素,它包含表示過程不同結果的任意個可能取值。

《樹莓派開發實戰(第2版)》——2.2 建立模型和運作推理:重回Hello World

在scala中,類型可以由另外一種描述其内容的類型參數化。您可能從java泛型中已經熟悉了這個概念,例如,在java中可以得到一個整數或者字元串的清單。所有figaro元素都是element類的執行個體。element類由元素可能取值的類型參數化。這種類型稱作元素的值類型。因為flip(0.2)可以取布爾值,flip(0.2)的值類型為boolean。這一事實的标記方法是:flip(0.2)是element[boolean]的一個執行個體。

關鍵定義

元素——代表一個随機過程的figaro資料結構。

值——随機過程的一個可能結果。

值類型——代表元素可能取值的scala類型。

關于這個簡單模型有許多值得說明的地方。幸運的是,您已經學到的知識适用于所有figaro模型。figaro模型通過取得群組合簡單的figaro元素(構件)建立更複雜的元素和相關元素集合而建立。您剛剛學到的元素、值和值類型的定義是figaro中最為重要的定義。

在繼續建構更複雜的模型之前,我們先來看看如何用這個簡單模型進行推理。

您已經建構了一個簡單模型。我們運作推理,查詢sunnytoday為true的機率。首先,需要導入将要使用的推理算法:

println(variableelimination.probability(sunnytoday, true))<code>`</code>

上述指令列印輸出0.2。您的模型隻包含元素flip(0.2),結果為true的機率為0.2。變量消除算法正确計算出sunnytoday為true的機率是0.2。

詳細說來,您剛剛看到的指令完成好幾件工作:首先建立變量消除算法的一個執行個體,告訴執行個體查詢目标是sunnytoday。然後運作算法并傳回sunnytoday值為true的機率。這條指令還負責執行完畢的清理,釋放算法所用的任何資源。

現在,我們開始建構一個更有趣的模型。您需要一個figaro結構——if,是以要導入它。還需要一個名為select的結構,但是這已經随着com.cra.figaro.language導入:

val greetingtoday = if(sunnytoday,

對此的思維方式是元素代表一個随機過程。在本例中,名為greetingtoday的元素代表着這樣的過程:首先檢查sunnytoday的值,如果為true,選擇“hello,world!”的機率為0.6,“howdy, universe!”的機率為0.4。如果sunnytoday的值為false,選擇“hello, world!”的機率為0.2,“oh no, not again”的機率為0.8。greetingtoday是一個複合元素,因為它由3個元素建構而成。由于greetingtoday的可能取值為字元串,是以它是element[string]。

現在,假定您已經看到今天的問候語是“hello, world!”,您可以使用一個觀測值說明這一證據:

這條指令列印輸出0.4285714285714285。注意,結果明顯高于前一個答案(0.2)。這是因為問候語是“hello, world!”時,今天是晴天的可能性高于其他情況,是以證據支援今天是晴天。這一推理是貝葉斯法則的簡單執行個體,第9章将介紹這一法則。

您打算擴充該模型,用不同證據運作更多查詢,是以應該移除變量greetingtoday的觀測值。用如下指令可以完成:

您将得到和指定證據之前一樣的答案0.2。

在本節的最後,我們進一步細化模型:

println(variableelimination.probability(greetingtomorrow, "hello, world!"))

// prints 0.27999999999999997

greetingtoday.observe("hello, world!")

// prints 0.3485714285714286<code>`</code>

可以看到,在觀察到今天的問候語是“hello, world!”時,明天的問候語是“hello, world!”的機率增大,為什麼?因為今天的問候語是“hello, world!”,今天就更有可能是晴天,明天是晴天的可能性也就更大,最終使明天的問候語更可能是“hello, world!”。正如在第1章中所看到的,這是推斷過去更好預測未來的一個例子,figaro負責所有的計算。

現在,您已經看到了建立模型、指定證據和查詢、運作推理得到答案的所有步驟,接下來我們更仔細地觀察hello world模型,了解如何從構件(原子元素)和連接配接器(複合元素)建構它。

圖2-4是模型的圖形描述。該圖首先重制了模型定義,每個scala變量在一個單獨的方框中。在下半部分中,每個節點表示模型中的對應元素,同樣在單獨的方框中顯示。有些元素本身就是scala變量值。例如,scala變量sunnytoday的值是flip(0.2)元素。如果元素是scala變量值,圖上顯示變量名稱和元素。該模型還包含了一些不是特定scala變量值,但仍出現在模型中的元素。例如,因為sunnytomorrow的定義是if(sunnytoday, flip(0.8), flip(0.05)),flip(0.8) 和flip(0.05)也是模型的一部分,是以它們顯示為圖中的節點。

《樹莓派開發實戰(第2版)》——2.2 建立模型和運作推理:重回Hello World

該圖包含了元素之間的邊。例如,從flip(0.8)到取sunnytomorrow值的if元素之間有一條邊,表明if元素使用flip(0.8)元素。一般來說,如果第二個元素的定義中使用了第一個元素,則兩者之間存在一條邊。因為隻有複合元素是由其他元素建構而成的,是以隻有複合元素可能成為邊的終點。

需要注意的一點是,select(0.6 -&gt; "hello, world!", 0.4 -&gt; "howdy, universe!")在圖中出現了兩次,select(0.2 -&gt; "hello, world!", 0.8 -&gt; "oh no, not again")也是如此。這是因為代碼中定義出現了兩次,一次用于greetingtoday,另一次用于greetingtomorrow。盡管定義相同,但是這是兩個不同的元素。它們在figaro模型定義的随機過程的同一次執行中可能取不同的值。例如,該元素的第一個執行個體可能取值“hello, world!”,而第二個執行個體可能取值“howdy, universe!”。這是有意義的,因為第一個元素執行個體用于定義greetingtoday,第二個則用于定義greetingtomorrow。今天和明天的問候語很可能不一樣。

這和正常程式設計類似,想象一下您有一個greeting類和如下代碼:

val greetingtoday = new greeting

val anothergreetingtoday = greetingtoday

anothergreetingtoday.string = "howdy, universe!"<code>`</code>

anothergreetingtoday和greetingtoday是相同的scala變量,是以運作上述代碼之後,greetingtoday的值也是“howdy, universe!”,同樣,如果同一個scala變量代表程式中出現多次的一個元素,它在每次運作中也取相同的值。

了解這一點對于了解figaro模型的建構方式是必不可少的,是以我建議反複閱讀本節以確定了解。此時,您應該已經概要了解所有的figaro主要概念以及它們的組合方式。在下面幾節中,您将更詳細地研究其中一些概念,下一節首先介紹原子元素。