通过例子理解 LSTM

Understanding LSTM through example

我想在 LSTM 中编写一个时间步长。我的重点是理解忘记门层输入门层候选值的功能现在未来 细胞状态.

假设我在 t-1 和 xt 的隐藏状态如下。为简单起见,我们假设权重矩阵是单位矩阵,并且所有偏差都为零。

htminus1 = np.array( [0, 0.5, 0.1, 0.2, 0.6] )
xt = np.array( [-0.1, 0.3, 0.1, -0.25, 0.1] )

我知道忘记状态是 htminus1xt

的 sigmoid

所以,是吗?

ft = 1 / ( 1 + np.exp( -( htminus1 + xt ) ) )

>> ft = array([0.47502081, 0.68997448, 0.549834  , 0.4875026 , 0.66818777])

我指的是 this link 来实现一个块 LSTM 的一次迭代。 link 说 ft 应该是 0 或 1。我在这里遗漏了什么吗?

如何按照下图中给出的模式获取遗忘门层?一个例子对我来说是说明性的。

同理,如何获得输入门层it和新候选值向量\tilde{C}_t,如下图所示?

最后,如何根据下图给出的方案得到新的隐藏状态ht

一个简单的例子将有助于我理解。提前致谢。

所以这从数字上看并不明显,但它是这样工作的-

  1. 如果您看到两条线连接成一条线,这是一个串联操作。您已将其解释为添加。

  2. 无论你在哪里看到 sigmoidtanh 块,都暗示了与可训练权重矩阵的乘法。

  3. 如果两行通过显式 x+ 连接,则分别进行元素明智的乘法和加法。

因此,正确的操作应该是 sigmoid(Wf * np.concatenate(htminus1+xt)) + bf,而不是您所拥有的 sigmoid(htminus1+xt)Wf 是可训练参数矩阵,bf 是相应的偏置项。

请注意,我只是用 numpy 在图像的右侧写了方程式,其他的不多。将 [a, b] 解释为 ab 之间的连接操作。

您可以类似地定义其他操作。

ft = sigmoid(Wf * np.concatenate(htminus1, xt)) + bf
it = sigmoid(Wi * np.concatenate(htminus1, xt)) + bi
Ctt = tanh(Wc * np.concatenate(htminus1, xt)) + bc
Ot = sigmoid(Wo * np.concatenate(htminus1, xt)) + bo

Ct = (C_{t-1} * ft) + (Ctt * it)
ht = Ot * tanh(Ct)

注意:我将 C^{tilda} 表示为 Ctt

除了已经涵盖的细节之外,我还想阐明计算和发生的串联的一些更精细的方面。

权重矩阵W_f实际上由两个并排连接的权重矩阵组成,即沿轴=1,每个权重矩阵处理先前的时间步长激活(htminus1 ) 和当前输入 (xt)。而符号 [htminus1, xt] 表示通过垂直堆叠 htminus1xt 获得的矩阵,即沿 axis=0.

这些忽略偏差的矩阵计算可以这样表示-

了解这些计算是如何在 tensorflow LSTM 模型中进行的也很有帮助。下面的代码块仅包含与此处讨论相关的主要计算,完整代码请遵循此 link

# gate layers calculations on current inputs
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 )

# adding biases
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)

# gate layers calculations using previous output ---> h_tm1 i.e htminus1
i = self.recurrent_activation (x_i + K.dot(h_tm1 , self.recurrent_kernel_i) )
f = self.recurrent_activation (x_f + K . dot( h_tm1 , self.recurrent_kernel_f) )
c = f * c_tm1 + i * self.activation (x_c + K.dot(h_tm1, self.recurrent_kernel_c) )
o = self.recurrent_activation (x_o + K.dot(h_tm1 , self.recurrent_kernel_o) )

遗忘门在这张图上解释的很清楚

.将 ct-1 称为 at-1