如何解释路缘石LSTM层中的权重

2024-04-20 02:04:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前正在使用一个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"))  

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,)

简而言之,在这个LSTM层中似乎有四个“元素”。我现在想知道如何解释它们:

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

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

  • 有什么办法可以看到网络学到了什么吗?例如,如果我们想要预测t,那么从上一个时间步骤(t-1)中需要多少,从t-2中需要多少?例如,如果我们能从权重中读出输入t-5完全不相关,这将是一件有趣的事情。

如有澄清和提示,将不胜感激。


Tags: 网络addmodeltimecountstepshiddenfeature
2条回答

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

This post on 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]))

输出如下:

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, ...]]
...

现在您可以找到关于这些不同权重的here更多信息。 他们的名字有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=乙状结肠(W_f*x+U f*h{t-1}+b_f)

    f_t是一个介于0和1之间的值向量,它将对从上一个单元格状态保留(=1)和忘记(=0)的内容进行编码。

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

    i_t=乙状结肠(W_i*x+U i*h{t-1}+b_i)

    i_t是一个0到1之间的值向量,它将对用于更新新单元格状态的值进行编码。

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

    c t_t=tanh(W_c*x+U c*h{t-1}+b_c)

    C t是一个向量,包含更新细胞状态的潜在值(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将提供有关可能用于更新单元状态的信息。你可能会给你一些关于什么是用来产生输出的信息。。。但所有这些都是相对于其他权重的,因为先前的状态也有影响。

然而,如果你在wuc中看到一些很强的权值,这可能并不意味着什么,因为输入门(i_t)可能会完全关闭,并参与细胞状态的更新。。。它是复杂的,追溯神经网络中发生的事情的数学领域是非常复杂的。

神经网络对于大多数情况来说都是黑匣子。你可以在小册子里找到一些从输出到输入追溯信息的例子,但这是我读过的非常特殊的例子。

我希望这有帮助:-)

如果您使用的是Keras 2.2.0

当你打印时

print(model.layers[0].trainable_weights)

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

4 * number_of_units

其中单位数是你的神经元数。尝试:

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

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

i (input), f (forget), c (cell state) and o (output)

因此,为了提取权重,您可以简单地使用slice操作符:

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:]

来源:keras code

相关问题 更多 >