problem b: 一年中的第几天_Seq2Seq的建模解释和Keras中Simple RNN Cell的计算及其代码示例...

RNN的应用有很多,尤其是两个RNN组成的Seq2Seq结构,在时序预测、自然语言处理等方面有很大的用处,而每个RNN中一个节点是一个Cell,它是RNN中的基本结构。本文从如何使用RNN建模数据开始,重点解释RNN中Cell的结构,以及Keras中Cell相关的输入输出及其维度。我已经尽量解释了每个变量,但可能也有忽略,因此可能对RNN之前有一定了解的人会更友好,本文最主要的目的是描述Keras中RNNcell的参数以及输入输出的两个注意点。如有问题也欢迎指出,我会进行修改。

63790296ca489505bffb0e7095ef87fe.png

关于RNN模型的更加理论的解释,可以参考之前的文章:深度学习之RNN模型 | 数据学习者官方网站(Datalearner)

目录如下:

  • 一、基于Seq2Seq来预测时序数据
  • 二、RNN中的Cell如何对数据建模
  • 三、Simple RNN Cell的建模理论数学说明
  • 四、Keras中SimpleRNNCell的输入输出和参数

一、基于Seq2Seq来预测时序数据

我们知道多个RNN Cell连接就可以称为一个RNN模型,两个RNN相连接,可以组成一个Seq2Seq模型,即第一个RNN一般称为Encoder,第二个RNN称为Decoder,第一个RNN的最后一个输出作为第二个RNN的输入,这种Seq2Seq的结构在实际中有很多应用,包括时序数据预测、自然语言处理等。以时序数据为例,Encoder建模对象是过去N天的已知数据,如过去30天某个APP的流量,而Decoder建模对象就是未来M天的未知数据,如我们需要预测的未来7天某个APP的流量。

原理也很简单,就是说我们要用过去的数据预测未来,但是直接将过去的数据作为输入的话,形成回归或者分类模型的话,那么过去N天之间的关联关系我们就没有用到。例如,假如我们从历史数据中抽取了如下序列,来训练模型,预测未来:

51ccea7194f5d188b98f33b9a954344a.png

这种数据传统回归模型并不好用,一方面历史数据之间的关联关系没有利用,另一方面基于这种可以说是多分类的模型去预测也准确性很低。

利用Seq2Seq模型则比较适合,我们把过去30天当作一个RNN模型,即Seq2Seq的Encoder,Encoder中每一个Cell都对历史的一天建模,且都使用前一天的输出来构建后一个Cell的输入,那么最后一个Cell的输出也就包含了历史的信息(由于本文仅关注原理,因此这里不讨论过长的序列导致模型训练困难等其它缺点)。再使用这个Encoder输出作为Decoder阶段的输入来预测未来,那么就避免了上述问题。

二、RNN中的Cell如何对数据建模

那么一个Cell如何对数据建模呢?以上述时序数据预测为例,那么一个Encoder中的Cell就对应历史某一天。这时候Cell的输入数据就是两个,一个是前一天Cell的状态输出,另一个是当前Cell的特征输入,特征就是今天时序特征,通常,在时序数据预测中,某一个时间点的特征就是如一年的第几天,第几个季度,7天前流量值等等,这些都可以是特征。

三、Simple RNN Cell的建模理论数学说明

下图是一个Simple RNN Cell的图示:

4da800988e10e175c9a86e8fac19e549.png

如前所述,一个Cell的输入包括两个:

一个是前一阶段的状态,即上图中a​(0)​​,初始的第一个Cell的前一阶段的状态一般来说可以随机生成。

另一个是当前Cell的特征输入,即上图的x​(1)​​。也就是前面说的当前时间点的一些特征,如这是一年的第几天、第几个季度、是否是节假日、七天前的流量是多少、全年今天的流量是多少等等。

输出也是两个:一个是当前Cell的输出y​(1)​​,另一个是下一阶段的状态,即a​(1)​​。

维度相关

以一个时间点的数据为例,如果当前数据特征维度是K,前一个状态a​(0)​​的维度是L,那么输出状态a​(1)​​的状态依然是L,输出y​1​​的维度是1,当然Encoder阶段我们可能不太在意这个y输出,而Decoder阶段的y输出就是我们预测的结果了。

四、Keras中SimpleRNNCell的输入输出和参数

Keras中SimpleRNNCell的参数很多,包括权重参数如何初始化,是否添加bias,激活函数是啥等等。这些都是常见的参数,就不解释了,其中一个参数是units,这个定义容易混淆,原先我也以为这个unit是叠加多层RNN的输出,最后发现其实这个参数是隐状态的维度,也就是前面的a​(0)​​和a​(1)​​的维度。

SimpleRNNCell在创建的时候指定units就可以了,而使用的时候,它有两个输入参数,一个是当前阶段的特征输入,即input_x,另一个是前一个状态previous_states,注意,这里也有个坑,由于RNNCell的种类很多,包括后面的GRUCell或者是LSTMCell,这些更加复杂的Cell状态都不止一个,因此在代码中,Keras的状态并不单纯是一个state,它其实是一个列表。

我们看如下代码(tensorflow 1.15.x)

# 我们先定义一个cell,units=1,也就是隐状态的维度是1rnn_cell = tf.keras.layers.SimpleRNNCell(1, activation=None, kernel_initializer=tf.keras.initializers.Zeros())# 我们随机生成一个当前阶段的特征和前一阶段的状态input_x = tf.convert_to_tensor(np.asarray([[1, 1, 1], [2, 2, 2]]).astype(np.float32)                              )# 注意,这里state的维度是[1, 2, 1],因为Keras取前一阶段的状态会根据不同的Cell取不同的数量,如果是SimpleRNNCell,那么取第一个,如果是GRU,那么接着取,所以这里的第一个维度实际是第几种state,由于我们这里测试的是SimpleRNNCell,只有一个状态,那么用这个维度即可previous_states = tf.convert_to_tensor(np.asarray([[[0.1], [0.1]]]).astype(np.float32))# 输出测试rnn_output, next_states = rnn_cell(input_x, previous_states)init = tf.compat.v1.global_variables_initializer()with tf.compat.v1.Session() as sess:    sess.run(init)    rnn_output, next_states = sess.run([rnn_output, next_states])    print(rnn_output)    print(next_states)

注意,这里state的维度是[1, 2, 1],因为Keras取前一阶段的状态会根据不同的Cell取不同的数量,如果是SimpleRNNCell,那么取第一个,如果是GRU,那么接着取,所以这里的第一个维度实际是第几种state,由于我们这里测试的是SimpleRNNCell,只有一个状态,那么用这个维度即可。之前测试过[2,1],结果报错,也就是这个原因。输出也是类似,输出的第一个是当前阶段的结果和状态,对应前面的y​1​​和a​(1)​​。注意a​(1)​​是一个列表。这里列表中只有一个状态,该状态的维度是[2,1],和我们自己定义的previous_states变量都是一个意思。

当然,如果我们把units设置成其它数值如5,那么我们的previous_states构造就必须是一个列表,列表中有一个变量,其维度是[5,1],当然也可以构造成我们的[1,5,1]形式的变量。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值