基于LSTM的CDN网络流量预测(一)

举报
HWCloudAI 发表于 2022/12/19 14:35:44 2022/12/19
【摘要】 基于LSTM的CDN网络流量预测 实验目标掌握时序预测中基础的数据分析及训练模型的基本流程;掌握时序预测中基于多线路的单元多步时序预测的基本方法;掌握使用Pytorch进行LSTM模型的构建、训练、保存、加载、预测、统计准确率指标的方法; 案例内容介绍随着互联网、云业务的迅速发展,企业运转与云服务运维产生的数据与日俱增,在实际生产中,业务的运转往往遵循着相应的规律,时序数据所能带来的价值也...

基于LSTM的CDN网络流量预测

实验目标

  1. 掌握时序预测中基础的数据分析及训练模型的基本流程;
  2. 掌握时序预测中基于多线路的单元多步时序预测的基本方法;
  3. 掌握使用Pytorch进行LSTM模型的构建、训练、保存、加载、预测、统计准确率指标的方法;

案例内容介绍

随着互联网、云业务的迅速发展,企业运转与云服务运维产生的数据与日俱增,在实际生产中,业务的运转往往遵循着相应的规律,时序数据所能带来的价值也日益显现。

本案例是基于CDN(Content Delivery Network)的网络流量预测,CDN是构建在现有网络基础之上的智能虚拟网络,目的是将源站内容分发至最接近用户的节点,使用户可就近取得所需内容,提高用户访问的响应速度和成功率。CDN智能调度中的流量分配算法、95调度算法与错峰调度等算法的有效性高度依赖域名流量的趋势,若能较为准确的预测域名流量的趋势,则可以提升调度算法的效果。与此类似的还有零售预测、供需预测等相关场景。

时间序列预测按数据及场景类别主要可分为单元时序预测(单变量)、多元时序预测、单步预测(预测)、多步预测几类。时间序列预测算法有基于统计的、基于机器学习的和基于深度学习的等等。
本文根据实际场景(单元多步时序预测),针对多线路预测问题,从数据分析到模型预测,采用LSTM,端到端实现CDN网络流量预测模型。

注意事项

  1. 本案例需使用 GPU 运行,请查看《ModelAtrs JupyterLab 硬件规格使用指南》了解切换硬件规格的方法;
  2. 如果您是第一次使用 JupyterLab,请查看《ModelAtrs JupyterLab使用指导》了解使用方法;
  3. 如果您在使用 JupyterLab 过程中碰到报错,请参考《ModelAtrs JupyterLab常见问题解决办法》尝试解决问题。

实验步骤

1. 下载代码和数据集

本案例使用的数据集是来自于脱敏过的CDN网络流量预测项目数据集,因此数据及模型精度较真实效果有点偏差,仅供学习使用

运行下面的代码后可得到network_traffic_forecast目录,里面含有本案例所需的代码和数据集,其data子目录下有4个csv,数据的时间间隔是1分钟,每个区域下面有3个运营商,共31个区域,每个{区域,运营商}对应一条具体的线路,即共31*3条线路,4个csv文件分别对应不同区域流量的4天数据,例如:time_series_1.csv: {0-3}区域,time_series_2.csv: {4-7}区域

import os
import moxing as mox
if not os.path.exists('./network_traffic_predict'):
    mox.file.copy('obs://modelarts-labs-bj4-v2/course/modelarts/zjc_team/time_series_forecast/network_traffic_forecast/network_traffic_forecast.zip', './network_traffic_forecast.zip')
    os.system('unzip network_traffic_forecast.zip')

if not os.path.exists('./network_traffic_forecast'):
    raise Exception('错误!数据不存在!')
INFO:root:Using MoXing-v1.17.3-

INFO:root:Using OBS-Python-SDK-3.20.7

2. 查看数据

构建任何模型之前,都需要先对数据集进行分析,了解数据集的规模、属性名、属性值等情况。因为我们要先了解数据,才能用好数据

2.1 读取csv文件

pandas是常用的python数据分析模块,我们先用它来加载数据集中的csv文件。以time_series_1.csv为例,我们先加载该文件来分析数据的情况

import pandas as pd
df_data = pd.read_csv("./network_traffic_forecast/data/time_series_1.csv")

2.2 查看单个csv文件数据的规模

print('单个csv文件数据的规模,行数:%d, 列数:%d' % (df_data.shape[0], df_data.shape[1]))
单个csv文件数据的规模,行数:68601, 列数:4

2.3 查看前20行数据

使用pandas加载csv后,得到的是一个DataFrame对象,可以理解为一个表格,调用该对象的head()函数,我们查看一下该表格的头20行数据

df_data.head(20)
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
TimePoint att1 att2 Value
0 1592496000 0 0 1.683235e+08
1 1592496000 0 1 4.024828e+07
2 1592496000 0 2 1.537997e+08
3 1592496000 1 0 4.798478e+05
4 1592496000 1 1 1.437264e+08
5 1592496000 1 2 3.192533e+07
6 1592496000 2 0 1.193619e+08
7 1592496000 2 1 3.457281e+07
8 1592496000 2 2 2.276732e+07
9 1592496000 3 0 1.447897e+08
10 1592496000 3 1 5.181238e+07
11 1592496000 3 2 2.120722e+08
12 1592496060 0 0 7.017834e+07
13 1592496060 0 1 3.913830e+07
14 1592496060 0 2 5.822768e+05
15 1592496060 1 0 2.713144e+05
16 1592496060 1 1 1.095218e+08
17 1592496060 1 2 7.033603e+05
18 1592496060 2 0 1.161724e+08
19 1592496060 2 1 1.995452e+07

如上所示是表格的头20行数据,表头是属性名,属性名下面是属性值,各属性含义如下:

属性名 属性含义
TimePoint Unix时间戳
att1 区域
att2 运营商
Value 流量值(GB)

2.3.1 查看单条线路数据情况

df_data[(df_data['att1'] == 0) & (df_data['att2'] ==0)]
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
TimePoint att1 att2 Value
0 1592496000 0 0 1.683235e+08
12 1592496060 0 0 7.017834e+07
24 1592496120 0 0 5.218320e+07
36 1592496180 0 0 4.973728e+07
48 1592496240 0 0 2.627043e+07
60 1592496300 0 0 2.516527e+07
72 1592496360 0 0 5.241541e+04
84 1592496420 0 0 5.126166e+02
92 1592496480 0 0 1.253282e+03
104 1592496600 0 0 1.975488e+02
119 1592496720 0 0 6.139325e+02
136 1592496900 0 0 5.598084e+03
147 1592496960 0 0 2.088519e+03
190 1592497320 0 0 8.426582e+02
199 1592497380 0 0 2.255806e+04
210 1592497440 0 0 1.048735e+04
218 1592497500 0 0 4.599218e+03
229 1592497560 0 0 5.261509e+02
237 1592497620 0 0 1.098636e+02
256 1592497740 0 0 1.977122e+02
274 1592497920 0 0 6.781617e+02
282 1592497980 0 0 9.741788e+01
292 1592498040 0 0 5.603992e+03
303 1592498100 0 0 4.493011e+02
313 1592498160 0 0 1.461330e+03
321 1592498220 0 0 2.241611e+03
326 1592498280 0 0 1.335533e+03
331 1592498340 0 0 3.136885e+02
340 1592498460 0 0 3.227209e+02
347 1592498520 0 0 2.783268e+02
... ... ... ... ...
68571 1592839740 0 0 2.547898e+08
68572 1592839800 0 0 2.531656e+08
68573 1592839860 0 0 2.513123e+08
68574 1592839920 0 0 2.496070e+08
68575 1592839980 0 0 2.509131e+08
68576 1592840040 0 0 2.520332e+08
68577 1592840100 0 0 2.546929e+08
68578 1592840160 0 0 2.503867e+08
68579 1592840220 0 0 2.482838e+08
68580 1592840280 0 0 2.447917e+08
68581 1592840340 0 0 2.421030e+08
68582 1592840400 0 0 2.374323e+08
68583 1592840460 0 0 2.330100e+08
68584 1592840520 0 0 2.308231e+08
68585 1592840580 0 0 2.289234e+08
68586 1592840640 0 0 2.279097e+08
68587 1592840700 0 0 2.287882e+08
68588 1592840760 0 0 2.286189e+08
68589 1592840820 0 0 2.259465e+08
68590 1592840880 0 0 2.233548e+08
68591 1592840940 0 0 2.221803e+08
68592 1592841000 0 0 2.205086e+08
68593 1592841060 0 0 2.190259e+08
68594 1592841120 0 0 2.175316e+08
68595 1592841180 0 0 2.153261e+08
68596 1592841240 0 0 2.131482e+08
68597 1592841300 0 0 2.099739e+08
68598 1592841360 0 0 2.085667e+08
68599 1592841420 0 0 2.070421e+08
68600 1592841480 0 0 2.048070e+08

5717 rows × 4 columns

如上所示,以att1=0,att2=0 查看单条线路{区域,运营商}数据情况,可以看到数据是1min采样一次,共4天。

2.3.2 查看数据时序性情况

画出每条线路数据曲线图,根据曲线图判断数据时序性

import time
df_data["TimePoint"] = df_data["TimePoint"].apply(lambda x: time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(x)))  # 时间戳转换
%matplotlib inline
df_data = df_data.set_index(['TimePoint'])
print(df_data.groupby(["att1","att2"])['Value'].plot(figsize=(20,10)))
df_data = df_data.reset_index(['TimePoint']) 
INFO:matplotlib.font_manager:font search path ['/home/ma-user/anaconda3/envs/Pytorch-1.0.0/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf', '/home/ma-user/anaconda3/envs/Pytorch-1.0.0/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/afm', '/home/ma-user/anaconda3/envs/Pytorch-1.0.0/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/pdfcorefonts']

INFO:matplotlib.font_manager:generated new fontManager


att1  att2

0     0       AxesSubplot(0.125,0.125;0.775x0.755)

      1       AxesSubplot(0.125,0.125;0.775x0.755)

      2       AxesSubplot(0.125,0.125;0.775x0.755)

1     0       AxesSubplot(0.125,0.125;0.775x0.755)

      1       AxesSubplot(0.125,0.125;0.775x0.755)

      2       AxesSubplot(0.125,0.125;0.775x0.755)

2     0       AxesSubplot(0.125,0.125;0.775x0.755)

      1       AxesSubplot(0.125,0.125;0.775x0.755)

      2       AxesSubplot(0.125,0.125;0.775x0.755)

3     0       AxesSubplot(0.125,0.125;0.775x0.755)

      1       AxesSubplot(0.125,0.125;0.775x0.755)

      2       AxesSubplot(0.125,0.125;0.775x0.755)

Name: Value, dtype: object

时间序列数据构成要素:长期趋势,季节变动,循环变动,不规则变动。

  1. 长期趋势(T)现象在较长时期内受某种根本性因素作用而形成的总的变动趋势。
  2. 季节变动(S)现象在一年内随着季节的变化而发生的有规律的周期性变动。
  3. 循环变动(C)现象以若干年为周期所呈现出的波浪起伏形态的有规律的变动。
  4. 不规则变动(I)是一种无规律可循的变动,包括严格的随机变动和不规则的突发性影响很大的变动两种类型。

分析:

如上图所示,是将数据按照(att1,att2)分组后,每条线路的曲线示意图,图上每条曲线则对应不同的线路,横轴为时间,纵轴为单条线路对应的Value值。根据图中曲线及以上时间序列数据特点,可得出以下结论:

  • 数据存在周期性 每天一个周期,同一线路各周期间数据范围大致相同,不存在趋势性,季节性由于数据较少,暂看不出来,
  • 共31个区域,每个{区域,运营商}]对应一条具体的线路,即共31*3条线路 每条线路大致趋势相同,但是量级不一样 需要进行归一化
  • 数据峰值处波动较大,其余部分较平缓
  • 整体数据质量较好,不需要进行数据平滑等使得数据变平稳的操作,后续建模预测未来10min,将主要依赖待预测点前一段时序数据进行预测。
  • 数据中无明显脱离整体趋势范围的异常值。

2.4 数据分析

查看数据的统计值及空值情况

df_data.groupby(["att1","att2"]).describe()
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead tr th {
    text-align: left;
}

.dataframe thead tr:last-of-type th {
    text-align: right;
}
</style>
Value
count mean std min 25% 50% 75% max
att1 att2
0 0 5717.0 2.756998e+08 1.471390e+08 85.107962 1.608420e+08 2.940786e+08 3.754438e+08 6.095700e+08
1 5686.0 5.480488e+07 2.756697e+07 51.327340 3.322805e+07 5.950805e+07 7.381292e+07 1.162919e+08
2 5724.0 2.188223e+08 1.181942e+08 65.711383 1.333125e+08 2.329354e+08 2.915056e+08 5.042825e+08
1 0 5715.0 1.861563e+07 9.069485e+06 38.332234 1.034681e+07 2.209178e+07 2.592819e+07 3.338421e+07
1 5725.0 1.258266e+08 6.321933e+07 4.381480 6.769589e+07 1.459575e+08 1.770747e+08 2.377960e+08
2 5746.0 5.218107e+07 2.650715e+07 4.772777 2.804430e+07 6.088992e+07 7.308530e+07 9.835380e+07
2 0 5732.0 1.179337e+08 6.204479e+07 36.191396 6.684485e+07 1.292305e+08 1.580988e+08 2.522959e+08
1 5696.0 3.024132e+07 1.488895e+07 49.353860 1.792033e+07 3.356871e+07 4.138216e+07 5.848370e+07
2 5756.0 1.024740e+08 5.487324e+07 146.927647 5.985492e+07 1.095121e+08 1.376453e+08 2.203716e+08
3 0 5708.0 1.271339e+08 6.343431e+07 109.510294 7.234194e+07 1.381774e+08 1.783945e+08 2.426037e+08
1 5711.0 4.340486e+07 2.045753e+07 6.857371 2.588623e+07 4.660798e+07 6.067043e+07 7.981218e+07
2 5685.0 1.991225e+08 9.818788e+07 1.169489 1.234276e+08 2.079243e+08 2.744293e+08 3.993022e+08
  • 数据在时间列采样上存在缺失值,需要进行缺失值填充

    对于count列,不同的att1与att2组合(不同线路)对应的count长度不同,正常情况下,数据有4天,应该是1440*4 = 5760个点,说明数据在时间列采样上存在缺失值,需要进行缺失值填充

查看Value列的最大最小值

由于以上分析中,value的max和min显示并不直观,因此这里再做具体分析

print(df_data['Value'].min())
print(df_data['Value'].max()) 
1.1694885305466325

609569980.8860668

可以看到最小值是1.1694885305466325,最大值为609569980.8860668,无小于等于0的异常值;

未完待续

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。