基于LSTM-RNN的深度学习网络的训练对比matlab仿真
Posted 51matlab
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于LSTM-RNN的深度学习网络的训练对比matlab仿真相关的知识,希望对你有一定的参考价值。
1.算法仿真效果
matlab2022a仿真结果如下:
2.算法涉及理论知识概要
长短期记忆网络(LSTM,Long Short-Term Memory)是一种时间循环神经网络,是为了解决一般的RNN(循环神经网络)存在的长期依赖问题而专门设计出来的,所有的RNN都具有一种重复神经网络模块的链式形式。在标准RNN中,这个重复的结构模块只有一个非常简单的结构,例如一个tanh层。
长短期记忆网络(Long-Short Term Memory,LSTM)论文首次发表于1997年。由于独特的设计结构,LSTM适合于处理和预测时间序列中间隔和延迟非常长的重要事件。LSTM的表现通常比时间递归神经网络及隐马尔科夫模型(HMM)更好,比如用在不分段连续手写识别上。2009年,用LSTM构建的人工神经网络模型赢得过ICDAR手写识别比赛冠军。LSTM还普遍用于自主语音识别,2013年运用TIMIT自然演讲数据库达成17.7%错误率的纪录。作为非线性模型,LSTM可作为复杂的非线性单元用于构造更大型深度神经网络。
LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为它可以记忆不定时间长度的数值,区块中有一个gate能够决定input是否重要到能被记住及能不能被输出output。图1底下是四个S函数单元,最左边函数依情况可能成为区块的input,右边三个会经过gate决定input是否能传入区块,左边第二个为input gate,如果这里产出近似于零,将把这里的值挡住,不会进到下一层。左边第三个是forget gate,当这产生值近似于零,将把区块里记住的值忘掉。第四个也就是最右边的input为output gate,他可以决定在区块记忆中的input是否能输出 。LSTM有很多个版本,其中一个重要的版本是GRU(Gated Recurrent Unit),根据谷歌的测试表明,LSTM中最重要的是Forget gate,其次是Input gate,最次是Output gate。
传统RNN网络由于结构存在固有缺陷,在参数更新时会存在梯度消失以及梯度爆炸的问题,导致长距离的历史信息丢失,进一步造成网络极难收敛,无法训练出理想的模型。LSTM作为一种改进的循环神经网络,在原有网络结构的基础上加入了细胞状态(cell state)的结构来控制全局信息的传输,并通过遗忘门,输入门,输出门三种门控单元控制细胞状态信息值的更新。LSTM在极大程度上缓解了传统RNN模型存在的长期依赖问题,减少了长距离历史信息的丢失,输出的预测结果更准确 。
LSTM通过以下公式进行更新权值矩阵和偏置参数等网络信息:
3.MATLAB核心程序
clc; clear; close all; warning off; addpath(genpath(pwd)); RNN; LSTM_RNN; figure load R1.mat loglog(1:10:clc_times,errt(1:10:end),\'b.\'); hold on load R2.mat loglog(1:10:clc_times,errt(1:10:end),\'r.\'); grid on legend(\'RNN\',\'LSTM-RNN\'); xlabel(\'迭代次数\'); ylabel(\'误差\'); figure load R1.mat loglog(1:10:clc_times,smooth(errt(1:10:end),1024),\'b.\'); hold on load R2.mat loglog(1:10:clc_times,smooth(errt(1:10:end),1024),\'r.\'); grid on legend(\'RNN\',\'LSTM-RNN\'); xlabel(\'迭代次数\'); ylabel(\'误差\'); % 前向传播 for position = 0:binary_dim - 1 % x---->输出向量:1*input_dim (1*2) x = [a(binary_dim - position) - \'0\',b(binary_dim - position) - \'0\',bias]; % y---->真值标签:1*output_dim (1*1) y = c(binary_dim - position) - \'0\'; % 输入门 InGate_in = x * W_I + H(end,:) * U_I + S(end,:) * S_I; InGate_out = sigmoid(InGate_in); % 遗忘门 ForgetGate_in = x * W_F + H(end,:) * U_F + S(end,:) * S_F; ForgetGate_out = sigmoid(ForgetGate_in); % G门 G_in = x * W_G + H(end,:) * U_G; G_out = tanh(G_in); % Cell状态更新 S_t = ForgetGate_out .* S(end,:) + InGate_out .* G_out; % 输出门 OutGate_in = x * W_O + H(end,:) * U_O + S_t * S_O; OutGate_out = sigmoid(OutGate_in); % 记忆模块(隐藏层输出)H H_t = OutGate_out .* tanh(S_t); % 输出层输出 output_in = H_t * W_OUT; output_out = sigmoid(output_in); % 预测值输出,用于显示 d(binary_dim - position) = round(output_out); % 输出层的梯度记录 y_delta = [y_delta;(y - output_out).*dsigmoid(output_out)]; % 各门状态保存 I = [I;InGate_out]; F = [F;ForgetGate_out]; O = [O;OutGate_out]; G = [G;G_out]; S = [S;S_t]; H = [H;H_t];
为 LSTM-RNN 训练填充时间序列子序列
【中文标题】为 LSTM-RNN 训练填充时间序列子序列【英文标题】:Padding time-series subsequences for LSTM-RNN training 【发布时间】:2017-10-23 05:22:50 【问题描述】:我有一个时间序列数据集,我将其用作 LSTM-RNN 的输入以进行动作预测。时间序列包括 30 fps 的 5 秒时间(即 150 个数据点),数据表示面部特征的位置/移动。
我从我的数据集中抽取额外的较小长度的子序列,以便在数据集中添加冗余并减少过度拟合。在这种情况下,我知道子序列的开始和结束帧。
为了批量训练模型,所有时间序列需要具有相同的长度,并且根据文献中的许多论文,padding 不应影响网络的性能。
例子:
原序列:
1 2 3 4 5 6 7 8 9 10
子序列:
4 5 6 7
8 9 10
2 3 4 5 6
考虑到我的网络正在尝试预期一个动作(这意味着只要 P(action) > 阈值,它从 t = 0 到 T = tmax,它就会预测那个动作)填充物去哪里重要吗?
选项 1:用零替换原始值
0 0 0 4 5 6 7 0 0 0
0 0 0 0 0 0 0 8 9 10
0 2 3 4 5 6 0 0 0 0
选项 2:最后全为零
4 5 6 7 0 0 0 0 0 0
8 9 10 0 0 0 0 0 0 0
2 3 4 5 0 0 0 0 0 0
此外,一些时间序列丢失了一些帧,但不知道它们是哪些 - 这意味着如果我们只有 60 帧,我们不知道它们是否是从 0 到 2 秒,从 1 到 3 秒等。这些都需要在子序列被采用之前进行填充。在这种情况下,填充的最佳做法是什么?
提前谢谢你。
【问题讨论】:
【参考方案1】:如果你有可变长度的序列,pytorch
提供了一个实用函数torch.nn.utils.rnn.pack_padded_sequence。使用此功能的一般工作流程是
from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence
embedding = nn.Embedding(4, 5)
rnn = nn.GRU(5, 5)
sequences = torch.tensor([[1,2,0], [3,0,0], [2,1,3]])
lens = [2, 1, 3] # indicating the actual length of each sequence
embeddings = embedding(sequences)
packed_seq = pack_padded_sequence(embeddings, lens, batch_first=True, enforce_sorted=False)
e, hn = rnn(packed_seq)
可以收集每个token的嵌入
e = pad_packed_sequence(e, batch_first=True)
使用这个函数比自己填充要好,因为torch
将限制 RNN 只检查实际序列并在填充标记之前停止。
【讨论】:
【参考方案2】:最好在一开始就填充零,正如本文所建议的Effects of padding on LSTMs and CNNs,
虽然 post padding 模型在 6 个 epoch 时效率达到顶峰,然后开始过度拟合,但它的准确性远低于 pre-padding。
查看表1,pre-padding(开头补零)的准确率在80%左右,而post-padding(最后补零)的准确率只有50%左右
【讨论】:
【参考方案3】:一般来说,LSTM 和 RNN 最强大的属性是它们的参数在时间范围内共享(参数 recur 在时间范围内),但参数共享依赖于假设相同的参数可以用于不同的时间步,即前一个时间步和下一个时间步之间的关系不依赖于 t,如 here in page 388, 2nd paragraph 解释的那样。
简而言之,在末尾填充零,理论上不应该改变模型的准确性。我使用了副词理论上,因为在每个时间步长 LSTM 的决定取决于它的细胞状态以及其他因素,而这种细胞状态是过去帧的简短总结。据我了解,您的情况可能缺少过去的帧。我认为你在这里需要做一些权衡。
我宁愿在最后填充零,因为它不会与 RNN 的基本假设完全冲突,并且更便于实现和跟踪。
在实现方面,我知道 tensorflow 会在您给它序列和每个样本的实际序列大小后计算损失函数(例如,对于 4 5 6 7 0 0 0 0 0 0,您还需要给它实际的size 此处为 4)假设您正在实施选项 2。不过,我不知道是否有选项 1 的实施。
【讨论】:
谢谢,很有帮助!以上是关于基于LSTM-RNN的深度学习网络的训练对比matlab仿真的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Mat 重塑为张量以在 C++ 中的深度神经网络中使用?
深度学习基础-基于Numpy的循环神经网络(RNN)实现和反向传播训练
对比学习资料《深度学习入门:基于Python的理论与实现》+《深度学习原理与实践》+《深度学习理论与实战基础篇》电子资料