基于pytorch搭建神经网络进行气温预测

目录

1.环境依赖

2.读取文件+数据处理

3.绘制图表

4.数据处理

4.1 :  设置标签与特征,利用标准化加快收敛速度

4.2 构建网络模型:

4.2.1  稍微复杂的版本

4.2.2简化构建网络模型

5.输出成果

首先提供一下基本数据,需要自己实现的可以下载下来,自己玩下

链接:https://pan.baidu.com/s/1fWZ1T6f02OYG_C-euiMQJQ?pwd=6666 
提取码:6666

1.环境依赖

基本实现涉及以下python库:

import numpy as np
import pandas as pd #读取csv文件的库
import matplotlib.pyplot as plt
import torch
import torch.optim as optim
import datetime
from sklearn import preprocessing

2.读取文件+数据处理

ps:笔者用的是win10,路径前加上r表示‘\’不作特殊意义

features = pd.read_csv(r'C:\Users\yuehen\Desktop\PyTorch框架实战\神经网络实战分类与回归任务\temps.csv')
#print(features,type(features))
years = features['year']
months = features['month']
days = features['day']
dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]
#转换为datetime格式
dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in dates]

代码详解:
pd.read_csv(): 读取csv文件,并以DataFrame类型存储常用的几个参数:

                        header:指定某行作为列名,默认是infer,自动判断

                        names :指定列名的列表,若header参数设置为None则用names的作为列名

                        index_col :用于指定哪一列作为索引列的列号或列名

                        dtype : 用于指定列的数据类型和字典

效果:ps:temp1是昨天最高气温,temp2是前天最高气温

可以看出,单次读取csv文件后,时间属性是分开存储的,这并不利于我们后对其进行处理。所以我们导入datetime模块,并利用datetime.strptime()函数将数据转换成标准格式。datetime.strptime():根据xxxx-xx-xx的时间字符串格式,转换成时间元祖

ps:    补充python中时间日期格式化符号

        %y  表示两位数年份(00-99)                        %Y  表示四位数年份(0000-9999)

        %m  表示月份(01-12)                                  %d  表示月内某一天(00-31)

        %H  24小时制                                                   % I  12小时制

        %M  分(00-59)                                             %S  秒(00-59)

3.绘制图表

起草,画个图,可以直观的观察数据走向以及数据分布,基本代码解释都在注释中,细节就不多赘述了。

# 布局设置
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize = (10,10))
fig.autofmt_xdate(rotation = 45)

# 标签值,dates对应features列名:actual一列
ax1.plot(dates, features['actual'])
ax1.set_xlabel(''); ax1.set_ylabel('Temperature'); ax1.set_title('Max Temp')

# 昨天
ax2.plot(dates, features['temp_1'])
ax2.set_xlabel(''); ax2.set_ylabel('Temperature'); ax2.set_title('Previous Max Temp')

# 前天
ax3.plot(dates, features['temp_2'])
ax3.set_xlabel('Date'); ax3.set_ylabel('Temperature'); ax3.set_title('Two Days Prior Max Temp')

# 朋友预测值:emmm没啥实际意义可以忽略不计,但基本数据给了,还是画上吧
ax4.plot(dates, features['friend'])
ax4.set_xlabel('Date'); ax4.set_ylabel('Temperature'); ax4.set_title('Friend Estimate')
#自动调整子图参数,使之填充整个图像区域,这是个实验特性,可能在一些情况下不工作,它仅检查坐标轴标签,刻度标签以及标题的部分
plt.tight_layout(pad=2)
plt.show()
#独热编码:能够处理非连续型数值特征,一共7个星期,我们使用7个寄存器,利用True or False(0/1)的形式体现。
features = pd.get_dummies(features)
#DataFrame格式

图标输出效果:

ps:matplotlib支持基本的图表风格定制,我们可以使用pls.available获取支持的绘图风格:
 

import matplotlib.style as pls
print(pls.available)

这里我们使用‘’538‘风格重新绘制下,只需在布局前添加:plt.style.use('fivethirtyeight')这一串代码即可

 稍微解释下:pd.get_dummies(features)

独热编码:能够处理非连续型数值特征,譬如一共7个星期,我们使用7个寄存器,利用True or False(0/1)的形式体现。它会以下列形式给出存储。

还有个小问题:默认的设置无法显示完全列表数据,这需要我们手动设定下pd的参数修改后:
 

features = pd.get_dummies(features)
#最多行数
pd.set_option('display.max_rows',500)
#最多列数
pd.set_option('display.max_columns',100)
#最大宽度
pd.set_option('display.width',1000)
#DataFrame格式
print(features.head(5))

4.数据处理

4.1 :  设置标签与特征,利用标准化加快收敛速度

我们可以利用sklearn库来进行数据的标准化

#构建标签--以实际温度为标签
labels = np.array(features['actual'])
# 在特征中去掉标签
features= features.drop('actual', axis = 1)
# 名字单独保存一下,以备后面需要使用
feature_list = list(features.columns)
# 转换成ndarray
features = np.array(features)
#标准化
input_features = preprocessing.StandardScaler().fit_transform(features)

部分代码详解:

input_features = preprocessing.StandardScaler().fit_transform(features):

StandardScaler是sklearn库中的一个预处理类,用于实现标准化功能,其数学原理:将每个特征值的数值减去均值,然后除以标准差,有助于消除特征之间的量纲差异(譬如身高1.5-2m之间,年龄0-120(岁)之间,数值范围差异过大,会让模型倾向于较大数值范围的特征,标准化便是用于消除或是大幅度减少这种差异),加快收敛速度且不会因为数值差异而对某些特征产生过大影响。

preprocessing.StandardScaler()主要对训练和测试数据进行标准化:

训练数据:fit_transform()

测试数据:transform()

4.2 构建网络模型:

4.2.1  稍微复杂的版本

ps:这里采用的是比较复杂的构建方式,但是包含了所有基本的构建流程,当然,我们可以利用一些自带的模型来完成快速构建网络模型

基本的逻辑和解释都写在代码里的注释了,整体流程如下:

1.创建输入数据x,y

2.设置网络模型参数(权重矩阵、学习率、损失值对象)

3.设置模型函数(损失函数、激活函数),常见的激活函数可以参考:激活函数(Relu,sigmoid,Tanh,softmax)详解

4.输出损失值,更新参数(注意梯度需要清零,防止梯度叠加)

#将输入格式(narry)转换为torch能接受的tensor格式
x = torch.tensor(input_features, dtype = float)
#y是真实值
y = torch.tensor(labels, dtype = float)

# 权重参数初始化
'''
我们打算搭建一个具有隐藏层的多层感知模型,所以我们设置两个线性模型以及参数(也就是2个权重矩阵),并随机初始化他们的数值(一般都选用标准正态分布)
我们的输入数据是348*14的矩阵,所以我们设置的权重矩阵应该是14*n,这里n我们可以任取,此处我取得值是
128,所以第一个权重矩阵是14*128,第二个权重矩阵后便需要获得输出值,所以第二个权重矩阵应为128*1,后续涉及梯度下降算法,所以requires_grad属性置为True
'''
weights = torch.randn((14, 128), dtype = float, requires_grad = True) 
#设置偏置值
biases = torch.randn(128, dtype = float, requires_grad = True) 
weights2 = torch.randn((128, 1), dtype = float, requires_grad = True) 
biases2 = torch.randn(1, dtype = float, requires_grad = True) 
#设置学习率,如果出现梯度爆炸现象,一般是学习率过大导致的,可以适当下调学习率大小
learning_rate = 0.001 
#创建损失值对象
losses = []

for i in range(1000):
    # 计算隐藏层
    hidden = x.mm(weights) + biases
    # 加入激活函数:reulu函数:f(x) = 1/(1+e^-x)
    hidden = torch.relu(hidden)
    # 预测结果
    predictions = hidden.mm(weights2) + biases2
    # 通计算损失(s手动版均方误差法)
    loss = torch.mean((predictions - y) ** 2) 
    losses.append(loss.data.numpy())
    
    # 打印损失值,每100次打印一份
    if i % 100 == 0:
        print('loss:', loss)
    #返向传播计算
    loss.backward()
    
    #更新参数--x = x + (-)grad*rate 沿梯度反方向下降
    weights.data.add_(- learning_rate * weights.grad.data)  
    biases.data.add_(- learning_rate * biases.grad.data)
    weights2.data.add_(- learning_rate * weights2.grad.data)
    biases2.data.add_(- learning_rate * biases2.grad.data)
    
    # 每次迭代都得记得清空
    weights.grad.data.zero_()
    biases.grad.data.zero_()
    weights2.grad.data.zero_()
    biases2.grad.data.zero_()

跑一下:可以明显看出损失值在下降了:

4.2.2简化构建网络模型

上述流程基本是从头开始搭建模型,实际上torch为我们提供了丰富的API来辅助我们快速搭建神经网络模型.这里只是简单的举个例子,回头建个帖子,详细讨论下。

基本参数设置:

input_size = input_features.shape[1]
hidden_size = 128
output_size = 1
batch_size = 16
my_nn = torch.nn.Sequential(
    #加入隐藏层
    torch.nn.Linear(input_size, hidden_size),
    #加入激活函数
    torch.nn.Sigmoid(),
    #再加一个全连接层
    torch.nn.Linear(hidden_size, output_size),
)
#定义损失函数MSE--均方差
cost = torch.nn.MSELoss(reduction='mean')
#利用优化器实现反向传播,参数更新--Adam可以自适应学习率,可以根据不同的梯度信息,动态调整学习率
optimizer = torch.optim.Adam(my_nn.parameters(), lr = 0.001)

训练网络:

这里采用小批量梯度下降法作为训练方式,相关解释可以见:神经网络学习---学习笔记参数优化一栏。

# 存储每100个数值的损失值
losses = []
for i in range(1000):
    #用于存储每一个bacth的loss数值
    batch_loss = []
    # MINI-Batch方法来进行训练
    #每次迭代,从0开始,以batch_size为步长,逐渐增加起始索引
    for start in range(0, len(input_features), batch_size):
        end = start + batch_size if start + batch_size < len(input_features) else len(input_features)
        #利用切片获取输出的特征数据
        xx = torch.tensor(input_features[start:end], dtype=torch.float, requires_grad=True)
        #获取标签
        yy = torch.tensor(labels[start:end], dtype=torch.float, requires_grad=True)
        #my_nn中进行前向传播
        prediction = my_nn(xx)
        #计算预测结果与真实标签之间的损失,使用之前定义的均方差损失函数cost
        loss = cost(prediction, yy)
        #梯度清零
        optimizer.zero_grad()
        #retain_graph=True表示在计算梯度后保留计算图,以便进行多次梯度更新
        loss.backward(retain_graph=True)
        #根据计算的梯度自动更新模型的参数
        optimizer.step()
        #numpy转换,并添加到batch_loss列表
        batch_loss.append(loss.data.numpy())
    # 打印损失
    if i % 100 == 0:
        #np.mean()取均值,以均值损失值输出
        losses.append(np.mean(batch_loss))
        print(i, np.mean(batch_loss))

尝试运行有以下输出结果,但没有显示0-100的输出,产生报错:

UserWarning: Using a target size (torch.Size([16])) that is different to the input size (torch.Size([16, 1])). This will likely lead to incorrect results due to broadcasting. Please ensure they have the same size.

这是由于输入的尺寸是torch.Size([16, 1]),而目标的尺寸是torch.Size([16])

所以在传入标签数据的时候加上尺寸限定,这样就ok了

yy = torch.unsqueeze(yy, dim = 1)

5.输出成果

主要是利用matplotlib绘制预测图,红色圆点散点图表示预测值,蓝色线条表示真实值,可以看出,整体的趋势是基本符合的,到此,一个简单的预测模型就构建完成了。

#-------预测训练结果---------
x = torch.tensor(input_features, dtype = torch.float)
#便于画图,转换为Numpy
predict = my_nn(x).data.numpy()
#
# dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]
# dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in dates]

# 创建一个表格来存日期和其对应的标签数值
true_data = pd.DataFrame(data = {'date': dates, 'actual': labels})

# 同理,再创建一个来存日期和其对应的模型预测值
months = features[:, feature_list.index('month')]
days = features[:, feature_list.index('day')]
years = features[:, feature_list.index('year')]

test_dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]

test_dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in test_dates]

predictions_data = pd.DataFrame(data = {'date': test_dates, 'prediction': predict.reshape(-1)})
# 真实值,b--蓝色表示
plt.plot(true_data['date'], true_data['actual'], 'b-', label = 'actual')

# (散点图)预测值ro--红色圆点表示
plt.plot(predictions_data['date'], predictions_data['prediction'], 'ro', label = 'prediction')
plt.xticks(rotation = 60);
plt.legend()

# 图名
plt.xlabel('Date'); plt.ylabel('Maximum Temperature (F)'); plt.title('Actual and Predicted Values');
plt.show()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渊兮旷兮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值