Keras是一個用於深度學習的Python庫,它包含高效的數值庫Theano和TensorFlow。
本文的目的是學習如何從csv中加載數據並使其可供Keras使用,如何用神經網絡建立多類分類的數據進行建模,如何使用scikit-learn評估Keras神經網絡模型。
前言,對兩分類和多分類的概念描述
(前言是整理別人博客的筆記https://blog.csdn.net/qq_22238533/article/details/77774223)
1,在LR(邏輯回歸)中,如何進行多分類?
一般情況下,我們所認識的lr模型是一個二分類的模型,但是能否用lr進行多分類任務呢?答案當然是可以的。
不過我們需要注意的是,我們有許多種思想利用lr來進行分類
2,訓練多個二分類器的思想
既然天然的lr是用來做二分類,那么我們很自然地想到把多分類划分為多個二分類的任務。
具體有以下三種策略:
2.1 一對一
假如某個分類中有N個類別,我們將這N個類別進行兩兩配對(兩兩配對后轉化為二分類問題)。那么我們可以得到個二分類器。(簡單解釋一下,相當於在N個類別里面抽2個)



2.2 一對其余 (OvR)

2.3 多對多(MvM)
3,對於上面的方法其實都是訓練多個二分類器,那么有沒有更加直接的方法對LR來進行多分類呢?




一,問題描述
這個數據集經過深入研究,是在神經網絡上練習的一個很好的問題,因為所有4個輸入變量都是數字的,並且具有相同的厘米級別。每個實例描述觀察到的花測量的屬性,輸出變量是特定的鳶尾種類。
這是一個多類別的分類問題,意味着有兩個以上的類需要預測,實際上有三種花種。這是用神經網絡練習的一個重要問題類型,因為三個類值需要專門的處理。
鳶尾花數據集是一個充分研究的問題,我們可以期望實現模型精度為在95%至97%的范圍內,這為開發我們的模型提供了一個很好的目標。
您可以從UCI機器學習庫下載鳶尾花數據集,並將其放在當前工作目錄中,文件名為 “ iris.csv”。
5.1,3.5,1.4,0.2,Iris-setosa 4.9,3.0,1.4,0.2,Iris-setosa 4.7,3.2,1.3,0.2,Iris-setosa 4.6,3.1,1.5,0.2,Iris-setosa 5.0,3.6,1.4,0.2,Iris-setosa 5.4,3.9,1.7,0.4,Iris-setosa 4.6,3.4,1.4,0.3,Iris-setosa 5.0,3.4,1.5,0.2,Iris-setosa 4.4,2.9,1.4,0.2,Iris-setosa 4.9,3.1,1.5,0.1,Iris-setosa 5.4,3.7,1.5,0.2,Iris-setosa 4.8,3.4,1.6,0.2,Iris-setosa 4.8,3.0,1.4,0.1,Iris-setosa 4.3,3.0,1.1,0.1,Iris-setosa 5.8,4.0,1.2,0.2,Iris-setosa 5.7,4.4,1.5,0.4,Iris-setosa 5.4,3.9,1.3,0.4,Iris-setosa 5.1,3.5,1.4,0.3,Iris-setosa 5.7,3.8,1.7,0.3,Iris-setosa 5.1,3.8,1.5,0.3,Iris-setosa 5.4,3.4,1.7,0.2,Iris-setosa 5.1,3.7,1.5,0.4,Iris-setosa 4.6,3.6,1.0,0.2,Iris-setosa 5.1,3.3,1.7,0.5,Iris-setosa 4.8,3.4,1.9,0.2,Iris-setosa 5.0,3.0,1.6,0.2,Iris-setosa 5.0,3.4,1.6,0.4,Iris-setosa 5.2,3.5,1.5,0.2,Iris-setosa 5.2,3.4,1.4,0.2,Iris-setosa 4.7,3.2,1.6,0.2,Iris-setosa 4.8,3.1,1.6,0.2,Iris-setosa 5.4,3.4,1.5,0.4,Iris-setosa 5.2,4.1,1.5,0.1,Iris-setosa 5.5,4.2,1.4,0.2,Iris-setosa 4.9,3.1,1.5,0.1,Iris-setosa 5.0,3.2,1.2,0.2,Iris-setosa 5.5,3.5,1.3,0.2,Iris-setosa 4.9,3.1,1.5,0.1,Iris-setosa 4.4,3.0,1.3,0.2,Iris-setosa 5.1,3.4,1.5,0.2,Iris-setosa 5.0,3.5,1.3,0.3,Iris-setosa 4.5,2.3,1.3,0.3,Iris-setosa 4.4,3.2,1.3,0.2,Iris-setosa 5.0,3.5,1.6,0.6,Iris-setosa 5.1,3.8,1.9,0.4,Iris-setosa 4.8,3.0,1.4,0.3,Iris-setosa 5.1,3.8,1.6,0.2,Iris-setosa 4.6,3.2,1.4,0.2,Iris-setosa 5.3,3.7,1.5,0.2,Iris-setosa 5.0,3.3,1.4,0.2,Iris-setosa 7.0,3.2,4.7,1.4,Iris-versicolor 6.4,3.2,4.5,1.5,Iris-versicolor 6.9,3.1,4.9,1.5,Iris-versicolor 5.5,2.3,4.0,1.3,Iris-versicolor 6.5,2.8,4.6,1.5,Iris-versicolor 5.7,2.8,4.5,1.3,Iris-versicolor 6.3,3.3,4.7,1.6,Iris-versicolor 4.9,2.4,3.3,1.0,Iris-versicolor 6.6,2.9,4.6,1.3,Iris-versicolor 5.2,2.7,3.9,1.4,Iris-versicolor 5.0,2.0,3.5,1.0,Iris-versicolor 5.9,3.0,4.2,1.5,Iris-versicolor 6.0,2.2,4.0,1.0,Iris-versicolor 6.1,2.9,4.7,1.4,Iris-versicolor 5.6,2.9,3.6,1.3,Iris-versicolor 6.7,3.1,4.4,1.4,Iris-versicolor 5.6,3.0,4.5,1.5,Iris-versicolor 5.8,2.7,4.1,1.0,Iris-versicolor 6.2,2.2,4.5,1.5,Iris-versicolor 5.6,2.5,3.9,1.1,Iris-versicolor 5.9,3.2,4.8,1.8,Iris-versicolor 6.1,2.8,4.0,1.3,Iris-versicolor 6.3,2.5,4.9,1.5,Iris-versicolor 6.1,2.8,4.7,1.2,Iris-versicolor 6.4,2.9,4.3,1.3,Iris-versicolor 6.6,3.0,4.4,1.4,Iris-versicolor 6.8,2.8,4.8,1.4,Iris-versicolor 6.7,3.0,5.0,1.7,Iris-versicolor 6.0,2.9,4.5,1.5,Iris-versicolor 5.7,2.6,3.5,1.0,Iris-versicolor 5.5,2.4,3.8,1.1,Iris-versicolor 5.5,2.4,3.7,1.0,Iris-versicolor 5.8,2.7,3.9,1.2,Iris-versicolor 6.0,2.7,5.1,1.6,Iris-versicolor 5.4,3.0,4.5,1.5,Iris-versicolor 6.0,3.4,4.5,1.6,Iris-versicolor 6.7,3.1,4.7,1.5,Iris-versicolor 6.3,2.3,4.4,1.3,Iris-versicolor 5.6,3.0,4.1,1.3,Iris-versicolor 5.5,2.5,4.0,1.3,Iris-versicolor 5.5,2.6,4.4,1.2,Iris-versicolor 6.1,3.0,4.6,1.4,Iris-versicolor 5.8,2.6,4.0,1.2,Iris-versicolor 5.0,2.3,3.3,1.0,Iris-versicolor 5.6,2.7,4.2,1.3,Iris-versicolor 5.7,3.0,4.2,1.2,Iris-versicolor 5.7,2.9,4.2,1.3,Iris-versicolor 6.2,2.9,4.3,1.3,Iris-versicolor 5.1,2.5,3.0,1.1,Iris-versicolor 5.7,2.8,4.1,1.3,Iris-versicolor 6.3,3.3,6.0,2.5,Iris-virginica 5.8,2.7,5.1,1.9,Iris-virginica 7.1,3.0,5.9,2.1,Iris-virginica 6.3,2.9,5.6,1.8,Iris-virginica 6.5,3.0,5.8,2.2,Iris-virginica 7.6,3.0,6.6,2.1,Iris-virginica 4.9,2.5,4.5,1.7,Iris-virginica 7.3,2.9,6.3,1.8,Iris-virginica 6.7,2.5,5.8,1.8,Iris-virginica 7.2,3.6,6.1,2.5,Iris-virginica 6.5,3.2,5.1,2.0,Iris-virginica 6.4,2.7,5.3,1.9,Iris-virginica 6.8,3.0,5.5,2.1,Iris-virginica 5.7,2.5,5.0,2.0,Iris-virginica 5.8,2.8,5.1,2.4,Iris-virginica 6.4,3.2,5.3,2.3,Iris-virginica 6.5,3.0,5.5,1.8,Iris-virginica 7.7,3.8,6.7,2.2,Iris-virginica 7.7,2.6,6.9,2.3,Iris-virginica 6.0,2.2,5.0,1.5,Iris-virginica 6.9,3.2,5.7,2.3,Iris-virginica 5.6,2.8,4.9,2.0,Iris-virginica 7.7,2.8,6.7,2.0,Iris-virginica 6.3,2.7,4.9,1.8,Iris-virginica 6.7,3.3,5.7,2.1,Iris-virginica 7.2,3.2,6.0,1.8,Iris-virginica 6.2,2.8,4.8,1.8,Iris-virginica 6.1,3.0,4.9,1.8,Iris-virginica 6.4,2.8,5.6,2.1,Iris-virginica 7.2,3.0,5.8,1.6,Iris-virginica 7.4,2.8,6.1,1.9,Iris-virginica 7.9,3.8,6.4,2.0,Iris-virginica 6.4,2.8,5.6,2.2,Iris-virginica 6.3,2.8,5.1,1.5,Iris-virginica 6.1,2.6,5.6,1.4,Iris-virginica 7.7,3.0,6.1,2.3,Iris-virginica 6.3,3.4,5.6,2.4,Iris-virginica 6.4,3.1,5.5,1.8,Iris-virginica 6.0,3.0,4.8,1.8,Iris-virginica 6.9,3.1,5.4,2.1,Iris-virginica 6.7,3.1,5.6,2.4,Iris-virginica 6.9,3.1,5.1,2.3,Iris-virginica 5.8,2.7,5.1,1.9,Iris-virginica 6.8,3.2,5.9,2.3,Iris-virginica 6.7,3.3,5.7,2.5,Iris-virginica 6.7,3.0,5.2,2.3,Iris-virginica 6.3,2.5,5.0,1.9,Iris-virginica 6.5,3.0,5.2,2.0,Iris-virginica 6.2,3.4,5.4,2.3,Iris-virginica 5.9,3.0,5.1,1.8,Iris-virginica
二,導入類和函數
我們從導入本文需要的所有類和函數開始。其中包括需要Keras的功能,還包括來自pandas的數據加載以及來自scikit-learn的數據准備和模型評估。
import numpy import pandas from keras.models import Sequential from keras.layers import Dense from keras.wrappers.scikit_learn import KerasClassifier from keras.utils import np_utils from sklearn.model_selection import cross_val_score from sklearn.model_selection import KFold from sklearn.preprocessing import LabelEncoder from sklearn.pipeline import Pipeline
三,初始化隨機數生成器
下面,我們將隨機數生成器初始化為常量值(7)
這對於確保我們可以再次精確地實現從該模型獲得的結果非常重要,它確保可以再現訓練神經網絡模型的隨機過程。
# fix random seed for reproducibility seed = 7 numpy.random.seed(seed)
四,記載數據集
可以直接加載數據集。因為輸出變量包含字符串,所以最容易使用pandas加載數據。然后我們可以將屬性(列)拆分為輸入變量(X)和輸出變量(Y)。
# load dataset dataframe = pandas.read_csv("iris.csv", header=None) dataset = dataframe.values X = 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, label 1, Iris-setosa 2, Iris-versicolor 3, Iris-virginica
用one hot encoding轉化后如下:
sample, Iris-setosa, Iris-versicolor, Iris-virginica 1, 1, 0, 0 2, 0, 1, 0 3, 0, 0, 1
注意這里不要將label直接轉化成數值變量,如1,2,3,這樣的話與其說是預測問題更像是回歸預測的問題,后者的難度比前者大。(當類別比較多的時候輸出值的跨度就會比較大,此時輸出層的激活函數就只能用linear)
我們可以通過首先使用scikit-learn類LabelEncoder將字符串一致地編碼為整數來完成此操作。然后使用Keras函數to_categorical()將整數向量轉換為一個熱編碼
# encode class values as integers encoder = 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 model def baseline_model(): # create model model = Sequential() model.add(Dense(8, input_dim=4, activation='relu')) model.add(Dense(3, activation='softmax')) # Compile model model.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 np import pandas as pd from keras.models import Sequential from keras.layers import Dense, Dropout from keras.wrappers.scikit_learn import KerasClassifier from keras.utils import np_utils from sklearn.model_selection import train_test_split, KFold, cross_val_score from sklearn.preprocessing import LabelEncoder # load dataset dataframe = pd.read_csv("iris.csv", header=None) dataset = dataframe.values X = dataset[:, 0:4].astype(float) Y = dataset[:, 4] # encode class values as integers encoder = 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 structure def 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 model estimator = 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 predictions pred = estimator.predict(X_test) # inverse numeric variables to initial categorical labels init_lables = encoder.inverse_transform(pred) # k-fold cross-validate seed = 42 np.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