一文搞定深度學(xué)習(xí)建模預(yù)測全流程(Python)
來源 | 算法進(jìn)階本文詳細(xì)地梳理及實(shí)現(xiàn)了深度學(xué)習(xí)模型構(gòu)建及預(yù)測的全流程,代碼示例基于python及神經(jīng)網(wǎng)絡(luò)庫keras,通過設(shè)計(jì)一個(gè)深度神經(jīng)網(wǎng)絡(luò)模型做波士頓房價(jià)預(yù)測。主要依賴的Python庫有:keras、scikit-learn、pandas、tensorflow(建議可以安裝下anaconda包,自帶有常用的python庫)
一、基礎(chǔ)介紹
- 機(jī)器學(xué)習(xí)
- 深度學(xué)習(xí)
- keras簡介
二、建模流程
深度學(xué)習(xí)的建模預(yù)測流程,與傳統(tǒng)機(jī)器學(xué)習(xí)整體是相同的,主要區(qū)別在于深度學(xué)習(xí)是端對端學(xué)習(xí),可以自動(dòng)提取高層次特征,大大減少了傳統(tǒng)機(jī)器學(xué)習(xí)依賴的特征工程。如下詳細(xì)梳理流程的各個(gè)節(jié)點(diǎn)并附相應(yīng)代碼:
2.1 明確問題及數(shù)據(jù)選擇
2.1.1 明確問題
深度學(xué)習(xí)的建模預(yù)測,首先需要明確問題,即抽象為機(jī)器 / 深度學(xué)習(xí)的預(yù)測問題:需要學(xué)習(xí)什么樣的數(shù)據(jù)作為輸入,目標(biāo)是得到什么樣的模型做決策作為輸出。
2.1.2 數(shù)據(jù)選擇
深度學(xué)習(xí)是端對端學(xué)習(xí),學(xué)習(xí)過程中會提取到高層次抽象的特征,大大弱化特征工程的依賴,正因?yàn)槿绱?,?shù)據(jù)選擇也顯得格外重要,其決定了模型效果的上限。如果數(shù)據(jù)質(zhì)量差,預(yù)測的結(jié)果自然也是很差的——業(yè)界一句名言“garbage in garbage out”。
-
收集房價(jià)相關(guān)的數(shù)據(jù)信息(特征維度)和對應(yīng)房價(jià)(標(biāo)簽),以及盡量多的樣本數(shù)。數(shù)據(jù)信息如該區(qū)域的繁華程度、教育資源、治安等情況就和預(yù)測的房價(jià)比較相關(guān),有代表性。而諸如該區(qū)域“人均養(yǎng)的兔子數(shù)”類數(shù)據(jù)信息,對房價(jià)的預(yù)測就沒那么相關(guān),對于無代表性的數(shù)據(jù)特征的加入,主要會增加人工處理的成本、計(jì)算復(fù)雜度,還有可能引入了模型學(xué)習(xí)的噪音。
-
劃定好數(shù)據(jù)時(shí)間窗口。比如我們可以學(xué)習(xí)該區(qū)域歷史2010~2020年的房價(jià),預(yù)測未來2021的房價(jià)(這是一個(gè)經(jīng)典的時(shí)間序列預(yù)測問題,常用RNN模型)。但卻不能學(xué)習(xí)了2021年或者更后面的未來房價(jià)、人口數(shù)等相關(guān)信息,反過來去預(yù)測2021年房價(jià),這就是一個(gè)數(shù)據(jù)泄露的問題(模型都學(xué)習(xí)了與標(biāo)簽相關(guān)等未知的信息,還預(yù)測個(gè)啥?)。
本節(jié)代碼
如下加載數(shù)據(jù)的代碼,使用的是keras自帶的波士頓房價(jià)數(shù)據(jù)集。一些常用的機(jī)器學(xué)習(xí)開源數(shù)據(jù)集可以到kaggle.com/datasets、archive.ics.uci.edu等網(wǎng)站下載。
(train_x, train_y), (test_x, test_y) = boston_housing.load_data()
波士頓房價(jià)數(shù)據(jù)集是統(tǒng)計(jì)20世紀(jì)70年代中期波士頓郊區(qū)房價(jià)等情況,有當(dāng)時(shí)城鎮(zhèn)的犯罪率、房產(chǎn)稅等共計(jì)13個(gè)指標(biāo)(特征)以及對應(yīng)的房價(jià)中位數(shù)(標(biāo)簽)。
2.2 特征工程
特征工程就是對原始數(shù)據(jù)分析處理,轉(zhuǎn)化為模型可用的特征。這些特征可以更好地向預(yù)測模型描述潛在規(guī)律,從而提高模型對未見數(shù)據(jù)的準(zhǔn)確性。對于深度學(xué)習(xí)模型,特征生成等加工不多,主要是一些數(shù)據(jù)的分析、預(yù)處理,然后就可以灌入神經(jīng)網(wǎng)絡(luò)模型了。
2.2.1 探索性數(shù)據(jù)分析
選擇好數(shù)據(jù)后,可以先做探索性數(shù)據(jù)分析(EDA)去理解數(shù)據(jù)本身的內(nèi)部結(jié)構(gòu)及規(guī)律。如果你對數(shù)據(jù)情況不了解,也沒有相關(guān)的業(yè)務(wù)背景知識,不做相關(guān)的分析及預(yù)處理,直接將數(shù)據(jù)喂給模型往往效果不太好。通過探索性數(shù)據(jù)分析,可以了解數(shù)據(jù)分布、缺失、異常及相關(guān)性等情況。
本節(jié)代碼
我們可以通過EDA數(shù)據(jù)分析庫如pandas profiling,自動(dòng)生成分析報(bào)告,可以看到這份現(xiàn)成的數(shù)據(jù)集是比較"干凈的":
import pandas_profiling
# 特征名稱
feature_name = ['CRIM|住房所在城鎮(zhèn)的人均犯罪率',
'ZN|住房用地超過 25000 平方尺的比例',
'INDUS|住房所在城鎮(zhèn)非零售商用土地的比例',
'CHAS|有關(guān)查理斯河的虛擬變量(如果住房位于河邊則為1,否則為0 )',
'NOX|一氧化氮濃度',
'RM|每處住房的平均房間數(shù)',
'AGE|建于 1940 年之前的業(yè)主自住房比例',
'DIS|住房距離波士頓五大中心區(qū)域的加權(quán)距離',
'RAD|距離住房最近的公路入口編號',
'TAX 每 10000 美元的全額財(cái)產(chǎn)稅金額',
'PTRATIO|住房所在城鎮(zhèn)的師生比例',
'B|1000(Bk|0.63)^2,其中 Bk 指代城鎮(zhèn)中黑人的比例',
'LSTAT|弱勢群體人口所占比例']
train_df = pd.DataFrame(train_x, columns=feature_name) # 轉(zhuǎn)為df格式
pandas_profiling.ProfileReport(train_df)
2.2.2 特征表示
像圖像、文本字符類的數(shù)據(jù),需要轉(zhuǎn)換為計(jì)算機(jī)能夠處理的數(shù)值形式。圖像數(shù)據(jù)(pixel image)實(shí)際上是由一個(gè)像素組成的矩陣所構(gòu)成的,而每一個(gè)像素點(diǎn)又是由RGB顏色通道中分別代表R、G、B的一個(gè)三維向量表示,所以圖像實(shí)際上可以用RGB三維矩陣(3-channel matrix)的表示(第一個(gè)維度:高度,第二個(gè)維度:寬度,第三個(gè)維度:RGB通道),最終再重塑為一列向量(reshaped image vector)方便輸入模型。
本節(jié)代碼
數(shù)據(jù)集已是數(shù)值類數(shù)據(jù),本節(jié)不做處理。
2.2.2 特征清洗
-
異常值處理 收集的數(shù)據(jù)由于人為或者自然因素可能引入了異常值(噪音),這會對模型學(xué)習(xí)進(jìn)行干擾。通常需要處理人為引起的異常值,通過業(yè)務(wù)及技術(shù)手段(如數(shù)據(jù)分布、3σ準(zhǔn)則)判定異常值,再結(jié)合實(shí)際業(yè)務(wù)含義刪除或者替換掉異常值。
-
缺失值處理 神經(jīng)網(wǎng)絡(luò)模型缺失值的處理是必要的,數(shù)據(jù)缺失值可以通過結(jié)合業(yè)務(wù)進(jìn)行填充數(shù)值或者刪除。① 缺失率較高,結(jié)合業(yè)務(wù)可以直接刪除該特征變量。經(jīng)驗(yàn)上可以新增一個(gè)bool類型的變量特征記錄該字段的缺失情況,缺失記為1,非缺失記為0;② 缺失率較低,可使用一些缺失值填充手段,如結(jié)合業(yè)務(wù)fillna為0或-9999或平均值,或者訓(xùn)練回歸模型預(yù)測缺失值并填充。
本節(jié)代碼
從數(shù)據(jù)分析報(bào)告可見,波士頓房價(jià)數(shù)據(jù)集無異常、缺失值情況,本節(jié)不做處理。
2.2.3 特征生成
特征生成作用在于彌補(bǔ)基礎(chǔ)特征對樣本信息的表達(dá)有限,增加特征的非線性表達(dá)能力,提升模型效果。它是根據(jù)基礎(chǔ)特征的含義進(jìn)行某種處理(聚合 / 轉(zhuǎn)換之類),常用方法如人工設(shè)計(jì)、自動(dòng)化特征衍生(如featuretools工具):深度神經(jīng)網(wǎng)絡(luò)會自動(dòng)學(xué)習(xí)到高層次特征,常見的深度學(xué)習(xí)的任務(wù),圖像類、文本類任務(wù)通常很少再做特征生成。而對于數(shù)值類的任務(wù),加工出顯著特征對加速模型的學(xué)習(xí)是有幫助的,可以做嘗試。
本節(jié)代碼
特征已經(jīng)比較全面,本節(jié)不再做處理,可自行驗(yàn)證特征生成的效果。
2.2.4 特征選擇
特征選擇用于篩選出顯著特征、摒棄非顯著特征。這樣做主要可以減少特征(避免維度災(zāi)難),提高訓(xùn)練速度,降低運(yùn)算開銷;減少干擾噪聲,降低過擬合風(fēng)險(xiǎn),提升模型效果。常用的特征選擇方法有:過濾法(如特征缺失率、單值率、相關(guān)系數(shù))、包裝法(如RFE遞歸特征消除、雙向搜索)、嵌入法(如帶L1正則項(xiàng)的模型、樹模型自帶特征選擇)。
本節(jié)代碼
模型使用L1正則項(xiàng)方法,本節(jié)不再做處理,可自行驗(yàn)證其他方法。
2.3 模型訓(xùn)練
神經(jīng)網(wǎng)絡(luò)模型的訓(xùn)練主要有3個(gè)步驟:
- 構(gòu)建模型結(jié)構(gòu)(主要有神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計(jì)、激活函數(shù)的選擇、模型權(quán)重如何初始化、網(wǎng)絡(luò)層是否批標(biāo)準(zhǔn)化、正則化策略的設(shè)定)
- 模型編譯(主要有學(xué)習(xí)目標(biāo)、優(yōu)化算法的設(shè)定)
- 模型訓(xùn)練及超參數(shù)調(diào)試(主要有劃分?jǐn)?shù)據(jù)集,超參數(shù)調(diào)節(jié)及訓(xùn)練)
2.3.1 模型結(jié)構(gòu)
常見的神經(jīng)網(wǎng)絡(luò)模型結(jié)構(gòu)有全連接神經(jīng)網(wǎng)絡(luò)(FCN)、RNN(常用于文本 / 時(shí)間系列任務(wù))、CNN(常用于圖像任務(wù))等等。
- 輸入層:為數(shù)據(jù)特征輸入層,輸入數(shù)據(jù)特征維數(shù)就對應(yīng)著網(wǎng)絡(luò)的神經(jīng)元數(shù)。(注:輸入層不計(jì)入模型層數(shù))
- 隱藏層:即網(wǎng)絡(luò)的中間層(可以很多層),其作用接受前一層網(wǎng)絡(luò)輸出作為當(dāng)前的輸入值,并計(jì)算輸出當(dāng)前結(jié)果到下一層。隱藏層的層數(shù)及神經(jīng)元個(gè)數(shù)直接影響模型的擬合能力。
- 輸出層:為最終結(jié)果輸出的網(wǎng)絡(luò)層。輸出層的神經(jīng)元個(gè)數(shù)代表了分類類別的個(gè)數(shù)(注:在做二分類時(shí)情況特殊一點(diǎn),如果輸出層的激活函數(shù)采用sigmoid,輸出層的神經(jīng)元個(gè)數(shù)為1個(gè);如果采用softmax,輸出層神經(jīng)元個(gè)數(shù)為2個(gè)是與分類類別個(gè)數(shù)對應(yīng)的;)
2.3.2 激活函數(shù)
根據(jù)萬能近似原理,簡單來說,神經(jīng)網(wǎng)絡(luò)有“夠深的網(wǎng)絡(luò)層”以及“至少一層帶激活函數(shù)的隱藏層”,既可以擬合任意的函數(shù)。可見激活函數(shù)的重要性,它起著特征空間的非線性轉(zhuǎn)換。對于激活函數(shù)選擇的經(jīng)驗(yàn)性做法:
- 對于輸出層,二分類的輸出層的激活函數(shù)常選擇sigmoid函數(shù),多分類選擇softmax;回歸任務(wù)根據(jù)輸出值范圍來確定使不使用激活函數(shù)。
- 對于隱藏層的激活函數(shù)通常會選擇使用ReLU函數(shù),保證學(xué)習(xí)效率。
2.3.3 權(quán)重初始化
權(quán)重參數(shù)初始化可以加速模型收斂速度,影響模型結(jié)果。常用的初始化方法有:
- uniform均勻分布初始化
- normal高斯分布初始化 需要注意的是,權(quán)重不能初始化為0,這會導(dǎo)致多個(gè)隱藏神經(jīng)元的作用等同于1個(gè)神經(jīng)元,無法收斂。
2.3.4 批標(biāo)準(zhǔn)化
batch normalization(BN)批標(biāo)準(zhǔn)化,是神經(jīng)網(wǎng)絡(luò)模型常用的一種優(yōu)化方法。它的原理很簡單,即是對原來的數(shù)值進(jìn)行標(biāo)準(zhǔn)化處理:batch normalization在保留輸入信息的同時(shí),消除了層與層間的分布差異,具有加快收斂,同時(shí)有類似引入噪聲正則化的效果。它可應(yīng)用于網(wǎng)絡(luò)的輸入層或隱藏層,當(dāng)用于輸入層,就是線性模型常用的特征標(biāo)準(zhǔn)化處理。
2.3.5 正則化
正則化是在以(可能)增加經(jīng)驗(yàn)損失為代價(jià),以降低泛化誤差為目的,抑制過擬合,提高模型泛化能力的方法。經(jīng)驗(yàn)上,對于復(fù)雜任務(wù),深度學(xué)習(xí)模型偏好帶有正則化的較復(fù)雜模型,以達(dá)到較好的學(xué)習(xí)效果。常見的正則化策略有:dropout,L1、L2、earlystop方法。
2.3.6 選擇學(xué)習(xí)目標(biāo)
機(jī)器 / 深度學(xué)習(xí)通過學(xué)習(xí)到“好”的模型去決策,“好”即是機(jī)器 / 深度學(xué)習(xí)的學(xué)習(xí)目標(biāo),通常也就是預(yù)測值與目標(biāo)值之間的誤差盡可能的低。衡量這種誤差的函數(shù)稱為代價(jià)函數(shù) (Cost Function)或者損失函數(shù)(Loss Function),更具體地說,機(jī)器 / 深度學(xué)習(xí)的目標(biāo)是極大化降低損失函數(shù)。
- 均方誤差損失函數(shù)
- 交叉熵?fù)p失函數(shù)
2.3.7 選擇優(yōu)化算法
當(dāng)我們機(jī)器 / 深度學(xué)習(xí)的學(xué)習(xí)目標(biāo)是極大化降低(某個(gè))損失函數(shù),那么如何實(shí)現(xiàn)這個(gè)目標(biāo)呢?通常機(jī)器學(xué)習(xí)模型的損失函數(shù)較復(fù)雜,很難直接求損失函數(shù)最小的公式解。幸運(yùn)的是,我們可以通過優(yōu)化算法(如梯度下降、隨機(jī)梯度下降、Adam等)有限次迭代優(yōu)化模型參數(shù),以盡可能降低損失函數(shù)的值,得到較優(yōu)的參數(shù)值。
2.3.8 模型訓(xùn)練及超參數(shù)調(diào)試
- 劃分?jǐn)?shù)據(jù)集
- 超參數(shù)調(diào)試
本節(jié)代碼
- 創(chuàng)建模型結(jié)構(gòu)結(jié)合當(dāng)前房價(jià)預(yù)測任務(wù)是一個(gè)經(jīng)典簡單表格數(shù)據(jù)的回歸預(yù)測任務(wù)。我們采用基礎(chǔ)的全連接神經(jīng)網(wǎng)絡(luò),隱藏層的深度一兩層也就差不多。通過keras.Sequential方法來創(chuàng)建一個(gè)神經(jīng)網(wǎng)絡(luò)模型,并在依次添加帶有批標(biāo)準(zhǔn)化的輸入層,一層帶有relu激活函數(shù)的k個(gè)神經(jīng)元的隱藏層,并對這層隱藏層添加dropout、L1、L2正則的功能。由于回歸預(yù)測數(shù)值實(shí)際范圍(5~50 )直接用線性輸出層,不需要加激活函數(shù)。
import matplotlib.pyplot as plt
%matplotlib inline
from tensorflow import random
from keras import regularizers
from keras.layers import Dense,Dropout,BatchNormalization
from keras.models import Sequential, Model
from keras.callbacks import EarlyStopping
from sklearn.metrics import mean_squared_error
np.random.seed(1) # 固定隨機(jī)種子,使每次運(yùn)行結(jié)果固定
random.set_seed(1)
# 創(chuàng)建模型結(jié)構(gòu):輸入層的特征維數(shù)為13;1層k個(gè)神經(jīng)元的relu隱藏層;線性的輸出層;
for k in [5,20,50]: # 網(wǎng)格搜索超參數(shù):神經(jīng)元數(shù)k
model = Sequential()
model.add(BatchNormalization(input_dim=13)) # 輸入層 批標(biāo)準(zhǔn)化
model.add(Dense(k,
kernel_initializer='random_uniform', # 均勻初始化
activation='relu', # relu激活函數(shù)
kernel_regularizer=regularizers.l1_l2(l1=0.01, l2=0.01), # L1及L2 正則項(xiàng)
use_bias=True)) # 隱藏層
model.add(Dropout(0.1)) # dropout法
model.add(Dense(1,use_bias=True)) # 輸出層
- 模型編譯設(shè)定學(xué)習(xí)目標(biāo)為(最小化)回歸預(yù)測損失mse,優(yōu)化算法為adam
- 模型訓(xùn)練我們通過傳入訓(xùn)練集x,訓(xùn)練集標(biāo)簽y,使用fit(擬合)方法來訓(xùn)練模型,其中epochs為迭代次數(shù),并通過EarlyStopping及時(shí)停止在合適的epoch,減少過擬合;batch_size為每次epoch隨機(jī)采樣的訓(xùn)練樣本數(shù)目。
history = model.fit(train_x,
train_y,
epochs=500, # 訓(xùn)練迭代次數(shù)
batch_size=50, # 每epoch采樣的batch大小
validation_split=0.1, # 從訓(xùn)練集再拆分驗(yàn)證集,作為早停的衡量指標(biāo)
callbacks=[EarlyStopping(monitor='val_loss', patience=20)], #早停法
verbose=False) # 不輸出過程
print("驗(yàn)證集最優(yōu)結(jié)果:",min(history.history['val_loss']))
model.summary() #打印模型概述信息
# 模型評估:擬合效果
plt.plot(history.history['loss'],c='blue') # 藍(lán)色線訓(xùn)練集損失
plt.plot(history.history['val_loss'],c='red') # 紅色線驗(yàn)證集損失
plt.show()
最后,這里簡單采用for循環(huán),實(shí)現(xiàn)類似網(wǎng)格搜索調(diào)整超參數(shù),驗(yàn)證了隱藏層的不同神經(jīng)元數(shù)目(超參數(shù)k)的效果。由驗(yàn)證結(jié)果來看,神經(jīng)元數(shù)目為50時(shí),損失可以達(dá)到10的較優(yōu)效果(可以繼續(xù)嘗試模型增加深度、寬度,達(dá)到過擬合的邊界應(yīng)該有更好的效果)。
2.4 模型評估及優(yōu)化
機(jī)器學(xué)習(xí)學(xué)習(xí)的目標(biāo)是極大化降低損失函數(shù),但這不僅僅是學(xué)習(xí)過程中對訓(xùn)練數(shù)據(jù)有良好的預(yù)測能力(極低的訓(xùn)練損失),根本上還在于要對新數(shù)據(jù)(測試集)能有很好的預(yù)測能力(泛化能力)。
- 評估模型誤差的指標(biāo)
查準(zhǔn)率P:是指分類器預(yù)測為Positive的正確樣本(TP)的個(gè)數(shù)占所有預(yù)測為Positive樣本個(gè)數(shù)(TP FP)的比例;查全率R:是指分類器預(yù)測為Positive的正確樣本(TP)的個(gè)數(shù)占所有的實(shí)際為Positive樣本個(gè)數(shù)(TP FN)的比例。F1-score是查準(zhǔn)率P、查全率R的調(diào)和平均:注:如分類任務(wù)的f1-score等指標(biāo)只能用于評估模型最終效果,因?yàn)樽鳛閷W(xué)習(xí)目標(biāo)時(shí)它們無法被高效地優(yōu)化,訓(xùn)練優(yōu)化時(shí)常用交叉熵作為其替代的分類損失函數(shù) (surrogate loss function)。
- 評估擬合效果
- 優(yōu)化擬合效果的方法
本節(jié)代碼
# 模型評估:擬合效果import matplotlib.pyplot as plt
plt.plot(history.history['loss'],c='blue') # 藍(lán)色線訓(xùn)練集損失
plt.plot(history.history['val_loss'],c='red') # 紅色線驗(yàn)證集損失
從訓(xùn)練集及驗(yàn)證集的損失來看,訓(xùn)練集、驗(yàn)證集損失都比較低,模型沒有過擬合現(xiàn)象。
pred_y = model.predict(test_x)[:,0]
print("正確標(biāo)簽:",test_y)
print("模型預(yù)測:",pred_y )
print("實(shí)際與預(yù)測值的差異:",mean_squared_error(test_y,pred_y ))
#繪圖表示
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 設(shè)置圖形大小
plt.figure(figsize=(8, 4), dpi=80)
plt.plot(range(len(test_y)), test_y, ls='-.',lw=2,c='r',label='真實(shí)值')
plt.plot(range(len(pred_y)), pred_y, ls='-',lw=2,c='b',label='預(yù)測值')
# 繪制網(wǎng)格
plt.grid(alpha=0.4, linestyle=':')
plt.legend()
plt.xlabel('number') #設(shè)置x軸的標(biāo)簽文本
plt.ylabel('房價(jià)') #設(shè)置y軸的標(biāo)簽文本
# 展示
plt.show()
評估測試集的預(yù)測結(jié)果,其mse損失為19.7,觀察測試集的實(shí)際值與預(yù)測值兩者的數(shù)值曲線是比較一致的!模型預(yù)測效果較好。
2.5 模型預(yù)測結(jié)果及解釋性
決策應(yīng)用是機(jī)器學(xué)習(xí)最終目的,對模型預(yù)測信息加以分析解釋,并應(yīng)用于實(shí)際的工作領(lǐng)域。
本節(jié)代碼
如下通過SHAP方法,對模型預(yù)測單個(gè)樣本的結(jié)果做出解釋,可見在這個(gè)樣本的預(yù)測中,CRIM犯罪率為0.006、RM平均房間數(shù)為6.575對于房價(jià)是負(fù)相關(guān)的。LSTAT弱勢群體人口所占比例為4.98對于房價(jià)的貢獻(xiàn)是正相關(guān)的...,在綜合這些因素后模型給出最終預(yù)測值。
import tensorflow as tf # tf版本<2.0
# 模型解釋性
background = test_x[np.random.choice(test_x.shape[0],100, replace=False)]
explainer = shap.DeepExplainer(model,background)
shap_values = explainer.shap_values(test_x) # 傳入特征矩陣X,計(jì)算SHAP值
# 可視化第一個(gè)樣本預(yù)測的解釋
shap.force_plot(explainer.expected_value, shap_values[0,:], test_x.iloc[0,:])