构建波士顿房价预测任务的神经网络模型

不同场景的深度学习模型具备一定的通用性,一般归纳为五个步骤:数据处理-->模型设计-->训练配置-->训练过程-->模型保存

数据处理:从本地或URL读取数据,并完成预处理操作(如数据校验,格式转化等),保证模型可读性。

模型设计:网络结构设计,相当于模型的假设空间,即模型能够表达的关系的集合。

模型配置:设定模型采用的寻解算法,即优化器,并指定计算资源。

训练过程:循环调用训练过程,每轮都包括前向计算,损失函数(优化目标)和后向传播三个步骤。

模型保存:将训练好的模型保存,模型预测时调用。

正是由于深度学习的建模和训练过程存在通用性,在构建不同的模型时,只有模型的三要素不同,其他步骤基本一致。

下面,将会按照步骤进行讲解

1.数据处理

数据处理包含五个部分:数据导入,数据形状变换,数据集划分,数据归一化处理和封装load data函数。数据预处理后才可以被模型调用。

1.读入数据

读入数据,了解下波士顿房价的数据集结构。

#导入需要用到的package
import numpy as np
import json
#读入训练数据
datafile = './housing.data'
data = np.fromfile(datafile,sep='')

2.数据形状变换

由于读入的原始数据是1维的,所有数据都连接在一起。因此需要我们将数据的形状进行变换,形成一个2维的矩阵,每行为一个数据样本(14个值),每个数据样本包含13个X(影响放假的特征)和一个Y(该类型房屋的均价)。

#读入之后的数据被转化成1维array,其中array的第0~13项是度一条数据,第14~27项
#是第二条数据,以此类 推...
#这里对原数据做reshape,变成N * 14的形式
feature_names = ['CRIM','ZN','INDUS','CHAS','NOX','RM',
'AGE','DIS','RAD','TAX','PTRATIO','B','LSTAT','MEDV']
feature_num = len(feature_names)
data = data.reshape([data.shape[0] // feature_num,feature_num])

3.数据集划分

将数据集划分成训练集和测试集,其中训练集用于确定模型的参数,测试集用于评判模型的效果。

在本案例中,我们将80%的数据用作训练集,20%用作测试集,实现代码如下。通过打印训练集的形状,可以发现共有404个样本,每个样本含13个特征和1个预测值。

ratio = 0.8
offset = int(data.shape[0] * ratio)
training_data = data[:offset]
print(training_data.shape) 

4.数据归一化处理

对每个特征进行归一化处理,使得每个特征的取值放到0~1。这样做有两个好处:一是模型训练更高效;二是特征前的权重大小可以代表该变量对预测结果的贡献度(应为每个特征值本身的范围相同)。

#计算train数据集的最大值,最小值,平均值
maximums,minimums,avgs = training_data.max(axis=0),
                            training_data.min(axis=0),
                            training_data.sum(axis=0)/training_data.shaoe[0]
#对数据进行归一化处理
for i in range(feature_num):
    data[:,i] = (data[:,i] - minimums[i]) / (maximums[i] - minimums[i])

5.封装成load data 函数

将上述几个数据处理操作封装成load data函数,以便下一步模型的调用。

def load_data():

    #读入训练数据
    datafile = './housing.data'
    data = np.fromfile(datafile,sep='')

    #每条数据包括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.8
    offset = int(data.shape[0] * ratio)
    training_data = data[:offset]


    #计算train数据集的最大值,最小值,平均值
    maximums,minimums,avgs = training_data.max(axis=0),
                            training_data.min(axis=0),
                            training_data.sum(axis=0)/training_data.shaoe[0]
    #对数据进行归一化处理
    for i in range(feature_num):
        data[:,i] = (data[:,i] - minimums[i]) / (maximums[i] - minimums[i])

    #训练集和测试集的划分比例
    training_data = data[:offset]
    test_data = data[offset:]
    return training_data,test_data
    
    #获取数据
    training_data,test_data = load_data()
    x = training_data[:,:-1]
    y = training_data[:,-1:]

2.模型设计

模型设计是深度学习模型关键要素之一,也称为网络结构设计,相当于模型的假设空间,即实现模型“前向计算”(从输入到输出)的过程。

如果将输入特征和输出预测值均以向量表示,输入特征x有13个分量,y有1个分量,那么参数权重的形状(shape)是13 * 1。假设我们以如下任意数字赋值参数做初始化:

W = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,-0.1,-0.2,-0.3,-0.4,0.0]

W = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,-0.1,-0.2,-0.3,-0.4,0.0]
w = np.array(w).reshape([13,1])

取出第1条样本数据,观察样本的特征向量与参数向量相乘的结果

x1 = x[0]
t = np.dot(x1,w)
print(t)

完整的线性回归公式,还需要初始化偏移量b,同样随意赋初值-0.2。那么,线性回归模型的完整输出是z = t + b , 这个从特征和参数计算输出值的过程成为‘前向计算’。

b = -0.2
z = t + b
print(z)

将上述计算预测输出的过程以‘类和对象’的方式来描述,类成员变量有参数W和b。通过写一个forward函数(代表‘前向计算’)完成上述从特征和参数到输出预测值的计算过程,代码如下:

class Network(object):
    def __int__(self,num_of_weights):
        #随机产生w的初始值
        #为了保持程序员每次运行结果的一致性
        #此处设置固定的随机数种子
        np.random.seed(0)
        self.w = np.random.randn(num_of_weights,1)
        self.b = 0



    def forward(self,x):
        z = np.dot(x,self.w)  + self.b
        return z

基于Network类的定义,模型的计算过程如下:

net = Network(13)
x1 = x[0]
y1 = y[0]
z = net.forward(x1)
print(z)

3.训练配置

模型设计完成后,需要通过训练配置寻找模型的最优值,即通过损失函数来衡量模型的好坏。训练配置也是深度学习模型关键要素之一。

通过模型计算x1表示的影响因素所对应的房价应该 z,但实际数据告诉我们房价是y。这时需要有某种指标来衡量预测值z跟真实值y之间的差距。对于回归问题最常采用的衡量方法是使用均方误差作为评价模型好坏的指标,具体定义如下:

Loss = (y - z)** 2

上式中的Loss(简记为:L)通常也被称作损失函数,它是衡量模型好坏的指标。在回归问题中均方误差是一种比较常见的形式,分类问题中通常会采用交叉熵作为损失函数,对一个样本计算损失函数值的实现如下:

Loss = (y1 - z) * (y1 - z)
print(Loss)

 应为计算损失函数时需要把每个样本的损失函数值都考虑到,所以我们需要对单个样本的损失函数进行求和并除以样本总数N。

在Network类下面添加损失函数的计算过程如下:

class Network(object):
    def __init__(self,num_of_weights):
        #随机产生w的初始值
        #为了保持程序每次运行结果的一致性,此处设置固定的随机数种子
        np.random.seed(0)
        self.w = np.random.randn(num_of_weights,1)
        self.b = 0
    def forward(self,x):
        z = np.dot(x,self.w) + self.b
        return z
    def loss(self,z,y):
        error = z - y
        cost = error * error
        cost = np.mean(cost)
        return cost

使用定义的Network类,可以方便地计算预测值和损失函数,需要注意的是,类中的变量x,w,b,z,error等均是向量。以变量x为例,共有两个维度,一个代表特征数量(值为13),一个代表样本数量,代码如下:

net = Network(13)
#此处可以一次性计算多个样本的预测值和损失函数
x1 = x[0:3]
y1 = y[0:3]
z = net.forward(x1)
print('predict',z)
loss = net.loss(z,y1)
print('loss',loss)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值