【AI—pytorch学习】项目实战-单车预测器

Pytorch实战项目学习笔记——单车预测器

1.数据

原书中给出的地址好像有些问题或者被修改了,下载的数据与书中提到的数据不一致。查阅后可在 http://archive.ics.uci.edu/ml/datasets/Bike+Sharing+Dataset 地址下下载。下载后包含连个文件,书中案例使用的是hour文件
数据集
共享单车hour数据
在这里插入图片描述

2.原理

可以查看西瓜书中对于BP反向传播原理的解析,本书通过例举与可视化直观的展示了隐层神经网络的逼近原则。通过添加隐层神经元个数,当训练时参数变化时能得到不同的函数图像,因此可以用来拟合实际数据。这里激活函数使用的sigmoid函数,网络采用1-10-1的全连接网络,损失函数为平均差平方。
在这里插入图片描述

3.代码实现

需要的包为numpy,pandas,torch。由于条件限制,该系列的学习都使用的时windows,cpu版的torch,运行在junpyter中。可以分块实现也能看到及时效果,方便学习。

#导入相关的第三方库
import numpy as np
import pandas as pd
import torch
from torch.autograd import Variable
import torch.optim as optim
import matplotlib.pyplot as plt
%matplotlib inline
#数据处理
data_path ='hour.csv'            #放在文件根目录下即可,若在jupyter上运行可上传到同一目录下
rides=pd.read_csv(data_path)     #简书【函数学习】pandas.read_cvs
rides.head()                     #输出前五行观察 简书【函数学习】pandas.dataframe.head()
counts=rides['cnt'][:50]         #dataframe[索引][切片],详见pandas.dataframe
x=np.arange(len(counts))         #简书【函数学习】numpy.arange() 【函数学习】Python List len()
y=np.array(counts)               #简书【函数学习】numpy.array与Ndarray对象
plt.figure(figsize=(10,7))       #plt绘图函数
plt.plot(x,y,'o-')
plt.xlabel('X')
plt.ylabel('Y')
plt.show()

数据展示:
在这里插入图片描述


#定义参数
x=Variable(torch.FloatTensor(np.arange(len(counts),dtype=float)/len(counts)))   #x为坐标 简书【函数学习】torch.Variable()&torch—tensor张量转换
y=Variable(torch.FloatTensor(np.array(counts,dtype=float)))                     #y为数量
print(x,y)
sz=10                                                                           #隐含层神经元个数
weights=Variable(torch.randn(1,sz),requires_grad=True)                          #第一层权重  [J]【函数学习】torch—tensor张量生成
biases=Variable(torch.randn(sz),requires_grad=True)                             #第一层阈值
weights2=Variable(torch.randn(sz,1),requires_grad=True)                         #第二层权重
print(weights,biases,weights2)                                                  #输出查看初始值

整理下数据格式的变化
在这里插入图片描述

#定义网络结构
learning_rate=0.0001                                                                 #设置学习率
losses=[]                                                                            #设置损失值列表
for i in range(1000000):
    hidden=x.expand(sz,len(x)).t()*weights.expand(len(x),sz)+biases.expand(len(x),sz)
    #print(hidden)
    hidden=torch.sigmoid(hidden)
    predictions=hidden.mm(weights2)
    loss=torch.mean((predictions-y)**2)                                              #定义损失值
    losses.append(loss.data.numpy())
    if i%10000==0:
        print('loss',loss)
        #print(hidden)
        #print(predictions)
    loss.backward()
    #print(weights.grad.data)
    weights.data.add_(- learning_rate*weights.grad.data)
    biases.data.add_(- learning_rate*biases.grad.data)
    weights2.data.add_(- learning_rate*weights2.grad.data)
    weights.grad.data.zero_()
    biases.grad.data.zero_()
    weights2.grad.data.zero_()
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('loss')

这段代码里最难理解的是这行代码

hidden=x.expand(sz,len(x)).t()*weights.expand(len(x),sz)+biases.expand(len(x),sz)

我们在上一段代码块中将X定义的是1-50的一维数组,我曾经错误地将其认为是50个输入,但其实这五十个样本都是属于同一个变量x的50个值,因此输入的神经元个数应该看作1,也就是1个神经元输入,但是这个输入有50个样本值。所以网络结构应该是1-10-1的全连接网络。
由此得到的经验是要区分变量数与变量样本数,输入神经元的个数应该是相关的变量数。
在这行代码里面,每输入一个x都要与10个权重w相乘在加上偏置,所以对于每一个输入的x要扩充10份,而X中有50个样本,所以W权重向量要扩充50份,偏执B与W是相对应的。所以最终统一在一个矩阵里就变成了50*10的矩阵向量。

直观点来看,扩充后的三个矩阵如下图所示:
在这里插入图片描述
运算后的结果如图所示:
在这里插入图片描述
*在矩阵运算中代表对应元素相乘。一行代表一次输入,十个神经元的输入结果,总共有50个样本被输入。当然之后要加入激活函数后,再进行从隐层到输出层的计算。


错误的预测

print(predictions)
x_data=x.data.numpy()
plt.figure(figsize=(10,7))
xplot,=plt.plot(x_data,y.data.numpy(),'o')
yplot,=plt.plot(x_data,predictions.data.numpy())
plt.xlabel=('X')
plt.ylabel=('Y')
plt.legend([xplot,yplot],['data','prediction under 100000 epochs'])
plt.show()
counts_predict=rides['cnt'][50:100]
x=Variable(torch.FloatTensor((np.arange(len(counts_predict),dtype=float)+len(counts))/len(counts)))
y=Variable(torch.FloatTensor(np.array(counts_predict,dtype=float)))
hidden=x.expand(sz,len(x)).t()*weights.expand(len(x),sz)
hidden=torch.sigmoid(hidden)
predictions=hidden.mm(weights2)
loss=torch.mean((predictions-y)**2)
print(loss)

x_data=x.data.numpy()
plt.figure(figsize=(10,7))
xplot,=plt.plot(x_data,y.data.numpy(),'o')
yplot,=plt.plot(x_data,predictions.data.numpy())
plt.xlabel('X')
plt.ylabel('Y')
plt.legend([xplot,yplot],['data','prediction'])
plt.show()

这两块代码是对上面结果的展示,因为x是人为规定的1到50的均匀数组,并不是跟单车数量有关的变量,所以预测的结果并不理想。书中能实现对训练参数的拟合,但是我在自己的实现中,并不能实现对训练参数的拟合,损失函数维持再1010左右不再下降。但是这个预测本来就是错的,所以也不再深究了。主要的目的还是为了理清网络结构的搭建。之后就调用torch中的函数来实现网络构建了。


数据预处理,进行独热编码

#数据预处理,离散数据独热编码
dummy_fields=['season','weathersit','mnth','hr','weekday']
for each in dummy_fields:
    dummies=pd.get_dummies(rides[each],prefix=each,drop_first=False)   #[J]【函数学习】pandas.get_dummies
    rides=pd.concat([rides,dummies],axis=1)                            #[J]【函数学习】pandas.concat()
fields_to_drop=['instant','dteday','season','weathersit','weekday','atemp','mnth','workingday','hr']  #要删除的列名
data=rides.drop(fields_to_drop,axis=1)                                 #data为处理后的数据;[J]【函数学习】pandas.dataframe.drop()

数据预处理,对数值数据进行归一化

#数据预处理,对数值数据进行归一化
quant_features=['cnt','temp','hum','windspeed']    #要进行归一化的数值数据名
scaled_features={}
for each in quant_features:
    mean,std=data[each].mean(),data[each].std()   
    scaled_features[each]=[mean,std]
    data.loc[:,each]=(data[each]-mean)/std        #[J]【函数学习】pandas.DataFrame.loc&iloc;【名词解释】标准化(Z-Score)

数据预处理,划分训练集与测试集;特征量与预测量

#数据预处理,划分训练集与测试集;特征量与预测量
test_data=data[-21*24:]
train_data=data=data[:-21*24]
target_fields=['cnt','casual','registered']
features,targets=train_data.drop(target_fields,axis=1),train_data[target_fields]   #features输入的特征量,targets预测目标量
test_features,test_targets=test_data.drop(target_fields,axis=1),test_data[target_fields]
X=features.values                       #dataframe转化为numpy的ndarray格式
Y=targets['cnt'].values
Y=Y.astype(float)                       #[J]【函数学习】numpy.astype()
Y=np.reshape(Y,[len(Y),1])              #[J]【函数学习】numpy.reshape
losses=[]

用torch函数构建网络模型

#用torch函数构建网络模型
input_size=features.shape[1]                       #输入层;[J]【函数学习】pandas.DataFrame.shape
hidden_size=10                                     #隐藏层
output_size=1                                      #输出层
batch_size=128
neu=torch.nn.Sequential(                           #[J]【函数学习】torch.nn.sequential()
    torch.nn.Linear(input_size,hidden_size),
    torch.nn.Sigmoid(),
    torch.nn.Linear(hidden_size,output_size),)

构建网络

#训练
losses=[]
cost= torch.nn.MSELoss()                                                #均方误差损失
optimizer=torch.optim.SGD(neu.parameters(),lr=0.01)                     #随机梯度下降优化 [J]【函数学习】torch.nn.Parameter()
for i in range(1000):                                                   #训练轮数
    batch_loss=[]
    for start in range(0,len(X),batch_size):                            #分批训练
        end =start+batch_size if start+batch_size<len(X) else len(X)
        xx=Variable(torch.FloatTensor(X[start:end]))                    #批量学习特征
        yy=Variable(torch.FloatTensor(Y[start:end]))                    #批量目标真实值
        predict=neu(xx)                                                 #学习特征送入网络,得到目标预测值
        loss=cost(predict,yy)                                           #计算损失函数
        optimizer.zero_grad()                                           #清空所有被优化过的Variable的梯度                                         
        loss.backward()
        optimizer.step()                                                #进行单次优化 (参数更新).
        batch_loss.append(loss.data.numpy())
    if i%100==0:
        losses.append(np.mean(batch_loss))
        print(i,np.mean(batch_loss))                                    #每训练一百轮取平均loss存储
plt.plot(np.arange(len(losses))*100,losses)
plt.xlabel('epoch')
plt.ylabel('MSE')
plt.show()

结果损失函数值
0 0.06493953
100 0.06366216
200 0.06253059
300 0.06150228
400 0.060573395
500 0.059757657
600 0.059065226
700 0.058489937
800 0.058013152
900 0.057613485
在这里插入图片描述

targets=test_targets['cnt']                                #测试集抽取目标
targets=targets.values.reshape([len(targets),1])           #values将dataframe转化为numpy数组,reshape转成列向量
targets=targets.astype(float)                              #转成浮点数据
x=Variable(torch.FloatTensor(test_features.values))        #转为tensor
y=Variable(torch.FloatTensor(targets))
predict=neu(x)                                             #把x输入训练好的网络,输出网络预测量
predict=predict.data.numpy()                               #把输出的tensor转为numpy数组
fig,ax =plt.subplots(figsize=(10,7))
mean,std=scaled_features['cnt']                            #存储的目标量标准化的均值与方差
ax.plot(predict*std+mean,label='prediction')
ax.plot(targets*std+mean,label='data')
ax.set_xlabel('data-time')
ax.set_ylabel('counts')
dates=pd.to_datetime(rides.loc[test_data.index]['dteday']) #dteday为时间列
dates=dates.apply(lambda d: d.strftime('%b %d'))           #pd.apply()
ax.set_xticks(np.arange(len(dates))[12::24])
_=ax.set_xticklabels(dates[12::24],rotation=45) 

对比结果图,蓝色为预测值
在这里插入图片描述
以上代码中带[简书]或[J]标志的都能在我的简书https://www.jianshu.com/u/e430b816b53a中找到这个函数的详细用法,你也可以在简书中直接搜索[J]后面的内容就能看到啦
感谢!

  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值