用 Keras 編寫你的第一個人工神經網路(Python)—— Jinkey 翻譯

Jinkey發表於2017-01-27

譯者:Jinkey(微信公眾號 jinkey-love)
英文原版地址:點選跳轉

教程概述

這裡不需要編寫太多的程式碼,不過我們將一步步慢慢地告訴你怎麼以後怎麼建立自己的模型。
教程將會涵蓋以下步驟:

  1. 載入資料
  2. 定義模型
  3. 編譯模型
  4. 訓練模型
  5. 評估模型
  6. 結合所有步驟在一起

這個教程的前置條件:

  1. 有 python 2 或 3 的環境和程式設計基礎
  2. 安裝並配置好 Scipy 庫(包括 Numpy )
  3. 你安裝好 Keras 並且有一個後端(Theano or TensorFlow

建立一個新的檔案,命名為 keras_first_network.py ,然後將教程的程式碼一步步複製進去。

1. 載入資料

每當我們使用機器學習演算法使用隨機過程(如隨機數),先設定隨機數種子是一個好的習慣。

這樣您就可以執行相同的程式碼一次又一次,得到相同的結果。如果你需要證明結果,使用隨機資料比較演算法或除錯程式碼,這是很有用的。

你可以初始化隨機數發生器及其種子,例如:

from keras.models import Sequential
from keras.layers import Dense
import numpy
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)複製程式碼

現在我們可以載入我們的資料了。
在這個教程中,我們將使用皮馬印第安人糖尿病資料集.這是UCI 機器學習資料庫一個標準的機器學習資料集。它描述了病人醫療記錄和他們是否在五年內發病。

因此,它是一個二分類問題(出現糖尿病為1, 否則為 0)。
所有描述病人的輸入變數都是數值。這便於直接用於需要數值輸入輸出的神經網路, 適合我們第一個 Keras 神經網路。
下載資料集並且重新命名為 pima-indians-diabetes.csv 放入 python 指令碼所在的目錄的 data/pima-indians-diabetes.csv

你可以只直接使用 Numpy 庫的 loadtxt() 方法載入資料,一共 8 個輸出變數和 1 個輸出變數(最後一列)。載入之後我們就可以把資料分離為 X(輸出變數)和 Y(輸出分類)

# load pima indians dataset
dataset = numpy.loadtxt("data/pima-indians-diabetes.csv", delimiter=",")
# split into input (X) and output (Y) variables
X = dataset[:, 0:8]
Y = dataset[:, 8]複製程式碼

我們已經初始化了我們對的隨機數生成器來確保結果可復現, 也載入了資料。我們現在可以準備定義我們的神經網路模型了。

2. 定義模型

Keras 中的模型被定義為一系列的層。

我們例項化一個 Sequential 模型物件,每次新增一層知道我們對網路的拓撲結構滿意。

第一件事情我們需要確保的是輸出神經元的數量。這可以在模型建立的時候設定引數 input_dim 來定義,我們將這個引數設定為 8 對應 8 個輸出變數。
我們怎麼知道層的數量和他們的型別呢?

這是一個非常難回答的問題。這是啟發式的,我們通過不斷地試錯找出最好的網路結構、一般來說,你需要足夠大的網路去明白結構對於問題是否有用。
在這個例子中, 我們使用三層全連線的結構。

全連線層使用 Dense 定義。我們可以通過第一個引數定義層的神經元數量,第二個引數 init 定義權重的初始化方法, activation 引數定義啟用函式。

在這個例子中, 我們把權重初始化成一個服從均勻分佈的小隨機數(init='uniform'),在0到0.05直接(這是 Keras 標準均勻分佈權重初始值)。另一種傳統的選擇是‘normal’,會從高斯分佈(正態分佈)中產生一個小的隨機數。

我們在前兩層使用 (relu)[en.wikipedia.org/wiki/Rectif…)] 啟用函式, 在輸出層使用 Sigmoid 函式。曾經 Sigmoidtanh 啟用函式是所有的層首選的。但時至今日, 使用 relu 啟用函式可以達到更好的效能。我們在輸出層使用 Sigmoid 函式來確保網路輸出在 0 和 1 之間,

我們可以新增每一層將這些東西放到一起。第一層有 12 個神經元、8個輸出變數。第二層有 8 個神經元和最後 1 個神經元的輸出層用於預測類別(糖尿病有無發病)

# create model
model = Sequential()
model.add(Dense(12, input_dim=8, init='uniform', activation='relu'))
model.add(Dense(8, init='uniform', activation='relu'))
model.add(Dense(1, init='uniform', activation='sigmoid'))複製程式碼

3. 編譯模型

現在我們定義好模型, 那麼就可以編譯他了。

編譯使用高效的數學庫, 封裝了 Theano 或者 TensorFlow(稱為 backend)。後端(backend)在你的硬體上自動選擇最好的方式去表現用於訓練和預測的神經網路,比如 CPU、GPU 或者分散式。

編譯時, 我們需要額外定義訓練網路所需要的引數。記住, 訓練網路意味著尋找最優的權重集去預測。

我們需要定義評估權重集的損失函式, 用於尋找不同權重的優化器以及我們希望在訓練過程呈現的可選指標。

在這個例子中, 我們使用對數損失函式(logarithmic loss), 對於二分類問題, 其在 Keras 中稱為“binary_crossentropy”。我們還將使用梯度下降演算法‘adam’, 沒有為什麼, 它就是一種高效地預設方法。想了解更多這種演算法可以檢視論文: (Adam: A Method for Stochastic Optimization)[arxiv.org/abs/1412.69…]

最後, 以為這是一個分類問題, 所以我們會收集和彙報分類的準確率作為度量指標。

# Compile model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])複製程式碼

4. 訓練模型

我們已經定義和編譯了模型, 他是為高效地計算而準備的。

現在是時候在資料上訓練模型了。

我們可以在載入的資料上訓練和擬合模型,通過 fit() 函式。

訓練過程會在資料集迭代一定的次數,成為 epochs, 這個可以通過 nb_epoch 引數來設定。我們也可以設定 batch_size 引數來指定進行梯度下降時每個batch包含的樣本數。訓練時一個batch的樣本會被計算一次梯度下降, 使目標函式優化一步。在這個例子中, 我們將迭代150次、批處理大小為10。再說一次, 這些引數可以通過試錯來選擇。

# Fit the model
model.fit(X, Y, nb_epoch=150, batch_size=10)複製程式碼

這就是在你的 CPU 或者 GPU 上發生的事情。

5. 評估模型

我們已經在整個資料集上訓練了我們的神經網路, 我們可以線上通的資料集上評估神經網路的效能。

這隻會告訴我們模型有多適合已有的資料(訓練的準確率),但我們無從知道演算法在新資料上的效能。

我們可以簡單但很理想地把資料分為訓練集和測試集來分別訓練和評估模型。

你可以通過 evaluate() 函式在訓練集評估你的模型, 使用你訓練模型時相同的輸出和輸出。

這會針對每一個輸出-輸出產生預測並且收集分數,包括平均損失和其他我們定義的指標,比如準確率。

# evaluate the model
scores = model.evaluate(X, Y)
print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))複製程式碼

6. 將這些放在一起

你已經看到用 Keras 建立你的第一個神經網路有多麼簡單、

執行以上的程式碼, 將會看到150個迭代中, 每次迭代的損失和準確率,以及最終的模型在訓練集上的評估結果, 在我的 CPU 上耗時 10s(使用 Theano 作為後端)

...
Epoch 143/150
768/768 [==============================] - 0s - loss: 0.4614 - acc: 0.7878
Epoch 144/150
768/768 [==============================] - 0s - loss: 0.4508 - acc: 0.7969
Epoch 145/150
768/768 [==============================] - 0s - loss: 0.4580 - acc: 0.7747
Epoch 146/150
768/768 [==============================] - 0s - loss: 0.4627 - acc: 0.7812
Epoch 147/150
768/768 [==============================] - 0s - loss: 0.4531 - acc: 0.7943
Epoch 148/150
768/768 [==============================] - 0s - loss: 0.4656 - acc: 0.7734
Epoch 149/150
768/768 [==============================] - 0s - loss: 0.4566 - acc: 0.7839
Epoch 150/150
768/768 [==============================] - 0s - loss: 0.4593 - acc: 0.7839
768/768 [==============================] - 0s
acc: 79.56%

如果你嘗試在 IPython 或者 Jupyter , 你將會得到錯誤。原因是在訓練期間輸出進度條。你可以關閉這個, 通過讓 model.fit() 的引數 verbose=0

福利: 做出預測

我被問得最多的一個問題是:

在我訓練模型之後, 怎麼預測新資料的分類?

這是個好問題。

我們擬合了上述例子, 用他來在訓練集上作出預測, 假裝我們之前沒看到過這些資料。

做預測同樣非常簡單, 只需要使用 model.predict()。我們在輸出層使用 Sigmoid 啟用函式, 因此我們的預測值將會在 0 到 1 的區間內。在這個分類任務中,我們可以輕易地通過四捨五入轉換為離散二分類。

預測訓練集中每一個記錄的完整例子如下:

# Create first network with Keras
from keras.models import Sequential
from keras.layers import Dense
import numpy
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
# load pima indians dataset
dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")
# split into input (X) and output (Y) variables
X = dataset[:,0:8]
Y = dataset[:,8]
# create model
model = Sequential()
model.add(Dense(12, input_dim=8, init='uniform', activation='relu'))
model.add(Dense(8, init='uniform', activation='relu'))
model.add(Dense(1, init='uniform', activation='sigmoid'))
# Compile model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Fit the model
model.fit(X, Y, nb_epoch=150, batch_size=10,  verbose=2)
# calculate predictions
predictions = model.predict(X)
# round predictions
rounded = [round(x) for x in predictions]
print(rounded)複製程式碼

執行這個修改過的例子, 將會列印出每個輸出的預測值。如果有需要的話, 我們可以直接使用這些預測。

[1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0]

總結

在這篇文章當中, 我們學會了如何通過 Keras 建立自己的第一個神經網路模型。

特別是我們學會了 使用 Keras 來建立神經網路或深度學習模型時關鍵的 5 個步驟:

  1. 載入資料
  2. 定義模型
  3. 編譯模型
  4. 訓練模型
  5. 評估模型

有任何疑問歡迎關注我的公眾號 jinkey-love 和我交流。

相關文章