IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 深度学习神经网络实践:基于LSTM的电离层预报 -> 正文阅读

[人工智能]深度学习神经网络实践:基于LSTM的电离层预报

1 引言

在本科的毕业设计中,我的题目就是基于深度学习的电离层预报,在初期的测试了中,试了挺多的网络,也试了挺多的预报方法和输出的方式,多步预测和单步预测也都试了,最后选择了用LSTM网络进行预报,从0基础到最后写完毕设的论文,也不算容易。所以这里写篇文章记录一下,中间涉及到一些文件数据的读取处理及转换这边就不说了,毕竟主要想讲一讲我怎么跑通LSTM网络。
代码参考的就是Keras官方提供的文档,还是比较通俗易懂的。

2 环境配置

Python 3.8 + TensorFlow 2.3 + Keras 2.4keras还是比较适合小白的,上手简单,网络只需要暴力叠加。
对于tensorflow,我当时分别配了两个环境,一个是windows10我自己的电脑上的,另一个是在Linux超算服务器上配置的环境。
当时因为我做的是全球的电离层预报,里面涉及到的数据比较多,经常几千个程序一起运行,数据量也很大,所以我拿自己的电脑进行调代码,做测试,代码写好后就拿服务器来进行结果的运算。配环境的过程我都记录了一下,参考下面:

3 数据和方法

我选了两年多的数据,2018.1.1-2020.3.1。训练和验证时候用的2018和2019两年的数据,而2020年两个月的数据用来最后结果的评估分析。具体我在做的时候还用了几种不同方法来对全球的电离层进行建模,来对比同一个深度学习网络预报不同的东西得到最后全球的电离层结果的差异,这里就不展开说了。
评估的指标选的是比较常用的几个公式:(di 为网络输出的预报值,^di 为真值,n 代表统计天数)
{ r e l a t i v e ? e r r o r = 1 n ∑ i = 1 n ∣ d i ? d ^ i ∣ d ^ i × 100 % M A D = 1 n ∑ i = 1 n ∣ d i ? d ^ i ∣ b i a s = 1 n ∑ i = 1 n ( d i ? d ^ i ) S T D = ∑ i = 1 n ( d i ? d ^ i ? b i a s ) 2 n R M S = ∑ i = 1 n ( d i ? d ^ i ) 2 n \left\{ \begin{array}{l} \begin{array}{l} \begin{array}{l} relative\ error=\frac{1}{n}\sum_{i=1}^n{\frac{|d_i-\hat{d}_i|}{\hat{d}_i}}\times 100\%\\ MAD=\frac{1}{n}\sum_{i=1}^n{|d_i-\hat{d}_i|}\\ bias=\frac{1}{n}\sum_{i=1}^n{\left( d_i-\hat{d}_i \right)}\\ \end{array}\\ STD=\sqrt{\frac{\sum_{i=1}^n{\left( d_i-\hat{d}_i-bias \right) ^2}}{n}}\\ \end{array}\\ RMS=\sqrt{\frac{\sum_{i=1}^n{\left( d_i-\hat{d}_i \right) ^2}}{n}}\\ \end{array} \right. ????????????????????????relative?error=n1?i=1n?d^i?di??d^i??×100%MAD=n1?i=1n?di??d^i?bias=n1?i=1n?(di??d^i?)?STD=ni=1n?(di??d^i??bias)2? ??RMS=ni=1n?(di??d^i?)2? ??

4 网络结构和一些公式

介绍一些LSTM的内部结构和我搭建的网络

LSTM内部结构

LSTM神经网络是循环神经网络(RNN)的改进网络,是为了解决RNN模型梯度弥散的问题而提出的。该网络可基于输入的时间序列、通过内在遗忘的方式来学习历史数据并输出预测数据,其内部结构如图4-1所示。

图4-1  LSTM细胞内部结构
LSTM内部中共有三个控制门:输入门、输出门、遗忘门。细胞内通过这三个控制门选择性的记忆反馈实现时间上的记忆功能,并运用于进行预测。输入门确定需要在细胞状态中要保存的信息和待更新的信息:
Γ t i = σ ( W i ? [ h t ? 1 , X t ] + b i ) C ~ t = tan ? h ( W C ? [ h t ? 1 , X t ] + b C ) \varGamma _{t}^{i}=\sigma \left( W_i\cdot \left[ h_{t-1},X_t \right] +b_i \right) \\ \tilde{C}_t=\tan\text{h}\left( W_C\cdot \left[ h_{t-1},X_t \right] +b_C \right) Γti?=σ(Wi??[ht?1?,Xt?]+bi?)C~t?=tanh(WC??[ht?1?,Xt?]+bC?)
式中输入的是上一个细胞元的计算结果(上一次的隐向量) 和新一次的训练数据 。第一部分得到 确定哪些信息需要更新,第二部分通过一个tanh单元构建备选向量 ,用来添加至细胞状态中。为了得到细胞状态保存信息的 矩阵,引入sigmoid单元。
图4-2  sigmoid单元示意图
sigmoid单元的作用是将结果输出归算至0至1之间,表达对数据的更新信息。其中σ函数是sigmoid单元的形式,首先计算输入的线性组合,其次通过σ函数作为阈值单元来输出结果。σ函数的形式如下:
σ ( y ) = 1 1 + e ? y \sigma \left( y \right) =\frac{1}{1+e^{-y}} σ(y)=1+e?y1?
而对于tanh单元,使用tanh函数可以将输入映射到[-1,1]范围内。其次,遗忘门要决定哪些信息要丢失:
Γ t f = σ ( W f ? [ h t ? 1 , X t ] + b f ) \varGamma _{t}^{f}=\sigma \left( W_f\cdot \left[ h_{t-1},X_t \right] +b_f \right) Γtf?=σ(Wf??[ht?1?,Xt?]+bf?)
接收参数同样是*ht-1*和 Xt,并且使用sigmoid单元对细胞状态 中每一个参数的输出值归算至0至1之间,表达对数据的“遗忘程度”,1表示“完全接受”,0表示“完全忽略”。通过遗忘门后生成的向量 与上一个神经细胞的细胞状态向量 相乘以决定丢失选择忘记的数据。然后添加上 与新的备选向量 的乘积对之前的状态进行更新,得到更新后的细胞状态 :
C t = Γ t f ? C t ? 1 + Γ t i ? C ~ t C_t=\varGamma _{t}^{f}\otimes C_{t-1}+\varGamma _{t}^{i}\otimes \tilde{C}_t Ct?=Γtf??Ct?1?+Γti??C~t?
最后通过输出门来确定细胞输出的隐向量 ,输出依赖于本次的细胞状态:
Γ t O = σ ( W O [ h t ? 1 , X t ] + b O ) h t = O t × tan ? h ( C t ) \varGamma _{t}^{O}=\sigma \left( W_O\left[ h_{t-1},X_t \right] +b_O \right) \\ h_t=O_t\times \tan\text{h}\left( C_t \right) ΓtO?=σ(WO?[ht?1?,Xt?]+bO?)ht?=Ot?×tanh(Ct?)
确定细胞状态能够输出的部分 Γ t O \varGamma _{t}^{O} ΓtO? 后,将更新后的细胞状态 C t C_t Ct? 输入 函数使得数据调整到[-1,1],之后与输出门输出结果相乘,得到隐向量 。至此LSTM一个细胞的数据更新完毕。对于整个训练过程而言,输入数据 与上一个细胞元的隐向量分别于权重矩阵 W i , ? W C , ? W f , ? W O W_i,\ W_C,\ W_f,\ W_O Wi?,?WC?,?Wf?,?WO? 进行矩阵点乘操作,分别得到结果矩阵 Γ t i , ? Γ t f , ? Γ t O , ? C ~ t \varGamma _{t}^{i},\ \varGamma _{t}^{f},\ \varGamma _{t}^{O},\ \tilde{C}_t Γti?,?Γtf?,?ΓtO?,?C~t? ,其中 W i , ? W C , ? W f , ? W O W_i,\ W_C,\ W_f,\ W_O Wi?,?WC?,?Wf?,?WO? 矩阵内的参数就是该LSTM细胞的核心权重参数,训练的目的也就是通过结果来训练调整这些参数的值使得输出的结果符合预期与要求。
图4-3 单个LSTM层工作流程

用于预报的网络

输入层我选了一些和电离层关系比较密切的参数,经过处理后输入网络。
隐藏层叠加了两层的LSTM,神经元用的都是32,最后叠一个dense是为了把输出的结果展开为一个纬度为24的矩阵,因为我输出的数据是连续24个的时间序列,如果是只预报一个时刻,这里需要改成dense=1。

在这里插入图片描述
输出层就是把输出的数据还原,因为前面有数据预处理的过程,这里要返回真实数据。

4 训练代码

首先是读取数据的代码,csv文件存储的是我处理好后的数据

import pandas as pd
folder = r'C:\Users\GLASSYM\Desktop\LSTM\\'

csvname = 'TEC_map.csv'
input_dex = 'input_dex.csv'

dex_data = pd.read_csv(folder+input_dex)
ionex_data = pd.read_csv(folder+csvname)

print(ionex_data.shape[0],ionex_data.shape[1])

18720 5187

之后是进行一个简单的数据查看

import numpy as np
pre_ion = ionex_data.iloc[:,2580].values
pre_ion = pre_ion[:,np.newaxis];
pre_dex = dex_data.iloc[:,3:7].values
pre_data = np.hstack((pre_ion,pre_dex))
print(pre_data, len(pre_data))

[[ 12.5 -5. 66.8 0. 1. ]
[ 10. -7. 66.8 0.25881905 0.96592583]

[ 24.2 -21. 69.4 -0.5 0.8660254 ]
[ 23. -22. 69.4 -0.25881905 0.96592583]] 18720

进行数据预处理,归一化

#两年数据作为训练集
data_mean = pre_data.mean(axis=0)
data_std = pre_data.std(axis=0)

deal_data = (pre_data - data_mean) / data_std
print(data_mean, data_std)
print(deal_data)

[ 1.45496314e+01 -5.39118590e+00 6.97937179e+01 4.60220656e-18 -3.70074342e-18]
[ 8.91233958 11.478995 2.85311328 0.70710678 0.70710678]
[[-2.29976808e-01 3.40784100e-02 -1.04928114e+00 -6.50850293e-18 1.41421356e+00]

[ 1.08280979e+00 -1.35977184e+00 -1.37995905e-01 -7.07106781e-01 1.22474487e+00]
[ 9.48165014e-01 -1.44688748e+00 -1.37995905e-01 -3.66025404e-01 1.36602540e+00]]

准备数据生成器,生成对应的训练集验证集和测试集,返回的是你用于训练的数据和对应的标签
这里要注意一下,你需要生成标签的矩阵维度就是你叠加在网络里面dense层的值,如果你预报一个值,那么标签里面一定有一个维度(代码里面是delay)为1,dense=1。如果连续预报12小时,那么标签也有个连续12小时的数据,那么有一个维度为12,dense=12。

# data :浮点数据原始数组
# lookback :输入数据包含的时间步
# delay :目标在多少个时间步之后
# min_index,max_index :data数组的索引,用于界定需要抽取哪些时间步。保存一部分用于验证,一部分用于测试
# shuffle :决定是否打乱样本;TRUE:打乱 ;FLASE:按顺序处理样本
# batch_size :每个批量的样本数
def generator(data, lookback, delay, min_index, max_index,
              shuffle=False, batch_size=128):
    if max_index is None:
        max_index = len(data) - delay - 1
    i = min_index + lookback
    while 1:
        if shuffle:
            rows = np.random.randint(
                min_index + lookback, max_index, size=batch_size)
        else:
            if i + batch_size >= max_index:
                i = min_index + lookback
            rows = np.arange(i, min(i + batch_size, max_index))
            i += len(rows)

        samples = np.zeros((len(rows),
                           lookback,
                           data.shape[-1]))
        targets = np.zeros((len(rows),delay))
        
        for j, row in enumerate(rows):
                indices_sam = range(rows[j] - lookback, rows[j])
                indices_tar = range(rows[j] + 1, rows[j] + 1 + delay)
                samples[j] = data[indices_sam]
                targets[j] = data[indices_tar][:,0]

        yield samples, targets

生成对应的训练集验证集和测试集,lookback,delay,batch_size这些数据后续我都是在脚本外传入程序的。

lookback = 72
delay = 24
batch_size = 128

train_gen = generator(deal_data,
                      lookback=lookback,
                      delay=delay,
                      min_index=0,
                      max_index=17016,
                      shuffle=True,
                      batch_size=batch_size)
val_gen = generator(deal_data,
                    lookback=lookback,
                    delay=delay,
                    min_index=17017,
                    max_index=18720,
                    batch_size=batch_size)
test_gen = generator(deal_data,
                     lookback=lookback,
                     delay=delay,
                     min_index=17449,
                     max_index=None,
                     batch_size=batch_size)

# This is how many steps to draw from `val_gen`
# in order to see the whole validation set:
val_steps = (18720 - 17017 - lookback) // batch_size

# This is how many steps to draw from `test_gen`
# in order to see the whole test set:
test_steps = (len(deal_data) - 17449 - lookback) // batch_size

构建训练网络,两层LSTM层,mode.fit里面的的verbose参数是控制日志输出的格式。
激活函数我用的是默认的tanh,按理说relu函数应该效果会好些,但是我测试出来relutanh区别不大,而用relu的时候cudnn无法进行加速,训练的速度就很慢(这个应该是keras函数内部的一些原因),但是默认tanh的话用cudnn加速训练速度提升了90%,我只能说无敌。
给的参数是 steps_per_epoch=200, epochs=20 ,测试的时候训练还是挺快的。

from keras.models import Sequential
from keras import layers
from keras.optimizers import RMSprop
from keras.layers import LeakyReLU
import numpy as np

model = Sequential()
model.add(layers.LSTM(32,
            return_sequences = True,
            input_shape = (None,deal_data.shape[-1])))
model.add(layers.LSTM(32))
model.add(layers.Dense(24))

model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit(train_gen,
                    steps_per_epoch=200,
                    epochs=20,
                    validation_data=val_gen,
                    validation_steps=val_steps,
                    verbose = 1)

画出损失值的结果散点图

import matplotlib.pyplot as plt

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(loss))

plt.figure()
plt.subplots(figsize=(20,10))
plt.plot(epochs, loss, 'ro', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend(fontsize=24)

plt.show()

对训练完的模型输入测试集test进行预测并输出损失值

results=model.predict(test_gen, 
                      steps=test_steps,
                      verbose=1)
loss=model.evaluate(test_gen,
                    steps=test_steps,)
print(loss)

还原数据,画结果对比图,注意这里是隔24个数据读取一次,即连续的预报24小时

real_data = pre_data[17449+72:,0] 
pre_test = []
len_result = len(results)
for i in range(int(len_result/24)):
    pre_one_day = results[i*24] * data_std[0] + data_mean[0]
    pre_test = np.append(pre_test,pre_one_day)
#pre_test = results[:,0] * data_std[0] + data_mean[0]

print(real_data,len(real_data))
print(pre_test,len(pre_test))

[13.5 9.3 7.4 … 23.7 24.2 23. ] 1199
[ 9.86116982 8.84894657 8.43008041 … 20.85349083 17.75438309 14.54913998] 1152

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(20,10),)
plt.plot(real_data[:300], 'o', color='r', label='- really -', markersize=10)
plt.plot(pre_test[:300], 'o', color='b', label='- predict -', markersize=10)
plt.legend(fontsize=20)

在这里插入图片描述
这里图片画了300个散点,可以看出结果还是比价好的,如果要放论文的画必须得调整一下大小和图例文字分辨率等,这边就随便展示一下。

保存模型

# save model
LSTM_model = 'C:\Users\GLASSYM\Desktop\IONEX_file\model_lstm.h5'
model.save(LSTM_model)

这样基本上一个简单的LSTM训练和预报就完成了,现在回想起来,其实整个代码的难度不高,都很简单,只是刚开始看的时候容易漏掉很多细节,老出bug,其实注意一下细节就好。

5 小结

  • 使用的数据是最近几年的数据,而近几年太阳均处在平静期,太阳活动不强。对于太阳活动活跃期,网络的结构是否需要相应的变化以及网络的预报效果仍有待检验与测试。
  • 实验均为短期(1天)的预报,能否进行一个长期连续的预测预报,以及能否根据对历史数据的训练来对历史缺失的数据进行修复仍有待研究。

上面的东西都是之前写的和做的,暑假最近在跑一个新的方法,看看能不能在空间上对预报效果进行提升。也许有用也许没用,反正我觉的深度学习这东西就是个玄学,练练丹。也不知道未来三年的研究生能研究出个啥,也许会结合定位做点东西。Wish me good luck!

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-07-27 16:13:42  更:2021-07-27 16:14:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年3日历 -2024/3/29 18:59:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码