譯者 | 陳峻
審校 | 重樓
自去年以來,諸如ChatGPT 和 Bard之類的大語(yǔ)言模型已將機(jī)器學(xué)習(xí)提升到了一種現(xiàn)象級(jí)的地位。開發(fā)人員使用它們?cè)谳o助編程方面不斷探索了從圖像生成到疾病檢測(cè)等領(lǐng)域的應(yīng)用案例。
鑒于全球各大科技公司都在加大針對(duì)機(jī)器學(xué)習(xí)的投入,作為Java開發(fā)人員有必要了解如何訓(xùn)練和使用機(jī)器學(xué)習(xí)模型。下面,您將初步了解到機(jī)器學(xué)習(xí)的基本工作原理,有關(guān)如何實(shí)現(xiàn)和訓(xùn)練機(jī)器學(xué)習(xí)算法的簡(jiǎn)短指南,以及開發(fā)智能應(yīng)用的最常用監(jiān)督機(jī)器學(xué)習(xí)方法。
機(jī)器學(xué)習(xí)和人工智能
總的說來,機(jī)器學(xué)習(xí)是從試圖模仿人類智慧的AI領(lǐng)域發(fā)展而來,使得應(yīng)用程序能夠在無需人工參與的情況下,執(zhí)行流程改進(jìn),并按需更新代碼和擴(kuò)展其功能。
目前,監(jiān)督學(xué)習(xí)和無監(jiān)督學(xué)習(xí)是兩種最流行的機(jī)器學(xué)習(xí)方法。這兩種方法都需要向機(jī)器輸入大量的數(shù)據(jù)記錄,以便其進(jìn)行關(guān)聯(lián)和學(xué)習(xí)。而這些被收集到的數(shù)據(jù)記錄通常被稱為特征向量。例如,對(duì)于某個(gè)房屋類數(shù)據(jù)而言,特征向量可能包括了房屋的總體面積、房間數(shù)量、以及房齡等特征。
監(jiān)督學(xué)習(xí)
在監(jiān)督學(xué)習(xí)中,為了訓(xùn)練算法,機(jī)器需要輸入一組特征向量和相關(guān)標(biāo)簽。其中,標(biāo)簽通常是由人類注釋者提供的,代表了對(duì)于某個(gè)給定問題的正確回答。學(xué)習(xí)算法會(huì)分析特征向量、及其正確標(biāo)簽,以找出它們之間的內(nèi)部結(jié)構(gòu)和關(guān)系。據(jù)此,機(jī)器就能夠?qū)W會(huì)如何正確地回答問題。
舉例來說,一個(gè)智能房地產(chǎn)應(yīng)用為了接受特征向量的訓(xùn)練,人工標(biāo)注者會(huì)根據(jù)房屋面積、房間數(shù)和房齡等因素,為每套房屋標(biāo)注出正確的房?jī)r(jià)。通過對(duì)數(shù)據(jù)進(jìn)行分析,該房地產(chǎn)應(yīng)用將會(huì)被訓(xùn)練成能夠回答“這套房子能賣多少錢?”的問題。
而且在完成訓(xùn)練后,該應(yīng)用即使碰到未見過的、未標(biāo)記的特征向量,機(jī)器也能夠正確地回答新的查詢。
無監(jiān)督學(xué)習(xí)
在無監(jiān)督學(xué)習(xí)中,算法通過編程來預(yù)測(cè)答案,而無需人工標(biāo)注,甚至無需提問。無監(jiān)督學(xué)習(xí)并非預(yù)先確定標(biāo)簽或結(jié)果,而是利用海量數(shù)據(jù)集和處理能力,來發(fā)現(xiàn)以前未知的相關(guān)性。例如,在消費(fèi)品的營(yíng)銷過程中,無監(jiān)督學(xué)習(xí)可以被用于識(shí)別隱藏的關(guān)系或消費(fèi)者分組,以最終形成新的或改進(jìn)的營(yíng)銷策略。
監(jiān)督機(jī)器學(xué)習(xí)項(xiàng)目
鑒于所有的機(jī)器學(xué)習(xí)都以數(shù)據(jù)為基礎(chǔ),因此從本質(zhì)上講,算法需要根據(jù)源于現(xiàn)實(shí)世界的各種數(shù)據(jù)實(shí)例的輸入,建立一套數(shù)學(xué)模型,以最終學(xué)會(huì)使用新的數(shù)據(jù)來預(yù)測(cè)未知的結(jié)果。
本文將重點(diǎn)介紹監(jiān)督學(xué)習(xí),這一目前最常見的機(jī)器學(xué)習(xí)方法。讓我們延用上文提到的房地產(chǎn)應(yīng)用案例,用一種有意義的方式為數(shù)據(jù)貼上標(biāo)簽。在下表 1 中,房屋記錄的每一行都包含了一個(gè)“房?jī)r(jià)”標(biāo)簽。通過將行數(shù)據(jù)與房?jī)r(jià)標(biāo)簽相關(guān)聯(lián),算法最終將能夠預(yù)測(cè)不在其數(shù)據(jù)集中的房屋市場(chǎng)價(jià)(注意,房屋面積以平方米為單位,而房?jī)r(jià)以歐元為單位)。
表 1.房屋記錄
特征 | 特征 | 特征 | 標(biāo)簽 |
房屋尺寸 | 房間數(shù)量 | 房屋年齡 | 估計(jì)費(fèi)用 |
90平方米/295 英尺 | 2 | 23 年 | 249,000 歐元 |
101平方米/331 英尺 | 3 | 無 | 338,000 歐元 |
1330 平方米/4363 英尺 | 11 | 12 年 | 6,500,000 歐元 |
在早期階段,您可能需要手工標(biāo)注數(shù)據(jù)記錄,但最終您將訓(xùn)練應(yīng)用自動(dòng)完成該過程。也就是說,標(biāo)記數(shù)據(jù)集僅用于訓(xùn)練和測(cè)試目的。這一階段結(jié)束后,機(jī)器學(xué)習(xí)模型將能夠在無標(biāo)簽數(shù)據(jù)的實(shí)例上工作。例如,您可以向預(yù)測(cè)算法輸入一條新的、無標(biāo)簽的房屋記錄,它會(huì)根據(jù)曾經(jīng)的訓(xùn)練數(shù)據(jù)自動(dòng)預(yù)測(cè)房?jī)r(jià)。
訓(xùn)練機(jī)器學(xué)習(xí)模型
監(jiān)督機(jī)器學(xué)習(xí)的挑戰(zhàn)在于,為特定問題找到合適的預(yù)測(cè)函數(shù)。從數(shù)學(xué)角度講,我們的挑戰(zhàn)就是要找到接收輸入變量x,并能夠返回預(yù)測(cè)值的目標(biāo)預(yù)測(cè)函數(shù)。
圖 1.目標(biāo)預(yù)測(cè)函數(shù)示例
在大多數(shù)情況下,x代表了一個(gè)多數(shù)據(jù)點(diǎn)。而在該案例中,它是由房屋尺寸值和房間數(shù)量值定義的單個(gè)房屋的二維數(shù)據(jù)點(diǎn)。這些值的數(shù)組被稱為特征向量。為了預(yù)測(cè)單個(gè)房屋的價(jià)格,我們可以使用包含了房屋尺寸和房間數(shù)量的特征向量{ 101.0, 3.0 } 去調(diào)用目標(biāo)預(yù)測(cè)函數(shù):
清單 1.使用特征向量調(diào)用目標(biāo)預(yù)測(cè)函數(shù)
// 目標(biāo)預(yù)測(cè)函數(shù) h(學(xué)習(xí)過程的輸出)
Function<Double[], Double> h = ...;
// 設(shè)置房屋尺寸=101 和房間數(shù)=3 的特征向量
Double[] x = new Double[] { 101.0, 3.0 };
// 并預(yù)測(cè)房?jī)r(jià)(標(biāo)簽)
double y = h.apply(x);
在清單 1 中,數(shù)組變量x值代表房屋的特征向量。目標(biāo)預(yù)測(cè)函數(shù)返回的y值是預(yù)測(cè)的房?jī)r(jià)。
機(jī)器學(xué)習(xí)面臨的挑戰(zhàn)是:定義一個(gè)盡可能準(zhǔn)確地用于未知的、未見過的數(shù)據(jù)實(shí)例的目標(biāo)預(yù)測(cè)函數(shù)。在機(jī)器學(xué)習(xí)中,目標(biāo)預(yù)測(cè)函數(shù)(hθ)有時(shí)被稱為模型。模型是學(xué)習(xí)過程的結(jié)果,也被稱為模型訓(xùn)練。
圖 2.機(jī)器學(xué)習(xí)模型
學(xué)習(xí)算法以標(biāo)注的訓(xùn)練示例為基礎(chǔ),在訓(xùn)練數(shù)據(jù)中尋找各種結(jié)構(gòu)或模式。在此過程中,學(xué)習(xí)算法會(huì)逐步修改數(shù)值以減少損失,從而生成一個(gè)能夠從數(shù)據(jù)中進(jìn)行泛化的模型。
由于機(jī)器學(xué)習(xí)的過程通常是探索性的,因此在大多數(shù)情況下,不同的學(xué)習(xí)算法和配置會(huì)被執(zhí)行多次。當(dāng)一個(gè)模型被確定后,數(shù)據(jù)也會(huì)通過該模型被運(yùn)行多次。這些迭代也被稱為epoch。
最后,算法將根據(jù)性能指標(biāo)對(duì)所有模型進(jìn)行評(píng)估,以選出最佳模型,用于計(jì)算對(duì)于那些未標(biāo)記數(shù)據(jù)實(shí)例的預(yù)測(cè)。
線性回歸
首先,我們需要選擇待使用的學(xué)習(xí)算法。線性回歸是最簡(jiǎn)單、也是最流行的監(jiān)督學(xué)習(xí)算法之一。該算法假定輸入特征和輸出標(biāo)簽之間存在著線性關(guān)系。在圖 3 的公式中,通用線性回歸函數(shù)通過總結(jié)特征向量的每個(gè)元素,乘以一個(gè)theta 參數(shù) (θ) ,以返回預(yù)測(cè)值。在該訓(xùn)練過程中,θ 參數(shù)被用于根據(jù)訓(xùn)練數(shù)據(jù),來調(diào)整回歸函數(shù)。
圖 3.通用線性回歸函數(shù)
線性回歸雖然是一種簡(jiǎn)單的學(xué)習(xí)函數(shù),但是它為前饋式神經(jīng)網(wǎng)絡(luò)(Forward Neural Network)中使用的梯度下降等更高級(jí)形式,奠定了良好的基礎(chǔ)。在線性回歸函數(shù)中,θ 參數(shù)和特征參數(shù)由訂閱數(shù)進(jìn)行枚舉。此處的訂閱數(shù)表示theta 參數(shù) (θ) 和特征參數(shù) (x) 在向量中的位置。需要注意的是,特征x0是一個(gè)常數(shù)偏移項(xiàng)。為便于計(jì)算,其值被設(shè)為1。因此,針對(duì)特定領(lǐng)域特征(如房屋尺寸)的索引將從x1 開始。如果x1被設(shè)置為房屋特征向量的第一個(gè)值(房屋尺寸),那么x2將被設(shè)置為下一個(gè)值(房間數(shù)量),以此類推。
注意,在對(duì)線性回歸進(jìn)行可視化時(shí),您不妨想象一條在坐標(biāo)系上的直線,它試圖盡可能地接近數(shù)據(jù)點(diǎn)。下面的清單 2 展示了該線性回歸函數(shù)的 Java 實(shí)現(xiàn)。它在數(shù)學(xué)上顯示為hθ(x)。為了簡(jiǎn)單起見,該計(jì)算使用了double 數(shù)據(jù)類型。而在apply()方法中,數(shù)組的第一個(gè)元素已在該函數(shù)之外被設(shè)置為 1.0。
清單 2.Java 中的線性回歸
public class LinearRegressionFunction implements Function<Double[], Double> {
private final double[] thetaVector;
LinearRegressionFunction(double[] thetaVector) {
this.thetaVector = Arrays.copyOf(thetaVector, thetaVector.length);
}
public Double apply(Double[] featureVector) {
// 出于計(jì)算原因,第一個(gè)元素必須是 1.0
assert featureVector[0] == 1.0;
// simple, sequential implementation
double prediction = 0;
for (int j = 0; j < thetaVector.length; j++) {prediction += thetaVector[j] * featureVector[j];
}
return prediction;
}
public double[] getThetas() {
return Arrays.copyOf(thetaVector, thetaVector.length);
}
}
為了創(chuàng)建LinearRegressionFunction 的新實(shí)例,我們必須設(shè)置 theta 參數(shù)。theta 參數(shù)或向量被用于使得通用回歸函數(shù)能夠適應(yīng)基礎(chǔ)的訓(xùn)練數(shù)據(jù)。該代碼的 theta 參數(shù)將在學(xué)習(xí)過程中根據(jù)訓(xùn)練示例進(jìn)行調(diào)整。顯然,訓(xùn)練目標(biāo)預(yù)測(cè)函數(shù)的質(zhì)量,只能與給定訓(xùn)練數(shù)據(jù)的質(zhì)量相當(dāng)。
在下一個(gè)示例中,我們對(duì)LinearRegressionFunction進(jìn)行實(shí)例化,以根據(jù)房屋尺寸預(yù)測(cè)房?jī)r(jià)??紤]到x0必須是 1.0 的常量,目標(biāo)預(yù)測(cè)函數(shù)將使用兩個(gè) theta 參數(shù)進(jìn)行實(shí)例化。而theta 參數(shù)則是學(xué)習(xí)過程的輸出。在創(chuàng)建了新的實(shí)例后,面積為 1330 平方米的房屋價(jià)格預(yù)測(cè)結(jié)果如下:
// 這里使用的 Theta 向量是訓(xùn)練過程的輸出
double[] thetaVector = new double[] { 1.004579, 5.286822 };
LinearRegressionFunction targetFunction = new LinearRegressionFunction(thetaVector);
// create the feature vector function with x0=1 (for computational reasons) and x1=house-size
Double[] featureVector = new Double[] { 1.0, 1330.0 };
// 進(jìn)行預(yù)測(cè)
double predictedPrice = targetFunction.apply(featureVector);
目標(biāo)預(yù)測(cè)函數(shù)的預(yù)測(cè)線在圖 4 中顯示為一條藍(lán)線。這條線是通過對(duì)所有房屋面積值進(jìn)行目標(biāo)預(yù)測(cè)計(jì)算得出的。同時(shí),圖中還包括了用于訓(xùn)練的“價(jià)格-尺寸”對(duì)。
圖 4 目標(biāo)預(yù)測(cè)函數(shù)預(yù)測(cè)線
上圖坐標(biāo)的截距和斜率是由θ 向量{ 1.004579, 5.286822 } 定義。該預(yù)測(cè)圖看似十分貼切,但是我們又怎么知道該 Theta 向量一定適合自己的應(yīng)用呢?如果改變第一個(gè)或第二個(gè) theta 參數(shù),函數(shù)的適合度會(huì)更好嗎?為了確定最合適的 theta 參數(shù)向量,我們需要一個(gè)實(shí)用函數(shù)(Utility Function)來評(píng)估目標(biāo)預(yù)測(cè)函數(shù)的性能。
目標(biāo)預(yù)測(cè)函數(shù)的評(píng)估
在機(jī)器學(xué)習(xí)中,成本函數(shù)(J(θ))(又稱“損失函數(shù)”)通常被用于計(jì)算給定目標(biāo)預(yù)測(cè)函數(shù)的平均誤差或“成本”。圖 5 顯示了一個(gè)函數(shù)例子。
圖 5 成本函數(shù)
成本函數(shù)表示模型與訓(xùn)練數(shù)據(jù)的適合程度。若要確定訓(xùn)練目標(biāo)預(yù)測(cè)函數(shù)的成本,我們可以計(jì)算每個(gè)房屋示例(i) 的平方誤差。此處的誤差是計(jì)算得出的y值,與房屋示例i 的實(shí)際y值之間的距離。例如,面積為 1330 平方米的房屋的實(shí)際價(jià)格為 6,500,000 歐元,而經(jīng)過訓(xùn)練的目標(biāo)預(yù)測(cè)函數(shù)預(yù)測(cè)的房屋價(jià)格為 7,032,478 歐元,其差距(或誤差)為 532,478 歐元。您可以在圖 4中找到這一差距。圖中的差距(或誤差)是以垂直紅色虛線的形式,顯示在每個(gè)訓(xùn)練“價(jià)格-尺寸”對(duì)中。
要計(jì)算經(jīng)過訓(xùn)練的目標(biāo)預(yù)測(cè)函數(shù)的成本,我們必須總結(jié)示例中每棟房屋的平方誤差,并計(jì)算出平均值。只有J(θ) 的成本值越小,目標(biāo)預(yù)測(cè)函數(shù)的預(yù)測(cè)才越精確。
在下面的代碼列表中,代價(jià)函數(shù)的簡(jiǎn)單 Java 實(shí)現(xiàn)將目標(biāo)預(yù)測(cè)函數(shù)、訓(xùn)練記錄列表、及其相關(guān)標(biāo)簽作為輸入。預(yù)測(cè)值將在循環(huán)中被計(jì)算,而誤差則通過減去真實(shí)標(biāo)簽值來計(jì)算。據(jù)此,它將匯總平方誤差并計(jì)算平均誤差。成本也將以雙值的形式返回:
public static double cost(Function<Double[], Double> targetFunction,
List<Double[]> dataset,
List<Double> labels) {
int m = dataset.size();
double sumSquaredErrors = 0;
// 計(jì)算每個(gè)訓(xùn)練示例的平方誤差(“差距”),并將其與總和相加
for (int i = 0; i < m; i++) {
// 獲取當(dāng)前示例的特征向量
Double[] featureVector = dataset.get(i);
// 根據(jù)真實(shí)值(標(biāo)簽)預(yù)測(cè)值并計(jì)算誤差
double predicted = targetFunction.apply(featureVector);
double label = labels.get(i); double gap = targetFunction.ap ply(f eat ureVector); double label = labels.get(i);doublegap= targetFunction.apply(featureVector).get(i);
double gap = predicted - label;sumSquaredErrors += Math.pow(gap, 2);
}
// 計(jì)算并返回誤差的平均值(越小越好)
return (1.0 / (2 * m)) * sumSquaredErrors;
}
用梯度下降法訓(xùn)練目標(biāo)預(yù)測(cè)函數(shù)
雖然代價(jià)函數(shù)有助于分別評(píng)估目標(biāo)預(yù)測(cè)函數(shù)和 theta 參數(shù)的質(zhì)量,但仍需要計(jì)算最佳適合的 theta 參數(shù)。在此,我們可以使用梯度下降算法來進(jìn)行計(jì)算。
用梯度下降法計(jì)算 theta 參數(shù)
梯度下降法能夠使得成本函數(shù)最小化。也就是說,它能夠根據(jù)訓(xùn)練數(shù)據(jù)找到產(chǎn)生最低成本(J(θ))的 Theta 組合。 梯度下降法通過使用部分導(dǎo)數(shù),逐步調(diào)整每個(gè)變量來實(shí)現(xiàn)這一點(diǎn)。 這是反向傳播的一種典型形式,而所有其他形式都會(huì)基于該形式。
圖 6 顯示了一種簡(jiǎn)化算法,可用于計(jì)算新的、適合度更高的 Thetas:
圖 6.梯度下降使得成本函數(shù)最小化
在每次迭代中, Theta向量的每個(gè)參數(shù) θ 都會(huì)計(jì)算出一個(gè)新的、更好的值。同時(shí),學(xué)習(xí)率α持續(xù)控制著每次迭代的計(jì)算步長(zhǎng)。這種計(jì)算將會(huì)重復(fù)進(jìn)行,直到得到一個(gè)適合且夠好的 θ 值組合。例如,圖 7 中的線性回歸函數(shù)就有三個(gè) theta 參數(shù):
圖 7.帶有三個(gè)theta 參數(shù)的線性回歸函數(shù)
在每次迭代("epoch")中,算法都會(huì)并行地計(jì)算出每個(gè) theta 參數(shù)的新值:θ0、θ1 和θ2。而每次迭代后,您都可以使用新的 Theta 向量{θ0,θ1,θ2} 再創(chuàng)建一個(gè)新的、適合度更高的LinearRegressionFunction實(shí)例。
清單 3 顯示了梯度下降算法的 Java 代碼?;貧w函數(shù)的各個(gè) theta 將使用訓(xùn)練數(shù)據(jù)、數(shù)據(jù)標(biāo)簽和學(xué)習(xí)率(α)來進(jìn)行訓(xùn)練。函數(shù)的輸出則使用由新的 theta 參數(shù)改進(jìn)后的目標(biāo)預(yù)測(cè)函數(shù)。其中,train()方法將會(huì)被反復(fù)調(diào)用,并輸入新的目標(biāo)預(yù)測(cè)函數(shù)與上一次計(jì)算,得出的新 theta。這些調(diào)用都會(huì)重復(fù)進(jìn)行,直到調(diào)整后的目標(biāo)預(yù)測(cè)函數(shù)的成本達(dá)到最低點(diǎn)。
清單 3.Java 中的梯度下降算法示例
public static LinearRegressionFunction train(LinearRegressionFunction targetFunction,
List<Double[]> dataset,
List<Double> labels,
double alpha) {
int m = dataset.size();
double[] thetaVector = targetFunction.getThetas();
double[] newThetaVector = new double[thetaVector.length];
// 計(jì)算 theta 數(shù)組中每個(gè)元素的新 theta
for (int j = 0; j < thetaVector.length; j++) {
// 總結(jié)誤差差距 * 特征
double sumErrors = 0;
for (int i = 0; i < m; i++) {
Double[] featureVector = dataset.get(i);
double error = targetFunction.apply(featureVector) - labels.get(i);sumErrors += error * featureVector[j];
}
// 計(jì)算新的 theta 值
double gradient = (1.0 / m) * sumErrors;newThetaVector[j] = thetaVector[j] - alpha * gradient;
}
returnnew LinearRegressionFunction(newThetaVector);
}
若要驗(yàn)證成本是否持續(xù)下降,我們可以在每個(gè)訓(xùn)練步驟后執(zhí)行成本函數(shù)J(θ)。其預(yù)期結(jié)果是,每迭代一次,成本就必須降低一次。如果沒有減少的話,則說明學(xué)習(xí)率參數(shù)值過大,算法超過了最小值。那么在這種情況下,梯度下降算法就會(huì)失效。
為什么這種模式行不通
圖 8 顯示了使用計(jì)算出的新theta 參數(shù)的目標(biāo)預(yù)測(cè)函數(shù)。其初始 Theta 向量為{ 1.0, 1.0 }。左側(cè)一列顯示的是迭代了 50 次后的預(yù)測(cè)圖;中間一列顯示的是迭代了 200 次后的預(yù)測(cè)圖;而右側(cè)一列顯示的是迭代了 1000 次后的預(yù)測(cè)圖。如圖所示,隨著新目標(biāo)預(yù)測(cè)函數(shù)的適合效果越來越好,每次迭代后的成本都在降低。迭代 500 到 600 次后,θ 參數(shù)不再發(fā)生顯著變化,成本也就達(dá)到了穩(wěn)定的高點(diǎn)。此時(shí),目標(biāo)預(yù)測(cè)函數(shù)的精度將不再顯著提高。
圖 8.成本隨著每次迭代而降低
雖然經(jīng)過 500 到 600 次迭代后,成本不再顯著降低,但是目標(biāo)預(yù)測(cè)函數(shù)似乎仍然不是最優(yōu)的。在機(jī)器學(xué)習(xí)中,我們常用“欠適合(Underfitting)”一詞用來表示學(xué)習(xí)算法沒有捕捉到數(shù)據(jù)的潛在趨勢(shì)。
根據(jù)生活中的實(shí)際經(jīng)驗(yàn),對(duì)于面積大的房產(chǎn),其每平方米的預(yù)計(jì)價(jià)格會(huì)逐漸下降。據(jù)此,我們可以得出結(jié)論:該訓(xùn)練過程中使用到的模型,即目標(biāo)預(yù)測(cè)函數(shù),并沒能很好地適合真實(shí)數(shù)據(jù)。鑒于“欠適合”通常是由于模型過于簡(jiǎn)單造成的,那么在本案例中,是由于我們的簡(jiǎn)單目標(biāo)預(yù)測(cè)函數(shù)僅使用了單一的房屋尺寸特征所造成。顯然,僅憑這些數(shù)據(jù)是不足以準(zhǔn)確地預(yù)測(cè)房屋成本的。
添加和擴(kuò)展特征
如果您發(fā)現(xiàn)目標(biāo)預(yù)測(cè)函數(shù)不適合待解決的問題,一種常見的糾偏方法是,通過在特征向量中添加更多的特征來對(duì)其進(jìn)行調(diào)整。例如,在前面的房屋價(jià)格示例中,您可以添加諸如:房間數(shù)量或房齡等更多房屋特征。同時(shí),您也可以使用一個(gè)多值特征向量,如:{ 大小、房間數(shù)、房齡 },來描述房屋實(shí)例,而不僅僅使用{ 大小},這個(gè)單一的特定領(lǐng)域特征向量。
當(dāng)然,在某些情況下,可用的訓(xùn)練數(shù)據(jù)集中并沒有足夠的特征。那么您可以嘗試著添加由現(xiàn)有特征計(jì)算得出的多項(xiàng)式特征。例如,您可以擴(kuò)展房?jī)r(jià)目標(biāo)預(yù)測(cè)函數(shù),使其包含計(jì)算出的平方尺寸特征 (x2):
圖 9.利用多項(xiàng)式特征擴(kuò)展的目標(biāo)預(yù)測(cè)函數(shù)
值得注意的是,在使用多個(gè)特征時(shí),我們需要進(jìn)行特征的擴(kuò)展(或“歸一化”),以規(guī)范不同特征的范圍。例如,size2特征的取值范圍就比 size 特征的取值范圍大一個(gè)量級(jí)。如果不對(duì)特征進(jìn)行擴(kuò)展,size2特征將主導(dǎo)整個(gè)成本函數(shù)。而size2特征所產(chǎn)生的誤差值將遠(yuǎn)高于僅由尺寸特征產(chǎn)生的誤差值。下圖 10 顯示了一種簡(jiǎn)單的特征擴(kuò)展算法。
圖 10.簡(jiǎn)單的特征擴(kuò)展算法
該算法由如下Java 代碼清單中的FeaturesScaling類實(shí)現(xiàn)。FeaturesScaling類提供了一個(gè)工廠方法(Factory Method),可用于創(chuàng)建根據(jù)訓(xùn)練數(shù)據(jù)調(diào)整的擴(kuò)展函數(shù)。在內(nèi)部,訓(xùn)練數(shù)據(jù)的實(shí)例被用來計(jì)算平均值、最小值和最大值常數(shù)。而由此產(chǎn)生的函數(shù)會(huì)使用一個(gè)特征向量,并生成一個(gè)帶有擴(kuò)展特征的新特征向量。如下圖所示,訓(xùn)練過程和預(yù)測(cè)調(diào)用都需要對(duì)特征進(jìn)行擴(kuò)展:
// 創(chuàng)建數(shù)據(jù)集
List<Double[]> dataset = new ArrayList<>();dataset.add(new Double[] { 1.0, 90.0, 8100.0 }); // 房屋#1 的特征向量dataset.add(new Double[] { 1.0, 101.0, 10201.0 }); // 房屋#2 的特征向量dataset.add(new Double[] { 1.0, 103.0, 10609.0 }); // ...
//....
// 創(chuàng)建標(biāo)簽
List<Double> labels = new ArrayList<>();labels.add(249.0); // 房屋#1的價(jià)格標(biāo)簽labels.add(338.0); // 房屋#2的價(jià)格標(biāo)簽labels.add(304.0); // ...
//...
// 擴(kuò)展特征列表
Function<Double[], Double[]> scalingFunc = FeaturesScaling.createFunction(dataset);
List<Double[] > scaledDataset = dataset.stream().map(scalingFunc).collect(Collectors.toList());
// 使用初始值創(chuàng)建假設(shè)函數(shù),并以 0.1 的學(xué)習(xí)率對(duì)其進(jìn)行訓(xùn)練
LinearRegressionFunction targetFunction = new LinearRegressionFunction(new double[] { 1.0, 1.0, 1.0 });
for (int i = 0; i < 10000; i++) {targetFunction = Learner.train(targetFunction, scaledDataset, labels, 0.1);
}
// 對(duì)面積為 600 m2 的房屋進(jìn)行預(yù)測(cè)
Double[] scaledFeatureVector= scalingFunc.apply(new Double[] { 1.0, 600.0, 360000.0 });
double predictedPrice = targetFunction.apply(scaledFeatureVector);
隨著更多的特征被添加,您可能會(huì)發(fā)現(xiàn)目標(biāo)預(yù)測(cè)函數(shù)也適合得越來越好。不過值得注意的是,如果添加了太多的特征,則最終可能會(huì)導(dǎo)致目標(biāo)預(yù)測(cè)函數(shù)出現(xiàn)過度適合(Overfitting)。
過度適合和交叉驗(yàn)證
當(dāng)目標(biāo)預(yù)測(cè)函數(shù)或模型與訓(xùn)練數(shù)據(jù)適合得好過頭時(shí),就會(huì)出現(xiàn)過度適合。而過度適合的模型則會(huì)捕捉到訓(xùn)練數(shù)據(jù)中的噪聲或隨機(jī)波動(dòng)。圖 11 中最右側(cè)的圖表顯示了一種過度適合的行為模式。
圖 11.具有過度適合行為的目標(biāo)預(yù)測(cè)函數(shù)示例
雖然過度適合模型在訓(xùn)練數(shù)據(jù)上非常匹配,但當(dāng)需要求解未知的、未見過的數(shù)據(jù)時(shí),它的表現(xiàn)會(huì)相當(dāng)糟糕。目前,我們有如下三種方法可以避免過度適合:
- 使用更大的訓(xùn)練數(shù)據(jù)集。
- 通過增加正則化,來改進(jìn)機(jī)器學(xué)習(xí)算法。
- 如上面的中間圖表所示,減少特征的使用。
如果您的預(yù)測(cè)模型出現(xiàn)過度適合的話,則應(yīng)該刪除任何對(duì)其準(zhǔn)確性無益的特征。此處的挑戰(zhàn)在于,如何找到對(duì)于預(yù)測(cè)結(jié)果貢獻(xiàn)最大的特征。
如上圖所示,過度適合可以通過可視化圖形來識(shí)別。盡管這種方法在使用二維或三維圖形時(shí)效果很好,但是如果使用兩個(gè)以上的特定域特征,則會(huì)變得相當(dāng)困難。因此,交叉驗(yàn)證經(jīng)常被用來檢測(cè)過度適合。
在交叉驗(yàn)證中,一旦學(xué)習(xí)過程結(jié)束,我們便可使用未見過的驗(yàn)證數(shù)據(jù)集,對(duì)訓(xùn)練好的模型進(jìn)行評(píng)估。通常,我們可以將可用的標(biāo)注數(shù)據(jù)集分為三個(gè)部分:
- 訓(xùn)練數(shù)據(jù)集。
- 驗(yàn)證數(shù)據(jù)集。
- 測(cè)試數(shù)據(jù)集。
在上述案例中,60% 的房屋示例記錄可用于訓(xùn)練目標(biāo)算法的不同變體。一旦學(xué)習(xí)過程結(jié)束,剩余的一半未接觸過的示例記錄,將被用于驗(yàn)證訓(xùn)練過的目標(biāo)算法,是否能夠很好地處理未見過的數(shù)據(jù)。
通常情況下,我們會(huì)先選擇一種最合適的目標(biāo)算法。而另一半未經(jīng)處理的示例數(shù)據(jù)將用于計(jì)算最終選定模型的誤差指標(biāo)。當(dāng)然,這種技術(shù)也有其他的變種,比如:k 折交叉驗(yàn)證等。此處就不展開了。
小結(jié)
在上文中,我們?cè)诹私鈾C(jī)器學(xué)習(xí)相關(guān)概念的基礎(chǔ)上,介紹了一個(gè)監(jiān)督學(xué)習(xí)的示例,并使用梯度下降算法來訓(xùn)練目標(biāo)預(yù)測(cè)函數(shù)。同時(shí),我們也討論了一種模型的欠適合示例,以及如何通過添加和擴(kuò)展特征來實(shí)現(xiàn)糾偏。最后,我們還簡(jiǎn)要介紹了過度適合的危險(xiǎn)性,以及如何對(duì)其予以糾正。
譯者介紹
陳峻(Julian Chen),51CTO社區(qū)編輯,具有十多年的IT項(xiàng)目實(shí)施經(jīng)驗(yàn),善于對(duì)內(nèi)外部資源與風(fēng)險(xiǎn)實(shí)施管控,專注傳播網(wǎng)絡(luò)與信息安全知識(shí)與經(jīng)驗(yàn)。
原文標(biāo)題:Machine learning for Java developers: Algorithms for machine learning,作者:Gregor Roth和Matthew Tyson