CNTK - 神經網路分類



在本章中,我們將學習如何使用 CNTK 對神經網路進行分類。

簡介

分類可以定義為預測給定輸入資料類別輸出標籤或響應的過程。基於模型在訓練階段學習到的內容,分類輸出可以是“黑色”或“白色”或“垃圾郵件”或“非垃圾郵件”等形式。

另一方面,在數學上,它是近似對映函式(例如f)的任務,該函式將輸入變數(例如 X)對映到輸出變數(例如 Y)。

分類問題的經典示例可以是電子郵件中的垃圾郵件檢測。很明顯,輸出只有兩個類別,“垃圾郵件”和“非垃圾郵件”。

為了實現這種分類,我們首先需要對分類器進行訓練,其中“垃圾郵件”和“非垃圾郵件”電子郵件將用作訓練資料。一旦分類器成功訓練,它就可以用於檢測未知的電子郵件。

在這裡,我們將使用鳶尾花資料集建立一個 4-5-3 NN,該資料集具有以下特徵:

  • 4 個輸入節點(每個預測變數值一個)。

  • 5 個隱藏處理節點。

  • 3 個輸出節點(因為鳶尾花資料集中有三種可能的物種)。

載入資料集

我們將使用鳶尾花資料集,我們希望根據萼片寬度和長度以及花瓣寬度和長度的物理特性對鳶尾花的種類進行分類。資料集描述了不同品種鳶尾花的物理特性:

  • 萼片長度

  • 萼片寬度

  • 花瓣長度

  • 花瓣寬度

  • 類別,即山鳶尾或雜色鳶尾或弗吉尼亞鳶尾

我們有iris.CSV檔案,之前在前面的章節中也使用過。它可以使用Pandas庫載入。但是,在使用它或將其載入到我們的分類器中之前,我們需要準備訓練和測試檔案,以便它可以輕鬆地與 CNTK 一起使用。

準備訓練和測試檔案

鳶尾花資料集是機器學習專案中最流行的資料集之一。它有 150 個數據項,原始資料如下所示:

5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
…
7.0 3.2 4.7 1.4 versicolor
6.4 3.2 4.5 1.5 versicolor
…
6.3 3.3 6.0 2.5 virginica
5.8 2.7 5.1 1.9 virginica

如前所述,每行前四個值描述了不同品種的物理特性,即鳶尾花的萼片長度、萼片寬度、花瓣長度、花瓣寬度。

但是,我們必須將資料轉換為可以輕鬆被 CNTK 使用的格式,該格式為 .ctf 檔案(我們在上一節中也建立了一個 iris.ctf)。它將如下所示:

|attribs 5.1 3.5 1.4 0.2|species 1 0 0
|attribs 4.9 3.0 1.4 0.2|species 1 0 0
…
|attribs 7.0 3.2 4.7 1.4|species 0 1 0
|attribs 6.4 3.2 4.5 1.5|species 0 1 0
…
|attribs 6.3 3.3 6.0 2.5|species 0 0 1
|attribs 5.8 2.7 5.1 1.9|species 0 0 1

在上述資料中,|attribs 標籤標記特徵值的開始,|species 標籤標記類標籤值。我們也可以使用任何其他我們想要的標籤名稱,甚至可以新增專案 ID。例如,請檢視以下資料:

|ID 001 |attribs 5.1 3.5 1.4 0.2|species 1 0 0 |#setosa
|ID 002 |attribs 4.9 3.0 1.4 0.2|species 1 0 0 |#setosa
…
|ID 051 |attribs 7.0 3.2 4.7 1.4|species 0 1 0 |#versicolor
|ID 052 |attribs 6.4 3.2 4.5 1.5|species 0 1 0 |#versicolor
…

鳶尾花資料集中共有 150 個數據項,對於此示例,我們將使用 80-20 保留資料集規則,即 80%(120 個專案)資料項用於訓練目的,其餘 20%(30 個專案)資料項用於測試目的。

構建分類模型

首先,我們需要處理 CNTK 格式的資料檔案,為此我們將使用名為create_reader的輔助函式,如下所示:

def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='attribs', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='species', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src

現在,我們需要為我們的 NN 設定架構引數,並提供資料檔案的位置。這可以透過以下 Python 程式碼完成:

def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 5
output_dim = 3
train_file = ".\\...\\" #provide the name of the training file(120 data items)
test_file = ".\\...\\" #provide the name of the test file(30 data items)

現在,藉助以下程式碼行,我們的程式將建立未經訓練的 NN:

X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
nnet = oLayer
model = C.ops.softmax(nnet)

現在,一旦我們建立了雙重未經訓練的模型,我們需要設定 Learner 演算法物件,然後使用它來建立 Trainer 訓練物件。我們將使用 SGD 學習器和cross_entropy_with_softmax損失函式:

tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 2000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])

編寫學習演算法程式碼如下:

max_iter = 2000
batch_size = 10
lr_schedule = C.learning_parameter_schedule_per_sample([(1000, 0.05), (1, 0.01)])
mom_sch = C.momentum_schedule([(100, 0.99), (0, 0.95)], batch_size)
learner = C.fsadagrad(nnet.parameters, lr=lr_schedule, momentum=mom_sch)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])

現在,一旦我們完成了 Trainer 物件,我們需要建立一個 reader 函式來讀取訓練資料:

rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }

現在是時候訓練我們的 NN 模型了:

for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))

一旦我們完成了訓練,讓我們使用測試資料項評估模型:

print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 30
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)

在評估我們訓練的 NN 模型的準確性後,我們將使用它對看不見的資料進行預測:

np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[6.4, 3.2, 4.5, 1.5]], dtype=np.float32)
print("\nPredicting Iris species for input features: ")
print(unknown[0]) pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities are: ")
print(pred_prob[0])

完整分類模型

Import numpy as np
Import cntk as C
def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='attribs', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='species', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 5
output_dim = 3
train_file = ".\\...\\" #provide the name of the training file(120 data items)
test_file = ".\\...\\" #provide the name of the test file(30 data items)
X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
nnet = oLayer
model = C.ops.softmax(nnet)
tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 2000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
max_iter = 2000
batch_size = 10
lr_schedule = C.learning_parameter_schedule_per_sample([(1000, 0.05), (1, 0.01)])
mom_sch = C.momentum_schedule([(100, 0.99), (0, 0.95)], batch_size)
learner = C.fsadagrad(nnet.parameters, lr=lr_schedule, momentum=mom_sch)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 30
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[7.0, 3.2, 4.7, 1.4]], dtype=np.float32)
print("\nPredicting species for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities: ")
print(pred_prob[0])
if __name__== ”__main__”:
main()

輸出

Using CNTK version = 2.7
batch 0: mean loss = 1.0986, mean accuracy = 40.00%
batch 500: mean loss = 0.6677, mean accuracy = 80.00%
batch 1000: mean loss = 0.5332, mean accuracy = 70.00%
batch 1500: mean loss = 0.2408, mean accuracy = 100.00%
Evaluating test data
Classification accuracy = 94.58%
Predicting species for input features:
[7.0 3.2 4.7 1.4]
Prediction probabilities:
[0.0847 0.736 0.113]

儲存訓練好的模型

此鳶尾花資料集只有 150 個數據項,因此訓練 NN 分類器模型只需要幾秒鐘,但在具有數百或數千個數據項的大型資料集上進行訓練可能需要數小時甚至數天。

我們可以儲存我們的模型,這樣我們就無需從頭開始保留它。藉助以下 Python 程式碼,我們可以儲存我們訓練的 NN:

nn_classifier = “.\\neuralclassifier.model” #provide the name of the file
model.save(nn_classifier, format=C.ModelFormat.CNTKv2)

以下是上面使用的save()函式的引數:

  • 檔名是save()函式的第一個引數。它也可以與檔案路徑一起寫入。

  • 另一個引數是format引數,其預設值為C.ModelFormat.CNTKv2

載入訓練好的模型

儲存訓練好的模型後,載入該模型非常容易。我們只需要使用load()函式即可。讓我們在下面的示例中檢查一下:

import numpy as np
import cntk as C
model = C.ops.functions.Function.load(“.\\neuralclassifier.model”)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[7.0, 3.2, 4.7, 1.4]], dtype=np.float32)
print("\nPredicting species for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities: ")
print(pred_prob[0])

儲存模型的好處是,一旦載入了儲存的模型,就可以像剛剛訓練過模型一樣使用它。

廣告

© . All rights reserved.