CNTK - 神經網路迴歸



本章將幫助您瞭解關於 CNTK 的神經網路迴歸。

介紹

眾所周知,為了從一個或多個預測變數中預測數值,我們使用迴歸。讓我們以預測某個 100 個城鎮之一的房屋中位數為例。為此,我們擁有包含以下資料:-

  • 每個城鎮的犯罪統計資料。

  • 每個城鎮房屋的年齡。

  • 每個城鎮到主要位置的距離度量。

  • 每個城鎮的學生與教師比率。

  • 每個城鎮的人種人口統計資料。

  • 每個城鎮的房屋中位數。

基於這五個預測變數,我們希望預測房屋中位數。為此,我們可以建立一個類似於以下的線性迴歸模型:-

Y = a0+a1(crime)+a2(house-age)+(a3)(distance)+(a4)(ratio)+(a5)(racial)

在上式中:-

Y 是預測的中位數

a0 是常數,並且

a1 到 a5 都是與我們上面討論的五個預測變數相關的常數。

我們還可以使用神經網路作為替代方法。它將建立更準確的預測模型。

在這裡,我們將使用 CNTK 建立神經網路迴歸模型。

載入資料集

要使用 CNTK 實現神經網路迴歸,我們將使用波士頓地區房屋價值資料集。該資料集可從 UCI 機器學習儲存庫下載,網址為 https://archive.ics.uci.edu/。此資料集共有 14 個變數和 506 個例項。

但是,對於我們的實現程式,我們將使用 14 個變數中的 6 個和 100 個例項。在 6 箇中,5 個作為預測變數,1 個作為要預測的值。從 100 個例項中,我們將使用 80 個用於訓練,20 個用於測試。我們想要預測的值是城鎮的房屋中位數。讓我們看看我們將使用的五個預測變數:-

  • 城鎮的人均犯罪率 - 我們預計較小的值與該預測變數相關聯。

  • 自住單位比例 - 1940 年之前建造的 - 我們預計較小的值與該預測變數相關聯,因為較大的值表示房屋較舊。

  • 城鎮到波士頓五個就業中心的加權距離。

  • 區域學校學生與教師比率。

  • 城鎮黑人居民比例的間接指標。

準備訓練和測試檔案

像之前一樣,首先我們需要將原始資料轉換為 CNTK 格式。我們將使用前 80 個數據項進行訓練,因此製表符分隔的 CNTK 格式如下:-

|predictors 1.612820 96.90 3.76 21.00 248.31 |medval 13.50
|predictors 0.064170 68.20 3.36 19.20 396.90 |medval 18.90
|predictors 0.097440 61.40 3.38 19.20 377.56 |medval 20.00
. . .

接下來的 20 個專案也轉換為 CNTK 格式,將用於測試。

構建迴歸模型

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

def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='predictors', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='medval', 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

接下來,我們需要建立一個輔助函式,該函式接受 CNTK 小批次物件並計算自定義準確度指標。

def mb_accuracy(mb, x_var, y_var, model, delta):
   num_correct = 0
   num_wrong = 0
   x_mat = mb[x_var].asarray()
   y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
  v = model.eval(x_mat[i])
  y = y_mat[i]
if np.abs(v[0,0] – y[0,0]) < delta:
   num_correct += 1
else:
   num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)

現在,我們需要為我們的 NN 設定架構引數,並提供資料檔案的路徑。可以使用以下 Python 程式碼完成:-

def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 5
hidden_dim = 20
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file(80 data items)
test_file = ".\\...\\" #provide the name of the test file(20 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)
model = C.ops.alias(oLayer)

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

tr_loss = C.squared_error(model, Y)
max_iter = 3000
batch_size = 5
base_learn_rate = 0.02
sch=C.learning_parameter_schedule([base_learn_rate, base_learn_rate/2], minibatch_size=batch_size, epoch_size=int((max_iter*batch_size)/2))
learner = C.sgd(model.parameters, sch)
trainer = C.Trainer(model, (tr_loss), [learner])

現在,一旦我們完成了學習演算法物件,我們就需要建立一個 reader 函式來讀取訓練資料:-

rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
boston_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=boston_input_map) trainer.train_minibatch(curr_batch)
if i % int(max_iter/10) == 0:
mcee = trainer.previous_minibatch_loss_average
acc = mb_accuracy(curr_batch, X, Y, model, delta=3.00)
print("batch %4d: mean squared error = %8.4f, accuracy = %5.2f%% " \ % (i, mcee, acc))

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

print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=boston_input_map)
acc = mb_accuracy(all_test, X, Y, model, delta=3.00)
print("Prediction accuracy = %0.2f%%" % acc)

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

np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,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='predictors', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='medval', 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 mb_accuracy(mb, x_var, y_var, model, delta):
num_correct = 0
num_wrong = 0
x_mat = mb[x_var].asarray()
y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
   v = model.eval(x_mat[i])
   y = y_mat[i]
if np.abs(v[0,0] – y[0,0]) < delta:
   num_correct += 1
else:
   num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 5
hidden_dim = 20
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file(80 data items)
test_file = ".\\...\\" #provide the name of the test file(20 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)
model = C.ops.alias(oLayer)
tr_loss = C.squared_error(model, Y)
max_iter = 3000
batch_size = 5
base_learn_rate = 0.02
sch = C.learning_parameter_schedule([base_learn_rate, base_learn_rate/2], minibatch_size=batch_size, epoch_size=int((max_iter*batch_size)/2))
learner = C.sgd(model.parameters, sch)
trainer = C.Trainer(model, (tr_loss), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
boston_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=boston_input_map) trainer.train_minibatch(curr_batch)
if i % int(max_iter/10) == 0:
   mcee = trainer.previous_minibatch_loss_average
   acc = mb_accuracy(curr_batch, X, Y, model, delta=3.00)
   print("batch %4d: mean squared error = %8.4f, accuracy = %5.2f%% " \ % (i, mcee, acc))
   print("\nEvaluating test data \n")
   rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
   boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
   num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=boston_input_map)
acc = mb_accuracy(all_test, X, Y, model, delta=3.00)
print("Prediction accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])
if __name__== ”__main__”:
   main()

輸出

Using CNTK version = 2.7
batch 0: mean squared error = 385.6727, accuracy = 0.00%
batch 300: mean squared error = 41.6229, accuracy = 20.00%
batch 600: mean squared error = 28.7667, accuracy = 40.00%
batch 900: mean squared error = 48.6435, accuracy = 40.00%
batch 1200: mean squared error = 77.9562, accuracy = 80.00%
batch 1500: mean squared error = 7.8342, accuracy = 60.00%
batch 1800: mean squared error = 47.7062, accuracy = 60.00%
batch 2100: mean squared error = 40.5068, accuracy = 40.00%
batch 2400: mean squared error = 46.5023, accuracy = 40.00%
batch 2700: mean squared error = 15.6235, accuracy = 60.00%
Evaluating test data
Prediction accuracy = 64.00%
Predicting median home value for feature/predictor values:
[0.09 50. 4.5 17. 350.]
Predicted value is:
$21.02(x1000)

儲存訓練好的模型

此波士頓房屋價值資料集只有 506 個數據項(其中我們只使用了 100 個)。因此,訓練 NN 迴歸模型只需要幾秒鐘,但在擁有數百或數千個數據項的大型資料集上進行訓練可能需要數小時甚至數天。

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

nn_regressor = “.\\neuralregressor.model” #provide the name of the file
model.save(nn_regressor, 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(“.\\neuralregressor.model”)
np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting area median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])

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

廣告