CNTK - 神经网络回归

  • 简述

    本章将帮助您了解有关 CNTK 的神经网络回归。
  • 介绍

    众所周知,为了从一个或多个预测变量预测数值,我们使用回归。让我们以预测 100 个城镇之一的房屋中值为例。为此,我们的数据包括 -
    • 每个城镇的犯罪统计数据。
    • 每个城镇的房屋年龄。
    • 衡量从每个城镇到黄金地段的距离。
    • 每个城镇的师生比例。
    • 每个城镇的种族人口统计数据。
    • 每个城镇的房价中位数。
    基于这五个预测变量,我们想预测房价中值。为此,我们可以创建一个线性回归模型:
    
    
    Y = a0+a1(crime)+a2(house-age)+(a3)(distance)+(a4)(ratio)+(a5)(racial)
    
    
    在上面的等式中 -
    Y是预测的中值
    a 0 是一个常数,并且
    a 1 到a 5 都是与我们上面讨论的五个预测变量相关的常数。
    我们还有另一种使用神经网络的方法。它将创建更准确的预测模型。
    在这里,我们将使用 CNTK 创建一个神经网络回归模型。
  • 加载数据集

    为了使用 CNTK 实现神经网络回归,我们将使用波士顿地区房屋价值数据集。该数据集可以从 UCI 机器学习存储库下载,该存储库位于https://archive.ics.uci.edu/ml/machine-learning-databases/housing/。该数据集共有 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])
    
    
    现在,一旦我们完成了学习算法对象,我们需要创建一个读取器函数来读取训练数据 -
    
    
    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()函数的第一个参数。它也可以与文件的路径一起写入。
    • 另一个参数是具有默认值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])
    
    
    保存模型的好处是,一旦您加载保存的模型,就可以像刚刚训练模型一样使用它。