政安晨:【示例演绎机器学习】(四)—— 神经网络的标量回归问题示例 (价格预测)

news2024/11/19 5:27:19

政安晨的个人主页政安晨

欢迎 👍点赞✍评论⭐收藏

收录专栏政安晨的机器学习笔记

希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正,让小伙伴们一起学习、交流进步,不论是学业还是工作都取得好成绩!

前言

咱们这个系列的前面几篇机器学习示例演绎的文章中,演绎的都是分类问题,其目标是预测输入数据点所对应的单一离散标签。

其实还有另一种常见的机器学习问题是回归(regression)问题它预测的是一个连续值,而不是离散标签,比如根据气象数据预测明日气温,或者根据软件说明书预测完成软件项目所需时间。

这个系列的前面三篇文章为:

政安晨:【示例演绎机器学习】(一)—— 剖析神经网络:学习核心的Keras APIicon-default.png?t=N7T8https://blog.csdn.net/snowdenkeke/article/details/136187781政安晨:【示例演绎机器学习】(二)—— 神经网络的二分类问题示例 (影评分类)icon-default.png?t=N7T8https://blog.csdn.net/snowdenkeke/article/details/136204994政安晨:【示例演绎机器学习】(三)—— 神经网络的多分类问题示例 (新闻分类)icon-default.png?t=N7T8https://blog.csdn.net/snowdenkeke/article/details/136218745咱们准备好环境后开始机器学习的演绎。


导入数据集

本节将尝试预测上世纪某个时期波士顿郊区房价的中位数,已知当时郊区的一些数据点,如犯罪率、地方房产税率等。本节用到的数据集与前两个例子有一个有趣的区别。

它包含的数据点相对较少,只有506个,划分为404个训练样本和102个测试样本

输入数据的每个特征(比如犯罪率)都有不同的取值范围。

有的特征是比例,取值在0和1之间;

有的取值在1和12之间;

还有的取值在0和100之间。

我们首先加载波士顿房价数据集,如代码如下所示:

加载波士顿房价数据集

from tensorflow.keras.datasets import boston_housing
(train_data, train_targets), (test_data, test_targets) = (
    boston_housing.load_data())

咱们来看一下数据:

可以看到,我们有404个训练样本和102个测试样本,每个样本都有13个数值特征,比如人均犯罪率、住宅的平均房间数、高速公路可达性等。

目标是房价中位数,单位是千美元。

房价大都介于10 000美元~50 000美元。如果你觉得这很便宜,请不要忘记当时是20世纪70年代中期,而且这些价格没有按通货膨胀进行调整。

准备数据

将取值范围差异很大的数据输入到神经网络中,这是有问题的。

模型可能会自动适应这种取值范围不同的数据,但这肯定会让学习变得更加困难。

对于这类数据,普遍采用的最佳处理方法是对每个特征进行标准化,即对于输入数据的每个特征(输入数据矩阵的每一列),减去特征平均值,再除以标准差,这样得到的特征平均值为0,标准差为1。

用NumPy可以很容易实现数据标准化,如下代码所示:

数据标准化

mean = train_data.mean(axis=0)
train_data -= mean
std = train_data.std(axis=0)
train_data /= std
test_data -= mean
test_data /= std

注意,对测试数据进行标准化的平均值和标准差都是在训练数据上计算得到的。

在深度学习工作流程中,你不能使用在测试数据上计算得到的任何结果,即使是像数据标准化这么简单的事情也不行

构建模型

由于样本数量很少,因此我们将使用一个非常小的模型。它包含两个中间层,每层有64个单元,如下代码所示(模型定义):

(一般来说,训练数据越少,过拟合就会越严重,而较小的模型可以降低过拟合。)

from tensorflow import keras
from tensorflow.keras import layers

def build_model():

    # 由于需要将同一个模型多次实例化,因此我们用一个函数来构建模型
    model = keras.Sequential([  
        layers.Dense(64, activation="relu"),
        layers.Dense(64, activation="relu"),
        layers.Dense(1)
    ])

    model.compile(optimizer="rmsprop", loss="mse", metrics=["mae"])

    return model

模型的最后一层只有一个单元且没有激活,它是一个线性层。

这是标量回归(标量回归是预测单一连续值的回归)的典型设置。

添加激活函数将限制输出范围。

如果向最后一层添加sigmoid激活函数,那么模型只能学会预测0到1的值。这里最后一层是纯线性的,所以模型可以学会预测任意范围的值。

注意,我们编译模型用的是mse损失函数,即均方误差(mean squared error,MSE),预测值与目标值之差的平方。这是回归问题常用的损失函数。

在训练过程中还要监控一个新指标:平均绝对误差(mean absolute error,MAE)

它是预测值与目标值之差的绝对值。如果这个问题的MAE等于0.5,就表示预测房价与实际价格平均相差500美元。

利用K折交叉验证来验证你的方法

为了在调节参数(比如训练轮数)的同时对模型进行评估,我们可以将数据划分为训练集和验证集,正如前面的例子所做的那样。

但由于数据点很少,验证集会非常小(比如大约100个样本),因此验证分数可能会有很大波动,这取决于我们所选择的验证集和训练集。也就是说,验证分数对于验证集的划分方式可能会有很大的方差,这样我们就无法对模型进行可靠的评估。

在这种情况下,最佳做法是使用K折交叉验证,如下图所示:

这种方法将可用数据划分为K个分区(K通常取4或5),实例化K个相同的模型,然后将每个模型在K-1个分区上训练,并在剩下的一个分区上进行评估。模型的验证分数等于这K个验证分数的平均值。

这种方法的代码实现很简单,如下代码所示(K折交叉验证):

k = 4
num_val_samples = len(train_data) // k
num_epochs = 100
all_scores = []
for i in range(k):
    print(f"Processing fold #{i}")

    # 准备验证数据:第k个分区的数据
    val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
    val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]

    # 准备训练数据:其余所有分区的数据
    partial_train_data = np.concatenate(
        [train_data[:i * num_val_samples],
         train_data[(i + 1) * num_val_samples:]],
        axis=0)
    partial_train_targets = np.concatenate(
        [train_targets[:i * num_val_samples],
         train_targets[(i + 1) * num_val_samples:]],
        axis=0)

    # 构建Keras模型(已编译)
    model = build_model()

    # 训练模型(静默模式,verbose=0)
    model.fit(partial_train_data, partial_train_targets, 
              epochs=num_epochs, batch_size=16, verbose=0)
    # 验证数据上评估模型
    val_mse, val_mae = model.evaluate(val_data, val_targets, verbose=0)
    all_scores.append(val_mae)

演绎:

设置num_epochs = 100,运行结果如下:

每次运行模型得到的验证分数确实有很大差异,从2.1到3.1不等。

平均分数(2.6)是比单一分数更可靠的指标——这就是K折交叉验证的核心要点。

在这个例子中,预测房价与实际房价平均相差2600美元,考虑到实际房价范围是10 000美元~50000美元,这一差别还是很大的。

我们让模型训练时间更长一点:500轮。为了记录模型每轮的表现,我们需要修改训练循环,在每轮都保存每折的验证分数,如下代码所示(保存每折的验证分数):

num_epochs = 500
all_mae_histories = []

for i in range(k):
    print(f"Processing fold #{i}")

    # 准备验证数据:第k个分区的数据
    val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
    val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]

    # 准备训练数据:其余所有分区的数据
    partial_train_data = np.concatenate(
        [train_data[:i * num_val_samples],
         train_data[(i + 1) * num_val_samples:]],
        axis=0)
    partial_train_targets = np.concatenate(
        [train_targets[:i * num_val_samples],
         train_targets[(i + 1) * num_val_samples:]],
        axis=0)

    # 构建Keras模型(已编译)
    model = build_model()

    # 训练模型(静默模式,verbose=0)
    history = model.fit(partial_train_data, partial_train_targets,
                        validation_data=(val_data, val_targets),
                        epochs=num_epochs, batch_size=16, verbose=0)

    mae_history = history.history["val_mae"]

    all_mae_histories.append(mae_history)

演绎:

然后,计算每轮所有折MAE的平均值,如下代码所示:

(计算每轮的K折验证分数平均值)

average_mae_history = [
    np.mean([x[i] for x in all_mae_histories]) for i in range(num_epochs)]

我们来画图看看,如下代码所示:

(绘制验证MAE曲线)

import matplotlib.pyplot as plt

plt.plot(range(1, len(average_mae_history) + 1), average_mae_history)
plt.xlabel("Epochs")
plt.ylabel("Validation MAE")
plt.show()

由于比例问题,前几轮的验证MAE远大于后面的轮次,很难看清这张图的规律。我们忽略前10个数据点,因为它们的取值范围与曲线上的其他点不同,如下代码所示:

绘制验证MAE曲线(剔除前10个数据点)

truncated_mae_history = average_mae_history[10:]
plt.plot(range(1, len(truncated_mae_history) + 1), truncated_mae_history)
plt.xlabel("Epochs")
plt.ylabel("Validation MAE")
plt.show()

从上图可以看出,验证MAE在120~140轮(包含剔除的那10轮)后不再显著降低,再之后就开始过拟合了。

完成模型调参之后(除了轮数,还可以调节中间层大小),你可以使用最佳参数在所有训练数据上训练最终的生产模型,然后查看模型在测试数据上的表现,如下代码所示:

训练最终模型

# 一个全新的已编译模型
model = build_model()  

# 在所有训练数据上训练模型
model.fit(train_data, train_targets,
          epochs=130, batch_size=16, verbose=0)

test_mse_score, test_mae_score = model.evaluate(test_data, test_targets)

预测房价和实际房价还是相差不到2500美元。不过有进步!就像前两个任务一样,你可以尝试改变模型的层数或每层的单元个数,看是否能够降低测试误差。

对新数据进行预测

在调用二分类模型的predict()时,每个输入样本都得到一个介于0和1之间的标量值。

对于多分类模型,每个样本都得到一个在所有类别上的概率分布。对于这个标量回归模型,predict()返回的是模型对样本价格的猜测,单位是千美元。

predictions = model.predict(test_data)
predictions[0]

模型预测,测试集中的第一所房子的价格约为10 000美元。

结论

回归问题使用的损失函数与分类问题不同。回归常用的损失函数是均方误差(MSE)。

同样,回归问题使用的评估指标也与分类问题不同。显然,精度的概念不再适用于回归问题常用的回归指标是平均绝对误差(MAE)如果输入数据的特征具有不同的取值范围,那么应该先进行预处理,对每个特征单独进行缩放。如果可用的数据很少,那么K折交叉验证是评估模型的可靠方法。

如果可用的训练数据很少,那么最好使用中间层较少(通常只有一两个)的小模型,以避免严重的过拟合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1466672.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高并发系统实战课个人总结(极客时间)

高并发系统实战课 场景 读多写少 我会以占比最高的“读多写少”系统带你入门,梳理和改造用户中心项目。这类系统的优化工作会聚焦于如何通过缓存分担数据库查询压力,所以我们的学习重点就是做好缓存,包括但不限于数据梳理、做数据缓存、加缓…

FairyGUI × Cocos Creator 3.x 场景切换

前言 前文提要: FariyGUI Cocos Creator 入门 FairyGUI Cocos Creator 3.x 使用方式 个人demo:https://gitcode.net/qq_36286039/fgui_cocos_demo_dust 个人demo可能会更新其他代码,还请读者阅读本文内容,自行理解并实现。 官…

云HIS系统源码,基于云计算技术的B/S架构的云HIS系统,二甲医院信息管理系统

云HIS系统源码,采用云端SaaS服务的方式提供 基于云计算技术的B/S架构的云HIS系统,采用云端SaaS服务的方式提供,使用用户通过浏览器即能访问,无需关注系统的部署、维护、升级等问题,系统充分考虑了模板化、配置化、智能…

邮件发送/接收过程分析、常见邮箱sport/dport列举、检测规则开发思路分析

一、邮件发送和接收过程分析 (转载自:邮件的发送和接收过程——STMP、POP、IMAP、MIME_当收件人接收电子邮件时自己的邮件服务器通过什么收文件-CSDN博客) 电子邮件发送协议 是一种基于“ 推 ”的协议,主要包括 SMTP &#xff1…

博客 cn 站搭建 v3 v3.1

1. 架构设计 v3.1 版本 2. v2.x 存在的痛点 在v2.x版本中,围绕 服务器 遇到了两个主要的问题: 服务器成本高:博客以静态页面为主,理论上可以实现无服务器部署,但是为了防止恶意攻击,不得不使用服务器进…

RT-Thread-快速入门-3-内存管理

内存管理 定义与作用 内存池管理 基础定义 内存池是一种管理固定大小内存块的机制,主要用于减少碎片化,提高内存分配效率。在 RT-Thread 中,内存池允许用户预分配一定数量的具有相同大小的内存块,应用程序可以从中快速分配和释放内…

【电子书】人工智能

资料 wx:1945423050,备注来源和目的 个人整理了一些互联网电子书 人工智能 Julia机器学习核心编程:人人可用的高性能科学计算.epubKeras深度学习实战.epubMATLAB图像与视频处理实用案例详解.epubMATLAB金融算法分析实战:基于机器…

Android 开发一个耳返程序(录音,实时播放)

本文目录 点击直达 Android 开发一个耳返程序程序编写1. 配置 AndroidManifast.xml2.编写耳返管理器3. 录音权限申请4. 使用注意 最后我还有一句话要说怕相思,已相思,轮到相思没处辞,眉间露一丝 Android 开发一个耳返程序 耳返程序是声音录入…

开源分子对接程序rDock的安装及使用流程

欢迎浏览我的CSND博客! Blockbuater_drug …点击进入 前言 本文介绍开源分子对接程序rDock在Linux Ubuntu 22.04系统上的conda安装、编译安装过程及程序使用流程。 一、rDock是什么? rDock来源 rDock是一个快速、多功能的开源对接程序,可用…

鼠标右键助手专业版 MouseBoost PRO for Mac v3.3.6中文破解

MouseBoost Pro mac版是一款简单实用的鼠标右键助手专业版,MouseBoost Pro for Mac只要轻点你的鼠标右键,就可以激活你想要的各种功能,让你的工作效率大幅度提高,非常好用。 软件下载:MouseBoost PRO for Mac v3.3.6中…

Matlab/simulink光伏发电的扰动观察法MPPT仿真(持续更新)

1.光伏发电的电导增量法MPPT仿真 2.光伏发电的恒定电压法MPPT仿真 3.光伏发电的扰动观察法MPPT仿真 4.光伏发电的占空比法MPPT仿真 5.基于神经网络的MPPT光伏发电仿真 6. 基于模糊控制的MPPT光伏发电仿真 7. 基于粒子群算法(PSO)的500w光伏系统MPPT控…

WordPres Bricks Builder 前台RCE漏洞

免责声明:文章来源互联网收集整理,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…

spark 少量key倾斜的join优化

背景 在使用spark join时,我们经常遇到少量key拥有大量的数据而导致的数据倾斜的问题,这导致了task任务数据处理非常不均匀而影响最终时效 少量key数据倾斜的join优化 这里有一个前提,join的另一边的表没有数据倾斜问题,也就是…

问题慢慢解决-通过android emulator调试android kernel-内核条件断点遇到的问题和临时解决方案

起因 在摸索到这个方案之后,mac m1调试aarch64 android kernel最终方案,就准备调试内核了,预备下断点的地方是 b binder_poll b ep_ptable_queue_proc b remove_wait_queue但是由于是android系统,上面三个函数会被频繁的触发&am…

Window部署SkyWalking

SkyWalking mysql的驱动依赖 选择下载版本 v9.4 现在后解压缩目录结构 一、修改config目录文件 application.yml 修改1: selector: ${SW_STORAGE:h2} 修改后: selector: ${SW_STORAGE:mysql} 修改2:使用mysql数据库 mysql: properti…

windows 11+docker desktop+grafana+influxDB

下载安装docker desktop 出现WSL相关的错误。WSL是一个linux内核的子系统,docker是基于linux内核的,所以运行docker需要WSL。 以管理员权限打开powershell,查看WSL状态 wsl --status 我遇到的错误是因为我关闭了windows的某些更新 执行上…

comfyui节点编写示例文件(下)

** 1、先看示例文件的结构 ** ** 2、设置输入参数 ** ** 3、节点指定任务、输出啥 ** ** 4、这个节点干了啥,定义函数、输出结果 ** ** 5、多个节点,就多个类 ** ** 6、设置多个入口 ** ** 7、放置 ** 直接把py文件放到 .\Co…

Python+Selenium-使用Pillow库进行元素截图

1. Pillow库 Pillow库是Python图像处理的基库,是一个免费开源的第三方库。 通过Python PyPi第三方库官网(https://pypi.org/project/Pillow/#files)下载与平台系统相对应的版本: 下载完成后,进入下载文件的所在位置&…

Redis(十六)缓存预热+缓存雪崩+缓存击穿+缓存穿透

文章目录 面试题缓存预热缓存雪崩解决方案 缓存穿透解决方案 缓存击穿解决方案案例:高并发聚划算业务 总结表格 面试题 缓存预热、雪崩、穿透、击穿分别是什么?你遇到过那几个情况?缓存预热你是怎么做的?如何避免或者减少缓存雪崩?穿透和击穿有什么区别?他两是…

力扣hot100题解(python版7-9题)

7、接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,…