Python中組合分類和回歸的神經(jīng)網(wǎng)絡(luò)模型
Python中文社區(qū) (ID:python-china)
某些預(yù)測問題需要為同一輸入預(yù)測數(shù)字值和類別標(biāo)簽。一種簡單的方法是在同一數(shù)據(jù)上開發(fā)回歸和分類預(yù)測模型,然后依次使用這些模型。另一種通常更有效的方法是開發(fā)單個(gè)神經(jīng)網(wǎng)絡(luò)模型,該模型可以根據(jù)同一輸入預(yù)測數(shù)字和類別標(biāo)簽值。這被稱為多輸出模型,使用現(xiàn)代深度學(xué)習(xí)庫(例如Keras和TensorFlow)可以相對容易地開發(fā)和評估。
在本教程中,您將發(fā)現(xiàn)如何開發(fā)用于組合回歸和分類預(yù)測的神經(jīng)網(wǎng)絡(luò)。完成本教程后,您將知道:
- 一些預(yù)測問題需要為每個(gè)輸入示例預(yù)測數(shù)字和類別標(biāo)簽值。
- 如何針對需要多個(gè)輸出的問題開發(fā)單獨(dú)的回歸和分類模型。
- 如何開發(fā)和評估能夠同時(shí)進(jìn)行回歸和分類預(yù)測的神經(jīng)網(wǎng)絡(luò)模型。
教程概述
本教程分為三個(gè)部分:他們是:
- 回歸和分類的單一模型
- 單獨(dú)的回歸和分類模型
鮑魚數(shù)據(jù)集
回歸模型
分類模型
- 組合回歸和分類模型
回歸和分類的單一模型
開發(fā)用于回歸或分類問題的深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)模型是很常見的,但是在某些預(yù)測建模任務(wù)上,我們可能希望開發(fā)一個(gè)可以進(jìn)行回歸和分類預(yù)測的單一模型。回歸是指涉及預(yù)測給定輸入的數(shù)值的預(yù)測建模問題。分類是指預(yù)測建模問題,涉及預(yù)測給定輸入的類別標(biāo)簽或類別標(biāo)簽的概率。
我們可能要預(yù)測數(shù)值和分類值時(shí)可能會(huì)有一些問題。解決此問題的一種方法是為每個(gè)所需的預(yù)測開發(fā)一個(gè)單獨(dú)的模型。這種方法的問題在于,由單獨(dú)的模型做出的預(yù)測可能會(huì)有所不同。使用神經(jīng)網(wǎng)絡(luò)模型時(shí)可以使用的另一種方法是開發(fā)單個(gè)模型,該模型能夠?qū)ο嗤斎氲臄?shù)字和類輸出進(jìn)行單獨(dú)的預(yù)測。這稱為多輸出神經(jīng)網(wǎng)絡(luò)模型。這種類型的模型的好處在于,我們有一個(gè)模型可以開發(fā)和維護(hù),而不是兩個(gè)模型,并且同時(shí)在兩種輸出類型上訓(xùn)練和更新模型可以在兩種輸出類型之間的預(yù)測中提供更大的一致性。我們將開發(fā)一個(gè)能夠同時(shí)進(jìn)行回歸和分類預(yù)測的多輸出神經(jīng)網(wǎng)絡(luò)模型。
首先,讓我們選擇一個(gè)滿足此要求的數(shù)據(jù)集,并從為回歸和分類預(yù)測開發(fā)單獨(dú)的模型開始。
單獨(dú)的回歸和分類模型
在本節(jié)中,我們將從選擇一個(gè)實(shí)際數(shù)據(jù)集開始,在該數(shù)據(jù)集中我們可能需要同時(shí)進(jìn)行回歸和分類預(yù)測,然后針對每種類型的預(yù)測開發(fā)單獨(dú)的模型。
鮑魚數(shù)據(jù)集
我們將使用“鮑魚”數(shù)據(jù)集。確定鮑魚的年齡是一項(xiàng)耗時(shí)的工作,并且希望僅根據(jù)物理細(xì)節(jié)來確定鮑魚的年齡。這是一個(gè)描述鮑魚物理細(xì)節(jié)的數(shù)據(jù)集,需要預(yù)測鮑魚的環(huán)數(shù),這是該生物年齡的代名詞。
“年齡”既可以預(yù)測為數(shù)值(以年為單位),也可以預(yù)測為類別標(biāo)簽(按年為普通年)。無需下載數(shù)據(jù)集,因?yàn)槲覀儗⒆鳛楣ぷ魇纠囊徊糠肿詣?dòng)下載它。數(shù)據(jù)集提供了一個(gè)數(shù)據(jù)集示例,我們可能需要輸入的數(shù)值和分類。
首先,讓我們開發(fā)一個(gè)示例來下載和匯總數(shù)據(jù)集。
- # load and summarize the abalone dataset
- from pandas import read_csv
- from matplotlib import pyplot
- # load dataset
- url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/abalone.csv'
- dataframe = read_csv(url, header=None)
- # summarize shape
- print(dataframe.shape)
- # summarize first few lines
- print(dataframe.head())
首先運(yùn)行示例,然后下載并匯總數(shù)據(jù)集的形狀。我們可以看到有4,177個(gè)示例(行)可用于訓(xùn)練和評估模型,還有9個(gè)要素(列)包括目標(biāo)變量。我們可以看到,除了第一個(gè)字符串值之外,所有輸入變量都是數(shù)字變量。為了簡化數(shù)據(jù)準(zhǔn)備,我們將從模型中刪除第一列,并著重于對數(shù)字輸入值進(jìn)行建模。
- (4177, 9)
- 012345678
- 0 M 0.4550.3650.0950.51400.22450.10100.15015
- 1 M 0.3500.2650.0900.22550.09950.04850.0707
- 2 F 0.5300.4200.1350.67700.25650.14150.2109
- 3 M 0.4400.3650.1250.51600.21550.11400.15510
- 4 I 0.3300.2550.0800.20500.08950.03950.0557
我們可以將數(shù)據(jù)用作開發(fā)單獨(dú)的回歸和分類多層感知器(MLP)神經(jīng)網(wǎng)絡(luò)模型的基礎(chǔ)。
注意:我們并未嘗試為此數(shù)據(jù)集開發(fā)最佳模型;相反,我們正在展示一種特定的技術(shù):開發(fā)可以進(jìn)行回歸和分類預(yù)測的模型。
回歸模型
在本節(jié)中,我們將為鮑魚數(shù)據(jù)集開發(fā)回歸MLP模型。首先,我們必須將各列分為輸入和輸出元素,并刪除包含字符串值的第一列。我們還將強(qiáng)制所有加載的列都具有浮點(diǎn)類型(由神經(jīng)網(wǎng)絡(luò)模型期望)并記錄輸入特征的數(shù)量,稍后模型需要知道這些特征。
- # split into input (X) and output (y) variables
- X, y = dataset[:, 1:-1], dataset[:, -1]
- X, y = X.astype('float'), y.astype('float')
- n_features = X.shape[1]
接下來,我們可以將數(shù)據(jù)集拆分為訓(xùn)練和測試數(shù)據(jù)集。我們將使用67%的隨機(jī)樣本來訓(xùn)練模型,而剩余的33%則用于評估模型。
- # split data into train and test sets
- X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
然后,我們可以定義一個(gè)MLP神經(jīng)網(wǎng)絡(luò)模型。該模型將具有兩個(gè)隱藏層,第一個(gè)具有20個(gè)節(jié)點(diǎn),第二個(gè)具有10個(gè)節(jié)點(diǎn),都使用ReLU激活和“正常”權(quán)重初始化(一種好的做法)。層數(shù)和節(jié)點(diǎn)數(shù)是任意選擇的。輸出層將具有用于預(yù)測數(shù)值和線性激活函數(shù)的單個(gè)節(jié)點(diǎn)。
- # define the keras model
- model = Sequential()
- model.add(Dense(20, input_dim=n_features, activation='relu', kernel_initializer='he_normal'))
- model.add(Dense(10, activation='relu', kernel_initializer='he_normal'))
- model.add(Dense(1, activation='linear'))
使用隨機(jī)梯度下降的有效Adam版本,將訓(xùn)練模型以最小化均方誤差(MSE)損失函數(shù)。
- # compile the keras model
- model.compile(loss='mse', optimizer='adam')
我們將訓(xùn)練150個(gè)紀(jì)元的模型,并以32個(gè)樣本的小批量為樣本,再次任意選擇。
- # fit the keras model on the dataset
- model.fit(X_train, y_train, epochs=150, batch_size=32, verbose=2)
最后,在訓(xùn)練完模型后,我們將在保持測試數(shù)據(jù)集上對其進(jìn)行評估,并報(bào)告平均絕對誤差(MAE)。
- # evaluate on test set
- yhat = model.predict(X_test)
- error = mean_absolute_error(y_test, yhat)
- print('MAE: %.3f'% error)
綜上所述,下面列出了以回歸問題為框架的鮑魚數(shù)據(jù)集的MLP神經(jīng)網(wǎng)絡(luò)的完整示例。
- # regression mlp model for the abalone dataset
- from pandas import read_csv
- from tensorflow.keras.models importSequential
- from tensorflow.keras.layers importDense
- from sklearn.metrics import mean_absolute_error
- from sklearn.model_selection import train_test_split
- # load dataset
- url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/abalone.csv'
- dataframe = read_csv(url, header=None)
- dataset = dataframe.values
- # split into input (X) and output (y) variables
- X, y = dataset[:, 1:-1], dataset[:, -1]
- X, y = X.astype('float'), y.astype('float')
- n_features = X.shape[1]
- # split data into train and test sets
- X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
- # define the keras model
- model = Sequential()
- model.add(Dense(20, input_dim=n_features, activation='relu', kernel_initializer='he_normal'))
- model.add(Dense(10, activation='relu', kernel_initializer='he_normal'))
- model.add(Dense(1, activation='linear'))
- # compile the keras model
- model.compile(loss='mse', optimizer='adam')
- # fit the keras model on the dataset
- model.fit(X_train, y_train, epochs=150, batch_size=32, verbose=2)
- # evaluate on test set
- yhat = model.predict(X_test)
- error = mean_absolute_error(y_test, yhat)
- print('MAE: %.3f'% error)
運(yùn)行示例將準(zhǔn)備數(shù)據(jù)集,擬合模型并報(bào)告模型誤差的估計(jì)值。
注意:由于算法或評估程序的隨機(jī)性,或者數(shù)值精度的差異,您的結(jié)果可能會(huì)有所不同。考慮運(yùn)行該示例幾次并比較平均結(jié)果。
在這種情況下,我們可以看到該模型實(shí)現(xiàn)了約1.5 的誤差。
- Epoch145/150
- 88/88- 0s- loss: 4.6130
- Epoch146/150
- 88/88- 0s- loss: 4.6182
- Epoch147/150
- 88/88- 0s- loss: 4.6277
- Epoch148/150
- 88/88- 0s- loss: 4.6437
- Epoch149/150
- 88/88- 0s- loss: 4.6166
- Epoch150/150
- 88/88- 0s- loss: 4.6132
- MAE: 1.554
到目前為止,一切都很好。接下來,讓我們看一下開發(fā)類似的分類模型。
分類模型
鮑魚數(shù)據(jù)集可以歸類為一個(gè)分類問題,其中每個(gè)“環(huán)”整數(shù)都被當(dāng)作一個(gè)單獨(dú)的類標(biāo)簽。該示例和模型與上述回歸示例非常相似,但有一些重要的變化。這要求首先為每個(gè)“ ring”值分配一個(gè)單獨(dú)的整數(shù),從0開始,以“ class”總數(shù)減1結(jié)束。這可以使用LabelEncoder實(shí)現(xiàn)。我們還可以將類的總數(shù)記錄為唯一編碼的類值的總數(shù),稍后模型會(huì)需要。
- # encode strings to integer
- y = LabelEncoder().fit_transform(y)
- n_class = len(unique(y))
將數(shù)據(jù)像以前一樣分為訓(xùn)練集和測試集后,我們可以定義模型并將模型的輸出數(shù)更改為等于類數(shù),并使用對于多類分類通用的softmax激活函數(shù)。
- # define the keras model
- model = Sequential()
- model.add(Dense(20, input_dim=n_features, activation='relu', kernel_initializer='he_normal'))
- model.add(Dense(10, activation='relu', kernel_initializer='he_normal'))
- model.add(Dense(n_class, activation='softmax'))
假設(shè)我們已將類別標(biāo)簽編碼為整數(shù)值,則可以通過最小化適用于具有整數(shù)編碼類別標(biāo)簽的多類別分類任務(wù)的稀疏類別交叉熵?fù)p失函數(shù)來擬合模型
- # compile the keras model
- model.compile(loss='sparse_categorical_crossentropy', optimizer='adam')
在像以前一樣將模型擬合到訓(xùn)練數(shù)據(jù)集上之后,我們可以通過計(jì)算保留測試集上的分類準(zhǔn)確性來評估模型的性能。
- # evaluate on test set
- yhat = model.predict(X_test)
- yhat = argmax(yhat, axis=-1).astype('int')
- acc = accuracy_score(y_test, yhat)
- print('Accuracy: %.3f'% acc)
綜上所述,下面列出了針對鮑魚數(shù)據(jù)集的MLP神經(jīng)網(wǎng)絡(luò)的完整示例,該示例被歸類為分類問題。
- # classification mlp model for the abalone dataset
- from numpy import unique
- from numpy import argmax
- from pandas import read_csv
- from tensorflow.keras.models importSequential
- from tensorflow.keras.layers importDense
- from sklearn.metrics import accuracy_score
- from sklearn.model_selection import train_test_split
- from sklearn.preprocessing importLabelEncoder
- # load dataset
- url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/abalone.csv'
- dataframe = read_csv(url, header=None)
- dataset = dataframe.values
- # split into input (X) and output (y) variables
- X, y = dataset[:, 1:-1], dataset[:, -1]
- X, y = X.astype('float'), y.astype('float')
- n_features = X.shape[1]
- # encode strings to integer
- y = LabelEncoder().fit_transform(y)
- n_class = len(unique(y))
- # split data into train and test sets
- X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
- # define the keras model
- model = Sequential()
- model.add(Dense(20, input_dim=n_features, activation='relu', kernel_initializer='he_normal'))
- model.add(Dense(10, activation='relu', kernel_initializer='he_normal'))
- model.add(Dense(n_class, activation='softmax'))
- # compile the keras model
- model.compile(loss='sparse_categorical_crossentropy', optimizer='adam')
- # fit the keras model on the dataset
- model.fit(X_train, y_train, epochs=150, batch_size=32, verbose=2)
- # evaluate on test set
- yhat = model.predict(X_test)
- yhat = argmax(yhat, axis=-1).astype('int')
- acc = accuracy_score(y_test, yhat)
- print('Accuracy: %.3f'% acc)
運(yùn)行示例將準(zhǔn)備數(shù)據(jù)集,擬合模型并報(bào)告模型誤差的估計(jì)值。
注意:由于算法或評估程序的隨機(jī)性,或者數(shù)值精度的差異,您的結(jié)果可能會(huì)有所不同??紤]運(yùn)行該示例幾次并比較平均結(jié)果。
在這種情況下,我們可以看到該模型的準(zhǔn)確度約為27%。
- Epoch145/150
- 88/88- 0s- loss: 1.9271
- Epoch146/150
- 88/88- 0s- loss: 1.9265
- Epoch147/150
- 88/88- 0s- loss: 1.9265
- Epoch148/150
- 88/88- 0s- loss: 1.9271
- Epoch149/150
- 88/88- 0s- loss: 1.9262
- Epoch150/150
- 88/88- 0s- loss: 1.9260
- Accuracy: 0.274
到目前為止,一切都很好。接下來,讓我們看一下開發(fā)一種能夠同時(shí)進(jìn)行回歸和分類預(yù)測的組合模型。
組合回歸和分類模型
在本節(jié)中,我們可以開發(fā)一個(gè)單一的MLP神經(jīng)網(wǎng)絡(luò)模型,該模型可以對單個(gè)輸入進(jìn)行回歸和分類預(yù)測。這稱為多輸出模型,可以使用功能性Keras API進(jìn)行開發(fā)。
首先,必須準(zhǔn)備數(shù)據(jù)集。盡管我們應(yīng)該使用單獨(dú)的名稱保存編碼后的目標(biāo)變量以將其與原始目標(biāo)變量值區(qū)分開,但是我們可以像以前一樣為分類準(zhǔn)備數(shù)據(jù)集。
- # encode strings to integer
- y_class = LabelEncoder().fit_transform(y)
- n_class = len(unique(y_class))
然后,我們可以將輸入,原始輸出和編碼后的輸出變量拆分為訓(xùn)練集和測試集。
- # split data into train and test sets
- X_train, X_test, y_train, y_test, y_train_class, y_test_class = train_test_split(X, y, y_class, test_size=0.33, random_state=1)
接下來,我們可以使用功能性API定義模型。該模型采用與獨(dú)立模型相同的輸入數(shù)量,并使用以相同方式配置的兩個(gè)隱藏層
- # input
- visible = Input(shape=(n_features,))
- hidden1 = Dense(20, activation='relu', kernel_initializer='he_normal')(visible)
- hidden2 = Dense(10, activation='relu', kernel_initializer='he_normal')(hidden1)
然后,我們可以定義兩個(gè)單獨(dú)的輸出層,它們連接到模型的第二個(gè)隱藏層。
第一個(gè)是具有單個(gè)節(jié)點(diǎn)和線性激活函數(shù)的回歸輸出層。
- # regression output
- out_reg = Dense(1, activation='linear')(hidden2)
第二個(gè)是分類輸出層,對于每個(gè)要預(yù)測的類都有一個(gè)節(jié)點(diǎn),并使用softmax激活函數(shù)。
- # classification output
- out_clas = Dense(n_class, activation='softmax')(hidden2)
然后,我們可以使用一個(gè)輸入層和兩個(gè)輸出層定義模型。
- # define model
- model = Model(inputs=visible, outputs=[out_reg, out_clas])
給定兩個(gè)輸出層,我們可以使用兩個(gè)損失函數(shù)來編譯模型,第一個(gè)(回歸)輸出層的均方誤差損失和第二個(gè)(分類)輸出層的稀疏分類交叉熵。
- # compile the keras model
- model.compile(loss=['mse','sparse_categorical_crossentropy'], optimizer='adam')
我們還可以創(chuàng)建模型圖以供參考。這需要安裝pydot和pygraphviz。如果存在問題,則可以注釋掉該行以及 plot_model()函數(shù)的import語句。
- # plot graph of model
- plot_model(model, to_file='model.png', show_shapes=True)
每次模型進(jìn)行預(yù)測時(shí),它將預(yù)測兩個(gè)值。同樣,訓(xùn)練模型時(shí),每個(gè)輸出每個(gè)樣本將需要一個(gè)目標(biāo)變量。這樣,我們可以訓(xùn)練模型,并仔細(xì)地向模型的每個(gè)輸出提供回歸目標(biāo)和分類目標(biāo)數(shù)據(jù)。
- # plot graph of model
- plot_model(model, to_file='model.png', show_shapes=True)
然后,擬合模型可以對保留測試集中的每個(gè)示例進(jìn)行回歸和分類預(yù)測。
- # make predictions on test set
- yhat1, yhat2 = model.predict(X_test)
第一個(gè)數(shù)組可用于通過平均絕對誤差評估回歸預(yù)測。
- # calculate error for regression model
- error = mean_absolute_error(y_test, yhat1)
- print('MAE: %.3f'% error)
第二個(gè)數(shù)組可用于通過分類準(zhǔn)確性評估分類預(yù)測。
- # evaluate accuracy for classification model
- yhat2 = argmax(yhat2, axis=-1).astype('int')
- acc = accuracy_score(y_test_class, yhat2)
- print('Accuracy: %.3f'% acc)
就是這樣。結(jié)合在一起,下面列出了訓(xùn)練和評估用于鮑魚數(shù)據(jù)集上的組合器回歸和分類預(yù)測的多輸出模型的完整示例。
- # mlp for combined regression and classification predictions on the abalone dataset
- from numpy import unique
- from numpy import argmax
- from pandas import read_csv
- from sklearn.metrics import mean_absolute_error
- from sklearn.metrics import accuracy_score
- from sklearn.model_selection import train_test_split
- from sklearn.preprocessing importLabelEncoder
- from tensorflow.keras.models importModel
- from tensorflow.keras.layers importInput
- from tensorflow.keras.layers importDense
- from tensorflow.keras.utils import plot_model
- # load dataset
- url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/abalone.csv'
- dataframe = read_csv(url, header=None)
- dataset = dataframe.values
- # split into input (X) and output (y) variables
- X, y = dataset[:, 1:-1], dataset[:, -1]
- X, y = X.astype('float'), y.astype('float')
- n_features = X.shape[1]
- # encode strings to integer
- y_class = LabelEncoder().fit_transform(y)
- n_class = len(unique(y_class))
- # split data into train and test sets
- X_train, X_test, y_train, y_test, y_train_class, y_test_class = train_test_split(X, y, y_class, test_size=0.33, random_state=1)
- # input
- visible = Input(shape=(n_features,))
- hidden1 = Dense(20, activation='relu', kernel_initializer='he_normal')(visible)
- hidden2 = Dense(10, activation='relu', kernel_initializer='he_normal')(hidden1)
- # regression output
- out_reg = Dense(1, activation='linear')(hidden2)
- # classification output
- out_clas = Dense(n_class, activation='softmax')(hidden2)
- # define model
- model = Model(inputs=visible, outputs=[out_reg, out_clas])
- # compile the keras model
- model.compile(loss=['mse','sparse_categorical_crossentropy'], optimizer='adam')
- # plot graph of model
- plot_model(model, to_file='model.png', show_shapes=True)
- # fit the keras model on the dataset
- model.fit(X_train, [y_train,y_train_class], epochs=150, batch_size=32, verbose=2)
- # make predictions on test set
- yhat1, yhat2 = model.predict(X_test)
- # calculate error for regression model
- error = mean_absolute_error(y_test, yhat1)
- print('MAE: %.3f'% error)
- # evaluate accuracy for classification model
- yhat2 = argmax(yhat2, axis=-1).astype('int')
- acc = accuracy_score(y_test_class, yhat2)
- print('Accuracy: %.3f'% acc)
運(yùn)行示例將準(zhǔn)備數(shù)據(jù)集,擬合模型并報(bào)告模型誤差的估計(jì)值。
注意:由于算法或評估程序的隨機(jī)性,或者數(shù)值精度的差異,您的結(jié)果可能會(huì)有所不同??紤]運(yùn)行該示例幾次并比較平均結(jié)果。
創(chuàng)建了多輸出模型圖,清楚地顯示了連接到模型第二個(gè)隱藏層的回歸(左)和分類(右)輸出層。
在這種情況下,我們可以看到該模型既實(shí)現(xiàn)了約1.495 的合理誤差,又實(shí)現(xiàn)了與之前相似的約25.6%的精度。
- Epoch145/150
- 88/88- 0s- loss: 6.5707- dense_2_loss: 4.5396- dense_3_loss: 2.0311
- Epoch146/150
- 88/88- 0s- loss: 6.5753- dense_2_loss: 4.5466- dense_3_loss: 2.0287
- Epoch147/150
- 88/88- 0s- loss: 6.5970- dense_2_loss: 4.5723- dense_3_loss: 2.0247
- Epoch148/150
- 88/88- 0s- loss: 6.5640- dense_2_loss: 4.5389- dense_3_loss: 2.0251
- Epoch149/150
- 88/88- 0s- loss: 6.6053- dense_2_loss: 4.5827- dense_3_loss: 2.0226
- Epoch150/150
- 88/88- 0s- loss: 6.5754- dense_2_loss: 4.5524- dense_3_loss: 2.0230
- MAE: 1.495
- Accuracy: 0.256