目录
利用LSTM进行时间序列预测流程
lstm滞后性
理解lstm原理
一、预测
二、遗忘
三、筛选
四、忽视
202305补充:从公式角度理解,
原理示例
lstm参数
各参数的定义解释:
batch_size
如何选择batch_size的大小:
epoch
预测滞后问题
损失函数的选择
1、Mean Squared Error Loss(MSE)
2、Mean Squared Logarithmic Error Loss(MSLE)
3、Mean Absolute Error Loss (MAE)
4、Binary Classification Loss Functions
5、Binary Cross-Entropy Loss
6、Hinge Loss
7、Squared HInge Loss
8、Multi-Class Classification Loss Functions
如何选择优化器Optimizer
dropout层
1、什么时候应该加dropout层?
2、放在哪几个层之间?
利用LSTM进行时间序列预测流程
在用统计学方法(3σ原则、四分位距法)等对异常数据进行监测后 (异常监测①——统计学方法判断 )
由于业务特点,导致时序数据的规律趋势会变化。下方为举例:
时间点 原来的count 现在的count 2020-01-01 13:00:00 267 1000 2020-01-01 13:10:00 300 0 2020-01-01 13:20:00 261 0 2020-01-01 13:30:00 289 1023 2020-01-01 13:40:00 235 0 2020-01-01 13:50:00 273 0 2020-01-01 14:00:00 309 1014
此时原统计学方法可能不再适用,可以重新观察新的数据分布规律,手动修改代码逻辑。
但考虑到后续规律仍可能发生变动,为避免后续需要继续改异常监测逻辑,选择使用深度学习模型——lstm 对时序数据的分布进行预测。并且增添 模型更新 逻辑,使得模型不需要再人工更改。
参考以下资料:
干货 | 携程实时智能异常检测平台的算法及工程实现 (视频链接 )
简单粗暴LSTM:LSTM进行时间序列预测
异常检测在苏宁的实践
基于TensorFlow一次简单的RNN实现
确定逻辑:
1、原始数据存储
mongodb
2、数据预处理
去除节假日数据,异常点替换、缺失值填充
3、模型设计及训练
训练集:近十天数据(不含近三天)。 预测集:近三天
多轮超参优化,确定最优超参,及预测范围(用历史多长数据预测未来多长)
保存模型
4、异常判断
①https://www.slideshare.net/ssuserbefd12/ss-164777085 异常边界取90%分位数,持续几次异常产生告警(邮件、微信)
② 3σ原则
5、模型更新
数据监控:通过均值、标准差、中位数、IQR等统计指标以天为粒度监控数据漂移,数据漂移超过阈值
模型监控:每天自动统计模型输出的全部异常点占比的概率,概率分布变化超出阈值后模型自动提取最新数据重新训练
注:关于训练集和测试集 该一起归一化还是分开归一化参考:
机器学习中,对于数据的预处理是否是测试集和训练集一起进行? 浅谈归一化对于LSTM进行时间序列预测的影响
待补充:
捕捉过多的非异常 VS 漏掉真正的异常,怎么权衡
为什么选择lstm而不是别的算法?
lstm原理理解(各超参数的定义)
算法如何调参(看什么指标https://www.cnblogs.com/kamekin/p/10163743.html )
lstm滞后性
1、摘自stackoverflow ——预测值滞后问题是过拟合现象,那么就按过拟合的解决方法来尝试,例如:增加dropout 层等。
2、摘自CSDN——“滞后性”的原因是LSTM过于重视时间步长中最后一个t-1时刻的数据,导致预测结果就是t-1时刻数据的复现。
理解lstm原理
参考的文章以及油管视频:(这个文章所在的网站似乎没了,视频还可以看)
递归神经网路和长短期记忆模型 RNN & LSTM · 資料科學・機器・人
Recurrent Neural Networks (RNN) and Long Short-Term Memory (LSTM)
下面是我的总结以及理解:
模型包含 预测、忽视、遗忘、筛选 四条路径。
注释:激活函数在本示例中的符号表示 (见下图右上角:
双曲正切函数tanh
逻辑函数sigmoid (和双曲正切函数类似,只是它的输出值介于0和1之间)
一、预测
传统RNN中,利用先前的预测(昨天的预测)以及新的信息(昨天的结果)。我们会利用两者作出新的预测,而这些新的预测会用于下一时间步的输出的运算。
图1
二、遗忘
可能出现的错误: 模型只有很短期的记忆,只会参考前一步的结果,不会参考更早之前的信息,为解决这个问题,需要加入
记忆/遗忘 路径 ;
(这里的原因展开讲是 ‘ 当时间步数T较大时,目标函数L关于隐藏状态
的梯度容易出现梯度衰减 ’,涉及的公式推导可参考
李沐书 P233)
①在这条路径里,我们会通过sigmoid函数,创建一个记忆
或遗忘特定信息
的闸门(即图中的「圈叉」符号),
②此圈叉闸门的输入是上一轮的预测结果。
③此闸门的输出会加到本次的预测当中 (即图中的「圈加」符号) 。
注:圈圈里包含十字的符号是(矩阵)
逐元素加法
;
圈圈里有个叉的符号是(矩阵)
逐元素乘法
图2
三、筛选
现在不一定会直接将这组结果当做最终的预测。所以模型中还要加一个
筛选路径
(selection),将一部分的预测结果保留在模型中(从预测结果中选出特定几项作为该次循环的预测结果)。
图3
①这个筛选路径也自成一个神经网络,每次输入的新信息 和 旧预测 都会影响筛选路径中 阀门的大小;
②筛选路径也有一个sigmoid挤压函数(中文里一般叫激活函数),因为在之前我们做了一次逐元素相加,预测结果可能会比1大、或比-1小,所以这个压缩函数是用来确保数值大小仍在(-1,1)区间内。
四、忽视
在完成整个模型前,还需要加上一个
忽视路径(ignoring)
忽视路径可以让近期内不是
很相关的结果先被忽视,避免它们影响之后的路径。和其他路径一样,忽视路径有自己的神经网络、激活函数和矩阵运算 (即图中右下角的「圈叉」符号) 。
图4
202305补充: 从 公式角度理解,
(图4 和下面的 图6.10搭配理解)
1、forgetting这条路径通常叫作
遗忘门 ,这条路径上sigmoid函数的输出为:
2、最上面这条selecting路径,常见的说法叫
输出门 ,这条路径是输出门控制 从记忆细胞
到隐藏状态
的信息流动。而这条路径的sigmoid函数输出为:
右上角的prediction可看做当前时刻的隐藏状态(实际上不算是最后的预测值,最终预测值还需要经过全连接层),当前时刻的隐藏状态:
当输出门
近似1时,记忆细胞信息将传递到隐藏状态供输出层使用。
当输出门近似0时,记忆细胞信息只自己保留。
3、ignoring路径通常叫作
输入门 ,
4、最下方这条是生成 候选记忆细胞(也可以看做一种特殊的隐藏状态)的路径。
而当前时间步的记忆细胞:
遗忘门控制上一时间步的记忆细胞 中的信息是否传递到当前时间步;
输入门控制当前时间步的输入 通过 如何流入当前时间步的记忆细胞
总结:下图给出整个LSTM中,三个门的工作流程。(原图见李沐书的P245 )
sigmoid函数输出值在0,1之间,可以被用作一种控制阀门。
、
、
都是由sigmoid函数得出,
控制的是上一时间步的记忆细胞
中留下多少,所以叫遗忘门。
控制
,实质是控制
有多少信息流入当前时间步记忆细胞,所以叫输入门(因为本质控制的是输入数据X。
而决定3个门输出值的权重参数W是在训练中学到的,即LSTM能自适应地调整参数,从而不断优化3个门的策略,学习到序列规律。
原理示例
童书里只有三种句子:「道格看见珍(句号)」、「珍看见小点(句号)」、以及「小点看见道格(句号)」。
one-hot 编码应用:
如果道格是我最后读到的单字,那我的信息矢量中,就只有道格的数值为 1,其他的数值都为 0。我们也可以按前面的方法,利用昨天(前一次)的预测结果,继续预测明天(下一次)的结果。经过一定的训练后,我们应该能从模型中看出一些特定的规律。
进行预测:
如果截止目前的故事为
「珍看见小点(句号),道格⋯⋯」
1、本次输入=道格,上次预测包含 「道格、珍、小点」 (因为前一次是“句号”为输入,所以前一次预测包含所有人的名字)
将两个向量输入模型中:
初步预测结果:
看见、非道格 (分别为正预测
positive prediction 和负预测
negative prediction )
2、本例子不需考虑忽视路径,于是进入遗忘路径,初次预测当做此模型没有历史memory,所以进入筛选路径
3、假设筛选路径学习到的是
「在前一个单字是名字的状况下,接下来的结果只能是『看见』或句号」这项规则,于是「非道格」这项预测就被挡掉了,
剩下「
看见
」成为最终预测
。
新的一轮循环:
1、本次输入=看见 ,上次预测=看见,
「看见」同时是新信息和旧预测。
初步预测结果:「
道格、珍、小点」 其中之一
2、跳过忽视路径
3、进入遗忘路径,前一轮预测结果是
「非道格」和「看见」,
遗忘闸门学习到的是 :
既然前一个单字是『看见』,根据经验我可以将回忆中的『看见』忘掉,保留名字就好。
于是遗忘路径输出的是 「非道格」
4、
遗忘路径输出的「非道格」 和初步预测的 「
道格、珍、小点」进行逐元素加法,
「道格」的预测正负抵消,只留下了「珍」和「小点」继续前往下条路径。
5、筛选路径学习到 :
当「看见」是前一个单字时,下个出现的单字应该是一个名字,所以它让「珍」和「小点」双双通过。
于是,在最后的预测结果中,我们得到了 「珍」和「小点」。
lstm参数
各参数的定义解释:
model.add(LSTM(neurons,input_shape=(None,1))) #输入数据的形状
model.add(Dropout(dropout_value)) #dropout层
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam') # 编译(损失函数、优化器)
model.fit(train_x, train_y, epochs=epochs, batch_size=batch_size,verbose=verbose)
参数解释:
1、neurons:LSTM神经元数量
2、input_shape=(timesteps,input_dim)中, input_dim :features/embeddings 的维度
3、dropout_value:为了抑制过拟合,需要添加dropout层,详细见《dropout层》
float between 0 and 1.DEfault:0.
This value is the percentage of the considered network connections per epoch/batch.
4、verbose:
fit中的verbose: 日志显示
verbose = 0 为不在标准输出流输出日志信息
verbose = 1 为输出进度条记录
verbose = 2 为每个epoch输出一行记录
注意: 默认为 1
evaluate中的verbose:
verbose:日志显示
verbose = 0 为不在标准输出流输出日志信息
verbose = 1 为输出进度条记录
注意: 只能取 0 和 1;默认为 1
one
epoch
= one forward pass and one backward pass of
all
the training examples
batch size
= the number of training examples in one forward/backward pass. The higher the batch size, the more memory space you'll need.
number of
iterations
= number of passes, each pass using [batch size] number of examples. To be clear, one pass = one forward pass + one backward pass (we do not count the forward pass and backward pass as two different passes).
Example: if you have 1000 training examples, and your batch size is 500, then it will take 2 iterations to complete 1 epoch.
(为便于理解,将一次forward/backward 称作 一次pass)
一次epoch= 所有训练数据都经历一次 pass 后更新参数的过程。
batch_size= 一次 pass 用的训练数据的数量
iteration= pass 的次数。 一个iteration=1个pass=batch_size个训练数据
另:一般是iteration译成“迭代”
1个iteration * batch_size= 训练样本的数量
batch_size
若training samples有1050个, batch_size =100。则模型第一次取第 1-100的samples 训练网络,第二次取第 101-200 的样本去训练网络。最后一次用最后50个样本去训练网络。
Batch_Size 越大,其确定的下降方向越准,引起训练震荡越小。且减少训练时间。
但容易陷入局部最小(如鞍点)。
小的batch_size 收敛速度慢
①batch_size=训练数据集的长度时,为批量梯度下降算法——>
Gradient is more general, but intractable for huge datasets.
②batch_size=1时就是随机梯度下降算法(在线学习)——>
Gradient can be noisy.
③batch_size介于上述两者之间
如何选择batch_size的大小:
epoch
epoch过大:过拟合;训练时间长。
epochs过小:欠拟合
需要根据损失函数的减小速率来选定epoch,当loss减小速率趋于平缓时即为合适的epoch
预测滞后问题
模型有些参数可以自己手动调一下,看看模型在不同参数下的效果(虽然我估计数据量太少,可能调参带来的变化不是很大,但是可以体验调参的过程),下面我就可以调的参数说明:
(1)损失函数现在使用的是 mean_squared_error ,可以调成别的
(2)优化器是
adam
,也可以调,甚至对优化器内的参数进行调整(比如学习率)
(3)训练次数是50,可以调低点(因为我看后面模型的损失不下降了)
(4)基于历史多少数据的参数
look_back
可调,你可以设置为3,5.....
损失函数的选择
1、Mean Squared Error Loss(MSE)
是回归类问题的默认损失函数;
从数学角度看,当目标变量符合高斯分布时,此损失函数是最佳的、最应该首先考虑的。只有当有足够理由时才选别的损失函数。
Mean squared error is calculated as the average of the squared differences between the predicted and actual values.
model.compile(loss=‘mean_squared_error')
2、Mean Squared Logarithmic Error Loss(MSLE)
当目标值较分散,且预测值很大;此时可以先计算每个预测值的自然对数,再计算此对数 和 actual values的mean squared error
model.compile(loss=‘mean_squared_logarithmic_error’)
3、Mean Absolute Error Loss (MAE)
目标值大部分符合高斯分布,但有一些界外点(原理均值的过大或过小值)
‘
mean_absolute_error
’
4、 Binary Classification Loss Functions
二分,预测值是两种标签之一的问题。
5、Binary Cross-Entropy Loss
交叉熵是用于二元分类问题的默认损失函数。适用于目标值在 {0,1}集合中的二分类问题。
loss=‘binary_crossentropy’
6、Hinge Loss
对于二分类问题,交叉熵的另一种替代方法是Hinge Loss(铰链损失函数),它主要用于支持向量机(SVM)模型。
适用于目标值在 {-1,1}集合中的二分类问题。
loss=‘hinge’
7、Squared HInge Loss
8、Multi-Class Classification Loss Functions
多类分类是指那些示例被指定为两个以上类中的一个的预测建模问题。
如何选择优化器Optimizer
dropout层
1、什么时候应该加dropout层?
过拟合的表现:
在训练集下的表现过于优越,导致在验证集(测试集)上的表现不佳。
在神经网络中,有一个普遍现象可以说明是出现了过拟合,验证集的准确率回载训练了多个epoch后达到当val_loss达到一个最低值的时候突然回升,val_loss又不断升高。
过拟合原因:模型复杂度过高,模型将训练数据中的噪声或随机误差视为真实模式,可以理解为模型只是死记硬背住了训练数据,而不能很好地泛化到新数据上。而模型复杂度由模型中的 参数数量 和 参数值大小 决定。
过拟合的解决方法: dropout 或 L1/L2正则化
简单理解:L1、L2正则化是在损失函数中加入正则化项,相当于加入了约束条件,从而可以约束参数w的大小。而dropout是在训练时按一定概率弃用某些隐藏层神经元,减少神经元之间的相互依赖性,从而降低模型复杂度。
判断过拟合的代码:
通过model.evaluate计算测试精度判断 模型是否在训练集上性能过优:
train_acc = model.evaluate(trainX, trainy, verbose=0)
test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
模型在训练数据集上的性能优于测试数据集,这是过度拟合的一个可能标志。
如:Train: 1.000, Test: 0.757 ,则可能为过拟合
2、放在哪几个层之间?
可以放任意层之间,但在不同位置,选取的dropout_value值应该采用不同的大小。
经验法则是,当dropout应用于全连接层时,将保留概率(1 - drop概率)设置为0.5,而当应用于卷积层时,将其设置为更大的数字(通常为0.8、0.9),即(1-dropout_value)=0.8或0.9 (dropout_value=0.1或0.2)。