Pytorch——波士顿房价预测模型搭建

1,300 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第22天,点击查看活动详情


前言

上一篇文章中,我们介绍神经网络的基本概念,包括感知器的基本概念,前向计算,反向传播,分类与回归,过拟合和欠拟合,正则化问题。

今天,我们来利用使用Pytorch进行波士顿房价预测模型搭建。


  • 1.1 Pytorch搭建神经网络基本组成模块

  • 数据:对训练数据进行加载,并且用于对网络参数进行训练

  • 网络结构:搭建的神经网络最重要的一个模块

  • 损失:在进行问题建模的时候,针对分类问题和回归问题构造出来的优化形式,如何去计算预测值和真实值之间的偏差,并且利用计算出来的偏差完成对网络参数的优化

  • 优化:采用的优化算法,如:梯度下降法

  • 测试:对训练好的网络进行测试,测试是伴随在训练的过程中的操作

  • 推理:对训练好的网络进行推理,推理是在训练好网络之后,利用网络来完成我们想要解决的一些任务

  • 1.2 Pytorch完成波士顿房价预测模型搭建

    • 波士顿返奖这些数据于1978年开始统计,共506个数据点,涵盖了麻省波士顿不同郊区房屋14种特征信息
    • 数据集下载地址:t.cn/RfHTAgY
    • 损失函数: MSE-LOSS

代码实现:

  • 1.2.1 数据集加载
# data
import numpy as np
import re
data = []
ff = open("housing.data").readlines()    # 将数据的每一列都读取出来
for item in ff:
    out = re.sub(r"\s{2,}", " ", item).strip()
    print(out)
    data.append(out.split(" "))
data = np.array(data).astype(np.float64)  # 将数据进行类型转换为float
print(data.shape)

运行结果:

(506, 14)
  • 1.2.2 数据集的划分
# 这些数据前十三个是x,后一个是y
# 切分数据
Y = data[:, -1]
X = data[:, 0:-1]
# 划分测试集和训练集,定义前496个样本为训练集的样本
X_train = X[0:496, ...]
Y_train = Y[0:496, ...]
X_test = X[496:, ...]
Y_test = Y[496:, ...]
print(X_train.shape)
print(Y_train.shape)
print(X_test.shape)
print(Y_test.shape)

运行结果:

(496, 13)
(496,)
(10, 13)
(10,)

可以看到,训练集由496个样本,测试集有10个样本

  • 1.2.3 定义网络结构

在这里,只定义一个简单的回归网络结构

# 定义一个简单的神经网络:只有一个隐藏层,也就是线性层
class Net(torch.nn.Module):
    def __init__(self, n_feature, n_output):
        super(Net, self).__init__()
        self.predict = torch.nn.Linear(n_feature, n_output)

    def forward(self, x):
        out = self.predict(x)
        return out

# 初始化网络
net = Net(13, 1)
  • 1.2.4 定义loss和optimizer

采用MES-LOSS的方法

# loss
# 采用均方损失
loss_func = torch.nn.MSELoss()

# optimizer
optimizer = torch.optim.SGD(net.parameters(), lr=0.01)
  • 1.2.5 定义训练的过程

在通过线性函数拿到的pred是一个二维的,而y_data通过Y_train来进行初始化的时候,是一维的,这时,可以对pred做一个维度的删除,或者对y_data做维度的扩展

# training
for i in range(1000):
    x_data = torch.tensor(X_train, dtype=torch.float32)
    y_data = torch.tensor(Y_train, dtype=torch.float32)
    pred = net.forward(x_data)
    pred = torch.squeeze(pred)
    loss = loss_func(pred, y_data)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    # 打印迭代次数和loss的变化
    print("ite:{}, loss_train:{}".format(i, loss))
    print(pred[0:10])
    print(y_data[0:10])

执行当前的脚本之后会发现,我们计算出来的损失都是nan,那么loss为什么会产生nan的情况呢?

  • 学习率可能太高了
  • loss本身太大了

将loss降低1000倍,将lr降低100倍

# optimizer
optimizer = torch.optim.SGD(net.parameters(), lr=0.0001)

# training
for i in range(1000):
    x_data = torch.tensor(X_train, dtype=torch.float32)
    y_data = torch.tensor(Y_train, dtype=torch.float32)
    pred = net.forward(x_data)
    pred = torch.squeeze(pred)
    loss = loss_func(pred, y_data) * 0.001

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    # 打印迭代次数和loss的变化
    print("ite:{}, loss_train:{}".format(i, loss))
    print(pred[0:10])
    print(y_data[0:10])

这时可以发现loss不再为nan了

最终loss收敛在了97这个位置上,观察预测结果和真实结果之间的偏差还是比较大的,这说明我们的模型处于欠拟合的状态,

对于模型处于欠拟合的状态可以做的:

  • 加大训练的次数
  • 在初始学习的时候使用大的学习率,在迭代过一定次数之后对学习率进行动态的调整
  • 采用其他的优化函数,比如dam
  • 将模型变得更复杂,比如再加入一个隐藏层

打印测试集的loss

# test
x_data = torch.tensor(X_test, dtype=torch.float32)
y_data = torch.tensor(Y_test, dtype=torch.float32)
pred = net.forward(x_data)
pred = torch.squeeze(pred)
loss_test = loss_func(pred, y_data) * 0.001
print("ite:{}, loss_test:{}".format(i, loss))

可以发现,测试集的loss也是下降的,在多轮训练之后,训练集的loss在3.5,测试集的loss在6.0

  • 1.2.6 保存模型

把模型全部保存下来

torch.save(net, "model.pkl")

保存模型的参数:

torch.save(net.state_dict(), "params.pkl")
  • 1.2.7 推理

加载模型

import torch

torch.load("model.kpl")

推理代码展示:

class Net(torch.nn.Module):
    def __init__(self, n_feature, n_output):
        super(Net, self).__init__()
        self.hidden = torch.nn.Linear(n_feature, 100)
        self.predict = torch.nn.Linear(100, n_output)
    def forward(self, x):
        out = self.hidden(x)
        out = torch.relu(out)
        out = self.predict(out)
        return out




data = []
ff = open("housing.data").readlines()    # 将数据的每一列都读取出来
for item in ff:
    out = re.sub(r"\s{2,}", " ", item).strip()
    data.append(out.split(" "))
data = np.array(data).astype(np.float64)  # 将数据进行类型转换为float
print(data.shape)
# 这些数据前十三个是x,后一个是y
# 切分数据
Y = data[:, -1]
X = data[:, 0:-1]

# 划分测试集和训练集,定义前496个样本为训练集的样本
X_train = X[0:496, ...]
Y_train = Y[0:496, ...]
X_test = X[496:, ...]
Y_test = Y[496:, ...]
print(X_train.shape)
print(Y_train.shape)
print(X_test.shape)
print(Y_test.shape)


net = torch.load("model.pkl")
loss_func = torch.nn.MSELoss()
# test
x_data = torch.tensor(X_test, dtype=torch.float32)
y_data = torch.tensor(Y_test, dtype=torch.float32)
pred = net.forward(x_data)
pred = torch.squeeze(pred)
loss_test = loss_func(pred, y_data) * 0.001
print("loss_test:{}".format(loss_test))

运行结果:

loss_test:0.006096621975302696

通过save和load model就可以完成对模型的保存

9JQ4ZCQY3M({Q$KEN%9BFQX.png