Keras是一個用於深度學習的Python庫,它包含高效的數值庫Theano和TensorFlow。
本文的目的是學習如何從csv中載入資料並使其可供Keras使用,如何用神經網路建立多類分類的資料進行建模,如何使用scikit-learn評估Keras神經網路模型。
前言,對兩分類和多分類的概念描述
(前言是整理別人部落格的筆記77774223)
1,在LR(羅吉斯迴歸)中,如何進行多分類?
一般情況下,我們所認識的lr模型是一個二分類的模型,但是能否用lr進行多分類任務呢?答案當然是可以的。
不過我們需要注意的是,我們有許多種思想利用lr來進行分類
2,訓練多個二分類器的思想
既然天然的lr是用來做二分類,那麼我們很自然地想到把多分類劃分為多個二分類的任務。
具體有以下三種策略:
2.1 一對一
假如某個分類中有N個類別,我們將這N個類別進行兩兩配對(兩兩配對後轉化為二分類問題)。那麼我們可以得到個二分類器。(簡單解釋一下,相當於在N個類別裡面抽2個)
之後,在測試階段,我們把新樣本交給這個二分類器。於是我們可以得到個分類結果。把預測的最多的類別作為預測的結果。下面,我給一個具體的例子來理解一下。 的意思其實很明顯,首先把類別兩兩組合(6種組合)。組合完之後,其中一個類別作為正類,另一個作為負類(這個正負只是相對而言,目的是轉化為二分類)。然後對每個二分類器進行訓練。可以得到6個二分類器。然後把測試樣本在6個二分類器上面進行預測。從結果上可以看到,類別1被預測的最多,故測試樣本屬於類別1。
2.2 一對其餘 (OvR)一對其餘其實更加好理解,每次將一個類別作為正類,其餘類別作為負類。此時共有(N個分類器)。在測試的時候若僅有一個分類器預測為正類,則對應的類別標記為最終的分類結果。例如下面這個例子。 大概解釋一下,就是有當有4個類別的時候,每次把其中一個類別作為正類別,其餘作為負類別,共有4種組合,對於這4中組合進行分類器的訓練,我們可以得到4個分類器。對於測試樣本,放進4個分類器進行預測,僅有一個分類器預測為正類,於是取這個分類器的結果作為預測結果,分類器2預測的結果是類別2,於是這個樣本便屬於類別2。 其實,有人會有疑問,那麼預測為負類的分類器就不用管了嗎?是的,因為預測為負類的時候有多種可能,無法確定,只有預測為正類的時候才能唯一確定屬於哪一類。比如對於分類器3,分類結果是負類,但是負類有類別1,類別2,類別4三種,到底屬於哪一種?
2.3 多對多(MvM) 所謂多對多其實就是把多個類別作為正類,多個類別作為負類。本文不介紹這個方法,詳細可以參考周志華西瓜書P64-P65。 3,對於上面的方法其實都是訓練多個二分類器,那麼有沒有更加直接的方法對LR來進行多分類呢?我們知道,對於二分類的LR時,正類和負類的機率分別如下: 對於多分類,其實我只需要做簡單的修改就可以了。假設某分類任務有K個類別,那麼對於每一個類別的機率有:對於第K類來說對於其餘類而言 一,問題描述
在本文學習中,我們將使用鳶尾花資料集的標準機器學習問題。
這個資料集經過深入研究,是在神經網路上練習的一個很好的問題,因為所有4個輸入變數都是數位,並且具有相同的厘米層級。每個執行個體描述觀察到的花測量的屬性,輸出變數是特定的鳶尾種類。
這是一個多類別的分類問題,意味著有兩個以上的類需要預測,實際上有三種花種。這是用神經網路練習的一個重要問題類型,因為三個類值需要專門的處理。
鳶尾花資料集是一個充分研究的問題,我們可以期望實現模型精度為在95%至97%的範圍內,這為開發我們的模型提供了一個很好的目標。
您可以從UCI機器學習庫下載鳶尾花資料集,並將其放在當前工作目錄中,檔案名為 “ iris.csv”。
5.1,3.5,1.4,0.2,Iris-setosa4.9,3.0,1.4,0.2,Iris-setosa4.7,3.2,1.3,0.2,Iris-setosa4.6,3.1,1.5,0.2,Iris-setosa5.0,3.6,1.4,0.2,Iris-setosa5.4,3.9,1.7,0.4,Iris-setosa4.6,3.4,1.4,0.3,Iris-setosa5.0,3.4,1.5,0.2,Iris-setosa4.4,2.9,1.4,0.2,Iris-setosa4.9,3.1,1.5,0.1,Iris-setosa5.4,3.7,1.5,0.2,Iris-setosa4.8,3.4,1.6,0.2,Iris-setosa4.8,3.0,1.4,0.1,Iris-setosa4.3,3.0,1.1,0.1,Iris-setosa5.8,4.0,1.2,0.2,Iris-setosa5.7,4.4,1.5,0.4,Iris-setosa5.4,3.9,1.3,0.4,Iris-setosa5.1,3.5,1.4,0.3,Iris-setosa5.7,3.8,1.7,0.3,Iris-setosa5.1,3.8,1.5,0.3,Iris-setosa5.4,3.4,1.7,0.2,Iris-setosa5.1,3.7,1.5,0.4,Iris-setosa4.6,3.6,1.0,0.2,Iris-setosa5.1,3.3,1.7,0.5,Iris-setosa4.8,3.4,1.9,0.2,Iris-setosa5.0,3.0,1.6,0.2,Iris-setosa5.0,3.4,1.6,0.4,Iris-setosa5.2,3.5,1.5,0.2,Iris-setosa5.2,3.4,1.4,0.2,Iris-setosa4.7,3.2,1.6,0.2,Iris-setosa4.8,3.1,1.6,0.2,Iris-setosa5.4,3.4,1.5,0.4,Iris-setosa5.2,4.1,1.5,0.1,Iris-setosa5.5,4.2,1.4,0.2,Iris-setosa4.9,3.1,1.5,0.1,Iris-setosa5.0,3.2,1.2,0.2,Iris-setosa5.5,3.5,1.3,0.2,Iris-setosa4.9,3.1,1.5,0.1,Iris-setosa4.4,3.0,1.3,0.2,Iris-setosa5.1,3.4,1.5,0.2,Iris-setosa5.0,3.5,1.3,0.3,Iris-setosa4.5,2.3,1.3,0.3,Iris-setosa4.4,3.2,1.3,0.2,Iris-setosa5.0,3.5,1.6,0.6,Iris-setosa5.1,3.8,1.9,0.4,Iris-setosa4.8,3.0,1.4,0.3,Iris-setosa5.1,3.8,1.6,0.2,Iris-setosa4.6,3.2,1.4,0.2,Iris-setosa5.3,3.7,1.5,0.2,Iris-setosa5.0,3.3,1.4,0.2,Iris-setosa7.0,3.2,4.7,1.4,Iris-versicolor6.4,3.2,4.5,1.5,Iris-versicolor6.9,3.1,4.9,1.5,Iris-versicolor5.5,2.3,4.0,1.3,Iris-versicolor6.5,2.8,4.6,1.5,Iris-versicolor5.7,2.8,4.5,1.3,Iris-versicolor6.3,3.3,4.7,1.6,Iris-versicolor4.9,2.4,3.3,1.0,Iris-versicolor6.6,2.9,4.6,1.3,Iris-versicolor5.2,2.7,3.9,1.4,Iris-versicolor5.0,2.0,3.5,1.0,Iris-versicolor5.9,3.0,4.2,1.5,Iris-versicolor6.0,2.2,4.0,1.0,Iris-versicolor6.1,2.9,4.7,1.4,Iris-versicolor5.6,2.9,3.6,1.3,Iris-versicolor6.7,3.1,4.4,1.4,Iris-versicolor5.6,3.0,4.5,1.5,Iris-versicolor5.8,2.7,4.1,1.0,Iris-versicolor6.2,2.2,4.5,1.5,Iris-versicolor5.6,2.5,3.9,1.1,Iris-versicolor5.9,3.2,4.8,1.8,Iris-versicolor6.1,2.8,4.0,1.3,Iris-versicolor6.3,2.5,4.9,1.5,Iris-versicolor6.1,2.8,4.7,1.2,Iris-versicolor6.4,2.9,4.3,1.3,Iris-versicolor6.6,3.0,4.4,1.4,Iris-versicolor6.8,2.8,4.8,1.4,Iris-versicolor6.7,3.0,5.0,1.7,Iris-versicolor6.0,2.9,4.5,1.5,Iris-versicolor5.7,2.6,3.5,1.0,Iris-versicolor5.5,2.4,3.8,1.1,Iris-versicolor5.5,2.4,3.7,1.0,Iris-versicolor5.8,2.7,3.9,1.2,Iris-versicolor6.0,2.7,5.1,1.6,Iris-versicolor5.4,3.0,4.5,1.5,Iris-versicolor6.0,3.4,4.5,1.6,Iris-versicolor6.7,3.1,4.7,1.5,Iris-versicolor6.3,2.3,4.4,1.3,Iris-versicolor5.6,3.0,4.1,1.3,Iris-versicolor5.5,2.5,4.0,1.3,Iris-versicolor5.5,2.6,4.4,1.2,Iris-versicolor6.1,3.0,4.6,1.4,Iris-versicolor5.8,2.6,4.0,1.2,Iris-versicolor5.0,2.3,3.3,1.0,Iris-versicolor5.6,2.7,4.2,1.3,Iris-versicolor5.7,3.0,4.2,1.2,Iris-versicolor5.7,2.9,4.2,1.3,Iris-versicolor6.2,2.9,4.3,1.3,Iris-versicolor5.1,2.5,3.0,1.1,Iris-versicolor5.7,2.8,4.1,1.3,Iris-versicolor6.3,3.3,6.0,2.5,Iris-virginica5.8,2.7,5.1,1.9,Iris-virginica7.1,3.0,5.9,2.1,Iris-virginica6.3,2.9,5.6,1.8,Iris-virginica6.5,3.0,5.8,2.2,Iris-virginica7.6,3.0,6.6,2.1,Iris-virginica4.9,2.5,4.5,1.7,Iris-virginica7.3,2.9,6.3,1.8,Iris-virginica6.7,2.5,5.8,1.8,Iris-virginica7.2,3.6,6.1,2.5,Iris-virginica6.5,3.2,5.1,2.0,Iris-virginica6.4,2.7,5.3,1.9,Iris-virginica6.8,3.0,5.5,2.1,Iris-virginica5.7,2.5,5.0,2.0,Iris-virginica5.8,2.8,5.1,2.4,Iris-virginica6.4,3.2,5.3,2.3,Iris-virginica6.5,3.0,5.5,1.8,Iris-virginica7.7,3.8,6.7,2.2,Iris-virginica7.7,2.6,6.9,2.3,Iris-virginica6.0,2.2,5.0,1.5,Iris-virginica6.9,3.2,5.7,2.3,Iris-virginica5.6,2.8,4.9,2.0,Iris-virginica7.7,2.8,6.7,2.0,Iris-virginica6.3,2.7,4.9,1.8,Iris-virginica6.7,3.3,5.7,2.1,Iris-virginica7.2,3.2,6.0,1.8,Iris-virginica6.2,2.8,4.8,1.8,Iris-virginica6.1,3.0,4.9,1.8,Iris-virginica6.4,2.8,5.6,2.1,Iris-virginica7.2,3.0,5.8,1.6,Iris-virginica7.4,2.8,6.1,1.9,Iris-virginica7.9,3.8,6.4,2.0,Iris-virginica6.4,2.8,5.6,2.2,Iris-virginica6.3,2.8,5.1,1.5,Iris-virginica6.1,2.6,5.6,1.4,Iris-virginica7.7,3.0,6.1,2.3,Iris-virginica6.3,3.4,5.6,2.4,Iris-virginica6.4,3.1,5.5,1.8,Iris-virginica6.0,3.0,4.8,1.8,Iris-virginica6.9,3.1,5.4,2.1,Iris-virginica6.7,3.1,5.6,2.4,Iris-virginica6.9,3.1,5.1,2.3,Iris-virginica5.8,2.7,5.1,1.9,Iris-virginica6.8,3.2,5.9,2.3,Iris-virginica6.7,3.3,5.7,2.5,Iris-virginica6.7,3.0,5.2,2.3,Iris-virginica6.3,2.5,5.0,1.9,Iris-virginica6.5,3.0,5.2,2.0,Iris-virginica6.2,3.4,5.4,2.3,Iris-virginica5.9,3.0,5.1,1.8,Iris-virginica
二,匯入類和函數
我們從匯入本文需要的所有類和函數開始。其中包括需要Keras的功能,還包括來自pandas的資料載入以及來自scikit-learn的資料準備和模型評估。
import numpyimport pandasfrom keras.models import Sequentialfrom keras.layers import Densefrom keras.wrappers.scikit_learn import KerasClassifierfrom keras.utils import np_utilsfrom sklearn.model_selection import cross_val_scorefrom sklearn.model_selection import KFoldfrom sklearn.preprocessing import LabelEncoderfrom sklearn.pipeline import Pipeline
三,初始化隨機數產生器
下面,我們將隨機數產生器初始化為常量值(7)
這對於確保我們可以再次精確地實現從該模型獲得的結果非常重要,它確保可以再現訓練神經網路模型的隨機過程。
# fix random seed for reproducibilityseed = 7numpy.random.seed(seed)
四,記載資料集
可以直接載入資料集。因為輸出變數包含字串,所以最容易使用pandas載入資料。然後我們可以將屬性(列)拆分為輸入變數(X)和輸出變數(Y)。
# load datasetdataframe = pandas.read_csv("iris.csv", header=None)dataset = dataframe.valuesX = dataset[:,0:4].astype(float)Y = dataset[:,4]
五,編碼輸出變數
輸出變數包含三個不同的字串值。
當使用神經網路對多類分類問題進行建模時,優良作法是將包含每個類值的值的向量的輸出屬性重新整形為一個矩陣,每個類值都有一個布爾值,以及給定執行個體是否具有該值是否有類值。
這稱為one hot encoding 或者從分類變數建立虛擬變數。
例如:在這個問題中,三個類值是Iris-setosa,Iris-versicolor和Iris-virginica。如果我們有觀察結果:
多類分類問題本質上可以分解為多個二分類問題,而解決二分類問題的方法有很多。這裡我們利用Keras機器學習架構中的ANN(artificial neural network)來解決多分類問題。這裡我們採用的例子是著名的UCI Machine Learning Repository中的鳶尾花資料集(iris flower dataset)。
多類分類問題與二類分類問題類似,需要將類別變數(categorical function)的輸出標籤轉化為數值變數。這個問題在二分類的時候直接轉換為(0,1)(輸出層採用sigmoid函數)或(-1,1)(輸出層採用tanh函數)。類似的,在多分類問題中我們將轉化為虛擬變數(dummy variable):即用one hot encoding方法將輸出標籤的向量(vector)轉化為只在出現對應標籤的那一列為1,其餘為0的布爾矩陣。以我們所用的鳶尾花資料為例:
sample, label1, Iris-setosa2, Iris-versicolor3, Iris-virginica
用one hot encoding轉化後如下:
sample, Iris-setosa, Iris-versicolor, Iris-virginica1, 1, 0, 02, 0, 1, 03, 0, 0, 1
注意這裡不要將label直接轉化成數值變數,如1,2,3,這樣的話與其說是預測問題更像是迴歸預測的問題,後者的難度比前者大。(當類別比較多的時候輸出值的跨度就會比較大,此時輸出層的啟用函數就只能用linear)
我們可以通過首先使用scikit-learn類LabelEncoder將字串一致地編碼為整數來完成此操作。然後使用Keras函數to_categorical()將整數向量轉換為一個熱編碼
# encode class values as integersencoder = LabelEncoder()encoder.fit(Y)encoded_Y = encoder.transform(Y)# convert integers to dummy variables (i.e. one hot encoded)dummy_y = np_utils.to_categorical(encoded_Y)
六,定義神經網路模型
Keras庫提供了封裝類,允許您在scikit-learn中使用Keras開發的神經網路模型。
Keras中有一個KerasClassifier類,可用作scikit-learn中的Estimator,它是庫中基本類型的模型。KerasClassifier將函數的名稱作為參數。該函數必須返回構建的神經網路模型,為訓練做好準備。
下面是一個函數,它將為鳶尾花分類問題建立一個基準神經網路。它建立了一個簡單的完全串連的網路,其中一個隱藏層包含8個神經元。
隱藏層使用整流器啟用功能,這是一種很好的做法。因為我們對鳶尾花資料集使用了單熱編碼,所以輸出層必須建立3個輸出值,每個類一個。具有最大值的輸出值將被視為模型預測的類。
這個簡單的單層神經網路的網路拓撲可以概括為:
4 inputs -> [8 hidden nodes] -> 3 outputs
請注意,我們在輸出層使用“ softmax ”啟用功能。這是為了確保輸出值在0和1的範圍內,並且可以用作預測機率。
最後,網路使用具有對數損失函數的高效Adam梯度下降最佳化演算法,在Keras中稱為“ categorical_crossentropy ”。
# define baseline modeldef baseline_model():# create modelmodel = Sequential()model.add(Dense(8, input_dim=4, activation='relu'))model.add(Dense(3, activation='softmax'))# Compile modelmodel.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])return model
我們現在可以建立我們的KerasClassifier用於scikit-learn。
我們還可以在構造KerasClassifier類中傳遞參數,該類將傳遞給內部用於訓練神經網路的fit()函數。在這裡,我們將時期數量傳遞為200,批量大小為5,以便在訓練模型時使用。通過將verbose設定為0,在訓練時也會關閉調試。
estimator = KerasClassifier(build_fn=baseline_model, epochs=200, batch_size=5, verbose=0)
七,使用k-fold交叉驗證評估模型
Keras是基於Theano或Tensorflow底層開發的簡單模組化的神經網路架構,因此用Keras搭建網路結構會比Tensorflow更加簡單。這裡我們將使用Keras提供的KerasClassifier類,這個類可以在scikit-learn包中作為Estimator使用,故利用這個類我們就可以方便的調用sklearn包中的一些函數進行資料預先處理和結果評估(此為sklearn包中模型(model)的基本類型)。
對於網路結構,我們採用3層全向串連的,輸入層有4個節點,隱含層有10個節點,輸出層有3個節點的網路。其中,隱含層的啟用函數為relu(rectifier),輸出層的啟用函數為softmax。損失函數則相應的選擇categorical_crossentropy(此函數來著theano或tensorflow,具體可以參見這裡)(二分類的話一般選擇activation=‘sigmoid’, loss=‘binary_crossentropy’)。
PS:對於多類分類網路結構而言,增加中間隱含層能夠提升訓練精度,但是所需的計算時間和空間會增大,因此需要測試選擇一個合適的數目,這裡我們設為10;此外,每一層的捨棄率(dropout)也需要相應調整(太高容易欠擬合,太低容易過擬合),這裡我們設為0.2。
我們現在可以在訓練資料上評估神經網路模型。
scikit-learn具有使用一套技術評估模型的出色能力。評估機器學習模型的黃金標準是k倍交叉驗證。
首先,我們可以定義模型評估程式。在這裡,我們將摺疊數設定為10(一個很好的預設值)並在分區之前對資料進行洗牌。
kfold = KFold(n_splits=10, shuffle=True, random_state=seed)
現在我們可以使用10倍交叉驗證程式(kfold)在我們的資料集(X和dummy_y)上評估我們的模型(估計器)。
評估模型僅需要大約10秒鐘,並返回一個對象,該對象描述了對資料集的每個分割的10個構建模型的評估。
results = cross_val_score(estimator, X, dummy_y, cv=kfold)print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))
結果總結為資料集上模型精度的均值和標準差。這是對看不見的資料的模型效能的合理估計。對於這個問題,它也屬於已知的最佳結果範圍。
Accuracy: 97.33% (4.42%)
八, 代碼實現
import numpy as npimport pandas as pdfrom keras.models import Sequentialfrom keras.layers import Dense, Dropoutfrom keras.wrappers.scikit_learn import KerasClassifierfrom keras.utils import np_utilsfrom sklearn.model_selection import train_test_split, KFold, cross_val_scorefrom sklearn.preprocessing import LabelEncoder# load datasetdataframe = pd.read_csv("iris.csv", header=None)dataset = dataframe.valuesX = dataset[:, 0:4].astype(float)Y = dataset[:, 4]# encode class values as integersencoder = LabelEncoder()encoded_Y = encoder.fit_transform(Y)# convert integers to dummy variables (one hot encoding)dummy_y = np_utils.to_categorical(encoded_Y)# define model structuredef baseline_model(): model = Sequential() model.add(Dense(output_dim=10, input_dim=4, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(output_dim=3, input_dim=10, activation='softmax')) # Compile model model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) return modelestimator = KerasClassifier(build_fn=baseline_model, nb_epoch=40, batch_size=256)# splitting data into training set and test set. If random_state is set to an integer, the split datasets are fixed.X_train, X_test, Y_train, Y_test = train_test_split(X, dummy_y, test_size=0.3, random_state=0)estimator.fit(X_train, Y_train)# make predictionspred = estimator.predict(X_test)# inverse numeric variables to initial categorical labelsinit_lables = encoder.inverse_transform(pred)# k-fold cross-validateseed = 42np.random.seed(seed)kfold = KFold(n_splits=10, shuffle=True, random_state=seed)results = cross_val_score(estimator, X, dummy_y, cv=kfold)
九,總結
在這篇文章中,我們學習了如何使用Keras Python庫開發和評估神經網路以進行深度學習。學習了以下知識:
- 如何載入資料並使其可用於Keras。
- 如何使用一個熱編碼準備多類分類資料進行建模。
- 如何使用keras神經網路模型與scikit-learn。
- 如何使用Keras定義神經網路進行多類分類。
- 如何使用帶有k-fold交叉驗證的scikit-learn來評估Keras神經網路模型
十,參考
- http://machinelearningmastery.com/multi-class-classification-tutorial-keras-deep-learning-library/
- http://datascience.stackexchange.com/questions/10048/what-is-the-best-keras-model-for-multi-label-classification
- http://stackoverflow.com/questions/28064634/random-state-pseudo-random-numberin-scikit-learn
- http://scikit-learn.org/stable/modules/classes.html