运用PyTorch动手搭建一个共享单车预测器-创新互联
本文摘自 《深度学习原理与PyTorch实战》
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:主机域名、虚拟空间、营销软件、网站建设、五莲网站维护、网站推广。我们将从预测某地的共享单车数量这个实际问题出发,带领读者走进神经网络的殿堂,运用PyTorch动手搭建一个共享单车预测器,在实战过程中掌握神经元、神经网络、激活函数、机器学习等基本概念,以及数据预处理的方法。此外,还会揭秘神经网络这个“黑箱”,看看它如何工作,哪个神经元起到了关键作用,从而让读者对神经网络的运作原理有更深入的了解。
3.1 共享单车的烦恼
大约从2016年起,我们的身边出现了很多共享单车。五颜六色、各式各样的共享单车就像炸开花了一样,遍布城市的大街小巷。
共享单车在给人们带来便利的同时,也存在一个麻烦的问题:单车的分布很不均匀。比如在早高峰的时候,一些地铁口往往聚集着大量的单车,而到了晚高峰却很难找到一辆单车了,这就给需要使用共享单车的人造成了不便。
那么如何解决共享单车分布不均匀的问题呢?目前的方式是,共享单车公司会雇用一些工人来搬运单车,把它们运送到需要单车的区域。但问题是应该运多少单车?什么时候运?运到什么地方呢?这就需要准确地知道共享单车在整个城市不同地点的数量分布情况,而且需要提前做出安排,因为工人运送单车还有一定的延迟性。这对于共享单车公司来说是一个非常严峻的挑战。
为了更加科学有效地解决这个问题,我们需要构造一个单车数量的预测器,用来预测某一时间、某一停放区域的单车数量,供共享单车公司参考,以实现对单车的合理投放。
巧妇难为无米之炊。要构建这样的单车预测器,就需要一定的共享单车数据。为了避免商业纠纷,也为了让本书的开发和讲解更方便,本例将会使用一个国外的共享单车公开数据集(Capital Bikeshare)来完成我们的任务,数据集下载链接:
www.capitalbikeshare.com/ system-data 。
下载数据集之后,我们可以用一般的表处理软件或者文本编辑器直接打开,如图3.1所示。
该数据是从2011年1月1日到2012年12月31日之间某地的单车使用情况,每一行都代表一条数据记录,共17 379条。一条数据记录了一个小时内某一个地点的星期几、是否是假期、天气和风速等情况,以及该地区的单车使用量(用cnt变量记载),它是我们最关心的量。
我们可以截取一段时间的数据,将cnt随时间的变化关系绘制成图。图3.2是2011年1月1日到1月10日的数据。横坐标是时间,纵坐标是单车的数量。单车数量随时间波动,并且呈现一定的规律性。不难看出,工作日的单车数量高峰远高于周末的。
我们要解决的问题就是,能否根据历史数据预测接下来一段时间该地区单车数量的走势情况呢?在本章中,我们将学习如何设计神经网络模型来预测单车数量。对于这一问题,我们并不是一下子提供一套完美的解决方案,而是通过循序渐进的方式,尝试不同的解决方案。结合这一问题,我们将主要讲解什么是人工神经元、什么是神经网络、如何根据需要搭建一个神经网络,以及什么是过拟合,如何解决过拟合问题,等等。除此之外,我们还将学到如何对一个神经网络进行解剖,从而理解其工作原理以及与数据的对应。
3.2 单车预测器1.0
本节将做出一个单车预测器,它是一个单一隐含单元的神经网络。我们将训练它学会拟合共享单车的波动曲线。
不过,在设计单车预测器之前,我们有必要了解一下人工神经网络的概念和工作原理。
3.2.1 人工神经网络简介
人工神经网络(简称神经网络)是一种受人脑的生物神经网络启发而设计的计算模型。人工神经网络非常擅长从输入的数据和标签中学习到映射关系,从而完成预测或者解决分类问题。人工神经网络也被称为通用拟合器,这是因为它可以拟合任意的函数或映射。
前馈神经网络是我们最常用的一种网络,它一般包括3层人工神经单元,即输入层、隐含层和输出层,如图3.3所示。其中,隐含层可以包含多层,这就构成了所谓的深度神经网络。
图中的每一个圆圈代表一个人工神经元,连线代表人工突触,它将两个神经元联系了起来。每条连边上都包含一个数值,叫作权重,我们通常用w来表示。
神经网络的运行通常包含前馈的预测过程(或称为决策过程)和反馈的学习过程。
在前馈的预测过程中,信号从输入单元输入,并沿着网络连边传输,每个信号会与连边上的权重进行乘积,从而得到隐含层单元的输入;接下来,隐含层单元对所有连边输入的信号进行汇总(求和),然后经过一定的处理(具体处理过程将在下节讲述)进行输出;这些输出的信号再乘以从隐含层到输出的那组连线上的权重,从而得到输入给输出单元的信号;最后,输出单元再对每一条输入连边的信号进行汇总,并进行加工处理再输出。最后的输出就是整个神经网络的输出。神经网络在训练阶段将会调节每条连边上的权重w数值。
在反馈的学习过程中,每个输出神经元会首先计算出它的预测误差,然后将这个误差沿着网络的所有连边进行反向传播,得到每个隐含层节点的误差。最后,根据每条连边所连通的两个节点的误差计算连边上的权重更新量,从而完成网络的学习与调整。
下面,我们就从人工神经元开始详细讲述神经网络的工作过程。
3.2.2 人工神经元
人工神经网络类似于生物神经网络,由人工神经元(简称神经元)构成。神经元用简单的数学模型来模拟生物神经细胞的信号传递与激活。为了理解人工神经网络的运作原理,我们先来看一个最简单的情形:单神经元模型。如图3.4所示,它只有一个输入层单元、一个隐含层单元和一个输出层单元。
x表示输入的数据,y表示输出的数据,它们都是实数。从输入单元到隐含层的权重w、隐含层单元偏置b、隐含层到输出层的权重w'都是可以任意取值的实数。
我们可以将这个最简单的神经网络看成一个从x映射到y的函数,而w、b和w'是该函数的参数。该函数的方程如图3.5中的方程式所示,其中σ表示sigmoid函数。当w=1,w'=1,b=0的时候,这个函数的图形如图3.5所示。
这就是sigmoid函数的形状及σ(x)的数学表达式。通过观察该曲线,我们不难发现,当x小于0的时候,σ(x)都是小于1/2的,而且x越小,σ(x)越接近于0;当x大于0的时候,σ(x)都是大于1/2的,而且x越大,σ(x)越接近于1。在x=0的点附近存在着一个从0到1的突变。
当我们变换w、b和w'这些参数的时候,函数的图形也会发生相应的改变。例如,我们不妨保持 w'=1, b=0不变,而变换w的大小,其函数图形的变化如图3.6所示。
由此可见,当w>0的时候,它的大小控制着函数的弯曲程度,w越大,它在0点附近的弯曲程度就会越大,因此从x=0的突变也就越剧烈;当w<0的时候,曲线发生了左右翻转,它会从1突变到0。
再来看看参数b对曲线的影响,保持w=w'=1不变,如图3.7所示。
可以清晰地看到,b控制着sigmoid函数曲线的水平位置。b>0,函数图形往左平移;反之往右平移。最后,让我们看看w'如何影响该曲线,如图3.8所示。
不难看出,当w' > 0的时候,w'控制着曲线的高矮;当w' < 0的时候,曲线的方向发生上下颠倒。
可见,通过控制w、w'和b这3个参数,我们可以任意调节从输入x到输出y的函数形状。但是,无论如何调节,这条曲线永远都是S形(包括倒S形)的。要想得到更加复杂的函数图像,我们需要引入更多的神经元。
3.2.3 两个隐含层神经元
下面我们把模型做得更复杂一些,看看两个隐含层神经元会对曲线有什么影响,如图3.9所示。
输入信号进入网络之后就会兵分两路,一路从左侧进入第一个神经元,另一路从右侧进入第二个神经元。这两个神经元分别完成计算,并通过w'1和w'2进行加权求和得到y。所以,输出y实际上就是两个神经元的叠加。这个网络仍然是一个将x映射到y的函数,函数方程为:
在这个公式中,有w1, w2, w'1, w'2, b1, b2这样6个不同的参数。它们的组合也会对曲线的形状有影响。
例如,我们可以取w1=w2=w'1=w'2=1,b1=-1,b2=0,则该函数的曲线形状如图3.10所示。
由此可见,合成的函数图形变为了一个具有两个阶梯的曲线。
让我们再来看一个参数组合,w1=w2=1,b1=0,b2=-1,w'1=1,w'2=-1,则函数图形如图3.11所示。
由此可见,我们合成了一个具有单一波峰的曲线,有点类似于正态分布的钟形曲线。一般地,只要变换参数组合,我们就可以用两个隐含层神经元拟合出任意具有单峰的曲线。
那么,如果有4个或者6个甚至更多的隐含层神经元,不难想象,就可以得到具有双峰、三峰和任意多个峰的曲线,我们可以粗略地认为两个神经元可以用来逼近一个波峰(波谷)。事实上,对于更一般的情形,科学家早已从理论上证明,用有限多的隐含层神经元可以逼近任意的有限区间内的曲线,这叫作通用逼近定理(universal approximation theorem)。
3.2.4 训练与运行
在前面的讨论中,我们看到,只要能够调节神经网络中各个参数的组合,就能得到任意想要的曲线。可问题是,我们应该如何选取这些参数呢?答案就在于训练。
要想完成神经网络的训练,首先要给这个神经网络定义一个损失函数,用来衡量网络在现有的参数组合下输出表现的好坏。这就类似于第2章利用线性回归预测房价中的总误差函数(即拟合直线与所有点距离的平方和)L。同样地,在单车预测的例子中,我们也可以将损失函数定义为对于所有的数据样本,神经网络预测的单车数量与实际数据中单车数量之差的平方和的均值,即:
这里,N为样本总量,
为神经网络计算得来的预测单车数,
为实际数据中该时刻该地区的单车数。
有了这个损失函数L,我们就有了调整神经网络参数的方向——尽可能地让L最小化。因此,神经网络要学习的就是神经元之间连边上的权重及偏置,学习的目的是得到一组能够使总误差最小的参数值组合。
这是一个求极值的优化问题,高等数学告诉我们,只需要令导数为零就可以求得。然而,由于神经网络一般非常复杂,包含大量非线性运算,直接用数学求导数的方法行不通,所以,我们一般使用数值的方式来进行求解,也就是梯度下降算法。每次迭代都向梯度的负方向前进,使得误差值逐步减小。参数的更新要用到反向传播算法,将损失函数L沿着网络一层一层地反向传播,来修正每一层的参数。我们在这里不会详细介绍反向传播算法,因为PyTorch已经自动将这个复杂的算法变成了一个简单的命令:backward。只要调用该命令,PyTorch就会自动执行反向传播算法,计算出每一个参数的梯度,我们只需要根据这些梯度更新参数,就可以完成一步学习。
神经网络的学习和运行通常是交替进行的。也就是说,在每一个周期,神经网络都会进行前馈运算,从输入端运算到输出端;然后,根据输出端的损失值来进行反向传播算法,从而调整神经网络上的各个参数。不停地重复这两个步骤,就可以令神经网络学习得越来越好。
3.2.5 失败的神经预测器
在弄清楚了神经网络的工作原理之后,下面我们来看看如何用神经网络预测共享单车的曲线。我们希望仿照预测房价的做法,利用人工神经网络来拟合一个时间段内的单车曲线,并给出在未来时间点单车使用量的曲线。
为了让演示更加简单清晰,我们仅选择了数据中的前50条记录,绘制成如图3.12所示的曲线。在这条曲线中,横坐标是数据记录的编号,纵坐标则是对应的单车数量。
接下来,我们就要设计一个神经网络,它的输入x就是数据编号,输出则是对应的单车数量。通过观察这条曲线,我们发现它至少有3个峰,采用10个隐含层单元就足以保证拟合这条曲线了。因此,我们的人工神经网络架构如图3.13所示。
接下来,我们就要动手写程序实现这个网络。首先导入本程序所使用的所有依赖库。这里我们会用到pandas库来读取和操作数据。读者需要先安装这个程序包,在Anaconda环境下运行conda install pandas
即可。
import numpy as np import pandas as pd #读取csv文件的库 import torch from torch.autograd import Variable import torch.optim as optim import matplotlib.pyplot as plt #让输出图形直接在Notebook中显示 %matplotlib inline
新闻标题:运用PyTorch动手搭建一个共享单车预测器-创新互联
网站URL:http://pwwzsj.com/article/csiicd.html