基于经过训练的 Keras 模型在纯 Numpy 中实现有状态 GRU

Posted

技术标签:

【中文标题】基于经过训练的 Keras 模型在纯 Numpy 中实现有状态 GRU【英文标题】:Implementing a stateful GRU in pure Numpy based on a trained Keras Model 【发布时间】:2018-09-20 04:52:00 【问题描述】:

我正在尝试在纯 Numpy 中手动编写一个经过训练的有状态 RNN Keras 模型,带有 tensorflow 后端。

我的模型是这样构建的:

model = Sequential()
num_layers_first_stage = 64
model.add(GRU(num_layers_first_stage, stateful=True, name=input_node_name, batch_input_shape=(1,1,4), return_sequences=True))
model.add(GRU(64, stateful=True, name='gru_layer_1', return_sequences=True))
model.add(GRU(64, stateful=True, name='gru_layer_2', return_sequences=True))


model.add(Dense(2, activation='softmax', name=output_node_name))
model.compile(loss='categorical_crossentropy',
              optimizer='Adam',
              metrics=['accuracy'])

return model

训练后,我保存模型,然后在不同的会话中再次加载它。我用来构建纯 Numpy 模型的代码如下所示:

def hard_sigmoid(x):
    return  np.clip(x * 0.2 + 0.5, 0.0, 1.0)

class MyKerasGRULayer(object):
    def __init__(self, keras_layer):
        self.num_units = keras_layer.units


        self.W_z = keras_layer.cell.kernel_z.eval(session=K.get_session())
        self.W_r = keras_layer.cell.kernel_r.eval(session=K.get_session())
        self.W_h = keras_layer.cell.kernel_h.eval(session=K.get_session())

        self.U_z = keras_layer.cell.recurrent_kernel_z.eval(session=K.get_session())
        self.U_r = keras_layer.cell.recurrent_kernel_r.eval(session=K.get_session())
        self.U_h = keras_layer.cell.recurrent_kernel_h.eval(session=K.get_session())

        self.b_z = keras_layer.cell.input_bias_z.eval(session=K.get_session())
        self.b_r = keras_layer.cell.input_bias_r.eval(session=K.get_session())
        self.b_h = keras_layer.cell.input_bias_h.eval(session=K.get_session())

        self.input_shape = keras_layer.input_shape

        self.h = np.zeros((1, self.num_units), dtype=np.float32)

    def forward_pass(self, x):
        z = hard_sigmoid(np.dot(x, self.W_z) + np.dot(self.h, self.U_z) + self.b_z)

        r = hard_sigmoid(np.dot(x, self.W_r) + np.dot(self.h, self.U_r) + self.b_r)

        h_ =  np.tanh(np.dot(x, self.W_h) + np.dot(np.multiply(r, self.h), self.U_h) + self.b_h)  

        self.h = np.multiply((1-z), self.h) + np.multiply(z, h_)

        print(self.h)

我正在尝试将此与我加载的 Keras 模型进行比较,如下所示:

model = load_model(model_file)
model.reset_states()
model.predict(np.ones((1,1,4)))
print(model.updates[0][0].eval(session=K.get_session()))

GRU0 = MyKerasGRULayer(model.layers[0])
GRU0.forward_pass(np.ones((4,)))

但结果不同。希望在这里得到不正确的指针

【问题讨论】:

【参考方案1】:

Keras GRU 使用以下代码计算h

h = z * h_tm1 + (1 - z) * hh

这与您的 forward_pass 方法不同。

通过将最后一行更改为:

self.h = np.multiply(z, self.h) + np.multiply(1 - z, h_)

你应该能够得到相同的结果。

【讨论】:

以上是关于基于经过训练的 Keras 模型在纯 Numpy 中实现有状态 GRU的主要内容,如果未能解决你的问题,请参考以下文章

从经过训练的 keras 模型中获取训练超参数

如何在 Keras 中使用经过训练的模型进行预测

如何在 Keras 中保存经过训练的模型以在应用程序中使用它?

Cnn keras模型没有经过训练的参数表示和改进模型

从 Keras 中经过训练的自动编码器模型中获取解码器

是否可以保存经过训练的图层以在 Keras 上使用图层?