免費(fèi)Python機(jī)器學(xué)習(xí)課程七:如何應(yīng)對(duì)算法效果不佳
我們花了很多時(shí)間來(lái)開(kāi)發(fā)機(jī)器學(xué)習(xí)算法。但是在部署后,如果該算法性能不佳,那將令人沮喪。問(wèn)題是,如果算法無(wú)法按預(yù)期工作,下一步應(yīng)該怎么做。什么地方出了錯(cuò)?訓(xùn)練數(shù)據(jù)的數(shù)量是否足夠?我們使用了正確的功能嗎?我們是否應(yīng)該繼續(xù)收集更多數(shù)據(jù)?我們可以,但是那是非常耗時(shí)且昂貴的。我們應(yīng)該添加更多功能嗎?那也可能很昂貴。
往哪個(gè)方向走?
如果您的機(jī)器學(xué)習(xí)算法無(wú)法正常工作,下一步該怎么做?有幾種選擇:
- 獲取更多的訓(xùn)練數(shù)據(jù)非常耗時(shí)。甚至可能需要數(shù)月的時(shí)間才能獲得更多的研究數(shù)據(jù)。
 - 獲得更多的訓(xùn)練特征。也可能需要很多時(shí)間。但是,如果添加一些多項(xiàng)式特征可以工作,那就太酷了。
 - 選擇較小的一組訓(xùn)練特征。
 - 增加正則項(xiàng)
 - 減少正則項(xiàng)。
 
那么,接下來(lái)您應(yīng)該嘗試哪一個(gè)呢?開(kāi)始嘗試任何操作都不是一個(gè)好主意。因?yàn)槟赡茏罱K會(huì)花太多時(shí)間在無(wú)用的事情上。您需要先發(fā)現(xiàn)問(wèn)題,然后采取相應(yīng)措施。學(xué)習(xí)曲線有助于輕松檢測(cè)問(wèn)題,從而節(jié)省大量時(shí)間。
學(xué)習(xí)曲線對(duì)于確定如何提高算法性能非常有用。確定算法是否遭受偏差或擬合不足,方差或擬合過(guò)度,或兩者兼而有之,這很有用。
學(xué)習(xí)曲線的工作原理
學(xué)習(xí)曲線是成本函數(shù)的圖。在同一圖中,訓(xùn)練數(shù)據(jù)的成本函數(shù)和交叉驗(yàn)證數(shù)據(jù)的成本函數(shù)為算法提供了重要的見(jiàn)解。提醒一下,這是成本函數(shù)的公式:


換句話說(shuō),它是預(yù)測(cè)輸出減去原始輸出的平方除以訓(xùn)練數(shù)據(jù)數(shù)量的兩倍。要繪制學(xué)習(xí)曲線,我們需要將這些成本函數(shù)繪制為訓(xùn)練數(shù)據(jù)數(shù)量(m)的函數(shù)。代替使用所有訓(xùn)練數(shù)據(jù),我們將僅使用訓(xùn)練數(shù)據(jù)的較小子集來(lái)訓(xùn)練數(shù)據(jù)。
看看下面的圖片:

如果我們使用太少的數(shù)據(jù)來(lái)訓(xùn)練數(shù)據(jù),則該算法將完全適合訓(xùn)練數(shù)據(jù),并且成本函數(shù)將返回0。
在上面的圖片中清楚地表明,當(dāng)我們僅使用一個(gè),兩個(gè)或三個(gè)數(shù)據(jù)算法來(lái)訓(xùn)練數(shù)據(jù)時(shí),就可以很好地了解到很少的數(shù)據(jù),并且訓(xùn)練成本為零或接近于零。但是,這種類型的算法無(wú)法在其他數(shù)據(jù)上很好地執(zhí)行。
當(dāng)您嘗試使交叉驗(yàn)證數(shù)據(jù)適合此算法時(shí),在交叉驗(yàn)證數(shù)據(jù)上執(zhí)行效果很差的可能性很高。因此,交叉驗(yàn)證數(shù)據(jù)的成本函數(shù)將返回非常高的值。
另一方面,當(dāng)我們將需要越來(lái)越多的數(shù)據(jù)來(lái)訓(xùn)練算法時(shí),它將不再完全適合訓(xùn)練數(shù)據(jù)。因此,培訓(xùn)成本將變得更高。
同時(shí),由于該算法針對(duì)大量數(shù)據(jù)進(jìn)行訓(xùn)練,因此在交叉驗(yàn)證數(shù)據(jù)上的性能會(huì)更好,并且交叉驗(yàn)證數(shù)據(jù)的成本函數(shù)將返回較低的值。這是如何建立學(xué)習(xí)曲線的方法。
開(kāi)發(fā)學(xué)習(xí)算法
我將演示如何逐步繪制學(xué)習(xí)曲線。為了繪制學(xué)習(xí)曲線,我們首先需要機(jī)器學(xué)習(xí)算法。為簡(jiǎn)單起見(jiàn),我將使用線性回歸算法。首先,我們開(kāi)發(fā)一個(gè)線性回歸算法。
首先,導(dǎo)入包和數(shù)據(jù)集。我在這里使用的數(shù)據(jù)集取材于安德魯·伍(Andrew Ng)的Coursera機(jī)器學(xué)習(xí)課程。在此數(shù)據(jù)集中,X值和y值在Excel文件中的單獨(dú)工作表中進(jìn)行組織。
提醒一下,X是我們將用來(lái)開(kāi)發(fā)和訓(xùn)練機(jī)器學(xué)習(xí)算法的功能。y是我們需要預(yù)測(cè)的輸出特征。
交叉驗(yàn)證數(shù)據(jù)的X和y值也被組織在同一Excel文件中的其他兩個(gè)工作表中。我在本文結(jié)尾處提供了到數(shù)據(jù)集的鏈接。請(qǐng)隨時(shí)下載數(shù)據(jù)集并進(jìn)行練習(xí)。
- %matplotlib inline
 - import pandas as pd
 - import numpy as np
 - import matplotlib.pyplot as plt
 - file = pd.ExcelFile('dataset.xlsx')
 - df = pd.read_excel(file, 'Xval', header=None)
 - df.head()
 

以相同的方式,導(dǎo)入訓(xùn)練集的y值:
- y = pd.read_excel(file, 'yval', header=None)
 - y.head()
 

讓我們快速開(kāi)發(fā)線性回歸算法。
(1) 定義假設(shè)
線性回歸使用非?;镜木€性方程式進(jìn)行我們?cè)趯W(xué)校學(xué)習(xí)的預(yù)測(cè)。公式如下:
Y = C + BX
對(duì)于機(jī)器學(xué)習(xí),我們使用不同的術(shù)語(yǔ)。
在這里," h"是假設(shè)或預(yù)測(cè)值,theta0和theta1是系數(shù),X是輸入特征。
在這里,我們已經(jīng)有了X。我們必須計(jì)算" h",并且期望它與y的值匹配。因?yàn)槲覀兊哪繕?biāo)是能夠預(yù)測(cè)y的值。
Theta0和theta1在開(kāi)始時(shí)是隨機(jī)初始化的。我們將通過(guò)迭代不斷完善theta0和theta1的值。
在每次迭代中,我們將使用成本函數(shù)和梯度公式來(lái)計(jì)算成本以更新theta值
(2) 成本函數(shù)和梯度下降
成本函數(shù)為我們提供了有關(guān)我們的預(yù)測(cè)值與原始輸出特征有何不同的想法。在這里,我們的輸出特征為y,預(yù)測(cè)輸出為" h"。因此,成本函數(shù)將告訴我們" h"與" y"的偏離量。我們希望成本函數(shù)值盡可能低。
這是成本函數(shù)的公式:

在成本函數(shù)最小之前,我們將不斷淘汰算法。在每次迭代中,我們使用梯度下降來(lái)更新theta值。
要更新theta值,我們將從先前的theta值中減去梯度下降。當(dāng)我們對(duì)其進(jìn)行編碼時(shí),它將更加清晰。

此處,m是訓(xùn)練數(shù)據(jù)的數(shù)量,而alpha是學(xué)習(xí)率。
(3) 開(kāi)發(fā)線性回歸算法
使用上述公式開(kāi)發(fā)假設(shè)和成本函數(shù)。
- m = len(df)
 - def hypothesis(theta, X):
 - return theta[0] + theta[1]*X
 - def cost_calc(theta, X, y):
 - return (1/2*m) * np.sum((hypothesis(theta, X) - y)**2)
 
現(xiàn)在,我們將定義梯度下降以優(yōu)化參數(shù)theta0和theta1。在每次迭代中,我們將更新theta值并跟蹤成本函數(shù)和theta值。
最后,它將返回每個(gè)迭代theta值中的成本列表。代碼很簡(jiǎn)單。請(qǐng)?jiān)谶@里檢查。
- def gradient_descent(theta, X, y, epoch, alpha):
 - cost = []
 - theta_hist = []
 - i = 0
 - while i < epoch:
 - hx = hypothesis(theta, X)
 - theta[0] -= alpha*(sum(hx-y)/m)
 - theta[1] -= (alpha * np.sum((hx - y) * X))/m
 - cost.append(cost_calc(theta, X, y))
 - i += 1
 - return theta, cost
 
完成了線性回歸算法。我們需要一種預(yù)測(cè)輸出的方法。在預(yù)測(cè)方法中,我們將使用來(lái)自梯度下降函數(shù)和假設(shè)函數(shù)的最終theta進(jìn)行預(yù)測(cè)。
- def predict(theta, X, y, epoch, alpha):
 - theta, cost = gradient_descent(theta, X, y, epoch, alpha)
 - return hypothesis(theta, X), cost, theta
 
現(xiàn)在,將參數(shù)初始化為零,并使用預(yù)測(cè)函數(shù)預(yù)測(cè)輸出變量。
- theta = [0,0]
 - y_predict, cost, theta = predict(theta, df[0], y[0], 1400, 0.001)
 
現(xiàn)在,在同一圖中繪制df或X的預(yù)測(cè)輸出(h)和原始輸出(y)。
- plt.figure()
 - plt.scatter(df, y)
 - plt.scatter(df, y_predict)
 

看來(lái)算法運(yùn)作良好。預(yù)測(cè)的輸出線從中間位置開(kāi)始。
是時(shí)候建立學(xué)習(xí)曲線了!!!
畫(huà)出學(xué)習(xí)曲線
現(xiàn)在,我們可以畫(huà)出學(xué)習(xí)曲線。首先,讓我們?yōu)槲覀兊慕徊骝?yàn)證數(shù)據(jù)集導(dǎo)入X和y值。如前所述,我們將它們組織在單獨(dú)的Excel工作表中。
- file = pd.ExcelFile('dataset.xlsx')
 - cross_val = pd.read_excel(file, 'X', header=None)
 - cross_val.head()
 

- cross_y = pd.read_excel(file, 'y', header=None)
 - cross_y.head()
 

為此,我想稍微修改一下gradient_descent函數(shù)。
在之前的gradient_descent函數(shù)中,我們計(jì)算了每次迭代的成本。我這樣做是因?yàn)檫@是傳統(tǒng)機(jī)器學(xué)習(xí)算法開(kāi)發(fā)中的一種很好的做法。
但是對(duì)于學(xué)習(xí)曲線,我們不需要每次迭代的成本。因此,為了節(jié)省運(yùn)行時(shí)間,我將在每個(gè)時(shí)期中排除計(jì)算成本函數(shù)。我們將僅返回更新的參數(shù)。
- def grad_descent(theta, X, y, epoch, alpha):
 - i = 0
 - while i < epoch:
 - hx = hypothesis(theta, X)
 - theta[0] -= alpha*(sum(hx-y)/m)
 - theta[1] -= (alpha * np.sum((hx - y) * X))/m
 - i += 1
 - return theta
 
如前所述,要開(kāi)發(fā)學(xué)習(xí)曲線,我們需要使用訓(xùn)練數(shù)據(jù)的不同子集來(lái)訓(xùn)練學(xué)習(xí)算法。
在我們的訓(xùn)練數(shù)據(jù)集中,我們有21個(gè)數(shù)據(jù)。我將僅使用一個(gè)數(shù)據(jù),然后使用兩個(gè)數(shù)據(jù),然后使用三個(gè)數(shù)據(jù)一直到21個(gè)數(shù)據(jù)來(lái)訓(xùn)練算法。
因此,我們將在21個(gè)訓(xùn)練數(shù)據(jù)子集上對(duì)算法進(jìn)行21次訓(xùn)練。我們還將跟蹤每個(gè)訓(xùn)練數(shù)據(jù)子集的成本函數(shù)。請(qǐng)仔細(xì)看一下代碼,它將更加清晰。
- j_tr = []
 - theta_list = []
 - for i in range(0, len(df)):
 - theta = [0,0]
 - theta_list.append(grad_descent(theta, df[0][:i], y[0][:i], 1400, 0.001))
 - j_tr.append(cost_calc(theta, df[0][:i], y[0][:i]))
 - theta_list
 
以下是每個(gè)訓(xùn)練數(shù)據(jù)子集的訓(xùn)練參數(shù):

這是每個(gè)訓(xùn)練子集的費(fèi)用:

查看每個(gè)子集的成本。當(dāng)訓(xùn)練數(shù)據(jù)僅為1或2時(shí),成本為零或幾乎為零。隨著我們不斷增加培訓(xùn)數(shù)據(jù),成本也上升了,這是預(yù)期的。
現(xiàn)在,對(duì)訓(xùn)練數(shù)據(jù)的所有子集使用上面的參數(shù)來(lái)計(jì)算交叉驗(yàn)證數(shù)據(jù)的成本:
- j_val = []
 - for i in theta_list:
 - j_val.append(cost_calc(i, cross_val[0], cross_y[0]))
 - j_val
 

剛開(kāi)始時(shí),成本確實(shí)很高,因?yàn)橛?xùn)練參數(shù)來(lái)自太少的訓(xùn)練數(shù)據(jù)。但是隨著參數(shù)的增加和更多訓(xùn)練數(shù)據(jù)的改進(jìn),交叉驗(yàn)證錯(cuò)誤不斷下降。
讓我們?cè)谕粓D中繪制訓(xùn)練誤差和交叉驗(yàn)證誤差:
- %matplotlib inline
 - import matplotlib.pyplot as plt
 - plt.figure()
 - plt.scatter(range(0, 21), j_tr)
 - plt.scatter(range(0, 21), j_val)
 

這是我們的學(xué)習(xí)曲線。
從學(xué)習(xí)曲線中得出決策
上面的學(xué)習(xí)曲線看起來(lái)不錯(cuò)。它以我們預(yù)期的方式流動(dòng)。最初,訓(xùn)練誤差太小,驗(yàn)證誤差太高。
慢慢地,它們彼此完全重疊。太完美了!但是在現(xiàn)實(shí)生活中,這種情況并不經(jīng)常發(fā)生。
大多數(shù)機(jī)器學(xué)習(xí)算法并不是第一次都能完美運(yùn)行。它幾乎始終都遭受一些我們需要解決的問(wèn)題的困擾。在這里,我將討論一些問(wèn)題。
我們可能會(huì)發(fā)現(xiàn)學(xué)習(xí)曲線如下所示:

訓(xùn)練誤差和驗(yàn)證誤差之間是否存在重大差異,表明存在高方差問(wèn)題。也可以稱為過(guò)度擬合問(wèn)題。
獲取更多的訓(xùn)練數(shù)據(jù)或選擇較小的功能集或同時(shí)使用這兩種功能都可以解決此問(wèn)題。

如果傾斜曲線看起來(lái)像這樣,則意味著開(kāi)始時(shí)訓(xùn)練誤差太小而驗(yàn)證誤差太高。緩慢地,訓(xùn)練誤差變高而驗(yàn)證誤差變低。但在某種程度上,它們變得平行。您可以從圖片中看到一點(diǎn),即使有了更多訓(xùn)練數(shù)據(jù),交叉驗(yàn)證錯(cuò)誤也不再減少。
在這種情況下,獲取更多訓(xùn)練數(shù)據(jù)將不會(huì)改善機(jī)器學(xué)習(xí)算法。
這表明學(xué)習(xí)算法正在遭受高偏差問(wèn)題。在這種情況下,獲得更多訓(xùn)練功能可能會(huì)有所幫助。
修正學(xué)習(xí)算法
假設(shè)我們正在執(zhí)行線性回歸。但是該算法無(wú)法正常工作。
該怎么辦?
首先,畫(huà)出一個(gè)學(xué)習(xí)曲線,如我在此處演示的。
- 如果檢測(cè)到高方差問(wèn)題,請(qǐng)根據(jù)要素的重要性選擇一組較小的要素。如果有幫助,可以節(jié)省一些時(shí)間。如果不是,請(qǐng)嘗試獲取更多訓(xùn)練數(shù)據(jù)。
 - 如果您從學(xué)習(xí)曲線中發(fā)現(xiàn)高偏差問(wèn)題,那么您已經(jīng)知道獲得附加功能是一種可能的解決方案。您甚至可以嘗試添加一些多項(xiàng)式特征。大量時(shí)間可以幫助您節(jié)省大量時(shí)間。
 - 如果您要使用正則化項(xiàng)lambda實(shí)現(xiàn)算法,請(qǐng)?jiān)谠撍惴ㄓ龅礁咂畹那闆r下嘗試降低lambda,并在該算法遇到高方差問(wèn)題的情況下嘗試增加lambda。
 
在神經(jīng)網(wǎng)絡(luò)的情況下,我們也可能遇到這種偏差或方差問(wèn)題。
對(duì)于高偏差或欠擬合問(wèn)題,我們需要增加神經(jīng)元的數(shù)量或隱藏層的數(shù)量。為了解決高方差或過(guò)度擬合的問(wèn)題,我們應(yīng)該減少神經(jīng)元的數(shù)量或隱藏層的數(shù)量。我們甚至可以使用不同數(shù)量的神經(jīng)元繪制學(xué)習(xí)曲線。
非常感謝您閱讀本文。我希望這可以幫到你。















 
 
 





 
 
 
 