如何解释Keras中LSTM层的权重

Isa*_*Isa 11 python neural-network lstm keras

我目前正在使用LSTM层训练一个用于天气预报的递归神经网络.网络本身非常简单,看起来大致如下:

model = Sequential()  
model.add(LSTM(hidden_neurons, input_shape=(time_steps, feature_count), return_sequences=False))  
model.add(Dense(feature_count))  
model.add(Activation("linear"))  
Run Code Online (Sandbox Code Playgroud)

LSTM图层的权重具有以下形状:

for weight in model.get_weights(): # weights from Dense layer omitted
    print(weight.shape)

> (feature_count, hidden_neurons)
> (hidden_neurons, hidden_neurons)
> (hidden_neurons,)
> (feature_count, hidden_neurons)
> (hidden_neurons, hidden_neurons)
> (hidden_neurons,)
> (feature_count, hidden_neurons)
> (hidden_neurons, hidden_neurons)
> (hidden_neurons,)
> (feature_count, hidden_neurons)
> (hidden_neurons, hidden_neurons)
> (hidden_neurons,)
Run Code Online (Sandbox Code Playgroud)

简而言之,看起来这个LSTM层中有四个"元素".我现在想知道如何解释它们:

  • time_steps这个表示中的参数在哪里?它如何影响重量?

  • 我读过LSTM由几个块组成,比如输入和遗忘门.如果那些在这些权重矩阵中表示,哪个矩阵属于哪个门?

  • 有没有办法看到网络学到了什么?例如,从上一个时间步骤(t-1如果我们想要预测t)需要花多少钱t-2?等等多少?例如,知道我们是否可以从权重中读取输入t-5完全不相关的内容将会很有趣.

澄清和提示将不胜感激.

Tom*_*iak 15

如果您使用的是Keras 2.2.0

当你打印

print(model.layers[0].trainable_weights)
Run Code Online (Sandbox Code Playgroud)

你应该看到三个张量:lstm_1/kernel, lstm_1/recurrent_kernel, lstm_1/bias:0 每个张量的一个维度应该是

4*number_of_units

其中number_of_units是你的神经元数量.尝试:

units = int(int(model.layers[0].trainable_weights[0].shape[1])/4)
print("No units: ", units)
Run Code Online (Sandbox Code Playgroud)

这是因为每个张量包含四个LSTM单位的权重(按此顺序):

i(输入),f(忘记),c(单元状态)和o(输出)

因此,为了提取权重,您可以简单地使用切片运算符:

W = model.layers[0].get_weights()[0]
U = model.layers[0].get_weights()[1]
b = model.layers[0].get_weights()[2]

W_i = W[:, :units]
W_f = W[:, units: units * 2]
W_c = W[:, units * 2: units * 3]
W_o = W[:, units * 3:]

U_i = U[:, :units]
U_f = U[:, units: units * 2]
U_c = U[:, units * 2: units * 3]
U_o = U[:, units * 3:]

b_i = b[:units]
b_f = b[units: units * 2]
b_c = b[units * 2: units * 3]
b_o = b[units * 3:]
Run Code Online (Sandbox Code Playgroud)

来源:keras代码


Nas*_*Ben 6

我可能无法回答您的所有问题,但我能做的是提供有关LSTM单元及其组成的不同组件的更多信息.

github上的这篇文章提出了一种在打印时查看参数名称的方法:

model = Sequential()
model.add(LSTM(4,input_dim=5,input_length=N,return_sequences=True))
for e in zip(model.layers[0].trainable_weights, model.layers[0].get_weights()):
    print('Param %s:\n%s' % (e[0],e[1]))
Run Code Online (Sandbox Code Playgroud)

输出如下:

Param lstm_3_W_i:
[[ 0.00069305, ...]]
Param lstm_3_U_i:
[[ 1.10000002, ...]]
Param lstm_3_b_i:
[ 0., ...]
Param lstm_3_W_c:
[[-1.38370085, ...]]
...
Run Code Online (Sandbox Code Playgroud)

现在您可以在这里找到有关这些不同重量的更多信息.它们具有不同索引的名称W,U,V和b.

  • W矩阵是将输入转换为其他内部值的矩阵.他们有形状[input_dim, output_dim].
  • U矩阵是将先前的隐藏状态转换为另一个内部值的矩阵.他们有形状[output_dim, output_dim].
  • b向量是每个块的偏差.他们都有形状[output_dim]
  • V仅用于输出门,它选择从新的内部状态输出的值.它有一个形状[output_dim, output_dim]

简而言之,你确实有4个不同的"块"(或内部层).

  • 忘记门:它根据先前的隐藏状态(h_ {t-1})和输入(x)决定哪个值从单元的先前内部状态(C_ {t-1})中忘记:

    f_t = sigmoid(W_f*x + U_f*h_ {t-1} + b_f)

    f_t是介于0和1之间的值的向量,它将编码要保留的内容(= 1)以及从前一个单元状态中忘记(= 0)的内容.

  • 输入门:它根据先前的隐藏状态(h_ {t-1})和输入(x)决定从输入(x)使用的值:

    i_t = sigmoid(W_i*x + U_i*h_ {t-1} + b_i)

    i_t是介于0和1之间的值的向量,它将编码用于更新新单元状态的值.

  • 候选值:我们使用输入(x)和先前隐藏状态(h_ {t-1})构建新的候选值以更新内部Cell状态:

    Ct_t = tanh(W_c*x + U_c*h_ {t-1} + b_c)

    Ct_t是包含更新Cell状态(C_ {t-1})的潜在值的向量.

我们使用这三个值来构建新的内部单元状态(C_t):

C_t = f_t*C_ {t-1} + i_t*Ct_t

正如您所看到的,新的内部单元状态由两部分组成:我们从最后一个状态中忘记的部分,以及我们想要从输入中学习的部分.

  • 输出门:我们不想输出单元状态,因为它可能被视为我们想要输出的抽象(h_t).所以我们根据我们拥有的所有信息构建h_t,这一步的输出:

    h_t = W_o*x + U_o*h_ {t-1} + V_o*C_t + b_o

我希望这可以澄清LSTM单元的工作原理.我邀请您阅读有关LSTM的教程,因为它们使用了很好的模式,分步示例等等.这是一个相对复杂的层.

关于你的问题,我现在已经知道如何跟踪输入中使用的内容以修改状态.您最终可以查看不同的W矩阵,因为它们是处理输入的矩阵.W_c将为您提供有关可能用于更新单元状态的信息.W_o可能会给你一些关于用于产生输出的信息......但是所有这些都与其他权重相关,因为之前的状态也有影响.

如果你在W_c中看到一些强权重,它可能没有任何意义,因为输入门(i_t)可能会被完全关闭并且会更新单元状态......这很复杂,数学领域追溯到在神经网络中发生的事情实际上非常复杂.

对于最常见的情况,神经网络实际上是黑盒子.你可以在文献中找到一些从输出到输入追溯信息的情况,但这是我所读过的非常特殊的情况.

我希望这有帮助 :-)