如何在Keras中使用reset_states(states)函数?

时间:2017-10-31 11:59:56

标签: python deep-learning keras lstm rnn

我正在尝试在训练每个批次之前设置LSTM内部状态。 我正在分享我的测试代码和发现,希望找到答案并帮助解决类似问题的其他人。

特别地,对于每个数据,我具有特征X(其不随时间改变)和序列P = p1,p2,p3,... p30。 目标是:给定X和p1,p2,p3预测p4,p5,.. p30。

为了达到这个目的,我想用X来初始化LSTM的隐藏状态,就像在几个工作中所做的那样(例如,神经元),然后LSTM必须与p1,p2,p3拟合以预测p4,... ,P30。 在每个批处理(batch_size = 1)之前需要进行初始化,因此我需要控制LSTM状态初始化。 仔细考虑这个问题Initializing LSTM hidden state Tensorflow/Keras我测试了以下代码:

首先,我在recurrent.py中定义的reset_states()函数中添加了一些打印件,以便了解究竟发生了什么。

def reset_states(self, states=None):
    if not self.stateful:
        raise AttributeError('Layer must be stateful.')
    batch_size = self.input_spec[0].shape[0]

    if not batch_size:
        raise ValueError('If a RNN is stateful, it needs to know '
                         'its batch size. Specify the batch size '
                         'of your input tensors: \n'
                         '- If using a Sequential model, '
                         'specify the batch size by passing '
                         'a `batch_input_shape` '
                         'argument to your first layer.\n'
                         '- If using the functional API, specify '
                         'the time dimension by passing a '
                         '`batch_shape` argument to your Input layer.')
    # initialize state if None
    if self.states[0] is None:
        self.states = [K.zeros((batch_size, self.units))
                       for _ in self.states]
        print "reset states A (all zeros)"  
    elif states is None:
        for state in self.states:
            K.set_value(state, np.zeros((batch_size, self.units)))
        print "reset states B (all zeros)"  

    else:
        if not isinstance(states, (list, tuple)):
            states = [states]
            print "reset states C (list or tuple copying)"  

        if len(states) != len(self.states):
            raise ValueError('Layer ' + self.name + ' expects ' +
                             str(len(self.states)) + ' states, '
                             'but it received ' + str(len(states)) +
                             ' state values. Input received: ' +
                             str(states))
        for index, (value, state) in enumerate(zip(states, self.states)):
            if value.shape != (batch_size, self.units):
                raise ValueError('State ' + str(index) +
                                 ' is incompatible with layer ' +
                                 self.name + ': expected shape=' +
                                 str((batch_size, self.units)) +
                                 ', found shape=' + str(value.shape))
            K.set_value(state, value)
            print "reset states D (set values)"                
            print value
            print "\n"

这是测试代码:

import tensorflow as tf
from keras.layers import LSTM
from keras.layers import Input
from keras.models import Model
import numpy as np
import keras.backend as K

input = Input(batch_shape=(1,3,1))
lstm_layer = LSTM(10,stateful=True)(input)
>>> reset states A (all zeros)

如您所见,第一次打印是在创建lstm图层时执行的

model = Model(input,lstm_layer)
model.compile(optimizer="adam", loss="mse")

with tf.Session() as sess:
    tf.global_variables_initializer().run()
    h = sess.run(model.layers[1].states[0])
    c = sess.run(model.layers[1].states[1])
print h
>>> [[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]]
print c
>>> [[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]]

内部状态已设置为全零。 作为替代方案,可以使用函数reset_states()

model.layers[1].reset_states()
>>> reset states B (all zeros)

在这种情况下打印了第二条消息。一切似乎都正常。 现在我想用任意值设置状态。

new_h = K.variable(value=np.ones((1, 10)))
new_c = K.variable(value=np.ones((1, 10))+1)

model.layers[1].states[0] = new_h
model.layers[1].states[1] = new_c
with tf.Session() as sess:
     tf.global_variables_initializer().run()
     h = sess.run(model.layers[1].states[0])
     c = sess.run(model.layers[1].states[1])

print h
>>> [[ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.]]
print c
>>> [[ 2.,  2.,  2.,  2.,  2.,  2.,  2.,  2.,  2.,  2.]]

好的,我已经用我的所有一个和所有两个向量成功设置了两个隐藏状态。 但是,值得利用类函数reset_states(),它将状态作为输入。 该函数利用函数K.set_values(x,values),它期望'values'是一个numpy数组。

new_h_5 = np.zeros((1,10))+5
new_c_24 = np.zeros((1,10))+24
model.layers[1].reset_states([new_h_5,new_c_24])

它似乎有效,确实输出是:

>>> reset states D (set values)
>>> [[ 5.  5.  5.  5.  5.  5.  5.  5.  5.  5.]]
>>> 
>>> 
>>> 
>>> 
>>> reset states D (set values)
>>> [[ 24.  24.  24.  24.  24.  24.  24.  24.  24.  24.]]

但是,如果我想检查状态是否已初始化,我会找到先前的初始化值(全部为1,全部为两个)。

with tf.Session() as sess:
 tf.global_variables_initializer().run()
 hh = sess.run(model.layers[1].states[0])
 cc = sess.run(model.layers[1].states[1])
print hh
>>> [[ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.]]
print cc
>>> [[ 2.,  2.,  2.,  2.,  2.,  2.,  2.,  2.,  2.,  2.]]

这里到底发生了什么?为什么函数似乎根据打印工作但不改变内部状态的值?

1 个答案:

答案 0 :(得分:2)

正如您可能阅读here,value参数设置一个值,通过该值可以初始化变量。因此,当您致电tf.global_variables_initializer().run()时,您的状态会使用此处定义的值进行初始化:

new_h = K.variable(value=np.ones((1, 10)))
new_c = K.variable(value=np.ones((1, 10))+1)

修改

对我来说这似乎很明显,但我会再次解释为什么reset_states无效。

  1. 变量定义:当您将内部状态定义为由某个值初始化的变量时,每次调用variable_initializer时都会设置此特定的vaklue。

  2. 重置状态:它将更新此变量的当前值,但不会更改初始化程序的默认值。为了做到这一点,你需要通过另一个变量将这些状态重新分配给定状态设置为默认值。