【问题标题】:How to interpret weights in a LSTM layer in Keras [closed]如何在 Keras 中解释 LSTM 层中的权重 [关闭]
【发布时间】:2017-08-09 05:50:54
【问题描述】:

我目前正在使用 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-1,如果我们要预测t)需要多少,从t-2 等需要多少?例如,如果我们可以从权重中读取到输入 t-5 完全不相关,将会很有趣。

非常感谢您的澄清和提示。

【问题讨论】:

    标签: python keras neural-network lstm


    【解决方案1】:

    如果您使用的是 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

    其中 number_of_units 是您的神经元数量。试试:

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

    这是因为每个张量包含四个 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:]
    

    来源:keras code

    【讨论】:

    • 这个答案应该被接受为答案,谢谢@Tomasz Bartkowiak
    • @TomazhBartkowiak,在这种情况下WU 有什么区别?
    • @garej 他们的区别解释了herehere。在 Keras 的上下文中,WkernelUrecurrent_kernel
    • c 指的是什么? tanh的结果是候选细胞状态,还是先前细胞状态和当前候选细胞状态组合而成的实际细胞状态?
    【解决方案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 = 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) 可能会完全关闭,从而消除细胞状态的更新......这很复杂,数学领域追溯神经网络中发生的事情确实很复杂。

    对于最一般的情况,神经网络确实是黑盒子。您可以在文献中找到一些案例,它们将信息从输出追溯到输入,但这是我所读到的非常特殊的情况。

    我希望这会有所帮助:-)

    【讨论】:

    • 从 Github 发布的上述代码可能已经过时,不再提供 W_i 等信息。由于我需要来自这些门的一些特定值,因此有一种更新的方法可以找到权重矩阵中的哪个权重对应于什么。会要求你帮助我更新它的版本@NassimBen
    猜你喜欢
    • 2018-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 2019-04-09
    • 2017-04-24
    • 1970-01-01
    相关资源
    最近更新 更多