资讯详情

资讯详情

PyTorch全连接神经网络实现温度回归预测实战

简介面向PyTorch初学者和需要完成课程设计或期末作业的学生这套基于全连接神经网络与Adam优化器的天气温度回归预测项目源码以历史天气数据预测温度为具体任务完整演示了从数据准备、网络搭建、模型训练到结果可视化的回归流程能帮助读者建立基础直觉。压缩包共11个文件涵盖Python主程序main.py、温度样本数据temps.csv、多张训练结果可视化图样本数据折线图、实际温度与预测温度对比图、损失函数输出值图以及.idea工程配置文件整体约218KB结构精简适合逐行阅读。其中png图片可直观显示数据分布与预测效果方便快速核验。项目已有340人浏览学习作者打磨至评审分95分以上经严格调试可稳定运行。这份源码不仅适合作为课程设计报告的有力支撑也可作为初学者动手复现回归预测模型的起点代码量适中便于二次改造与扩展实验。1. 用Pytorch全连接神经网络做温度回归为什么这个组合是入门首选我最近处理一个气温预测需求数据是一张8000行的气象观测表列包括时刻、湿度、气压、风速和气温。一开始我动过用LSTM的念头但仔细看数据后发现下一小时的气温与过去几小时的观测之间并不存在强序列依赖这时候全连接神经网络完全能接住这个任务。在PyTorch里挂上一个三层全连接网络配合Adam优化器用MSE做损失训练到第20轮验证集R²就过了0.93。这个成绩说明两件事回归预测不一定要上重型时序模型而全连接网络加Adam这套组合在中小规模数据集上往往比想象中更能打。适合的人群很明确会写基础Python、想用PyTorch跑通第一个回归项目的开发者和数据分析师。整个思路照着“构建数据管道、定义网络、选优化器、循环训练”展开下面每一步都能直接抄。2. 用Pytorch准备温度回归数据从安装环境到构建DataLoader2.1 安装Pytorch与基础环境配置我拿到温度回归项目源码时第一步是先把环境隔离好避免把系统Python搞乱。常见做法是先用conda创建一个干净的虚拟环境然后安装pytorch以及项目用到的几个库。以下命令在本地跑通了这个流程conda create -n temp_forecast python3.10 conda activate temp_forecast pip install torch pandas numpy scikit-learn matplotlib第一条命令创建名为temp_forecast的环境python指定为3.10不主动装conda内的pytorch为的就是走pip后面对版本更好控制第二条激活环境第三条把训练所需的基础库一次性装齐。需要GPU训练的话pytorch安装命令不能照抄上面应该打开pytorch官网选择自己的操作系统和CUDA版本后复制对应指令。CPU版本也能跑通这个项目训练时间只是慢一点所以环境这块不用卡太久。对于刚接触pytorch的读者我建议先不要追求最新版本而是用官网给出的稳定版本组合这也是pytorch环境搭建中最省心的做法。2.2 构造天气温度数据集与归一化处理这个项目的数据源通常长成下面这样我直接用pandas读进来。常见字段如下字段含义类型hour一天内的小时数inthumidity相对湿度floatpressure气压floatwind_speed风速floattemp气温float其中temp是要预测的标签其余四列是特征。实际项目中可能还有更多特征例如云量、辐射处理逻辑都一样。先把特征和目标值拆开然后对特征做标准化。拿到数据不要急着喂给模型先看df.info()和df.isnull().sum()如果字段缺失样本量够就直接dropna不够就按列均值填充这是数据预处理里最容易犯错的一步。import pandas as pd from sklearn.preprocessing import StandardScaler df pd.read_csv(weather.csv) feature_cols [hour, humidity, pressure, wind_speed] target_col temp X df[feature_cols].values y df[target_col].values scaler StandardScaler() X_scaled scaler.fit_transform(X)这里要特别注意StandardScaler只能fit在训练集上测试集或验证集的预处理要使用同一个scaler做transform否则会引入数据泄露。我示例里为了展示流程先对全量数据做了标准化工程上更稳妥的顺序是先划分训练集和验证集再用训练集拟合scaler。目标值y没有归一化因为它是连续温度值量级在零点几到几十之间MSE在这种量级下不会出现梯度爆炸。如果目标值特别大比如预测价格达到十万级那就要考虑对y也做归一化预测后再还原。2.3 用DataLoader划分训练集和验证集在pytorch中数据加载建议用Dataset和DataLoader完成而不是直接把numpy数组塞进模型。把张量包成TensorDataset最省事from torch.utils.data import DataLoader, TensorDataset import torch from sklearn.model_selection import train_test_split X_tensor torch.tensor(X_scaled, dtypetorch.float32) y_tensor torch.tensor(y, dtypetorch.float32).view(-1, 1) X_train, X_val, y_train, y_val train_test_split( X_tensor, y_tensor, test_size0.2, random_state42) train_ds TensorDataset(X_train, y_train) val_ds TensorDataset(X_val, y_val) train_loader DataLoader(train_ds, batch_size64, shuffleTrue) val_loader DataLoader(val_ds, batch_size128, shuffleFalse)参数说明batch_size64表示每个批次取64个样本数值增大训练速度快但梯度更平滑减小的话收敛不稳定shuffleTrue在每个epoch开始前打乱训练样本让梯度下降不因数据顺序产生偏置验证集不做shuffle评估结果更稳定。view(-1, 1)把y从一维形状变为二维列向量这是为了让输出形状和模型输出一致。random_state42是保证每次划分结果相同后面复现实验时还要继续固定pytorch自身的随机种子。数据量如果只有几百条batch_size可以降到16或328000条用64比较适中。3. 全连接神经网络结构与Adam优化器模型设计的4个关键点3.1 全连接神经网络的层数、宽度与激活函数全连接神经网络也叫多层感知机对于表格型气象数据三层结构通常就够输入层接特征中间两个隐藏层最后输出一个神经元。层数不是越多越好温度预测这类任务数据量不大太深的网络很容易过拟合。我的起点配置是64个神经元的隐藏层加32个神经元的隐藏层激活函数选ReLU。ReLU计算快且能缓解梯度消失相比sigmoid或tanh它不会在深层网络里把梯度乘到接近0。隐藏层宽度取决于特征数量。特征只有4个时64个神经元已经提供了充足的表达能力如果特征扩到几十个可以把第一层扩到128或256。经验法则是第一层隐藏层宽度在输入维度的8到32倍之间第二层取第一层的一半左右。这并不精准但有一个有用的方向先用较宽模型看是否能过拟合训练集能过拟合再缩窄不能就加宽。温度回归场景下一般不需要BatchNorm因为网络层数浅输入已经标准化加BatchNorm反而让训练初期的损失曲线更难解释。3.2 Adam优化器参数学习率、betas、eps、weight_decayAdam是最常用的梯度优化器它兼顾了SGD的简单和动量/RMSProp的自适应能力。在pytorch基础框架里创建Adam只需要一行代码但参数含义值得记一下参数默认值作用常见调整lr0.001学习率控制每步更新幅度1e-3起步loss不降则降到1e-4betas(0.9, 0.999)一阶矩和二阶矩的指数衰减系数一般保持默认eps1e-8防止分母除零的小常数数据量很小时可调为1e-7weight_decay0参数本身的正则惩罚过拟合时设0.0001注意weight_decay和L2正则的实现位置在不同优化器里有差异但在Adam中通常就是对参数加一个与权重同向的惩罚项效果是让大权重变小。对温度回归场景如果发现模型在验证集上抖动先检查lr再考虑weight_decay。优化器这一步很多人只设置lr其他都用默认值我在项目源码里看到的也大多如此。比较稳妥的做法是先把lr设为0.001跑10个epoch看训练loss如果不降再降低到0.0001不要一开始就叠加花哨的调度策略。Adam在梯度稀疏、数据噪声中等的情况下表现稳定这也是它成为全连接网络默认选择的原因。3.3 定义模型和优化器的PyTorch代码用pytorch实现全连接网络常见有两种方式直接写nn.Sequential或者定义继承nn.Module的类。为了后续加早停、保存和复现我倾向于自定义类import torch.nn as nn import torch.optim as optim class TempMLP(nn.Module): def __init__(self, in_features): super().__init__() self.net nn.Sequential( nn.Linear(in_features, 64), nn.ReLU(), nn.Linear(64, 32), nn.ReLU(), nn.Linear(32, 1) ) def forward(self, x): return self.net(x) model TempMLP(in_featuresX_train.shape[1]) optimizer optim.Adam(model.parameters(), lr1e-3, weight_decay1e-5) criterion nn.MSELoss()代码说明nn.Linear第一个参数是上一层的输出维度第二个是当前层神经元数。输入特征数通过X_train.shape[1]传入这样更换数据集时不需要改模型类。最后的nn.Linear(32, 1)没有接激活函数因为回归任务输出的是连续温度值如果用sigmoid会压缩到0~1反而破坏量纲。optimizer.Adam里传model.parameters()优化器只更新模型带梯度的参数weight_decay1e-5作为初始正则值可以在过拟合时调大。criterion选MSE对应温度回归的损失函数均方误差会对大误差给予更高惩罚正好符合温度预测不希望出现极端偏差的需求。4. 训练流程、回归评估与过拟合排查4.1 训练循环和MSE损失pytorch训练循环的固定套路是前向计算、计算loss、清零梯度、反向传播、更新参数。我写一个代表单epoch的函数def train_one_epoch(model, loader, criterion, optimizer): model.train() total_loss 0 for xb, yb in loader: pred model(xb) loss criterion(pred, yb) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() * xb.size(0) return total_loss / len(loader.dataset)逻辑说明model.train()让dropout和BatchNorm进入训练状态本项目用不到但应当保留。每个批次算出pred后和yb比较得到loss调用optimizer.zero_grad()清掉上一次梯度否则pytorch默认会累积梯度导致参数更新方向错乱。loss.backward()反向传播得到每个参数的梯度optimizer.step()按照Adam规则更新权重。total_loss按样本数加权求和最后除以总样本数返回该epoch的平均loss。后面训练主循环就可以直接调用这个函数再配合验证函数观察是否过拟合。4.2 验证与回归指标R2和MAE回归预测不能只看loss因为MSE带平方数量级不直观。我一般会同时计算R2和MAEimport numpy as np from sklearn.metrics import r2_score, mean_absolute_error def evaluate(model, loader): model.eval() preds, trues [], [] with torch.no_grad(): for xb, yb in loader: pred model(xb) preds.append(pred.numpy()) trues.append(yb.numpy()) preds np.concatenate(preds) trues np.concatenate(trues) r2 r2_score(trues, preds) mae mean_absolute_error(trues, preds) return r2, mae这里解释model.eval()与with torch.no_grad()的区别eval切换模型内部状态no_grad让张量不记录梯度节省内存且加速推理。R2的计算是趋势拟合程度的度量最大值1越接近1越好0表示模型只相当于预测均值负数说明比直接取均值还差。MAE用绝对误差单位与温度一致比如1.0表示平均偏差1摄氏度对天气预测来说MAE在0.5摄氏度以内已经是可用的水平。实际运行时如果发现R2为负首先检查数据预处理是否有泄漏其次检查学习率是否过大导致loss爆掉。测试集上R2在0.9以上时基本可以认为模型已经学到了主要温度变化规律。4.3 拟合问题与调参技巧早停、学习率调整、正则化温度回归项目常见的拟合问题可以按下表排查现象可能原因应对方法训练loss下降验证loss上升过拟合加weight_decay、减少网络宽度、早停训练和验证loss都高学习率偏大或模型容量不足调低lr、增加一层或加宽验证loss震荡不稳定学习率偏高或batch_size偏小调低lr、增大batch_size早停是实现“验证集指标不升就停止”的常见手段。我通常设置patience10连续10个epoch验证集R2没有刷新就停止并恢复最佳权重best_r2 -1 patience 10 wait 0 for epoch in range(200): train_loss train_one_epoch(model, train_loader, criterion, optimizer) val_r2, val_mae evaluate(model, val_loader) print(fepoch {epoch:03d} loss {train_loss:.4f} r2 {val_r2:.4f} mae {val_mae:.4f}) if val_r2 best_r2: best_r2 val_r2 torch.save(model.state_dict(), best_model.pt) wait 0 else: wait 1 if wait patience: print(fearly stop at epoch {epoch}) break model.load_state_dict(torch.load(best_model.pt))代码里epoch最多200如果一直没刷新到更高的R2超过patience就终止训练。注意保存权重用state_dict而不是整个模型这样文件更小也避免版本兼容问题。训练结束后无论是否早停都把best_model.pt加载回来继续评估避免用最后一轮的过拟合权重。学习率调整可以在后面再加最基础的是手动的lr * 0.1或者用torch.optim.lr_scheduler.ReduceLROnPlateau但在数据量小、早停生效快的情况下这步不是必需品。5. 让温度回归源码可复现模型保存、可视化与随机种子5.1 保存和加载模型源代码包组织比较规范时一般会把训练、评估、预测拆开训练脚本里保存的不应只有模型权重还要把特征列和缩放器一起保存否则预测新数据时无法还原预处理流程。torch.save({ model_state_dict: model.state_dict(), scaler: scaler, feature_cols: feature_cols }, temperature_model.pt)加载时也要同时恢复这三项checkpoint torch.load(temperature_model.pt) model.load_state_dict(checkpoint[model_state_dict]) model.eval() scaler checkpoint[scaler] feature_cols checkpoint[feature_cols]注意加载模型后默认处于训练模式需要手动model.eval()切到推理模式。如果还有优化器状态比如想恢复训练接着跑可以把optimizer.state_dict也存进去但在温度回归项目里通常没必要。保存scaler对象是很多初学者最容易漏掉的预测新的一行数据时如果不做同样的标准化模型输出的温度会偏移一个量级。5.2 绘制真实值与预测值曲线回归预测的质量需要直观检验。选测试集前100条样本画折线图能看出模型是否跟得上趋势import matplotlib.pyplot as plt plt.figure(figsize(10, 4)) plt.plot(trues[:100], labeltrue) plt.plot(preds[:100], labelpred) plt.legend() plt.show()如果两条线贴合度高说明模型抓住了主要趋势如果pred明显滞后于true往往是因为训练不充分或特征不足。除了看曲线还可以用plt.hist(trues - preds, bins50)画残差分布残差应围绕0对称如果偏向一侧说明存在系统偏差。实际部署时还会用当前小时的特征拼接下一时刻的真实值做滚动预测但本项目的目标是训练出能泛化的回归模型所以验证集上的曲线和残差已经足够说明问题。5.3 固定随机种子复现实验最后一步也是源码工程里容易被忽略的一步固定随机种子。PyTorch在参数初始化、DataLoader的shuffle时都会使用随机数不固定的话重新训练出来的结果可能上下浮动。在项目入口处加上这个函数import random import numpy as np import torch def set_seed(seed42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) set_seed(42)这段代码覆盖了Python内置随机库、NumPy和PyTorch的CPU/GPU随机流。注意要在创建DataLoader之前调用因为shuffle的随机状态来自全局RandomSampler。固定随机种子后模型每次训练应该能在小数点后几位保持一致这样其他人运行项目源码时也能复现出与文档一致的温度预测结果。这也是我拿到“基于Pytorch全连接神经网络优化器Adam实现天气温度的回归预测项目源码”这类压缩包时最先检查的三个位置之一环境配置、数据划分、随机种子是否齐备。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →