使用Keras实现 基于注意力机制(Attention)的 LSTM 时间序列预测

时隔半年多,毕设男孩终于重操旧业,回到了LSTM进行时间序列预测和异常检测的路上。如果有阅读过我之前的博客,可以发现使用LSTM作单类的时间序列异常检测也是基于对于时间序列的预测进行登堂入室LSTM:使用LSTM进行简单的时间序列异常检测本次我们要进行的是使用注意力机制+LSTM进行时间序列预测,项目地址为KerasAttentionMechanism首先我们把它git…

大家好,又见面了,我是你们的朋友全栈君。

时隔半年多,毕设男孩终于重操旧业,回到了 LSTM进行时间序列预测和异常检测的路上。

如果有阅读过我之前的博客,可以发现使用 LSTM作单类的时间序列异常检测也是基于对于时间序列的预测进行 登堂入室LSTM:使用LSTM进行简单的时间序列异常检测

本次我们要进行的是 使用 注意力机制 + LSTM 进行时间序列预测,项目地址为Keras Attention Mechanism

对于时间步的注意力机制

首先我们把它git clone 到本地,然后配置好所需环境 笔者的 tensorflow版本为1.6.0 Keras 版本为 2.0.2
打开文件夹,我们主要需要的是attention_lstm.py 以及 attention_utils.py 脚本

项目中生成数据的函数为

def get_data_recurrent(n, time_steps, input_dim, attention_column=10):
    """ Data generation. x is purely random except that it's first value equals the target y. In practice, the network should learn that the target = x[attention_column]. Therefore, most of its attention should be focused on the value addressed by attention_column. :param n: the number of samples to retrieve. :param time_steps: the number of time steps of your series. :param input_dim: the number of dimensions of each element in the series. :param attention_column: the column linked to the target. Everything else is purely random. :return: x: model inputs, y: model targets """
    x = np.random.standard_normal(size=(n, time_steps, input_dim))
    y = np.random.randint(low=0, high=2, size=(n, 1))
    x[:, attention_column, :] = np.tile(y[:], (1, input_dim))
    return x, y

默认的 n = 30000, input_dim = 2 ,timesteps = 20。生成的数据为:

shape
x 30000 x 20 x 2
y 30000 x 1

其中 x 的第11个 timestep 两维的数据 与y相同,其他timestep 维的数据为随机数。

所以当我们使用这样的数据去进行 注意力机制 LSTM 的训练,我们希望得到的结果是 注意力层 主要关注第11个timestep 而对其他timestep 的关注度较低。

直接运行 attention_lstm.py 脚本
此时的网络结构为:
在这里插入图片描述
可以看到是在 LSTM 层之后使用了注意力机制

最后会汇总画一张图
在这里插入图片描述
可以看到 可以看到注意力的权重主要汇总在了第11个timestep,说明注意力机制很成功

对于维的注意力机制

上述的例子 是将注意力机制使用在了 timestep 上,决定哪个时间步对于结果的影响较大。
而如果我们想将 注意力机制使用在维上呢? 比如使用多维去预测一维的数据,我们想使用注意力机制
决定哪些维对于预测维起关键作用。

比较简单的方法就是将输入数据 reshape 一下 将timesteps 与 input_dim 维对换 再运行就可以了,因为本代码的设置就是对 输入的第2维加入注意力机制.

进阶的方法就是 自写一下 attention_3d_block 函数:

def attention_3d_block(inputs):
    # inputs.shape = (batch_size, time_steps, input_dim)
    input_dim = int(inputs.shape[2])
    a = inputs
    #a = Permute((2, 1))(inputs)
    #a = Reshape((input_dim, TIME_STEPS))(a) # this line is not useful. It's just to know which dimension is what.
    a = Dense(input_dim, activation='softmax')(a)
    if SINGLE_ATTENTION_VECTOR:
        a = Lambda(lambda x: K.mean(x, axis=1), name='dim_reduction')(a)
        a = RepeatVector(input_dim)(a)
    a_probs = Permute((1, 2), name='attention_vec')(a)
    #a_probs = a
    output_attention_mul = merge([inputs, a_probs], name='attention_mul', mode='mul')
    return output_attention_mul

其实严格来讲我们所做的改变不多,作者使用了 Permute层对于数据进行了 第2和第3维的对换,我们则没有进行对换操作。

接下来 再在attention_utils.py 脚本中写一个产生数据集的新函数:

def get_data_recurrent2(n, time_steps, input_dim, attention_dim=5):
    """ 假设 input_dim = 10 time_steps = 6 产生一个 x 6 x 10 的数据 其中每步的第 6 维 与 y相同 """
    x = np.random.standard_normal(size=(n, time_steps, input_dim))
    y = np.random.randint(low=0, high=2, size=(n, 1))
    x[:,:,attention_dim] =  np.tile(y[:], (1, time_steps))

    return x,y

试着产生一组数据 get_data_recurrent2(1,6,10)
在这里插入图片描述

然后我们稍微改动一下main函数进行新的训练。迭代十次后结果为:
在这里插入图片描述
可以看到,第6维的权重比较大。
如果我们对于timesteps的注意力画一个汇总图,即改动一下

  attention_vector = np.mean(get_activations(m, testing_inputs_1,print_shape_only=False,layer_name='attention_vec')[0], axis=2).squeeze()

可以看到对于timesteps的注意力是相同的(其实如果对于开头时间步的注意力机制,对输入维的注意力画一个汇总图,也是相同的)
在这里插入图片描述

对于时间步和输入维的注意力机制

待补充

注:参考 keras-attention-mechanism
以及 Keras中文文档

代码已上传到我的github

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/125920.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 基于python的情感分析案例_关于python爬虫的情感分析

    基于python的情感分析案例_关于python爬虫的情感分析今天给大家分享的是通过情感词典来对文本进行情感分析最后计算出情感得分通过情感得分来判断正负调性主要步骤:数据准备本次情感词典采用的是BosonNLP的情感词典,来源于社交媒体文本,所以词典适用于处理社交媒体的情感分析本次分析准备的文本数据有:BosonNLP情感词典停用词表否定词表程度副词表生成停用…

    2022年8月23日
    6
  • JS中对象转数组方法总结[通俗易懂]

    JS中对象转数组方法总结[通俗易懂]方法一:Array.from()方法例:letobj={0:’nihao’,1:’haha’,2:’gansha’,’length’:3}letarr=Array.from(obj)console.log(arr);注意:1.object中必须有length属性,返回的数组长度取决于length长度2.key值必须是…

    2025年11月4日
    5
  • AirSim和UE4的环境配置

    关于具体的环境配置网上有很多的资料,之前也配置过这个环境,但是没有好好的整理过,每次遇到问题都是瞎搞,然后莫名其妙的解决了。这次的博客主要是把配置的过程要注意的地方记录一下。1、前提条件cmake3.10.3、VisualStudio2015professionalupdate3、UE4.16.3这是我的机器上的环境,作为参考。2、编译AirSim源码首先要到Air…

    2022年4月14日
    55
  • JAVA基础知识之OutputStreamWriter流

    JAVA基础知识之OutputStreamWriter流一、OutputStreamWriter流   API说明:OutputStreamWriter是从字符流到字节流的桥接:使用指定的字符集将写入其中的字符编码为字节。它使用的字符集可以通过名称指定,也可以明确指定,或者可以接受平台的默认字符集。每次调用write()方法都会导致在给定字符上调用编码转换器。生成的字节在写入底层输出流之前在缓冲区中累积。可以指定此缓冲区的大小,但默认情况下,它…

    2025年11月1日
    3
  • Servlet和JSP的交互方式[通俗易懂]

    Servlet和JSP的交互方式[通俗易懂]文章目录Servlet和JSP的交互方式Servlet:jsp:1.表单:2.超链接超链接3.forward:获取参数值request.getParameter(“id”)处理乱码newString(request.getParameter(“name”).getBytes(“ISO8859_1″),”UTF-8”)Servlet和JSP的交互方式Servlet:1.request.getRequestDispatcher(“url”).forward(requsest,response);这个是

    2022年6月22日
    25
  • 虚拟机CentOS系统没有UNIX2dos或dos2UNIX命令的解决方案(参考各路大佬后的总结)

    虚拟机CentOS系统没有UNIX2dos或dos2UNIX命令的解决方案(参考各路大佬后的总结)首先申明一下,只是本人在该问题上遇到的弯路,再通过查看各路大佬的方法总结出来的解决方法:因为是看到了这篇文章https://blog.csdn.net/w616589292/article/details/38274475,然后我就走上了我的弯路了,下载了hd2u-1.0.0.tgz还有popt-1.8-1.x86_64.rpm 配置好了一切发现没有一点卵用。然后我又看见了这篇文章http:/…

    2022年5月18日
    34

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号