1. 程式人生 > >【Iris】【Keras】神經網路分類器和【scikit-learn】邏輯迴歸分類器的構建

【Iris】【Keras】神經網路分類器和【scikit-learn】邏輯迴歸分類器的構建

原文連結:https://github.com/fastforwardlabs/keras-hello-world/blob/master/kerashelloworld.ipynb

原文標題:“Hello world” in Keras

本文全部程式碼基於python2,使用編輯器為ipython notebook,入門級。

高階神經網路庫的出現,使開發人員能夠快速構建神經網路模型,而不必擔心浮點運算、張量代數和GPU程式設計的數值細節。

Keras是一種高階神經網路庫,它基於Theano或TensorFlow的後端(backends)工作,提供了一種類似於scikit-learn的API。

我將提供一個快速上手教程,詳細比對Keras和scikit-learn,並教會你如何使用Keras。

一、Scikit-learn

Scikit-learn是Python開發人員使用的最為流行的、功能完備的機器學習庫。Scikit-learn的API圍繞Estimator物件構建,表現出簡單、連貫、一致的特性。這套API是針對機器學習工作流程的一個很好的描述,許多工程師都習慣於此,也在很多工具包中得到廣泛使用。

我們從匯入所需的庫開始工作:scikit-learn、Keras和一些繪圖功能。

%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

from sklearn.cross_validation import train_test_split
from sklearn.linear_model import LogisticRegressionCV

from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.utils import np_utils

1、Iris data

著名的鳶尾花(Iris)資料集(由Ronald Fisher於1936年發表)是一種展示機器學習框架API的好方法。從某種程度上說,Iris資料集是機器學習界的”Hello world“。

資料很簡單,可以使用非常簡單的分類器獲得高精度。因此,使用神經網路解決這個問題有點小題大做。但是這不錯啊!我們的目的是探索從資料到可用分類器所需的程式碼,而不是模型設計和選擇的細節。

Iris資料集內置於許多機器學習庫中。我更喜歡它在seaborn中的副本,因為這一副本是個有標籤的資料框(dataframe),可以很容易的做資料視覺化。既然我們使用seaborn庫,不妨載入該資料集並觀察一下前5個樣本。

iris = sns.load_dataset("iris")
iris.head()

對於每個樣本(本例中是花),存在五個資料。其中前四項是花的尺寸(釐米)的標準測量,第五項是鳶尾花的種類。資料集中有三種鳶尾花:setosa、verscicolor和virginica。我們的工作是建立一個分類器,給定兩個花瓣和兩個萼片的測量,可以預測鳶尾花的種類。

2、調整並切分資料用於訓練和測試

首先,我們需要從iris資料框中提取原始資料。我們將花瓣和萼片資料儲存到陣列X中,將種類標記儲存到響應的陣列Y中。

X = iris.values[:, :4]
y = iris.values[:, 4]

按照有監督機器學習的標準,我們使用一部分資料訓練模型,並使用剩餘的資料衡量模型的效能。這是很容易做到的,已經內建成為scikit-learn的train_test_split()函式。

train_X, test_X, train_y, test_y = train_test_split(X, y, train_size=0.5, random_state=0)

3、訓練一個scikit-learn分類器

我們將要訓練一個logistic迴歸分類器。訓練分類器、使用內建的超引數交叉驗證,是scikit-learn中的一條工作線。

像所有其他scikit-learn的Estimator物件一樣,LogisticRegressionCV分類器有一個.fit()方法,可以處理模型訓練細節,搜尋到最適於訓練集的模型引數。這個方法就是我們所要做的全部:

lr = LogisticRegressionCV()
lr.fit(train_X, train_y)

4、基於正確率評估模型效能

現在我們可以測量訓練得到的分類器在測試集上的效能優劣(如正確率:accuracy)。

print("Accuracy = {:.2f}".format(lr.score(test_X, test_y)))
正確率大概等於0.83.

二、Keras

說明:本教程中的Keras選擇Theano作為後端。

Keras預設使用TensorFlow作為後端來進行張量操作,也可以按需切換到Theano。

如果你至少執行過一次Keras,你將在下面的目錄下找到Keras的配置檔案:

~/.keras/keras.json

如果該目錄下沒有該檔案,你可以手動建立一個,檔案的預設配置如下:

{
“image_dim_ordering”:”tf”,
“epsilon”:1e-07,
“floatx”:”float32”,
“backend”:”tensorflow”
}

將backend欄位的值改寫為你需要使用的後端:theano或tensorflow,即可完成後端的切換。注意image_dim_ordering欄位需要與之對應:th或tf,該選項指定了Keras將要使用的維度順序,可通過keras.backend.image_dim_ordering()來獲取當前的維度順序。對2D資料來說,tf假定維度順序為(rows,cols,channels)而th假定維度順序為(channels, rows, cols)。對3D資料而言,tf假定(conv_dim1, conv_dim2, conv_dim3, channels),th則是(channels, conv_dim1, conv_dim2, conv_dim3)。

1、現在做一些與Keras非常相似的事情

正如我們剛剛看到的,scikit-learn構建分類器非常簡單:一行程式碼用於例項化分類器;一行程式碼用於訓練分類器;一行程式碼用於衡量分類器效能。

在Keras上構建分類器只是稍微複雜一點。資料的預處理有一點變化,另外,我們必須做一些工作來定義網路,然後將其例項化為分類器,除此之外,Keras的使用與scikit-learn非常相似。

在資料預處理方面,scikit-learn分類器接收字元型標籤,如”setosa“。但是,Keras需要將標籤做獨熱編碼(One-Hot-Encoded)。有很多方法可以實現獨熱編碼。如果你是一個Pandas使用者,那麼可以使用pandas.get_dummies(),基於scikit-learn實現獨熱編碼。此處我們使用一個Keras實用程式和一些numpy。

def one_hot_encode_object_array(arr):
    '''One hot encode a numpy array of objects (e.g. strings)'''
    uniques, ids = np.unique(arr, return_inverse=True)
    return np_utils.to_categorical(ids, len(uniques))

train_y_ohe = one_hot_encode_object_array(train_y)
test_y_ohe = one_hot_encode_object_array(test_y)

2、構建神經網路模型

除了這種在特定情況下需要的資料預處理之外,與scikit-learn最大的區別在於,使用Keras工作,你必須先指定模型的結構,然後才能例項化和使用它。

在scikit-learn中,模型是現成的。Keras是一個神經網路庫,因此,即使你的資料特徵或資料類別的數目存在限制,你可以定義模型結構所有的其他方面:網路層數、層的大小、層間連線性質等。(如果這些引數沒有意義,Keras是一種很偉大的實驗方法)

這樣的自由度帶來一個缺點,例項化一個最小的分類器也會涉及到比scikit-learn更多的工作需求。

在本例中,我們將構建一個極簡的網路。資料本身為我們做了兩個決定,我們有4個特徵和3個類別,因此輸入層必有4個單元,輸出層必有3個單元。我們只需要定義隱藏層。本例中,我們只定義一個隱藏層,該層包含16個單元。從GPU的角度考慮,16是一個完整的數!在使用神經網路的過程中,你會發現許多2的指數值被使用。

我們將以最常見的方式定義我們的模型:作為層的順序堆疊。另一種方式是作為一個計算圖,但我們在這裡堅持Sequential()。

model = Sequential()

接下來的兩行定義了輸入層的大小(input_shape=(4,))、隱藏層的大小和啟用函式的種類。

model.add(Dense(16, input_shape=(4,)))
model.add(Activation('sigmoid'))

下一行定義了輸出層的大小和啟用函式的種類。

model.add(Dense(3))
model.add(Activation('softmax'))

最後,我們指定優化策略和損失函式進行優化。我們還指定了模型工作是的計算準確度。

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=["accuracy"])

3、使用神經網路分類器

現在我們定義了模型結構並編譯了它,這樣我們得到一個物件,其API幾乎與scikit-learn中的分類器完全一致。特別的,該物件有.fit()和.predict()方法。現在讓我們訓練該模型。

神經網路的訓練通常涉及到”mini-batching“的概念,指的是神經網路一次只讀取訓練集的一個子集,訓練模型調整權重,隨後再讀取訓練集的下一個子集。神經網路完整的讀取整個訓練集一次,稱之為一個”epoch“。Mini-batch/epoch策略的調整,是神經網路訓練中的一個難點。但在本例中,我們設定mini-batch=1,則該策略變成經典的隨機梯度下降策略。神經網路每次從訓練集讀取一個花的樣本,並立即調整網路權重。

下一行程式碼中的引數verbose=0也可以移除。注意,如果你希望實驗mini-batch/epoch策略,你需要重新執行前面的程式碼段,重新編譯模型(model.compile)並初始化模型權重。


model.fit(train_X, train_y_ohe, nb_epoch=100, batch_size=1, verbose=0)

對於一些基本的方法函式,編譯好的Keras模型和scikit-learn分類器之間唯一的語法API差異是,Keras中與scikit-learn.score()方法等效的方法是.evaluate()。

Evaluate()返回損失函式和我們在編譯模型是要求的任何其他度量。在本例中,我們要求的是正確率(accuracy),可以與我們從scikit-learn的LogisticRegressionCV分類器的.score()方法中獲得的正確率進行比較。

loss, accuracy = model.evaluate(test_X, test_y_ohe, verbose=0)
print("Accuracy = {:.2f}".format(accuracy))
正確率大概等於0.97.

可以看到,神經網路模型的測試精度優於簡單邏輯迴歸分類器。

但是也隱藏了神經網路的危險之一:過度擬合。如果有一些過度擬合,可以通過新增dropout(這也是內置於Keras)來處理。

4、下一步應該做什麼?

此處我們構建了一個非常簡單的前饋神經網路。想要進行更多的實驗,可以載入手寫數字的MNIST資料庫,看看是否能夠擊敗標準的scikit-learn分類器。與Iris資料集不同,這種情況下神經網路的功率和相對複雜性是合理的。參考連結:

Keras還有別的層允許你建立模型:

卷積層,其給出計算機垂直問題的最先進的結果;

迴圈層,其特別好地適合於語言建模和其他序列資料。

實際上,神經網路的一個關鍵力量(以及純粹的預測能力)是它們的可組合型。使用像Keras這樣的高階庫,建立一個非常不同的網路只需要幾秒鐘的工作。模型可以像樂高構建一樣。

Have fun!