利用前馈神经网络(FNN)进行气温预测任务

news/2024/12/29 15:10:28/文章来源:https://www.cnblogs.com/lostin9772/p/18523162

一、前馈神经网络

前馈神经网络(Feedforward Neural Networks, FNN)是人工神经网络中的一种,它的信息流动是单向的,从输入层到隐藏层,再到输入层,没有反向的连接。其中,隐藏层可以有多个,用于处理输入层的数据,且每一个隐藏层通常配合一个非线性的激活函数来进行训练。

前馈神经网络的架构如下:

我们通过构建上图的网络模型来进行我们今天的气温预测任务。

首先,我们需要去下载对应的数据集,我们可以通过下面的网址下载到世界上基本所有国家的历史以及实时气温数据:https://rp5.ru

广州(机场)气象站的气温数据为例,下载 2005.2.1 - 2023.12.31 期间的数据作为训练集,2024.1.1-2024.11.02 期间的数据作为验证集,最后预测 2024.11.03 的温度。

在上述网址下载了数据后,对数据进行简单地手工处理,结果如下:

下载完数据集后,我们就可以开始搭建网络进行训练了!

1 导入数据并对数据进行预处理

我们首先在代码中假如如下语句,如有 GPU 则用 GPU 训练,这样能大大提高训练的速度:

# 如有 GPU 则用 GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

然后我们利用 pandas 库中的函数 read_excelexcel 中的数据进行读取:

# 导入训练集和验证集
train_file_name = './data/FNN/temperature_history.xls'
valid_file_name = './data/FNN/temperature_2024.xls'
train_features = pd.read_excel(train_file_name, skiprows=6)    # 跳过前 6 行无效数据
valid_features = pd.read_excel(valid_file_name, skiprows=6)

由于我们下载的 excel 数据中含有年份时间数据,我们要将其拆分为月、日、时,并舍弃年份,并入到原来的数据中:

# 定义一个函数来拆分日期和时间
def split_datetime(date_str):date_part, time_part = date_str.split(' ')date_parts = date_part.split('.')time_parts = time_part.split(':')return pd.Series([ int(date_parts[1]), int(date_parts[0]), int(time_parts[0])])# 拆分日期和时间,但不保留年份
train_features[['月', '日', '时']] = train_features['时间'].apply(split_datetime)
valid_features[['月', '日', '时']] = valid_features['时间'].apply(split_datetime)# 删除原始的 '时间' 列
train_features.drop('时间', axis=1, inplace=True)
valid_features.drop('时间', axis=1, inplace=True)

查看处理后的数据我们会发现,其中有一些行的特征是空值,我们需要将其剔除,以免影响训练效果:

# 删除包含 NaN 的行(若有特征不存在则删除改行)
train_features.dropna(inplace=True)
valid_features.dropna(inplace=True)

然后,我们通过 print 语句来打印一下,看看我们处理后的数据:

接下来,我们需要将标签从数据中剥离出来,并将数据格式转换为 ndarry(即 numpy 格式):

# 从 features 中取出标签列并转换为 numpy 数据格式
train_labels = np.array(train_features['温度'], dtype=np.float32).reshape(-1, 1)
valid_labels = np.array(valid_features['温度'], dtype=np.float32).reshape(-1, 1)# 从 features 中剔除 ‘温度' 标签列
train_features = train_features.drop('温度', axis=1)
valid_features = valid_features.drop('温度', axis=1)# 将 features 转化为 numpy 数据格式
train_features = np.array(train_features, dtype=np.float32)
valid_features = np.array(valid_features, dtype=np.float32)

在将数据传入到 GPU 训练之前,我们还有一步重要的操作要做,那就是对数据进行标准化操作(以原点为中心对称,缩小取值范围和维度差异)。这是由于,在人工神经网络中,模型并不知道我们传入的特征哪些是重要的,哪些是不重要的,模型会潜在的认为特征值越大就表示该特征越重要,从而会把它所谓的重要的特征学的越大,而实际上,不同维度的取值范围可能会差异很大,所以不同维度的取值范围并不具备参考意义,为了降低模型的误解,需要对数据进行标准化操作:

input_train_features = preprocessing.StandardScaler().fit_transform(train_features)
input_valid_features = preprocessing.StandardScaler().fit_transform(valid_features)

然后我们就可以将 ndarry 格式的数据转为 tensor 格式,传入到 GPU 或 CPU 中:

# 将输入数据从 ndarray 转换成 tensor 并传入 GPU 或 CPU
train_inputs = torch.tensor(input_train_features, dtype=torch.float32).to(device)
valid_inputs = torch.tensor(input_valid_features, dtype=torch.float32).to(device)
train_labels = torch.tensor(train_labels, dtype=torch.float32).to(device)
valid_labels = torch.tensor(valid_labels, dtype=torch.float32).to(device)

二、构建模型

首先我们按照开篇给的网络模型来进行构建:

# 定义模型结构
class FNN(nn.Module):def __init__(self):    # 定义模型的构造函数super(FNN, self).__init__()    # 调用父类的构造函数self.linear1 = nn.Linear(13, 50)    # 输入层到隐藏层1self.linear2 = nn.Linear(50, 100)    # 隐藏层1到隐藏层2self.linear3 = nn.Linear(100, 1)    # 隐藏层2到输出层self.relu = nn.ReLU()  # 非线性激活函数def forward(self, x):    # 定义模型的前向传播函数x = self.relu(self.linear1(x))    # 通过第一个隐藏层并激活x = self.relu(self.linear2(x))    # 通过第二个隐藏层并激活x = self.linear3(x)    # 通过输出层return x

在这个模型中,我们定义了两个隐藏层(全连接层),每层后面加入了一个非线性激活函数,最后通过输出层进行输出,得到一个预测值。定义好模型结构后,我们将模型进行实例化,并输入到 GPU 或 CPU:

# 初始化模型并把模型输入到 GPU 或 CPU
model = FNN().to(device)

三、设定模型的超参数

接下来我们需要为模型设定超参数,分别是迭代次数学习率优化器损失函数

epochs = 50000    # 迭代次数
learning_rate = 0.0001    # 学习率
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)    # 优化器
criterion = nn.MSELoss()    # 损失函数(均方误差)

四、训练模型并保存参数

设定好超参数之后,我们就可以进行模型的训练了:

# 训练模型
for epoch in range(epochs):epoch += 1# 每次迭代之前将梯度清零optimizer.zero_grad()# 进行前向传播train_outputs = model(train_inputs)# 计算损失train_loss = criterion(train_outputs, train_labels)# 反向传播train_loss.backward()# 更新权重参数optimizer.step()# 每 1000 个 epoch 打印一次损失,跑一次验证集if epoch % 1000 == 0:# 打印损失print('epoch: {0}, train loss: {1}'.format(epoch, train_loss.item()))# 在验证集上评估模型model.eval()    # 将模型设置为评估模式with torch.no_grad():    # 关闭梯度计算# 将验证集输入模型,并计算损失valid_outputs = model(valid_inputs)valid_loss = criterion(valid_outputs, valid_labels)# 计算准确率correct = (torch.abs(valid_outputs - valid_labels) < 1.5).sum().item()    # 温度误差上下 1.5° 为准确total = valid_labels.size(0)accuracy = correct / total * 100print('epoch: {0}, valid loss: {1}, accuracy: {2:.4f}%\n'.format(epoch, valid_loss.item(), accuracy))model.train()    # 将模型转回训练模式

在训练过程中,我们设置每隔 1000 次就去验证集上跑一下损失和准确率,当验证集上跑出的预测温度和实际温度误差在 1.5° 以内,我们就定义为预测正确,然后计算出正确率。

当模型训练完后,我们需要将模型训练好的参数进行保存:

# 训练好后对模型参数进行保存
torch.save(model.state_dict(), './data/FNN/model.pk1')

五、加载模型和训练好的参数用于预测

我们的模型参数训练完毕后已经保存到了本地,之后就可以随时利用本地已经训练好的参数来进行实际温度的预测:

# 如有 GPU 则用 GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# 加载模型参数
pred_model = FNN().to(device)    # 加载模型到 GPU 或 CPU
pred_model.load_state_dict(torch.load('./data/FNN/model.pk1'))    # 加载模型参数
pred_model.eval()    # 将模型设置为评估模式# 创建单个数据的输入张量,并添加批次维度,输入数据特征对应如下:
# Po(气象站水平大气压)、P(海平面大气压)、Pa(气压趋势)、U(相对湿度)、Ff(风速)
# ff3(5) 、Tn(最低气温)、Tx(最高气温)、VV(水平能见度)、Td(露点温度)、月、日、时
# 当日上午 8 点的实际温度为:22.3
single_data = [757.7, 764.0, 1.0, 69, 2, 4, 19.7, 27.5, 30, 16.3, 11, 3, 8]
actual_temp = 22.3# 将 list 数据格式转为 numpy 数据格式,并将数据从一维提升到二维
single_data = np.array(single_data, dtype=np.float32).reshape(1, -1)# 对数据进行标准化处理
single_data = preprocessing.StandardScaler().fit_transform(single_data)# 将 numpy 数据格式转为 tensor 数据格式并传入 GPU 或 CPU
inputs = torch.tensor(single_data, dtype=torch.float32).to(device)# 进行预测
with torch.no_grad():prediction = pred_model(inputs)# 输出预测结果
print('2024-11-03 8:00 的实际温度为:{},模型预测温度为:{}'.format(actual_temp, prediction.item()))

输出的预测结果如下:

可以从上图看到,我们将学习率设置为 0.0001,并迭代了 50000 次后,能够在验证集上跑出 84.6398% 的准确率,并且我们加载训练好的参数,对 2024-11-03 8:00 时的气温进行了预测,和实际温度基本一致,说明模型训练的效果还算可以。

其他

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CoSeR桥接图像和语言以实现认知超分辨率

CoSeR桥接图像和语言以实现认知超分辨率 6.10.1 CoSeR桥接图像和语言以实现认知超分辨率概述 现有的超分辨率(SR)模型主要侧重于恢复局部纹理细节,往往忽略了场景中的全局语义信息。这种疏忽可能会导致在恢复过程中遗漏关键的语义细节或引入不准确的纹理。 引入了认知超分辨…

综合、诊断和优化:迈向精细视觉语言理解

综合、诊断和优化:迈向精细视觉语言理解 6.8.1 综合、诊断和优化:迈向精细视觉语言理解概述视觉语言模型(VLM)在各种下游任务中表现出了卓越的性能。然而,理解细粒度的视觉语言概念,如属性和对象间关系,仍然是一个重大的挑战。虽然有几个基准旨在以更精细的粒度评估VLM,…

Nuxt.js 应用中的 nitro:init 事件钩子详解

title: Nuxt.js 应用中的 nitro:init 事件钩子详解 date: 2024/11/3 updated: 2024/11/3 author: cmdragon excerpt: nitro:init 是 Nuxt 3 中的一个生命周期钩子,在 Nitro 初始化完成后被调用。这个钩子允许开发者注册 Nitro 钩子,并直接与 Nitro 进行交互。这种灵活性使…

【人脸伪造检测后门攻击】Imperceptible Face Forgery Attack via Adversarial Semantic Mask

原文Github地址:https://github.com/clawerO-O/ASMA一、研究动机 ​ 目前的后门攻击模型是基于数字像素上的操作,例如增加噪声,从而使得深度模型在推理阶段表现为不正常,但这种attack隐蔽性很差,可以被人眼所观察到。因为这些模型是在整个面部区域增加对抗性扰动,增加了许…

MTR: 网络排查神器 / 网络诊断工具介绍

原创 晓致知 电脑知识MTR(My Traceroute)是一款功能全面且高效的网络诊断工具,它巧妙地将traceroute和ping的功能融为一体。通过MTR,用户可以实时追踪数据包在网络中的传输路径,清晰地看到数据包从源地址到目标地址所经过的所有节点。同时,MTR还能提供详细的网络性能指标…

随想

日复又一日,重复再重复。

相册

国风版,相册 好看的你

锋利的在线诊断工具——Arthas

导航前言 火线告警,CPU飚了 服务重启,迅速救火 黑盒:无尽的猜测和不安 Arthas:锋利的Java诊断工具 在线追踪Cpu占比高的代码段 代码重构,星夜上线,稳了 结语 参考肮脏的代码必须重构,但漂亮的代码也需要很多重构。前言 有些代码在当初编写的时候是非常稳健的,但是随着数…

制作一个ai丛雨(附Python代码)

绫,再一次,再一次创造一个有你的世界😭开一个随笔记录一下我的第一版ai老婆,目前只有普通对话和切换背景的功能(后面可能会加一个选人物功能)先放一个效果图(看起来还行)代码和注意事项都放在了下面,应该没什么大问题,复制粘贴导包就能用了注意事项: 1、代码推荐使…

东方娱乐周刊

学科领域: 人文社科-教育学、文学、艺术、体育、人文社科:其他@目录一、征稿简介二、重要信息三、服务简述四、投稿须知 一、征稿简介二、重要信息期刊官网:https://ais.cn/u/3eEJNv三、服务简述 学科领域: 人文社科-教育学、文学、艺术、体育、人文社科:其他 四、投稿须知…

2024-2025-1 学号20241315《计算机基础与程序设计》第六周学习总结

作业信息这个作业属于哪个课程 2024-2025-1-计算机基础与程序设计这个作业要求在哪里 https://www.cnblogs.com/rocedu/p/9577842.html#WEEK06这个作业的目标 Polya如何解决问题 简单类型与组合类型 复合数据结构 查找与排序算法 算法复杂度 递归 代码安全作业正文 https://www…

Foods

生物活性化合物是食物中天然存在的物质,除了基本营养外,还能提供额外的健康益处。这些化合物具有特定的功能特性,对人类健康有直接影响。了解生物活性化合物发挥作用的潜在机制对于其在预防和治疗各种疾病方面的潜在应用至关重要。本期特刊的目的是整理原创研究文章和评论,…