Keras: 多输入及混合数据输入的神经网络模型
目錄
?
摘要
正文
什么是混合數(shù)據(jù)?
Keras如何接受多個(gè)輸入?
房價(jià)數(shù)據(jù)集
獲取房價(jià)數(shù)據(jù)集
項(xiàng)目結(jié)構(gòu)
加載數(shù)值和分類數(shù)據(jù)
加載圖像數(shù)據(jù)集
定義多層感知器(MLP)和卷積神經(jīng)網(wǎng)絡(luò)(CNN)
使用Keras的多個(gè)輸入
多輸入和混合數(shù)據(jù)結(jié)果
總結(jié)
翻譯自:Keras: Multiple Inputs and Mixed Data, by Adrian Rosebrock.
摘要
點(diǎn)擊此處下載源代碼:https://jbox.sjtu.edu.cn/l/NHfFZu
以回歸預(yù)測房價(jià)作為背景。房價(jià)數(shù)據(jù)集不僅包括數(shù)值和類別數(shù)據(jù),同樣也包括圖像數(shù)據(jù),稱之為多種類型的混合數(shù)據(jù)。模型需要能夠接受多種類型的混合數(shù)據(jù)輸入,并且計(jì)算得出回歸問題的輸出值。
在本教程的其余部分,您將學(xué)習(xí)如何:
正文
在本教程的第一部分中,我們將簡要回顧混合數(shù)據(jù)的概念以及Keras如何接受多個(gè)類型輸入數(shù)據(jù)。
什么是混合數(shù)據(jù)?
圖1:使用靈活的Keras深度學(xué)習(xí)框架,可以定義一個(gè)多輸入模型,其分別包括CNN和MLP分支來分別處理混合數(shù)據(jù)。
混合數(shù)據(jù)指的是同時(shí)使用不同數(shù)據(jù)類型的輸入數(shù)據(jù)。
例如,假設(shè)我們是在一家醫(yī)院工作的機(jī)器學(xué)習(xí)工程師,要開發(fā)一個(gè)能夠?qū)Σ∪说慕】禒顩r進(jìn)行分類的系統(tǒng)。
我們擁有一個(gè)病人的多種類型的輸入數(shù)據(jù),包括:
我們的機(jī)器學(xué)習(xí)模型必須能夠?qū)⑦@些**“混合數(shù)據(jù)”**,并對病人的健康狀況做出(準(zhǔn)確的)預(yù)測。
開發(fā)能夠處理混合數(shù)據(jù)的機(jī)器學(xué)習(xí)系統(tǒng)非常具有挑戰(zhàn)性,因?yàn)槊糠N數(shù)據(jù)類型可能需要單獨(dú)的預(yù)處理步驟,包括縮放、標(biāo)準(zhǔn)化和特征工程(feature engineering)。
處理混合數(shù)據(jù)仍然是一個(gè)非常開放的研究領(lǐng)域,并且常常嚴(yán)重依賴于特定的任務(wù)/目標(biāo)。
Keras如何接受多個(gè)輸入?
Keras能夠通過它的函數(shù)API處理多個(gè)輸入(甚至多個(gè)輸出)。
您以前肯定通過Sequential 類使用過順序式API,函數(shù)式API與之相反相反,可用于定義非順序的復(fù)雜得多的模型,包括:
- 多輸入模型
- 多輸出模型
- 模型包括多個(gè)輸入和多個(gè)輸出
- 有向無環(huán)圖
- 具有共享層的模型
例如,我們可以將一個(gè)簡單的序列神經(jīng)網(wǎng)絡(luò)定義為:
model = Sequential() model.add(Dense(8, input_shape=(10,), activation="relu")) model.add(Dense(4, activation="relu")) model.add(Dense(1, activation="linear"))該網(wǎng)絡(luò)是一個(gè)簡單的前饋神經(jīng)網(wǎng)絡(luò),有10個(gè)輸入,第一個(gè)隱層有8個(gè)節(jié)點(diǎn),第二個(gè)隱層有4個(gè)節(jié)點(diǎn),最后一個(gè)輸出層用于回歸。
我們可以使用functional API定義樣本神經(jīng)網(wǎng)絡(luò):
inputs = Input(shape=(10,)) x = Dense(8, activation="relu")(inputs) x = Dense(4, activation="relu")(x) x = Dense(1, activation="linear")(x) model = Model(inputs, x)# define two sets of inputs inputA = Input(shape=(32,)) inputB = Input(shape=(128,))# the first branch operates on the first input x = Dense(8, activation="relu")(inputA) x = Dense(4, activation="relu")(x) x = Model(inputs=inputA, outputs=x)# the second branch opreates on the second input y = Dense(64, activation="relu")(inputB) y = Dense(32, activation="relu")(y) y = Dense(4, activation="relu")(y) y = Model(inputs=inputB, outputs=y)# combine the output of the two branches combined = concatenate([x.output, y.output])# apply a FC layer and then a regression prediction on the # combined outputs z = Dense(2, activation="relu")(combined) z = Dense(1, activation="linear")(z)# our model will accept the inputs of the two branches and # then output a single value model = Model(inputs=[x.input, y.input], outputs=z)可以看到我們定義了Keras神經(jīng)網(wǎng)絡(luò)的兩個(gè)輸入:
- inputA: 32維
- inputB: 128維
可視化模型架構(gòu)為:
圖2:這個(gè)模型有兩個(gè)輸入分支,它們最終合并并產(chǎn)生一個(gè)輸出。Keras函數(shù)API允許這種類型的體系結(jié)構(gòu),你也可以構(gòu)建任何其他您可以想象的架構(gòu)。
注意我們的模型有兩個(gè)不同的分支。
第一個(gè)分支接受128維輸入,而第二個(gè)分支接受32維輸入。這些分支在連接之前彼此獨(dú)立運(yùn)行,連接之后輸出一個(gè)值。
在本教程的其余部分中,您將學(xué)習(xí)如何使用Keras創(chuàng)建多輸入的網(wǎng)絡(luò)。
房價(jià)數(shù)據(jù)集
圖4:房價(jià)數(shù)據(jù)集包括數(shù)值數(shù)據(jù),類別數(shù)據(jù)和圖像數(shù)據(jù)。使用Keras,我們將構(gòu)建一個(gè)支持多種輸入和混合數(shù)據(jù)類型的模型,并且通過這個(gè)回歸模型預(yù)測房屋的價(jià)值。
在這一系列文章中,我們使用了Ahmed和Mustafa在2016年發(fā)表的論文《從視覺和文本特征估計(jì)房價(jià)》(House price estimate from visual and text features)中的房價(jià)數(shù)據(jù)集。
這個(gè)數(shù)據(jù)集包括535個(gè)示例房屋的數(shù)值數(shù)據(jù),類別數(shù)據(jù)以及圖像數(shù)據(jù)。
數(shù)值屬性和分類屬性包括:
每棟房子一共提供了四幅圖片:
在本系列的第一篇文章中,您學(xué)習(xí)了如何根據(jù)數(shù)值和分類數(shù)據(jù)訓(xùn)練Keras回歸網(wǎng)絡(luò)。
在本系列的第二篇文章中,您學(xué)習(xí)了如何使用Keras CNN進(jìn)行回歸。
今天我們將使用Keras處理多個(gè)輸入和混合數(shù)據(jù)。
我們將接受數(shù)值數(shù)據(jù),類別數(shù)據(jù)和圖像數(shù)據(jù),通過定義網(wǎng)絡(luò)的兩個(gè)分支來處理每種類型的數(shù)據(jù),最后將這些分支合并起來,得到我們最終的房價(jià)預(yù)測。通過這種方式,我們將能夠利用Keras處理多個(gè)輸入和混合數(shù)據(jù)。
獲取房價(jià)數(shù)據(jù)集
點(diǎn)擊此處下載源代碼:https://jbox.sjtu.edu.cn/l/NHfFZu
房價(jià)數(shù)據(jù)集應(yīng)該在keras-multi-input目錄中,這是我們在這個(gè)項(xiàng)目中使用的目錄。
項(xiàng)目結(jié)構(gòu)
$ tree --dirsfirst --filelimit 10 . ├── Houses-dataset │ ├── Houses\ Dataset [2141 entries] │ └── README.md ├── pyimagesearch │ ├── __init__.py │ ├── datasets.py │ └── models.py └── mixed_training.py3 directories, 5 filesHouses-dataset文件夾包含我們在本系列中使用的房價(jià)數(shù)據(jù)集。當(dāng)我們準(zhǔn)備好運(yùn)行mixed_training.py腳本時(shí),您只需要提供一個(gè)路徑作為數(shù)據(jù)集的命令行參數(shù)(我將在結(jié)果部分向您詳細(xì)說明這是如何完成的)。
今天我們將回顧三個(gè)Python腳本:
-
pyimagesearch/datasets.py: 加載和預(yù)處理我們的數(shù)字?jǐn)?shù)據(jù),類別數(shù)據(jù)以及圖像數(shù)據(jù)。
-
pyimagesearch/models.py: 包含多層感知器(MLP)和卷積神經(jīng)網(wǎng)絡(luò)(CNN)。這些組件是我們的多輸入混合數(shù)據(jù)模型的輸入分支。
-
mixed_training.py: 首先我們的訓(xùn)練腳本將使用pyimagesearch模塊來加載和分割訓(xùn)練數(shù)據(jù)集,添加數(shù)據(jù)頭,并將兩個(gè)分支連接到我們的網(wǎng)絡(luò)。然后對模型進(jìn)行培訓(xùn)和評估。
加載數(shù)值和分類數(shù)據(jù)
# import the necessary packages from sklearn.preprocessing import LabelBinarizer from sklearn.preprocessing import MinMaxScaler import pandas as pd import numpy as np import glob import cv2 import osdef load_house_attributes(inputPath):# initialize the list of column names in the CSV file and then# load it using Pandascols = ["bedrooms", "bathrooms", "area", "zipcode", "price"]df = pd.read_csv(inputPath, sep=" ", header=None, names=cols)# determine (1) the unique zip codes and (2) the number of data# points with each zip codezipcodes = df["zipcode"].value_counts().keys().tolist()counts = df["zipcode"].value_counts().tolist()# loop over each of the unique zip codes and their corresponding# countfor (zipcode, count) in zip(zipcodes, counts):# the zip code counts for our housing dataset is *extremely*# unbalanced (some only having 1 or 2 houses per zip code)# so let's sanitize our data by removing any houses with less# than 25 houses per zip codeif count < 25:idxs = df[df["zipcode"] == zipcode].indexdf.drop(idxs, inplace=True)# return the data framereturn dfload_house_attributes函數(shù)。該函數(shù)通過panda的pd以CSV文件的形式從房價(jià)數(shù)據(jù)集中讀取數(shù)值和類別數(shù)據(jù)。
原始數(shù)據(jù)需要經(jīng)過過濾以適應(yīng)樣本分布的不均勻性。如有些郵編僅由1或2所房子表示,因此我們要?jiǎng)h除(第23-30行)來自郵編少于25所房子的任何記錄。這樣郵編樣本數(shù)量分布不均勻的問題可以得到緩解,這樣做的結(jié)果是得到一個(gè)更精確的模型。
定義process_house_attributes函數(shù):
def process_house_attributes(df, train, test):# initialize the column names of the continuous datacontinuous = ["bedrooms", "bathrooms", "area"]# performin min-max scaling each continuous feature column to# the range [0, 1]cs = MinMaxScaler()trainContinuous = cs.fit_transform(train[continuous])testContinuous = cs.transform(test[continuous])# one-hot encode the zip code categorical data (by definition of# one-hot encoding, all output features are now in the range [0, 1])zipBinarizer = LabelBinarizer().fit(df["zipcode"])trainCategorical = zipBinarizer.transform(train["zipcode"])testCategorical = zipBinarizer.transform(test["zipcode"])# construct our training and testing data points by concatenating# the categorical features with the continuous featurestrainX = np.hstack([trainCategorical, trainContinuous])testX = np.hstack([testCategorical, testContinuous])# return the concatenated training and testing datareturn (trainX, testX)這個(gè)函數(shù)通過scikit-learn的MinMaxScaler(第41-43行)對連續(xù)特性應(yīng)用最小-最大縮放。
然后,通過scikit-learn的LabelBinarizer(第47-49行)計(jì)算分類特征的one-hot編碼。
然后將連續(xù)的和分類的特性連接起來并返回
加載圖像數(shù)據(jù)集
圖6:我們模型的一個(gè)分支接受一個(gè)圖像——來自房屋的四個(gè)圖像的拼合圖像。利用拼合圖像結(jié)合數(shù)字,類別數(shù)據(jù),輸入到另一個(gè)分支,然后我們的模型使用Keras框架回歸與預(yù)測住宅的價(jià)值。
下一步是定義一個(gè)helper函數(shù)來加載輸入圖像。同樣,打開data .py文件并插入以下代碼:
def load_house_images(df, inputPath):# initialize our images array (i.e., the house images themselves)images = []# loop over the indexes of the housesfor i in df.index.values:# find the four images for the house and sort the file paths,# ensuring the four are always in the *same order*basePath = os.path.sep.join([inputPath, "{}_*".format(i + 1)])housePaths = sorted(list(glob.glob(basePath)))load_house_images函數(shù)有三個(gè)功能:
繼續(xù):
- 初始化圖像列表(第61行)并將用我們創(chuàng)建的所有拼合圖像填充這個(gè)列表。
- 循環(huán)遍歷數(shù)據(jù)幀中的房屋(第64行)以獲取當(dāng)前住宅的四張照片的路徑
循環(huán)內(nèi)部:
# initialize our list of input images along with the output image# after *combining* the four input imagesinputImages = []outputImage = np.zeros((64, 64, 3), dtype="uint8")# loop over the input house pathsfor housePath in housePaths:# load the input image, resize it to be 32 32, and then# update the list of input imagesimage = cv2.imread(housePath)image = cv2.resize(image, (32, 32))inputImages.append(image)# tile the four input images in the output image such the first# image goes in the top-right corner, the second image in the# top-left corner, the third image in the bottom-right corner,# and the final image in the bottom-left corneroutputImage[0:32, 0:32] = inputImages[0]outputImage[0:32, 32:64] = inputImages[1]outputImage[32:64, 32:64] = inputImages[2]outputImage[32:64, 0:32] = inputImages[3]# add the tiled image to our set of images the network will be# trained onimages.append(outputImage)# return our set of imagesreturn np.array(images)到目前為止,代碼已經(jīng)完成了上面討論的第一個(gè)目標(biāo)(每個(gè)房子抓取四個(gè)圖像)。
-
在循環(huán)中,我們:
-
執(zhí)行初始化(第72行和第73行)。我們的inputImages將以列表的形式包含每條記錄的四張照片。我們的inputImages將是照片的拼接圖像(如圖6所示)。
-
循環(huán)4張照片(第76行):
- 加載、調(diào)整大小并將每張照片附加到?inputImages中(第79-81行)。
-
為四個(gè)房子的圖片(第87-90行)創(chuàng)建平鋪(拼接圖像):
- 左上方的浴室圖片。
- 右上角的臥室圖片。
- 右下角的正面視圖。
- 廚房在左下角。
-
添加拼接outputImage到images(第94行)。
-
-
跳出循環(huán),我們以NumPy數(shù)組的形式返回所有圖像(第97行)。
定義多層感知器(MLP)和卷積神經(jīng)網(wǎng)絡(luò)(CNN)
圖7:Keras多輸入(混合數(shù)據(jù))模型有一個(gè)分支接受數(shù)字/類別數(shù)據(jù)(左),另一個(gè)分支接受4張照片拼接形式的圖像數(shù)據(jù)(右)。
到目前為止,我們已經(jīng)使用了多個(gè)庫對數(shù)據(jù)進(jìn)行了仔細(xì)的處理:panda、scikit-learn、OpenCV和NumPy。
我們已經(jīng)通過datasets.py對數(shù)據(jù)集的兩種模式進(jìn)行了組織和預(yù)處理。
- 數(shù)字和分類數(shù)據(jù)
- 圖像數(shù)據(jù)
為了實(shí)現(xiàn)這一點(diǎn),我們所使用的技能是通過經(jīng)驗(yàn)和實(shí)踐一點(diǎn)點(diǎn)調(diào)試開發(fā)出來的。請不要忽視我們到目前為止所討論和使用的數(shù)據(jù)處理技巧,因?yàn)樗俏覀冺?xiàng)目成功的關(guān)鍵。
讓我們換個(gè)話題,討論一下我們將如何使用Keras的函數(shù)API構(gòu)建的多輸入和混合數(shù)據(jù)網(wǎng)絡(luò)。
為了建立我們的多輸入網(wǎng)絡(luò),我們需要兩個(gè)分支:
- 第一個(gè)分支是一個(gè)簡單的多層感知器(MLP),用于處理數(shù)值輸入。
- 第二個(gè)分支是卷積神經(jīng)網(wǎng)絡(luò),用于對圖像數(shù)據(jù)進(jìn)行操作。
- 然后將這些分支連接在一起,形成最終的多輸入Keras模型。
我們將在下一節(jié)中處理構(gòu)建最終的連接多輸入模型,我們當(dāng)前的任務(wù)是定義這兩個(gè)分支。
打開models.py文件,插入如下代碼:
# import the necessary packages from keras.models import Sequential from keras.layers.normalization import BatchNormalization from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.layers.core import Activation from keras.layers.core import Dropout from keras.layers.core import Dense from keras.layers import Flatten from keras.layers import Input from keras.models import Modeldef create_mlp(dim, regress=False):# define our MLP networkmodel = Sequential()model.add(Dense(8, input_dim=dim, activation="relu"))model.add(Dense(4, activation="relu"))# check to see if the regression node should be addedif regress:model.add(Dense(1, activation="linear"))# return our modelreturn model我們的類別/數(shù)值數(shù)據(jù)將由一個(gè)簡單的多層感知器(MLP)處理。
MLP由create_mlp定義。
我們的MLP很簡單:
- 具有ReLU激活的完全連接(密集)輸入層
- 一個(gè)完全連接的隱藏層,也帶有ReLU激活
- 最后,一個(gè)線性激活的可選的回歸輸出
雖然我們在第一篇文章中使用了MLP的回歸輸出,但是在這個(gè)多輸入混合數(shù)據(jù)網(wǎng)絡(luò)中不會(huì)使用它。您很快就會(huì)看到,我們將顯式地設(shè)置regress=False,即使它也是默認(rèn)值。稍后將在整個(gè)多輸入混合數(shù)據(jù)網(wǎng)絡(luò)的頭部執(zhí)行回歸。
根據(jù)圖7,我們現(xiàn)在已經(jīng)構(gòu)建了網(wǎng)絡(luò)的左上分支。
現(xiàn)在讓我們來定義我們網(wǎng)絡(luò)的右上角分支,CNN:
def create_cnn(width, height, depth, filters=(16, 32, 64), regress=False):# initialize the input shape and channel dimension, assuming# TensorFlow/channels-last orderinginputShape = (height, width, depth)chanDim = -1# define the model inputinputs = Input(shape=inputShape)# loop over the number of filtersfor (i, f) in enumerate(filters):# if this is the first CONV layer then set the input# appropriatelyif i == 0:x = inputs# CONV => RELU => BN => POOLx = Conv2D(f, (3, 3), padding="same")(x)x = Activation("relu")(x)x = BatchNormalization(axis=chanDim)(x)x = MaxPooling2D(pool_size=(2, 2))(x)create_cnn函數(shù)處理圖像數(shù)據(jù)并接受五個(gè)參數(shù):
- 寬度:輸入圖像的寬度,單位為像素。
- 高度:輸入圖像的高度,單位為像素。
- 深度:輸入圖像中的通道數(shù)。對于RGB彩色圖像,它是3。
- 過濾器:一組逐漸變大的過濾器,使我們的網(wǎng)絡(luò)可以學(xué)習(xí)更多的區(qū)分功能。
- 回歸:一個(gè)布爾值,指示是否將一個(gè)完全連接的線性激活層添加到CNN以進(jìn)行回歸。
從這里開始,我們開始遍歷過濾器并創(chuàng)建一組CONV => RELU > BN =>POOL 層。循環(huán)的每次迭代都會(huì)累加這些層。
讓我們完成CNN網(wǎng)絡(luò)分支的建設(shè):
# flatten the volume, then FC => RELU => BN => DROPOUTx = Flatten()(x)x = Dense(16)(x)x = Activation("relu")(x)x = BatchNormalization(axis=chanDim)(x)x = Dropout(0.5)(x)# apply another FC layer, this one to match the number of nodes# coming out of the MLPx = Dense(4)(x)x = Activation("relu")(x)# check to see if the regression node should be addedif regress:x = Dense(1, activation="linear")(x)# construct the CNNmodel = Model(inputs, x)# return the CNNreturn model我們將下一層壓平,意味著我們將所有提取到的特征組成一維特征向量,然后添加一個(gè)帶有BatchNormalization和Dropout的全連接層。
另一個(gè)全連接層用于匹配來自多層感知器的四個(gè)節(jié)點(diǎn)。匹配節(jié)點(diǎn)的數(shù)量不是必需的,但它確實(shí)有助于平衡分支。
檢查是否添加回歸節(jié)點(diǎn),如果需要就相應(yīng)地將其添加進(jìn)來。實(shí)際上,我們不會(huì)在這個(gè)分支的末尾進(jìn)行回歸?;貧w將在多輸入混合數(shù)據(jù)網(wǎng)絡(luò)的頭部執(zhí)行(圖7的最底部)。
最后,模型由我們的輸入和組裝在一起的所有層組成。我們可以將CNN分支返回到調(diào)用函數(shù)(第68行)。
現(xiàn)在我們已經(jīng)定義了多輸入Keras模型的兩個(gè)分支,讓我們學(xué)習(xí)如何組合它們!
使用Keras的多個(gè)輸入
現(xiàn)在,我們準(zhǔn)備構(gòu)建最終的Keras模型,該模型能夠處理多個(gè)輸入和混合數(shù)據(jù)。這是分支聚集的地方——“魔法”發(fā)生的地方。
訓(xùn)練也將在這個(gè)腳本中進(jìn)行。
創(chuàng)建一個(gè)名為mixed_training.py的新文件,打開它,并插入以下代碼:
# import the necessary packages from pyimagesearch import datasets from pyimagesearch import models from sklearn.model_selection import train_test_split from keras.layers.core import Dense from keras.models import Model from keras.optimizers import Adam from keras.layers import concatenate import numpy as np import argparse import locale import os# construct the argument parser and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-d", "--dataset", type=str, required=True,help="path to input dataset of house images") args = vars(ap.parse_args())首先,讓我們導(dǎo)入必要的模塊并且解析命令行參數(shù)。
- datasets: 我們的三個(gè)方便的功能,從房屋數(shù)據(jù)集加載/處理CSV數(shù)據(jù)和加載/預(yù)處理房屋照片。
- models: 我們的MLP和CNN輸入分支,它們將作為我們的多輸入混合數(shù)據(jù)服務(wù)。
- train_test_split: 一個(gè)scikit-learn函數(shù),用于構(gòu)造我們的訓(xùn)練/測試數(shù)據(jù)分割。
- concatenate: 一個(gè)特殊的Keras函數(shù),它將接受多個(gè)輸入。
- argparse: 處理解析命令行參數(shù)。
在第15-18行中,我們有一個(gè)命令行參數(shù)需要解析,即dataset,它是您下載房價(jià)數(shù)據(jù)集的路徑。
接下來,讓我們加載我們的數(shù)值/分類數(shù)據(jù)和圖像數(shù)據(jù):
# construct the path to the input .txt file that contains information # on each house in the dataset and then load the dataset print("[INFO] loading house attributes...") inputPath = os.path.sep.join([args["dataset"], "HousesInfo.txt"]) df = datasets.load_house_attributes(inputPath)# load the house images and then scale the pixel intensities to the # range [0, 1] print("[INFO] loading house images...") images = datasets.load_house_images(df, args["dataset"]) images = images / 255.0在這里,我們將房價(jià)數(shù)據(jù)集加載為panda dataframe(第23行和第24行)。然后我們加載圖像并將其縮放到 [0,1] (第29-30行)。
如果需要提醒您這些函數(shù)的底層功能,請務(wù)必查看上面的load_house_attributes和load_house_images函數(shù)。
現(xiàn)在我們的數(shù)據(jù)已經(jīng)加載完畢,我們將構(gòu)建我們的培訓(xùn)/測試分割,調(diào)整價(jià)格,并處理房屋屬性:
我們的訓(xùn)練和測試是在第35行和第36行進(jìn)行的。我們分配了75%的數(shù)據(jù)用于培訓(xùn),25%的數(shù)據(jù)用于測試。
在此基礎(chǔ)上,我們從培訓(xùn)集(第41行)中找到maxPrice,并相應(yīng)地調(diào)整培訓(xùn)和測試數(shù)據(jù)(第42行和第43行)。將價(jià)值數(shù)據(jù)調(diào)整到[0,1]范圍內(nèi),可以更好地訓(xùn)練和收斂。
最后,我們通過對連續(xù)特征執(zhí)行最小-最大縮放和對分類特征執(zhí)行一次熱編碼繼續(xù)處理我們的房子屬性。
process_house_attributes函數(shù)處理這些操作,并將連續(xù)的和分類的特性連接在一起,返回結(jié)果(第48行和第49行)。
準(zhǔn)備好施魔法了嗎?
好吧,我說謊了。在下一個(gè)代碼塊中實(shí)際上沒有任何“魔力”!但我們將連接我們的網(wǎng)絡(luò)分支,完成我們的多輸入Keras網(wǎng)絡(luò):
當(dāng)您組織好代碼和模型后,使用Keras處理多個(gè)輸入是非常容易的。
在第52行和第53行,我們創(chuàng)建mlp和cnn模型。注意regress=False——我們的回歸頭出現(xiàn)在第62行后面。
然后我們將連接mlp輸出和cnn輸出如第57行所示。我將其稱為我們的combinedInput,因?yàn)樗蔷W(wǎng)絡(luò)其余部分的輸入(從圖3中可以看到,這是concatenate_1,兩個(gè)分支在一起)。
網(wǎng)絡(luò)中最后一層的組合輸入是基于MLP和CNN分支的 8-4-1 FC層的輸出(因?yàn)檫@兩個(gè)分支都輸出4維 FC層,然后我們將它們連接起來創(chuàng)建一個(gè)8維向量)。
我們將一個(gè)由四個(gè)神經(jīng)元組成的完全連接的層固定在combinedInput上(第61行)。然后我們添加“l(fā)iner”activation回歸頭(第62行),其輸出為預(yù)測價(jià)格。
讓我們繼續(xù)編譯、培訓(xùn)和評估我們新形成的模型:
# compile the model using mean absolute percentage error as our loss, # implying that we seek to minimize the absolute percentage difference # between our price *predictions* and the *actual prices* opt = Adam(lr=1e-3, decay=1e-3 / 200) model.compile(loss="mean_absolute_percentage_error", optimizer=opt)# train the model print("[INFO] training model...") model.fit([trainAttrX, trainImagesX], trainY,validation_data=([testAttrX, testImagesX], testY),epochs=200, batch_size=8)# make predictions on the testing data print("[INFO] predicting house prices...") preds = model.predict([testAttrX, testImagesX])我們的模型是用“mean_absolute_percentage_error”損失和一個(gè)Adam優(yōu)化器編譯的,該優(yōu)化器具有學(xué)習(xí)率衰減(第72行和第73行)。
訓(xùn)練在第77-80行開始。這就是所謂的模型擬合(也就是所有權(quán)重都由稱為反向傳播的過程進(jìn)行調(diào)優(yōu)的地方)。
通過對測試數(shù)據(jù)集調(diào)用model.predict(第84行)可以獲取模型預(yù)測的房屋價(jià)值來評估我們的模型。
現(xiàn)在讓我們進(jìn)行評估:
# compute the difference between the *predicted* house prices and the # *actual* house prices, then compute the percentage difference and # the absolute percentage difference diff = preds.flatten() - testY percentDiff = (diff / testY) * 100 absPercentDiff = np.abs(percentDiff)# compute the mean and standard deviation of the absolute percentage # difference mean = np.mean(absPercentDiff) std = np.std(absPercentDiff)# finally, show some statistics on our model locale.setlocale(locale.LC_ALL, "en_US.UTF-8") print("[INFO] avg. house price: {}, std house price: {}".format(locale.currency(df["price"].mean(), grouping=True),locale.currency(df["price"].std(), grouping=True))) print("[INFO] mean: {:.2f}%, std: {:.2f}%".format(mean, std))為了評估我們的模型,我們計(jì)算了絕對百分比(第89-91行),并使用它得出了最終的度量標(biāo)準(zhǔn)(第95和96行)。
這些度量(價(jià)格平均值、價(jià)格標(biāo)準(zhǔn)差和絕對百分比的平均值以及標(biāo)準(zhǔn)差)將以合適的格式(第100-103行)打印到終端。
多輸入和混合數(shù)據(jù)結(jié)果
圖8:房地產(chǎn)價(jià)格預(yù)測是一項(xiàng)困難的任務(wù),但是我們的Keras多輸入和混合輸入回歸模型在我們有限的房價(jià)數(shù)據(jù)集上產(chǎn)生了比較好的結(jié)果。
最后,我們在混合數(shù)據(jù)上訓(xùn)練我們的多輸入網(wǎng)絡(luò)!
確保你準(zhǔn)備好了:
在此基礎(chǔ)上,打開終端,執(zhí)行以下命令,開始網(wǎng)絡(luò)訓(xùn)練:
$ python mixed_training.py --dataset Houses-dataset/Houses\ Dataset/我們的平均絕對百分比誤差開始非常高,但在整個(gè)培訓(xùn)過程中不斷下降。
在訓(xùn)練結(jié)束時(shí),我們得到了22.41%的測試集絕對誤差,這意味著我們的網(wǎng)絡(luò)對房價(jià)的預(yù)測平均會(huì)下降22%左右。
我們將這個(gè)結(jié)果與本系列之前的兩篇文章進(jìn)行比較:
如你所見,處理混合數(shù)據(jù)的方法如下:
總結(jié)
在本教程中,您學(xué)習(xí)了如何定義能夠接受多個(gè)輸入的Keras網(wǎng)絡(luò)。
您還學(xué)習(xí)了如何使用Keras處理混合數(shù)據(jù)。
為了實(shí)現(xiàn)這些目標(biāo),我們定義了一個(gè)能夠接受的多輸入神經(jīng)網(wǎng)絡(luò):
- 數(shù)值數(shù)據(jù)
- 分類數(shù)據(jù)
- 圖像數(shù)據(jù)
在訓(xùn)練前,將數(shù)值數(shù)據(jù)的min-max縮放到[0,1]范圍。我們的類別數(shù)據(jù)是one-hot編碼的(確保得到的整數(shù)向量在[0,1]范圍內(nèi))。
然后將數(shù)值和類別數(shù)據(jù)連接成一個(gè)特征向量,形成Keras網(wǎng)絡(luò)的第一個(gè)輸入。
我們的圖像數(shù)據(jù)也被縮放到范圍[0,1]——這些數(shù)據(jù)作為Keras網(wǎng)絡(luò)的第二個(gè)輸入。
模型的一個(gè)分支包含嚴(yán)格的全連通層(對于連接的數(shù)值和類別數(shù)據(jù)),而多輸入模型的第二個(gè)分支本質(zhì)上是一個(gè)小的卷積神經(jīng)網(wǎng)絡(luò)。
將兩個(gè)分支的輸出組合起來,定義一個(gè)輸出(回歸預(yù)測)。
通過這種方式,我們能夠訓(xùn)練我們的多個(gè)輸入網(wǎng)絡(luò)端到端,從而獲得比僅使用其中一個(gè)輸入更好的準(zhǔn)確性。
翻譯自:Keras: Multiple Inputs and Mixed Data, by Adrian Rosebrock.
總結(jié)
以上是生活随笔為你收集整理的Keras: 多输入及混合数据输入的神经网络模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sobol敏感性分析 matlab代码
- 下一篇: dropout+Batch Normal