天天看點

《Arduino家居安全系統建構實戰》——1.6 改進我們的模型

本節書摘來異步社群《機器學習項目開發實戰》一書中的第1章,第1.6節,作者:【美】mathias brandewinder(馬蒂亞斯·布蘭德溫德爾),更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

我們實作了可能有效的最愚蠢的模型,它也确實幹得不錯——93.4%的正确率。我們還能讓它變得更好嗎?

遺憾的是,對此沒有通用的答案。除非你的模型預測已經100%正确,否則始終有可能改進,知道答案的方法隻有一個:嘗試各種方法,看看它們是否有效。建構好的預測模型涉及許多反複嘗試,正确建立模型以快速疊代、試驗和驗證思路至關重要。

我們可以探索哪些方向?我可以不假思索地提出一些。

調整距離函數。我們在此使用的曼哈頓距離隻是許多可能性中的一個,選擇“正确”的距離函數通常是獲得好模型的關鍵因素之一。距離函數(或者代價函數)本質上是向機器傳達如何在其世界中考慮類似或者不同僚物的手段,是以認真思考這一點是非常重要的。

搜尋多個最靠近的點,而不是隻考慮一個最近點,并進行“多數表決”。這可使模型變得更加健壯;觀察更多的候選可以降低無意中選擇錯誤對象的機率。這種方法有一個名稱——“k最近鄰”算法,是機器學習的經典方法之一。

對圖像進行一些巧妙的處理。例如,想象拍攝一張照片,但是向右移動一個像素。如果将這個圖像與原始版本比較,盡管它們是同一個圖像,但距離可能很大。用于補償這一問題的方法之一是使用某種模糊。用鄰近像素顔色的平均值代替每個像素能夠緩解“圖像不重合”問題。

我敢肯定,你也能想到其他的主意,下面我們一起來探索第一種思路。

我們從距離開始。為何不嘗試一下高中已經學過的距離(學術上叫作“歐幾裡得距離”)?下面是這種距離的公式:

dist(x,y)=sqrt{(x_{1}-y_{1})^{2}+(x_{2}-y_{2})^{2}+ cdots + (x_{n}-y_{n})^{2}}

上述公式說明,兩點x和y之間的距離是對應坐标內插補點平方和的平方根。你可能已經見過這一公式的簡化版本,如果取某個平面上的兩個點:x=(x 1,x 2)和y=(y 1,y 2),其歐幾裡得距離為:

相比數學,代碼可能讓你更舒服一些,下面是上式在f#中的表現形式:

type distance = int[] * int[] -> int

let manhattandistance (pixels1,pixels2) =

let euclideandistance (pixels1,pixels2) =

let train (trainingset:observation[]) (dist:distance) =

我們建立一個distance類型以代替接口,這是一個函數簽名,以一對像素為參數,傳回一個整數。現在可以傳遞任意多個distance作為train函數的參數,這将傳回使用特定距離的分類器。例如,我們可以用manhattandistance函數或者euclideandistance函數(或者想要進一步試驗的任意距離函數)訓練分類器,比較它們的表現。注意,這在c#中也完全可能做到。我們可以簡單地使用func,而不建立idistance接口,下面是代碼。

程式清單1-12 函數式c#示例

let manhattanclassifier = train trainingdata manhattandistance

let euclideanclassifier = train trainingdata euclideandistance

printfn "manhattan"

evaluate validationdata manhattanclassifier

printfn "euclidean"

evaluate validationdata euclideanclassifier<code>`</code>

在此,最好的一件事是我們不需要在記憶體中重新加載資料集,隻需要簡單地修改腳本檔案,選擇包含所要運作新代碼的部分,運作該部分即可。如果我們那麼做,就應該看到新模型euclideanmodel的分類圖像的正确率為94.4%,而不是manhattanmodel的93.4%。好極了!我們取得了1%的改進。1%看起來似乎不多,但是如果準确率已經達到93.4%,這就意味着錯誤率從6.6%降低到5.6%,有大約15%的收獲。

從距離函數中的一個小變化,我們得到了很明顯的改進。這似乎是一個有前景的方向,可能值得試驗更複雜的距離函數,或者嘗試前面提到的其他方向。如果不多加小心,就有可能因為多次試驗而留下一大堆亂七八糟的代碼。版本控制和自動化對經典軟體開發是必不可少的,同樣,在開發預測模型時,它們也是你的朋友。過程的細節和節奏可能不同,但是總體思路相同:你希望在對代碼進行更改時不需要擔心造成任何破壞,“在我的機器上可以正常工作”還不夠好。在任何時候,任何人都應該可以使用你的代碼,在沒有任何人工幹預的情況下複制你的結果。這種方法稱作“可複制研究”。我強烈鼓勵你朝着這個方向發展,盡可能在任何地方使用腳本和源代碼控制。我自己曾經經曆過這樣的恐怖場景:前一天你的模型工作得很好,但是因為沒有花時間清晰地進行儲存,忘記了自己究竟是怎麼做到的,進而弄丢了模型。不要成為那樣的人!特别是在用git或者mercurial等dvcs建立分支如此容易的時代,沒有任何借口犯那樣的錯誤。對某個模型有新想法時,可以建立一個分支,儲存在腳本中執行的步驟。