- 機器學習:使用OpenCV、Python和scikit-learn進行智能圖像處理(原書第2版)
- (印)阿迪蒂亞·夏爾馬 維什韋什·拉維·什里馬利 (美)邁克爾·貝耶勒
- 4250字
- 2020-11-24 18:12:59
3.2 理解監督學習
我們之前已經確定了監督學習的目標總是預測數據的標簽(或目標值)。然而,根據這些標簽的性質,監督學習可以有兩種不同形式:
- 分類:當我們使用數據預測類別時,就將監督學習稱為分類。分類的一個很好的例子是我們試圖預測一張圖像包含貓還是狗。這里,數據的標簽是類別,一個類別或另一個類別,但從來不是混合類別。例如,一個圖片包含一只貓或一只狗,從不會是50%的貓和50%的狗(這里我們從不考慮卡通角色CatDog),而我們的工作只是分辨出它是哪一種動物。當只有兩種選擇時,它就稱為二分類或二值分類。當有兩個以上的類別時,如預測鳶尾花的種類(回顧一下我們在第1章中使用的鳶尾花數據集),它稱為多分類。
- 回歸:當我們使用數據預測真實值時,就將監督學習稱為回歸。回歸的一個很好的例子是預測股票價格。回歸的目標不是預測股票的類別,而是盡可能準確地預測一個目標值,例如以最小誤差預測股票價格。
有許多不同的方法來進行分類和回歸,但我們只探討其中的幾種方法。判斷我們正在處理的是分類問題還是回歸問題,最簡單的方法也許是問我們自己下面這個問題:我們到底要預測什么?圖3-1給出了答案。

圖3-1 分類問題和回歸問題的區別
3.2.1 看看OpenCV中的監督學習
如果我們不能將其付諸實踐,僅知道監督學習的原理是沒有任何用處的。值得慶幸的是,OpenCV為所有統計學習模型(包括所有的監督學習模型)提供了一個非常簡單的接口。
在OpenCV中,每個機器學習模型都派生于cv::ml::StatModel基類。如果我們想要使用OpenCV中的一個機器學習模型,那么我們必須提供StatModel允許我們實現的所有功能。這包括訓練模型的一種方法(名為train)以及度量模型性能的一種方法(名為calcError)。
注意
在面向對象編程(Object-Oriented Programming,OOP)中,我們主要處理對象或者類。對象是由稱為方法的函數和稱為成員或屬性的變量組成。你可以在https://docs.python.org/3/tutorial/classes.html學習更多有關Python中的面向對象編程的知識。
因為軟件的這種組織方式,用OpenCV構建一個機器學習模型始終遵循相同的邏輯,如下:
- 初始化:我們通過名稱調用模型,創建模型的一個空實例。
- 設置參數:如果模型需要一些參數,我們可以通過setter方法設置這些參數,每個模型的setter方法都可以不同。例如,為了讓一個k-NN算法工作,我們需要指定它的開放參數k(我們稍后會學到)。
- 訓練模型:每個模型都必須提供一個名為train的方法,用于將模型與某些數據進行擬合。
- 預測新標簽:每個模型都必須提供一個名為predict的方法,用于預測新數據的標簽。
- 給模型評分:每個模型都必須提供一個名為calcError的方法,用于度量性能。對于每個模型,這種計算可能是不同的。
提示
因為OpenCV是一個龐大的、社區驅動的項目,所以并不是所有的算法都像用戶期望的那樣遵循這些規則。例如,k-NN算法的大部分工作是在findNearest方法中完成的,但是predict仍然有效。我們將通過不同的例子來說明這些差異。
因為我們會偶爾使用scikit-learn來實現OpenCV沒有提供的一些機器學習算法,所以有必要指出,scikit-learn中的算法遵循幾乎相同的邏輯。最顯著的區別是scikit-learn在初始化步驟中設置了所有需要的模型參數。此外,scikit-learn調用訓練函數fit,而不調用train;調用評分函數score,而不調用calcError。
3.2.2 用評分函數度量模型性能
構建機器學習系統最重要的一個部分是找到一種方法來度量模型預測質量。在真實場景中,模型很少能成功地預測所有的內容。從前幾章的學習中,我們知道應該使用測試集的數據來評估我們的模型。但是這到底是如何工作的呢?
簡短但不是很有用的答案是,這取決于模型。人們已經提出了各種評分函數,它可用于在所有可能的場景中評估訓練模型。好消息是,很多評分函數實際上是scikit-learn的metrics模塊的一部分。
讓我們快速了解一些最重要的評分函數。
1. 使用準確率、精度和召回率評分分類器
在二值分類任務中只有兩個不同的類標簽,有許多不同的方法來度量分類性能。一些常見的評估指標如下所示:
- accuracy_score:準確率(accuracy)計算測試集中預測正確的數據點數,并返回正確預測的數據點的比例。以將圖片分類為貓或狗為例,準確率表示正確分類為包含貓或狗的圖片比例。該函數是最基本的分類器評分函數。
- precision_score:精度(precision)描述了一個分類器不把包含狗的圖片標記為貓的能力。或者說,在分類器認為測試集所有包含貓的圖片中,精度是實際包含一只貓的圖片比例。
- recall_score:召回率(recall,或者敏感度)描述了一個分類器檢索包含貓的所有圖片的能力。或者說,測試集所有包含貓的圖片中,召回率是正確識別為貓的圖片比例。
假設我們有一些ground truth(正確與否取決于我們的數據集)類標簽,不是0就是1。我們使用NumPy的隨機數生成器隨機生成數據點。顯然,這意味著只要我們重新運行代碼,就會隨機生成新數據點。可是,對于本書而言,這并沒有多大的幫助,因為我們希望你能夠運行代碼,并總是得到和書中相同的結果。實現此目的的一個很好的技巧是固定隨機數生成器的種子。這會保證你在每次運行腳本時,都以相同的方式初始化生成器:
1)我們使用下列代碼可以固定隨機數生成器的種子:

2)然后,選取(0, 2)范圍內的隨機整數,我們可以生成0或1的5個隨機標簽:

注意
在文獻中,這兩類有時也被稱為正樣例(類標簽是1的所有數據點)和負樣例(其他所有數據點)。
假設我們有一個分類器試圖預測之前提到的類標簽。為方便討論,假設分類器不是很聰明,總是預測標簽為1。通過硬編碼預測標簽,我們可以模擬這種行為:

我們預測的準確率是多少?
如前所述,準確率計算測試集中預測正確的數據點數,并返回測試集大小的比例。我們只是正確地預測了第二個數據點(實際標簽是1)。除此之外,實際標簽是0,而我們預測為1。因此,我們的準確率應該是1/5或者0.2。
準確率指標的一個簡單實現可總結為:預測的類標簽與實際類標簽相符的所有情況。

scikit-learn的metrics模塊提供了一個更智能、更便捷的實現:

這并不難,不是嗎?但是,要理解精度和召回率,我們需要對I型錯誤和II型錯誤有大致的了解。讓我們來回憶一下,通常把類標簽為1的數據點稱為正樣例,把類標簽為0(或–1)的數據點稱為負樣例。然后,對特定數據點進行分類,可能會產生以下4種結果之一,如表3-1的混淆矩陣所示。
表3-1 4種可能的分類結果

讓我們進行一下分析。如果一個數據點實際是正樣例,并且我們也將其預測為正樣例,那么我們就預測對了!在這種情況下,將結果稱為真陽性。如果我們認為數據點是正樣例,但是該數據點實際是一個負樣例,那么我們錯誤地預測了一個正樣例(因此就有了假陽性這個術語)。類似地,如果我們認為數據點是負樣例,但是該數據點實際是一個正樣例,那么我們就錯誤地預測了一個負樣例(假陰性)。最后,如果我們預測了一個負樣例,而且該數據點確實是一個負樣例,那么我們就找到了一個真陰性。
提示
在統計學假設檢驗中,假陽性也稱為I型錯誤,而假陰性也稱為II型錯誤。
讓我們在模擬數據上快速計算一下這4個評估指標。我們有一個真陽性,實際標簽是1,并且我們預測為1:

類似地,一個假陽性是我們預測為1,但ground truth卻是0:

現在,我相信你已經掌握了竅門。但是我們必須做數學運算才能知道預測的負樣例嗎?我們的并不是很聰明的分類器從不會預測為0,因此(y_pred==0)應該不會是真的:

讓我們再來繪制一個混淆矩陣,如表3-2所示。
表3-2 混淆矩陣

要保證我們做的都是正確的,讓我們再計算一下準確率。準確率應該是真陽性數據點數量加上真陰性數據點數量(即所有正確預測的數據點數)除以數據點總數:

成功了!接著給出精度,為真陽性數據點數除以所有正確預測的數據點數:

在我們的例子中,精度并不比準確率好。讓我們用scikit-learn查看一下我們的數學運算:

最后,召回率是我們正確分類為正樣例占所有正樣例的比例:

召回率太棒了!但是,回到我們的模擬數據,很明顯,這個優秀的召回率得分僅僅是運氣好而已。因為在我們的模擬數據集中只有一個標簽為1,而我們碰巧正確地對其進行了分類,所以我們得到了一個完美的召回率得分。這是否就意味著我們的分類器是完美的呢?未必如此!但是我們卻發現了3個有用的評估指標,似乎從互補的方面度量了我們分類器性能。
2. 使用均方差、可釋方差和R平方評分回歸
在涉及回歸模型時上述評估指標就不再有效了。畢竟,我們現在預測的是連續輸出值,而不是區分分類標簽。幸運的是,scikit-learn還提供了一些其他有用的評分函數:
- mean_squared_error:對于回歸問題,最常用的誤差評估指標是對訓練集中每個數據點的預測值和真實目標值之間的平方誤差(所有數據點的平均值)進行度量。
- explained_variance_score:一個更復雜的評估指標是度量一個模型對測試數據的變化或分配的可解釋程度。通常使用相關系數度量可釋方差的數量。
- r2_score:R2得分(R平方)與可釋方差得分密切相關,但使用一個無偏方差估計。它也被稱為決定系數(coefficient of determination)。
讓我們創建另一個模擬數據集。假設我們的觀測數據看起來像是x值的一個sin函數。我們從生成0到10之間等間距的100個x值開始。

可是,真實數據總是有噪聲的。為了尊重這一事實,我們希望目標值y_true也是有噪聲的。我們通過在sin函數中加入噪聲來實現:

這里,我們使用NumPy的rand函數在[0,1]范圍內加入均勻分布的噪聲,然后通過減去0.5將噪聲集中在0周圍。因此,我們有效地將每個數據點上下抖動最大0.5。
假設我們的模型足夠聰明,能夠計算出sin(x)的關系。因此,預測的y值如下所示:

這些數據是什么樣子的呢?我們可以使用matplotlib對其進行可視化:

生成的線圖如圖3-2所示。

圖3-2 使用matplotlib生成的可視化結果
確定我們的模型預測性能最直接的評估指標是均方誤差。對于每個數據點,我們看預測值和實際y值之間的差異,然后對其進行平方。再計算所有數據點的平方誤差的平均值:

為了方便計算,scikit-learn提供了自有的均方誤差實現:

另一個常見的評估指標是測量數據的分散或變化:如果每個數據點都等于所有數據點的均值,那么數據中就沒有分散或變化,我們就可以用一個數據值來預測所有未來的數據點。這將是世上最無聊的機器學習問題。但我們發現這些數據點通常會遵循一些我們想要揭示的未知的、隱藏的關系。在前面的例子中,這就是導致數據分散的y=sin(x)關系。
我們可以測量能夠解釋的數據(或方差)的分散程度。這通過計算預測標簽和實際標簽之間的方差來實現;這是我們的預測無法解釋的所有方差。如果用數據的總方差對這個值進行歸一化,我們就得到未知方差的分數(fraction of variance unexplained):

因為這個評估指標是一個分數,其值在0到1之間。我們可以從1中減去這個分數,得到可釋方差的分數:

讓我們用scikit-learn驗證我們的數學運算:

完全正確!最后,我們可以計算出所謂的決定系數或者R2。R2與可釋方差分數密切相關,并將先前計算的均方誤差和數據中的實際方差進行比較:

通過scikit-learn也可以獲得同樣的值:

我們的預測與數據擬合得越好,與簡單的平均數相比,R2得分的值越接近1。R2得分可以取負值,因為模型預測可以是小于1的任意值。一個常量模型總是預測y的期望值,獨立于輸入x,得到的R2得分為0:

- 角色動畫制作(下)
- 3ds Max/VRay印象 商業大空間效果圖表現技法(第2版)
- 短視頻構圖與運鏡零基礎一本通
- 3ds Max&ZBrush次世代游戲模型貼圖火星課堂
- 網店商品視頻拍攝與制作從入門到精通
- 中文版Premiere Pro CC完全自學一本通(全彩)
- 我的視頻我做主:Premiere Pro CS5實戰精粹
- 中文版Photoshop CS6圖像處理培訓教程
- Origin科研繪圖與學術圖表繪制從入門到精通
- 多媒體技術應用
- 短視頻創作實戰(微課版)
- 傳奇 Photoshop超寫實手繪插畫表現技法
- 動畫大師煉成記:炮灰兔Maya動畫制作全解析(下冊)
- 中文版Maya 2013技術大全
- Photoshop+Lightroom數碼攝影后期處理完全手冊