Setting Keras Variables in Generator

Mer*_*klT 5 python lstm keras tensorflow

I want to set my LSTM hidden state in the generator. However, the set of the state only works outside the generator:

K.set_value(model.layers[0].states[0], np.random.randn(batch_size,num_outs)) # this works

def gen_data():
    x = np.zeros((batch_size, num_steps, num_input))
    y = np.zeros((batch_size, num_steps, num_output))
    while True:
        for i in range(batch_size):
            K.set_value(model.layers[0].states[0], np.random.randn(batch_size,num_outs)) # error
            x[i, :, :] = X_train[gen_data.current_idx]
            y[i, :, :] = Y_train[gen_data.current_idx]
            gen_data.current_idx += 1
        yield x, y
gen_data.current_idx = 0
Run Code Online (Sandbox Code Playgroud)

The generator is invoked in the fit_generator function:

model.fit_generator(gen_data(), len(X_train)//batch_size, 1, validation_data=None)
Run Code Online (Sandbox Code Playgroud)

This is the result when I print the state:

print(model.layers[0].states[0])
<tf.Variable 'lstm/Variable:0' shape=(1, 2) dtype=float32>
Run Code Online (Sandbox Code Playgroud)

This is the error that occurs in the generator:

ValueError: Tensor("Placeholder_1:0", shape=(1, 2), dtype=float32) must be from the same graph as Tensor("lstm/Variable:0", shape=(), dtype=resource)
Run Code Online (Sandbox Code Playgroud)

What am I doing wrong?

muj*_*iga 2

生成器是多线程的,因此生成器内部使用的图将在与创建图的线程不同的线程中运行。因此,访问模型表单生成器将访问不同的图。一种简单(但不好)的解决方案是强制生成器与通过设置创建图形的线程在同一线程中运行workers=0

model.fit_generator(gen_data(), len(X_train)//batch_size, 1, validation_data=None, workers=0))
Run Code Online (Sandbox Code Playgroud)

调试代码:

def gen_data():
    print ("-->",tf.get_default_graph())
    while True:
        for i in range(1):
            yield (np.random.randn(batch_size, num_steps, num_input), 
            np.random.randn(batch_size, num_steps, 8))

model = get_model()
print (tf.get_default_graph())
model.fit_generator(gen_data(), 8, 1)
print (tf.get_default_graph())
Run Code Online (Sandbox Code Playgroud)

输出

<tensorflow.python.framework.ops.Graph object at 0x1228a5e80>
--><tensorflow.python.framework.ops.Graph object at 0x14388e5c0>
Epoch 1/1 
8/8 [==============================] - 4s 465ms/step - loss: 1.0198 - acc: 0.1575
<tensorflow.python.framework.ops.Graph object at 0x1228a5e80>
Run Code Online (Sandbox Code Playgroud)

您可以看到图形对象是不同的。将强制workers=0生成器以单线程运行。

使用

model.fit_generator(gen_data(), 8, 1, workers=0)
Run Code Online (Sandbox Code Playgroud)

结果是

<tensorflow.python.framework.ops.Graph object at 0x1228a5e80>
--> <tensorflow.python.framework.ops.Graph object at 0x1228a5e80>
Epoch 1/1
8/8 [==============================] - 4s 466ms/step - loss: 1.0373 - acc: 0.0975
<tensorflow.python.framework.ops.Graph object at 0x1228a5e80>
Run Code Online (Sandbox Code Playgroud)

相同的单线程生成器可以访问相同的图。

然而,要启用多线程生成器,一种优雅的方法是将图保存到创建图的主进程中的变量中,并将其传递给生成器,生成器使用传递的图作为默认图。