DeepLearning in Pytorch|我的第一个NN-共享单车预测

news2024/11/15 15:50:02

目录

概要

一、数据准备

导入数据

数据可视化

二、设计神经网络

版本一

版本二(正片)

三、测试

小结


概要

我的第一个深度学习神经网络模型---利用Pytorch设计人工神经网络对某地区租赁单车的使用情况进行预测

输入节点为1个,隐含层为10个,输出节点数为1的小型人工神经网络,用数据的下标预测单车数量。

PS:

1.该神经网络无法达到解决实际问题的要求,但它结构简单,包含了神经网络的基本元素,可以达到初步入门深度学习以及熟悉Pytorch使用的效果,同时在实践过程中引出了过拟合现象。

2.Pytorch 2.2.1 (CPU) Python 3.6.13|Anaconda 环境

一、数据准备

导入数据

#导入需要使用的库
import numpy as np
import pandas as pd #读取csv文件的库
import matplotlib.pyplot as plt #绘图
import torch
import torch.optim as optim

这里我们使用来自GitHub的开源数据用作构建神经网络

#读取数据到内存中,rides为一个dataframe对象
data_path = 'dir/hour.csv' #文件路径
rides = pd.read_csv(data_path)
rides.head()

 可以看到成功读入的数据如下:c180d12fed994374b19958b1235a8648.png

数据可视化

我们用数据序号(0,1,2,3,···)与数据cnt(count)构建神经网络(hhh实际解决问题时当然不会这样做)

#我们取出最后一列的前50条记录来进行预测
counts = rides['cnt'][:50]

#获得变量x,它是1,2,……,50
x = np.arange(len(counts))

# 将counts转成预测变量(标签):y
y = np.array(counts)

# 绘制一个图形,展示曲线长的样子
plt.figure(figsize = (10, 7)) #设定绘图窗口大小
plt.plot(x, y, 'o-') # 绘制原始数据
plt.xlabel('X') #更改坐标轴标注
plt.ylabel('Y') #更改坐标轴标注
plt.show()

 这里我们取出前五十条记录用于模型,绘制出序号与cnt关系,大致数据分布图如下:

6e8d79ce91d948f0ae6f3135c89ca57e.png

二、设计神经网络

我们构建一个单一输入,10个隐含层单元,1个输出单元的人工神经网络预测器

版本一

#取出数据库中的最后一列的前50条记录来进行预测
counts = rides['cnt'][:50]

#创建变量x,它是1,2,……,50
x = torch.tensor(np.arange(len(counts), dtype = float), requires_grad = True)

# 将counts转成预测变量(标签):y
y = torch.tensor(np.array(counts, dtype = float), requires_grad = True)

# 设置隐含层神经元的数量
sz = 10

# 初始化所有神经网络的权重(weights)和阈值(biases)
weights = torch.randn((1, sz), dtype = torch.double, requires_grad = True) #1*10的输入到隐含层的权重矩阵
biases = torch.randn(sz, dtype = torch.double, requires_grad = True) #尺度为10的隐含层节点偏置向量
weights2 = torch.randn((sz, 1), dtype = torch.double, requires_grad = True) #10*1的隐含到输出层权重矩阵

learning_rate = 0.001 #设置学习率
losses = []

# 将 x 转换为(50,1)的维度,以便与维度为(1,10)的weights矩阵相乘
x = x.view(50, -1)
# 将 y 转换为(50,1)的维度
y = y.view(50, -1)

for i in range(100000):
    # 从输入层到隐含层的计算
    hidden = x * weights + biases
    # 将sigmoid函数作用在隐含层的每一个神经元上
    hidden = torch.sigmoid(hidden)
    #print(hidden.size())
    # 隐含层输出到输出层,计算得到最终预测
    predictions = hidden.mm(weights2)#
    #print(predictions.size())
    # 通过与标签数据y比较,计算均方误差
    loss = torch.mean((predictions - y) ** 2) 
    #print(loss.size())
    losses.append(loss.data.numpy())
    
    # 每隔10000个周期打印一下损失函数数值
    if i % 10000 == 0:
        print('loss:', loss)
        
    #对损失函数进行梯度反传
    loss.backward()
    
    #利用上一步计算中得到的weights,biases等梯度信息更新weights或biases中的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)
    
    # 清空所有变量的梯度值。
    # 因为pytorch中backward一次梯度信息会自动累加到各个变量上,因此需要清空,否则下一次迭代会累加,造成很大的偏差
    weights.grad.data.zero_()
    biases.grad.data.zero_()
    weights2.grad.data.zero_()

运行过程:7f9cf5dc759d4399b9bfa03035dc4496.png 

程序运行大约14min

# 打印误差曲线
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()

打印出误差曲线如下 

2519015d83b14c7dbf929bb8e857d6c5.png

由该曲线可以看出,随着时间的推移,神经网络预测的误差的确在一步步减小。而且,大约到20000步后,误差基本就不会出现明显的下降了

x_data = x.data.numpy() # 获得x包裹的数据
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 1000000 epochs']) #绘制图例
plt.show()

我们可以把训练好的网络对这50个数据点的预测曲线绘制出来,并与标准答案y进行对比: 

378621bc550142e0859e83852b78f0c7.png

预测曲线在第一个波峰比较好地拟合了数据,但在这之后却偏差较大

版本二(正片)

上面的程序之所以跑得慢,是因为x的取值范围1~50。 而由于所有权重和biases的取值范围被设定为-1,1的正态分布随机数,这样就导致 我们输入给隐含层节点的数值范围为-50~50, 要想将sigmoid函数的多个峰值调节到我们期望的位置需要耗费很多的计算时间

我们的解决方案就是将输入变量的范围归一化

#取出最后一列的前50条记录来进行预测
counts = rides['cnt'][:50]

#创建归一化的变量x,它的取值是0.02,0.04,...,1
x = torch.tensor(np.arange(len(counts), dtype = float) / len(counts), requires_grad = True)

# 创建归一化的预测变量y,它的取值范围是0~1
y = torch.tensor(np.array(counts, dtype = float), requires_grad = True)

#隐藏神经元个数
sz = 10

# 初始化所有神经网络的权重(weights)和阈值(biases)
weights = torch.randn((1, sz), dtype = torch.double, requires_grad = True) #1*10的输入到隐含层的权重矩阵
biases = torch.randn(sz, dtype = torch.double, requires_grad = True) #尺度为10的隐含层节点偏置向量
weights2 = torch.randn((sz, 1), dtype = torch.double, requires_grad = True) #10*1的隐含到输出层权重矩阵

learning_rate = 0.001 #设置学习率
losses = []

# 将 x 转换为(50,1)的维度,以便与维度为(1,10)的weights矩阵相乘
x = x.view(50, -1)
# 将 y 转换为(50,1)的维度
y = y.view(50, -1)

for i in range(100000):
    # 从输入层到隐含层的计算
    hidden = x * weights + biases
    # 将sigmoid函数作用在隐含层的每一个神经元上
    hidden = torch.sigmoid(hidden)
    # 隐含层输出到输出层,计算得到最终预测
    predictions = hidden.mm(weights2)# + biases2.expand_as(y)
    # 通过与标签数据y比较,计算均方误差
    loss = torch.mean((predictions - y) ** 2) 
    losses.append(loss.data.numpy())
    
    # 每隔10000个周期打印一下损失函数数值
    if i % 10000 == 0:
        print('loss:', loss)
        
    #对损失函数进行梯度反传
    loss.backward()
    
    #利用上一步计算中得到的weights,biases等梯度信息更新weights或biases中的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)
    
    # 清空所有变量的梯度值。
    # 因为pytorch中backward一次梯度信息会自动累加到各个变量上,因此需要清空,否则下一次迭代会累加,造成很大的偏差
    weights.grad.data.zero_()
    biases.grad.data.zero_()
    weights2.grad.data.zero_()

运行程序,耗时约9min 

plt.semilogy(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()

  绘出损失曲线:d5d5eb5946d344128eaf55a1b5d5ee8a.png

x_data = x.data.numpy() # 获得x包裹的数据
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()

得到曲线如下: 

7ab00ced5e4f44338319cfd32d3fc143.png

显然拟合效果更好了!

三、测试

我们就需要用训练好的模型来做预测,将后面50条数据(50~100)作为测试集。此时x取值是51, 52, …, 100,同样也要除以50: 

counts_predict = rides['cnt'][50:100] #读取待预测的接下来的50个数据点

#首先对接下来的50个数据点进行选取,注意x应该取51,52,……,100,然后再归一化
x = torch.tensor((np.arange(50, 100, dtype = float) / len(counts))
                 , requires_grad = True)
#读取下50个点的y数值,不需要做归一化
y = torch.tensor(np.array(counts_predict, dtype = float), requires_grad = True)

x = x.view(50, -1)
y = y.view(50, -1)

# 从输入层到隐含层的计算
hidden = x * weights + biases

# 将sigmoid函数作用在隐含层的每一个神经元上
hidden = torch.sigmoid(hidden)

# 隐含层输出到输出层,计算得到最终预测
predictions = hidden.mm(weights2)

# 计算预测数据上的损失函数
loss = torch.mean((predictions - y) ** 2) 
print(loss)


x_data = x.data.numpy() # 获得x包裹的数据
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()

得到结果如下:

直线是我们的模型给出的预测曲线,圆点是实际数据所对应的曲线。

62f5c9ff256e4f41bafb5906d352a872.png模型预测与实际数据竟然完全对不上!为什么我们的神经网络可以非常好地拟合已知的50个数据点,却在测试集上出错了呢?因为y(单车数量)与x(数据序号)根本没有关系!这就是在机器学习中最常见的困难---过拟合

过拟合(Overfitting)是指机器学习模型在训练数据上表现很好,但在测试数据上表现较差的情况。过拟合通常发生在模型过度复杂或者训练数据量太少的情况下。

对于我们的单车预测模型,问题显然在于我们要求模型学习 单车数量y 与 数据序号x 之间的关系,模型通过学习我们给出的前五十组数据(训练集)学会了它所认为的样本特征,但当我们引入后面50组样本(测试集)时,我们发现模型学到的特征是没有意义的,它只能反映训练集中的某些特点。

如果要解决这个问题,我们就应该让模型学习关于样本的更多特征,如:星期几、是否节假日、温度、湿度等(显然这些才是真正会影响x的因素)。当然从理论上讲,这样得到的神经网络更复杂,但显然他的预测更能达到我们想要的效果。

小结

对于我们的单车预测模型,问题显然在于我们要求模型学习 单车数量y 与 数据序号x 之间的关系,模型通过学习我们给出的前五十组数据(训练集)学会了它所认为的样本特征,但当我们引入后面50组样本(测试集)时,我们发现模型学到的特征是没有意义的,它只能反映训练集中的某些特点。

如果要解决这个问题,我们就应该让模型学习关于样本的更多特征,如:星期几、是否节假日、温度、湿度等(显然这些才是真正会影响x的因素)。当然从理论上讲,这样得到的神经网络更复杂,但显然他的预测更能达到我们想要的效果。

主要参考资料:《深度学习原理与Pytorch实践》

参考代码:bike1.py · che.melsm/DeepLearning Project - Gitee.com

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安装及管理docker

文章目录 1.Docker介绍2.Docker安装3.免sudo设置4. 使用docker命令5.Images6.运行docker容器7. 管理docker容器8.创建image9.Push Image 1.Docker介绍 Docker 是一个简化在容器中管理应用程序进程的应用程序。容器让你在资源隔离的进程中运行你的应用程序。类似于虚拟机&#…

PyTorch基础(20)-- torch.gt() / torch.ge() / torch.le() / torch.lt()方法

一、前言 嗯……最近遇到的奇奇怪怪的方法很多了,学无止境啊!学不完啊,根本学不完!本篇文章介绍四个方法:torch.gt()、torch.ge()、torch.le()和torch.lt()方法,由于这四个方法很相似,所以放到…

灯塔:CSS笔记(2)

一 选择器进阶 后代选择器:空格 作用:根据HTML标签的嵌套关系,,选择父元素 后代中满足条件的元素 选择器语法:选择器1 选择器2{ css } 结果: *在选择器1所找到标签的后代(儿子 孙子 重孙子…

Docker常见命令使用

Docker命令是使用Docker的基础。这里记录下Docker日常运维过程中经常使用到的一些命令,更全面的命令还请参考Docker官网。 docker用法概述 Docker命令可以通过CLI工具实现与服务器的交互。Docker命令的语法如下: docker [DOCKER-COMMAND] [OPTIONS] […

【高效开发工具系列】Windows 系统下将 Windows 键盘的 ctrl 和 alt 互换

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

vscode 配置opengl (glut), lib链接可参考

这里假定你已经配置好基础的vscode c环境 json介绍 这里其实主要配置的3种json, vscode其实就是通过launch.json和tasks.json来自动生成指令的 launch.json 这个用于启动程序用的,但是由于其可以指定preLaunchTask-即在启动之前需要做什么事情,所以这…

【面试精讲】Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别?

Java动态代理是如何实现的?JDK Proxy 和 CGLib 有什么区别? 目录 一、Java动态代理的实现 1、使用JDK Proxy实现动态代理 2、使用CGLib实现动态代理 二、JDK Proxy 与 CGLib 的区别 三、Spring中的动态代理 四、 Lombok代理原理 总结 前言 本文…

做跨境电商,选哪个浏览器好?跨境电商浏览器推荐

在我们的日常生活中,有很多浏览器可供选择,比如百度浏览器、谷歌浏览器和360、火狐等等。但是在跨境电商行业中,是否有特别适合我们卖家使用的浏览器呢?所谓跨境电商浏览器,就是为跨境电商用户设计的浏览器&#xff0c…

【LeetCode 算法专题突破】---二分查找(⭐⭐⭐)

前言 我在算法题目的海洋中畅游已久,也曾在算法竞赛中荣获佳绩。然而,我发现自己对于算法的学习,还缺乏一个系统性的总结和归类。尽管我已经涉猎过不少算法类型,但心中仍旧觉得有所欠缺,未能形成完整的算法体系。 因…

官方阴阳怪气?双标?《Nature》专访《中科院预警名单》,中国作者为何炸裂?

毕业推荐 SCIE: • 计算机类,6.5-7.0,JCR1区,中科院2区 • 2个月19天录用,6天见刊,36天检索 SCI&EI(CCF-C类) • 算法类,2.0-3.0,JCR3区&#xff0c…

Springboot+vue的养老院管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频: Springbootvue的养老院管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。 项目介绍: 本文设计了一个基于Springbootvue的养老院管理系统,采用M(model)V&…

SpringBoot 多平台文件配置

目录 一 主配置文件和辅配置文件 二 具体使用 1. 通过直接修改 application.yml 中的属性值 2. 通过 maven 进行配置修改 当我们需要部署项目的时候, 肯定会遇到不同的部署环境下, 需要有不同的配置. 例如开发环境下和生产环境下的配置肯定就不会是完全相同的, 如数据库的…

pytorch 批量归一化BatchNorm的BatchNorm1d和BatchNorm2d理解

BatchNorm即批量归一化,是深度学习中经常用到的加速神经网络训练,加速收敛速度及稳定性的算法,是神经网络训练必不可少的一部分。 BatchNorm作用:在进行批量训练过程中,每个batch具有不同的分布,使数据分布…

图片二维码不限扫码次数怎么做?长期有效的图片二维码在线生成技巧

图片制作二维码能长期使用吗?在生活中很多地方都可以看到很多存有图片的二维码,通过扫码后查看图片内容,比如一些公共场所、产品介绍、景区等场所中都有图片转二维码的应用。那么怎么做出可以长期扫码展示图片二维码呢,其实方法很…

CSS 弹性盒子模型

它主要是在一个大的容器当中里面子元素的一个设置。一个大的盒子里面里面的子元素如何摆放由我们的弹性盒子说的算。 之前的盒子模型是一个元素,内边距外边距,边框来调整在页面所显示的位置。 弹性盒子,在大容器里面,里面有很多…

基于C++的配置文件解析器/编码器——toml库

在平常的软件开发过程中,配置文件是重要的一环,使用配置文件在软件开发过程中具有以下好处和必要性: 灵活性:配置文件允许在不修改代码的情况下更改应用程序的行为,通过修改配置文件,可以调整应用程序的参…

智能合约语言(eDSL)—— proc_macro实现合约init函数

我们通过属性宏来实现合约的init函数,call函数其实和init是类似的; GitHub - XuHugo/xwasm 构建属性宏,要在cargo.toml里面设置一些参数,这是必须的。一般来说,过程宏必须是一个库,或者作为工程的子库&…

LabVIEW质谱仪开发与升级

LabVIEW质谱仪开发与升级 随着科技的发展和实验要求的提高,传统基于VB的质谱仪系统已经无法满足当前的高精度和高效率需求。这些系统通常存在着功能不全和操作复杂的问题,影响了科研和生产的进度。为了解决这些问题,开发了一套基于LabVIEW开…

【Web安全】htaccess攻击

.htaccess攻击 文章目录 .htaccess攻击1. .htaccess文件2. 常见用法2.1. 自定义出错界面2.2. 强制文件执行方式2.3. PCRE绕过正则匹配2.4. php_value修改php设定2.5. php_value文件包含2.6. 把htaccess当作php 1. .htaccess文件 .htaccess是Apache网络服务器一个配置文件&#…

MATLAB读取.nc(数据集)文件

MATLAB读取.nc(数据集)文件 以中国1km逐月潜在蒸散发数据集(1901-2022)为例 首先用FileZilla下载特定年份的数据集 用matlab进行处理,代码如下: clear;clc;ncdisp("pet_2022.nc") %读数据集的具体信息和变量eva ncr…