1.介绍

波士顿房价预测是一个经典的机器学习任务,类似于程序员世界的“Hello World”。和大家对房价的普遍认知相同,波士顿地区的房价受诸多因素影响。该数据集统计了13种可能影响房价的因素和该类型房屋的均价,期望构建一个基于13个因素进行房价预测的模型,如 图1 所示。


图1:波士顿房价影响因素示意图

对于预测问题,可以根据预测输出的类型是连续的实数值,还是离散的标签,区分为回归任务和分类任务。因为房价是一个连续值,所以房价预测显然是一个回归任务。下面我们尝试用最简单的线性回归模型解决这个问题,并用神经网络来实现这个模型。

1. 线性回归模型

假设房价和各影响因素之间能够用线性关系来描述:

y=∑j=1Mxjwj+b(公式1)y = {\sum_{j=1}^Mx_j w_j} + b (公式1)y=j=1∑M​xj​wj​+b(公式1)

模型的求解即是通过数据拟合出每个wjw_jwj​和bbb。其中,wjw_jwj​和bbb分别表示该线性模型的权重和偏置。一维情况下,wjw_jwj​ 和 bbb 是直线的斜率和截距。

线性回归模型使用均方误差作为损失函数(Loss),用以衡量预测房价和真实房价的差异,公式如下:

MSE=1n∑i=1n(Yi^−Yi)2(公式2)MSE = \frac{1}{n} \sum_{i=1}^n(\hat{Y_i} - {Y_i})^{2} (公式2)MSE=n1​i=1∑n​(Yi​^​−Yi​)2(公式2)


神经网络的标准结构中每个神经元由加权和与非线性变换构成,然后将多个神经元分层的摆放并连接形成神经网络。线性回归模型可以认为是神经网络模型的一种极简特例,是一个只有加权和、没有非线性变换的神经元(无需形成网络),如 图2 所示。


图2:线性回归模型的神经网络结构

2. 使用飞桨实现波士顿房价预测任务


图1:构建神经网络过程

我们学习了使用Python和NumPy实现波士顿房价预测任务的方法。在数据处理之前,需要先加载飞桨框架的相关类库。

#加载飞桨、NumPy和相关类库
import paddle
from paddle.nn import Linear
import paddle.nn.functional as F
import numpy as np
import os
import random

代码中参数含义如下:

  • paddle:飞桨的主库,paddle 根目录下保留了常用API的别名,当前包括:paddle.tensor、paddle.framework、paddle.device目录下的所有API;
  • Linear:神经网络的全连接层函数,包含所有输入权重相加的基本神经元结构。在房价预测任务中,使用只有一层的神经网络(全连接层)实现线性回归模型。
  • paddle.nn:组网相关的API,包括 Linear、卷积 Conv2D、循环神经网络LSTM、损失函数CrossEntropyLoss、激活函数ReLU等;
  • paddle.nn.functional:与paddle.nn一样,包含组网相关的API,如:Linear、激活函数ReLU等,二者包含的同名模块功能相同,运行性能也基本一致。 差别在于paddle.nn目录下的模块均是类,每个类自带模块参数;paddle.nn.functional目录下的模块均是函数,需要手动传入函数计算所需要的参数。在实际使用时,卷积、全连接层等本身具有可学习的参数,建议使用paddle.nn;而激活函数、池化等操作没有可学习参数,可以考虑使用paddle.nn.functional。

说明:

飞桨支持两种深度学习建模编写方式,更方便调试的动态图模式和性能更好并便于部署的静态图模式。

  • 动态图模式(命令式编程范式,类比Python):解析式的执行方式。用户无需预先定义完整的网络结构,每写一行网络代码,即可同时获得计算结果;
  • 静态图模式(声明式编程范式,类比C++):先编译后执行的方式。用户需预先定义完整的网络结构,再对网络结构进行编译优化后,才能执行获得计算结果。

飞桨框架2.0及之后的版本,默认使用动态图模式进行编码,同时提供了完备的动转静支持,开发者仅需添加一个装饰器( to_static ),飞桨会自动将动态图的程序转换为静态图的program,并使用该program训练并可保存静态模型以实现推理部署。


2.1 数据处理

  • 数据处理包含五个部分:数据导入、数据形状变换、数据集划分、数据归一化处理和封装load data函数。数据预处理后,才能被模型调用。
def load_data():# 从文件导入数据datafile = './work/housing.data'data = np.fromfile(datafile, sep=' ', dtype=np.float32)# 每条数据包括14项,其中前面13项是影响因素,第14项是相应的房屋价格中位数feature_names = [ 'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', \'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV' ]feature_num = len(feature_names)# 将原始数据进行Reshape,变成[N, 14]这样的形状data = data.reshape([data.shape[0] // feature_num, feature_num])# 将原数据集拆分成训练集和测试集# 这里使用80%的数据做训练,20%的数据做测试# 测试集和训练集必须是没有交集的ratio = 0.8offset = int(data.shape[0] * ratio)training_data = data[:offset]# 计算train数据集的最大值,最小值maximums, minimums = training_data.max(axis=0), training_data.min(axis=0)# 记录数据的归一化参数,在预测时对数据做归一化global max_valuesglobal min_valuesmax_values = maximumsmin_values = minimums# 对数据进行归一化处理for i in range(feature_num):data[:, i] = (data[:, i] - min_values[i]) / (maximums[i] - minimums[i])# 训练集和测试集的划分比例training_data = data[:offset]test_data = data[offset:]return training_data, test_data
# 验证数据集读取程序的正确性
training_data, test_data = load_data()
print(training_data.shape)
print(training_data[1,:])
打印:
(404, 14)
[2.35922547e-04 0.00000000e+00 2.62405723e-01 0.00000000e+001.72839552e-01 5.47997713e-01 7.82698274e-01 3.48961979e-014.34782617e-02 1.14822544e-01 5.53191364e-01 1.00000000e+002.04470202e-01 3.68888885e-01]

2.2 模型设计

模型定义的实质是定义线性回归的网络结构,飞桨建议通过创建Python类的方式完成模型网络的定义,该类需要继承paddle.nn.Layer父类,并且在类中定义init函数和forward函数。forward函数是框架指定实现前向计算逻辑的函数,程序在调用模型实例时会自动执行,forward函数中使用的网络层需要在init函数中声明。

  • 定义init函数:在类的初始化函数中声明每一层网络的实现函数。在房价预测任务中,只需要定义一层全连接层,模型结构和《使用Python和NumPy构建神经网络模型》章节保持一致;
  • 定义forward函数:构建神经网络结构,实现前向计算过程,并返回预测结果,在本任务中返回的是房价预测结果。
class Regressor(paddle.nn.Layer):# self代表类的实例自身def __init__(self):# 初始化父类中的一些参数super(Regressor, self).__init__()# 定义一层全连接层,输入维度是13,输出维度是1self.fc = Linear(in_features=13, out_features=1)# 网络的前向计算def forward(self, inputs):x = self.fc(inputs)return x

2.3 训练配置

训练配置过程如 图2 所示:


图2:训练配置流程示意图

  • 本教程默认使用jupyter notebook训练模型,因此无需指定机器资源;
  • 声明定义好的回归模型实例为Regressor,并将模型的状态设置为train
  • 使用load_data函数加载训练数据和测试数据;
  • 设置优化算法和学习率,优化算法采用随机梯度下降SGD,学习率设置为0.01。
# 声明定义好的线性回归模型
model = Regressor()
# 开启模型训练模式
model.train()
# 加载数据
training_data, test_data = load_data()
# 定义优化算法,使用随机梯度下降SGD
# 学习率设置为0.01
opt = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())

说明:

模型实例有两种状态:训练状态.train()和预测状态.eval()。训练时要执行正向计算和反向传播梯度两个过程,而预测时只需要执行正向计算,为模型指定运行状态,有两点原因:

  1. 部分高级的算子在两个状态执行的逻辑不同,如:Dropout和BatchNorm(在后续的“计算机视觉”章节会详细介绍);
  2. 从性能和存储空间的考虑,预测状态时更节省内存(无需记录反向梯度),性能更好。

基于Python实现神经网络模型实现梯度下降需要编写了大量代码,而使用飞桨框架只需要设置SGD函数的参数并调用,即可实现优化器设置,大大简化了这个过程。

2.4 训练过程

训练过程采用二层循环嵌套方式:

  • 内层循环: 负责整个数据集的一次遍历,采用分批次方式(batch)。假设数据集样本数量为1000,一个批次有10个样本,则遍历一次数据集的批次数量是1000/10=100,即内层循环需要执行100次。

      for iter_id, mini_batch in enumerate(mini_batches):
    
  • 外层循环: 定义遍历数据集的次数,通过参数EPOCH_NUM设置。

      for epoch_id in range(EPOCH_NUM):
    

说明:

batch的取值会影响模型训练效果,batch过大,会增大内存消耗和计算时间,且训练效果并不会明显提升(每次参数只向梯度反方向移动一小步,因此方向没必要特别精确);batch过小,每个batch的样本数据没有统计意义,计算的梯度方向可能偏差较大。由于房价预测模型的训练数据集较小,因此将batch设置为10。


每次内层循环都需要执行如 图3 所示的步骤,计算过程与使用Python编写模型完全一致。


图3:内循环计算过程

  • 数据准备:将一个批次的数据先转换成nparray格式,再转换成Tensor格式;
  • 前向计算:将一个批次的样本数据灌入网络中,计算输出结果;
  • 计算损失函数:以前向计算结果和真实房价作为输入,通过损失函数square_error_cost API计算出损失函数值(Loss)。飞桨所有的API接口都有完整的说明和使用案例,可以登录飞桨官网API文档获取;
  • 反向传播:执行梯度反向传播backward函数,即从后到前逐层计算每一层的梯度,并根据设置的优化算法更新参数(opt.step函数)。
EPOCH_NUM = 10   # 设置外层循环次数
BATCH_SIZE = 10  # 设置batch大小# 定义外层循环
for epoch_id in range(EPOCH_NUM):# 在每轮迭代开始之前,将训练数据的顺序随机的打乱np.random.shuffle(training_data)# 将训练数据进行拆分,每个batch包含10条数据mini_batches = [training_data[k:k+BATCH_SIZE] for k in range(0, len(training_data), BATCH_SIZE)]# 定义内层循环for iter_id, mini_batch in enumerate(mini_batches):x = np.array(mini_batch[:, :-1]) # 获得当前批次训练数据y = np.array(mini_batch[:, -1:]) # 获得当前批次训练标签(真实房价)# 将numpy数据转为飞桨动态图tensor的格式house_features = paddle.to_tensor(x)prices = paddle.to_tensor(y)# 前向计算predicts = model(house_features)# 计算损失loss = F.square_error_cost(predicts, label=prices)avg_loss = paddle.mean(loss)if iter_id%20==0:print("epoch: {}, iter: {}, loss is: {}".format(epoch_id, iter_id, avg_loss.numpy()))# 反向传播,计算每层参数的梯度值avg_loss.backward()# 更新参数,根据设置好的学习率迭代一步opt.step()# 清空梯度变量,以备下一轮计算opt.clear_grad()
打印:
epoch: 0, iter: 0, loss is: [0.0853824]
epoch: 0, iter: 20, loss is: [0.18994007]
epoch: 0, iter: 40, loss is: [0.24298067]
epoch: 1, iter: 0, loss is: [0.29436168]
epoch: 1, iter: 20, loss is: [0.22539787]
epoch: 1, iter: 40, loss is: [0.10328442]
epoch: 2, iter: 0, loss is: [0.17930698]
epoch: 2, iter: 20, loss is: [0.18505213]
epoch: 2, iter: 40, loss is: [0.12179875]
epoch: 3, iter: 0, loss is: [0.20329408]
epoch: 3, iter: 20, loss is: [0.09131122]
epoch: 3, iter: 40, loss is: [0.03362174]
epoch: 4, iter: 0, loss is: [0.11711848]
epoch: 4, iter: 20, loss is: [0.3558839]
epoch: 4, iter: 40, loss is: [0.13815254]
epoch: 5, iter: 0, loss is: [0.32075816]
epoch: 5, iter: 20, loss is: [0.03063034]
epoch: 5, iter: 40, loss is: [0.01313611]
epoch: 6, iter: 0, loss is: [0.21041]
epoch: 6, iter: 20, loss is: [0.15601318]
epoch: 6, iter: 40, loss is: [0.07257023]
epoch: 7, iter: 0, loss is: [0.12292767]
epoch: 7, iter: 20, loss is: [0.01622732]
epoch: 7, iter: 40, loss is: [0.17573807]
epoch: 8, iter: 0, loss is: [0.15115575]
epoch: 8, iter: 20, loss is: [0.09892335]
epoch: 8, iter: 40, loss is: [0.11091464]
epoch: 9, iter: 0, loss is: [0.08703983]
epoch: 9, iter: 20, loss is: [0.07675587]
epoch: 9, iter: 40, loss is: [0.01457744]

这个实现过程很简单,前向计算、计算损失和反向传播梯度,每个操作只需要1~2行代码即可实现!飞桨已经帮助我们自动实现了反向梯度计算和参数更新的过程,不再需要逐一编写代码!

2.5 保存并测试模型

2.5.1 保存模型

使用paddle.save API将模型当前的参数数据 model.state_dict() 保存到文件中,用于模型预测或校验的程序调用。

# 保存模型参数,文件名为LR_model.pdparams
paddle.save(model.state_dict(), 'LR_model.pdparams')
print("模型保存成功,模型参数保存在LR_model.pdparams中")
打印:模型保存成功,模型参数保存在LR_model.pdparams中

说明:

为什么要执行保存模型操作,而不是直接使用训练好的模型进行预测?理论而言,直接使用模型实例即可完成预测,但是在实际应用中,训练模型和使用模型往往是不同的场景。模型训练通常使用大量的线下服务器(不对外向企业的客户/用户提供在线服务);模型预测则通常使用线上提供预测服务的服务器实现或者将已经完成的预测模型嵌入手机或其他终端设备中使用。因此本教程中“先保存模型,再加载模型”的讲解方式更贴合真实场景的使用方法。


2.5.2 测试模型

下面选择一条数据样本,测试下模型的预测效果。测试过程和在应用场景中使用模型的过程一致,主要可分成如下三个步骤:

  1. 配置模型预测的机器资源。本案例默认使用本机,因此无需写代码指定。
  2. 将训练好的模型参数加载到模型实例中。由两个语句完成,第一句是从文件中读取模型参数;第二句是将参数内容加载到模型。加载完毕后,需要将模型的状态调整为eval()(校验)。上文中提到,训练状态的模型需要同时支持前向计算和反向传导梯度,模型的实现较为臃肿,而校验和预测状态的模型只需要支持前向计算,模型的实现更加简单,性能更好。
  3. 将待预测的样本特征输入到模型中,打印输出的预测结果。

通过load_one_example函数实现从数据集中抽一条样本作为测试样本,具体实现代码如下所示。

def load_one_example():# 从上边已加载的测试集中,随机选择一条作为测试数据idx = np.random.randint(0, test_data.shape[0])idx = -10one_data, label = test_data[idx, :-1], test_data[idx, -1]# 修改该条数据shape为[1,13]one_data =  one_data.reshape([1,-1])return one_data, label
# 参数为保存模型参数的文件地址
model_dict = paddle.load('LR_model.pdparams')
model.load_dict(model_dict)
model.eval()# 参数为数据集的文件地址
one_data, label = load_one_example()
# 将数据转为动态图的variable格式
one_data = paddle.to_tensor(one_data)
predict = model(one_data)# 对结果做反归一化处理
predict = predict * (max_values[-1] - min_values[-1]) + min_values[-1]
# 对label数据做反归一化处理
label = label * (max_values[-1] - min_values[-1]) + min_values[-1]print("Inference result is {}, the corresponding label is {}".format(predict.numpy(), label))
打印:
Inference result is [[21.068045]], the corresponding label is 19.700000762939453

通过比较“模型预测值”和“真实房价”可见,模型的预测效果与真实房价接近。房价预测仅是一个最简单的模型,使用飞桨编写起来很简单。

paddlepaddle波士顿房价预测相关推荐

  1. 教你使用百度深度学习框架PaddlePaddle完成波士顿房价预测(新手向)

    首先,本文是一篇纯新手向文章,我自己也只能算是入门,有说错的地方欢迎大家批评讨论 目录 一.人工智能.机器学习.深度学习 二.PaddlePaddle(飞桨) 三.波士顿房价预测模型 数据处理 模型设 ...

  2. PaddlePaddle实现波士顿房价预测

    PaddlePaddle实现波士顿房价预测 AIStudio地址 Github地址 #加载飞桨.Numpy 和相关库 import paddle import paddle.fluid as flui ...

  3. PaddlePaddle实战系列1——波士顿房价预测

    参考的项目是官方的一个入门项目:波士顿房价预测 首先点击上面网址,fork该项目. 输入项目名称和项目描述后,创建该项目. 然后就会来到这个页面.点击运行. 现在Baidu AI Studio,创建项 ...

  4. PaddlePaddle基本用法详解(一)、PaddelPaddle进行波士顿房价预测

    PaddlePaddle基本用法详解(一).PaddelPaddle进行波士顿房价预测 # helloworld示例 import paddle.fluid as fluid # 创建两个类型为int ...

  5. paddlepaddle学习—波士顿房价预测

    1. 机器学习 1.1 paddle使用场景 1.2 什么是机器学习 专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构,使之不断改善自身的性能. 训练:从一定数 ...

  6. 深度学习(波士顿房价预测)

    本程序采用百度paddlepaddle深度学习框架,并在百度AI Studio平台上运行. 目录 1实验背景 2 实验过程 2.1 数据处理 2.1.1数据集导入并按规定形状保存 2.1.2数据集的划 ...

  7. 机器学习(11)线性回归(2)实战 -- 正规方程优化、梯度下降优化(波士顿房价预测)

    目录 一.波士顿房价预测(正规方程优化) API 1.获取数据集 2.划分数据集 3.标准化 4. 创建预估器,得到模型 5.模型评估(均方差评估) 代码 二.波士顿房价预测(正规方程优化) API ...

  8. 竞赛大杀器xgboost,波士顿房价预测

    经常出入DC竞赛.kaggle.天池等大数据比赛的同学应该很了解xgboost这座大山. 几乎所有的比赛都绕不过它,可能只需要这一个库,在比赛中就可以得到很高的分数,究竟是为什么呢?那么就来窥探一下它 ...

  9. 线性回归之案例:波士顿房价预测

    线性回归之案例:波士顿房价预测 数据介绍   [13个特征值,1个目标值] 给定的这些特征,是专家们得出的影响房价的结果属性.此阶段不需要自己去探究特征是否有用,只需要使用这些特征.到后面量化很多特征 ...

  10. 【深度学习】实战Kaggle竞赛之线性模型解决波士顿房价预测问题(Pytorch)

    [深度学习]实战Kaggle竞赛之线性模型解决波士顿房价预测问题 文章目录 1 概述1.1 Competition Description1.2 Practice Skills 2 数据处理 3 训练 ...

最新文章

  1. PyTorch 进行 Neural-Transfer
  2. crontab -e
  3. 【BZOJ3514】Codechef MARCH14 GERALD07加强版 LCT+主席树
  4. (200)FPGA芯片选择原则
  5. Windows 64位下装Oracle 11g,PLSQL Developer的配置问题,数据库处显示为空白的解决方案...
  6. 让VMware ESXi 5.5与Windows时间服务器同步
  7. asp.net图书馆管理系统
  8. 动易CMS2006安装与配置
  9. 摄动法在计算机中的应用,H理论在计算机控制系统摄动模型中的应用研究
  10. AD PCBlayout 总结
  11. 女孩起名字:100个优秀的女孩名字大全
  12. java stringbuilder_Java stringBuilder的使用方法及实例解析
  13. Flutter开发(十一)—— 五种布局之Sliver滚动布局
  14. android wifi 获取 getBssiD
  15. python制作ppt动画_天呐,还能这么玩!用 Python 生成动态 PPT
  16. VS_设置护眼背景色
  17. 虚拟主机、VPS、云服务器三者的区别
  18. 第一章 概率论的基本概念 1.6 独立性
  19. 备份/恢复数据库资料
  20. Mixly 触摸开关的使用

热门文章

  1. CF #595 Div.3 F. Maximum Weight Subset//树形dp
  2. matlab中log和复数表示,matlab复数表示
  3. oracle user_source表
  4. Web前端面试指导(四):面试前准备-有备而去百战百胜
  5. 任正非:华为留不住人才是我的痛!
  6. 马太效应和幂律分布是怎么回事?终于有人讲明白了
  7. 运放参数的详细解释和分析-part2-如何测量输入偏置电流Ib和输入失调电流Ios
  8. Linux UOS 防火墙安装
  9. cos(a-b)=cosa*cosb+sina*sinb的推导过程
  10. 外贸建站教程,WordPress外贸自建站流程,会打字即可学会