将 Pytorch LSTM 的状态参数转换为 Keras LSTM

Posted

技术标签:

【中文标题】将 Pytorch LSTM 的状态参数转换为 Keras LSTM【英文标题】:Converting state-parameters of Pytorch LSTM to Keras LSTM 【发布时间】:2018-06-29 21:23:45 【问题描述】:

我试图将现有的经过训练的 PyTorch 模型移植到 Keras。

在移植过程中,我卡在了 LSTM 层。

LSTM 网络的 Keras 实现似乎有三种状态类型的状态矩阵,而 Pytorch 实现有四种。

例如,对于具有 hidden_​​layers=64、input_size=512 & output size=128 状态参数的双向 LSTM,如下所示

Keras LSTM 的状态参数

[<tf.Variable 'bidirectional_1/forward_lstm_1/kernel:0' shape=(512, 256) dtype=float32_ref>,
 <tf.Variable 'bidirectional_1/forward_lstm_1/recurrent_kernel:0' shape=(64, 256) dtype=float32_ref>,
 <tf.Variable 'bidirectional_1/forward_lstm_1/bias:0' shape=(256,) dtype=float32_ref>,
 <tf.Variable 'bidirectional_1/backward_lstm_1/kernel:0' shape=(512, 256) dtype=float32_ref>,
 <tf.Variable 'bidirectional_1/backward_lstm_1/recurrent_kernel:0' shape=(64, 256) dtype=float32_ref>,
 <tf.Variable 'bidirectional_1/backward_lstm_1/bias:0' shape=(256,) dtype=float32_ref>]

PyTorch LSTM 的状态参数

 ['rnn.0.rnn.weight_ih_l0', torch.Size([256, 512])],
 ['rnn.0.rnn.weight_hh_l0', torch.Size([256, 64])],
 ['rnn.0.rnn.bias_ih_l0', torch.Size([256])],
 ['rnn.0.rnn.bias_hh_l0', torch.Size([256])],
 ['rnn.0.rnn.weight_ih_l0_reverse', torch.Size([256, 512])],
 ['rnn.0.rnn.weight_hh_l0_reverse', torch.Size([256, 64])],
 ['rnn.0.rnn.bias_ih_l0_reverse', torch.Size([256])],
 ['rnn.0.rnn.bias_hh_l0_reverse', torch.Size([256])],

我试图查看这两种实现的代码,但不能理解太多。

有人可以帮我将 PyTorch 中的 4 组状态参数转换为 Keras 中的 3 组状态参数

【问题讨论】:

奇怪的是 Torch 在 LSTM 中有 4 个状态矩阵,考虑到模型应该有 3 个设计。 是的,LSTM 的 PyTorch 实现略有不同:pytorch.org/docs/0.3.0/nn.html?highlight=lstm#torch.nn.LSTM。有两组偏置参数。如果你想将 PyTorch 参数转换为 Keras,我的建议是关闭偏置参数。 【参考方案1】:

他们真的没有什么不同。如果将 PyTorch 中的两个偏置向量相加,则方程将与 Keras 中实现的相同。

这是PyTorch documentation上的LSTM公式:

PyTorch 对输入转换(下标以 i 开头)和循环转换(下标以 h 开头)使用两个单独的偏置向量。

在 Keras LSTMCell:

        x_i = K.dot(inputs_i, self.kernel_i)
        x_f = K.dot(inputs_f, self.kernel_f)
        x_c = K.dot(inputs_c, self.kernel_c)
        x_o = K.dot(inputs_o, self.kernel_o)
        if self.use_bias:
            x_i = K.bias_add(x_i, self.bias_i)
            x_f = K.bias_add(x_f, self.bias_f)
            x_c = K.bias_add(x_c, self.bias_c)
            x_o = K.bias_add(x_o, self.bias_o)

        if 0 < self.recurrent_dropout < 1.:
            h_tm1_i = h_tm1 * rec_dp_mask[0]
            h_tm1_f = h_tm1 * rec_dp_mask[1]
            h_tm1_c = h_tm1 * rec_dp_mask[2]
            h_tm1_o = h_tm1 * rec_dp_mask[3]
        else:
            h_tm1_i = h_tm1
            h_tm1_f = h_tm1
            h_tm1_c = h_tm1
            h_tm1_o = h_tm1
        i = self.recurrent_activation(x_i + K.dot(h_tm1_i,
                                                  self.recurrent_kernel_i))
        f = self.recurrent_activation(x_f + K.dot(h_tm1_f,
                                                  self.recurrent_kernel_f))
        c = f * c_tm1 + i * self.activation(x_c + K.dot(h_tm1_c,
                                                        self.recurrent_kernel_c))
        o = self.recurrent_activation(x_o + K.dot(h_tm1_o,
                                                  self.recurrent_kernel_o))

输入转换中只添加了一个偏差。但是,如果我们将 PyTorch 中的两个偏差相加,这些方程将是等价的。

二偏 LSTM 是在 cuDNN 中实现的(参见 developer guide)。我真的对 PyTorch 不太熟悉,但我想这就是他们使用两个偏置参数的原因。在 Keras 中,CuDNNLSTM 层也有两个偏置权重向量。

【讨论】:

谢谢。我验证了它,你是对的。两个输出之间只有很小的差异(按 1E-7 的顺序)。另外在检查时我发现,Pytorch 使用 sigmoid 作为激活函数,而 Keras 默认使用 hard_sigmoid @harish2704 如果这个答案对您有所帮助(似乎是这样),您应该考虑接受它。 更新:我将我的 OCR 引擎的 Pytorch Model 移植到 Keras 并使用 Keras-js 成功地 run the trained model inside web-browser

以上是关于将 Pytorch LSTM 的状态参数转换为 Keras LSTM的主要内容,如果未能解决你的问题,请参考以下文章

pytorch中LSTM各参数理解

Pytorch实战__LSTM做文本分类

pytorch1.0 搭建LSTM网络

[Pytorch系列-53]:循环神经网络 - torch.nn.LSTM()参数详解

pytorch nn.LSTM()参数详解

RuntimeError: Expected hidden[0] size (1, 1, 512), got (1, 128, 512) for LSTM pytorch