Keras 深度学习库提供了长短期记忆(LSTM)循环神经网络的实现。
作为该实现的一部分,Keras API 同时提供了 return sequences 和 return state 的访问。当设计复杂的循环神经网络模型(例如编码器-解码器模型)时,这些数据的用法和区别可能会令人困惑。
在本教程中,您将了解 Keras 深度学习库中 LSTM 层 return sequences 和 return states 的区别和结果。
完成本教程后,您将了解:
- return sequences 返回每个输入时间步的隐藏状态输出。
- return state 返回最后一个输入时间步的隐藏状态输出和单元状态。
- return sequences 和 return state 可以同时使用。
通过我的新书开始您的项目《Python 长短期记忆网络》,其中包含分步教程和所有示例的Python源代码文件。
让我们开始吧。

理解 Keras 中 LSTM 的 Return Sequences 和 Return States 的区别
照片由 Adrian Curt Dannemann 拍摄,部分权利保留。
教程概述
本教程分为4个部分,它们是:
- 长短期记忆网络
- 返回序列
- 返回状态
- 返回状态和序列
长短期记忆网络
长短期记忆(LSTM)是一种循环神经网络,它由内部门组成。
与其他循环神经网络不同,该网络的内部门使其能够通过随时间反向传播(BPTT)成功训练,并避免梯度消失问题。
在 Keras 深度学习库中,可以使用 LSTM() 类创建 LSTM 层。
创建 LSTM 记忆单元层可让您指定层中的记忆单元数量。
层中的每个单元或细胞都有一个内部单元状态,通常缩写为“c”,并输出一个隐藏状态,通常缩写为“h”。
Keras API 允许您访问这些数据,这在开发复杂的循环神经网络架构(例如编码器-解码器模型)时可能有用甚至必需。
在本教程的其余部分,我们将介绍访问这些数据的 API。
返回序列
每个 LSTM 单元都会为每个输入输出一个隐藏状态 *h*。
1 |
h = LSTM(X) |
我们可以通过一个非常简单的模型来演示这一点,该模型包含一个 LSTM 层,其中包含一个 LSTM 单元。
在此示例中,我们将有一个输入样本,包含 3 个时间步,每个时间步观察到一个特征。
1 2 3 |
t1 = 0.1 t2 = 0.2 t3 = 0.3 |
完整的示例如下所示。
注意:本文中的所有示例都使用Keras 函数式 API。
1 2 3 4 5 6 7 8 9 10 11 12 |
from keras.models import Model from keras.layers import Input 从 keras.layers 导入 LSTM from numpy import array # 定义模型 inputs1 = Input(shape=(3, 1)) lstm1 = LSTM(1)(inputs1) model = Model(inputs=inputs1, outputs=lstm1) # 定义输入数据 data = array([0.1, 0.2, 0.3]).reshape((1,3,1)) # 进行并显示预测 print(model.predict(data)) |
运行示例后,对于包含 3 个时间步的输入序列,输出一个隐藏状态。
鉴于 LSTM 权值和单元状态的随机初始化,您的具体输出值会有所不同。
1 |
[[-0.0953151]] |
有可能访问每个输入时间步的隐藏状态输出。
这可以通过在定义 LSTM 层时将 `return_sequences` 属性设置为 `True` 来完成,如下所示:
1 |
LSTM(1, return_sequences=True) |
我们可以使用此更改更新之前的示例。
完整的代码清单如下。
1 2 3 4 5 6 7 8 9 10 11 12 |
from keras.models import Model from keras.layers import Input 从 keras.layers 导入 LSTM from numpy import array # 定义模型 inputs1 = Input(shape=(3, 1)) lstm1 = LSTM(1, return_sequences=True)(inputs1) model = Model(inputs=inputs1, outputs=lstm1) # 定义输入数据 data = array([0.1, 0.2, 0.3]).reshape((1,3,1)) # 进行并显示预测 print(model.predict(data)) |
运行示例会返回一个包含 3 个值的序列,即层中单个 LSTM 单元的每个输入时间步的隐藏状态输出。
1 2 3 |
[[[-0.02243521] [-0.06210149] [-0.11457888]]] |
当堆叠 LSTM 层时,您必须将 `return_sequences=True` 设置为 `True`,以便第二个 LSTM 层具有三维序列输入。有关更多详细信息,请参阅此博文。
当使用 TimeDistributed 层封装的 Dense 输出层预测序列输出时,您可能还需要访问隐藏状态输出序列。有关更多详细信息,请参阅此博文。
返回状态
LSTM 单元或单元层的输出称为隐藏状态。
这令人困惑,因为每个 LSTM 单元会保留一个未输出的内部状态,称为单元状态,或 *c*。
通常,除非我们在开发复杂的模型,其中后续层需要使用另一个层的最终单元状态来初始化其单元状态(例如在编码器-解码器模型中),否则我们不需要访问单元状态。
Keras 在 LSTM 层中提供了 `return_state` 参数,该参数将提供对隐藏状态输出(*state_h*)和单元状态(*state_c*)的访问。例如:
1 |
lstm1, state_h, state_c = LSTM(1, return_state=True) |
这看起来可能令人困惑,因为 `lstm1` 和 `state_h` 都引用相同的隐藏状态输出。这两个张量分开的原因将在下一节中清楚。
我们可以通过下面列出的一个实际示例来演示访问 LSTM 层中单元的隐藏状态和单元状态。
1 2 3 4 5 6 7 8 9 10 11 12 |
from keras.models import Model from keras.layers import Input 从 keras.layers 导入 LSTM from numpy import array # 定义模型 inputs1 = Input(shape=(3, 1)) lstm1, state_h, state_c = LSTM(1, return_state=True)(inputs1) model = Model(inputs=inputs1, outputs=[lstm1, state_h, state_c]) # 定义输入数据 data = array([0.1, 0.2, 0.3]).reshape((1,3,1)) # 进行并显示预测 print(model.predict(data)) |
运行示例会返回 3 个数组:
- 最后一个时间步的 LSTM 隐藏状态输出。
- 最后一个时间步的 LSTM 隐藏状态输出(再次)。
- 最后一个时间步的 LSTM 单元状态。
1 2 3 |
[array([[ 0.10951342]], dtype=float32), array([[ 0.10951342]], dtype=float32), array([[ 0.24143776]], dtype=float32)] |
隐藏状态和单元状态反过来可以用于初始化另一个具有相同单元数量的 LSTM 层的状态。
返回状态和序列
我们可以同时访问隐藏状态序列和单元状态序列。
这可以通过配置 LSTM 层以同时返回序列和状态来完成。
1 |
lstm1, state_h, state_c = LSTM(1, return_sequences=True, return_state=True) |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 |
from keras.models import Model from keras.layers import Input 从 keras.layers 导入 LSTM from numpy import array # 定义模型 inputs1 = Input(shape=(3, 1)) lstm1, state_h, state_c = LSTM(1, return_sequences=True, return_state=True)(inputs1) model = Model(inputs=inputs1, outputs=[lstm1, state_h, state_c]) # 定义输入数据 data = array([0.1, 0.2, 0.3]).reshape((1,3,1)) # 进行并显示预测 print(model.predict(data)) |
运行示例,我们现在可以看到为什么 LSTM 输出张量和隐藏状态输出张量被声明为分开的。
该层返回每个输入时间步的隐藏状态,然后分别返回最后一个时间步的隐藏状态输出和最后一个输入时间步的单元状态。
可以通过查看返回序列(第一个数组)中的最后一个值是否与隐藏状态(第二个数组)中的值匹配来确认这一点。
1 2 3 4 5 |
[array([[[-0.02145359], [-0.0540871 ], [-0.09228823]]], dtype=float32), array([[-0.09228823]], dtype=float32), array([[-0.19803026]], dtype=float32)] |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
- Keras 函数式 API
- Keras 中的 LSTM API
- 长短期记忆网络, 1997.
- 理解 LSTM 网络。, 2015.
- Keras 中的序列到序列学习的十分钟入门
总结
在本教程中,您了解了 Keras 深度学习库中 LSTM 层 return sequences 和 return states 的区别和结果。
具体来说,你学到了:
- return sequences 返回每个输入时间步的隐藏状态输出。
- return state 返回最后一个输入时间步的隐藏状态输出和单元状态。
- return sequences 和 return state 可以同时使用。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
谢谢这个!
为了帮助人们直观地理解输出序列和状态的一些应用,像下面 Stack Overflow 回答中的图片会很有帮助!
https://stats.stackexchange.com/a/181544/37863
谢谢。
嗨,Jason,
您是否计划在您的博客系列中使用更多函数式 API?
如果是,为什么?
此致
Thabet
是的,这是更高级模型开发所必需的。
我很快就会有一篇关于函数式 API 的“操作方法”帖子。它已安排。
嗨 Jason,是否有可能通过 `return_state = True` 和 `return_sequences = True` 与 Sequential API 访问内部状态?此外,是否可以通过像 `set_state()` 这样的函数来设置隐藏状态?
谢谢!
也许吧,但我不知道或未测试过。
嘿 Jason,我想向您展示一个我一直在尝试的很酷的新 RNN 单元,称为“循环加权平均”——它将注意力机制集成到循环神经网络中——Keras 实现可在 https://github.com/keisuke-nakata/rwa 找到,白皮书可在 https://arxiv.org/pdf/1703.01253.pdf 找到。
我还看到 GRU 通常是更好的选择,除非 LSTM 的偏差被初始化为 1,并且它已经内置到 Keras 中(其白皮书请参见 http://proceedings.mlr.press/v37/jozefowicz15.pdf)。
太酷了!
只是想说明一下,return_state 似乎是 Keras 的一个较新添加项(自 tensorflow 1.3 起 - 如果您在 tensorflow contrib 中使用 Keras)。
可惜它在早期版本中不可用——我一直期待着能够玩玩它。
Alex
谢谢 Alex。
嗨 Jason,在这些示例中您没有进行拟合。
当您像这样定义模型时:`model = Model(inputs=inputs1, outputs=[lstm1, state_h, state_c])` 然后进行拟合,`fit()` 函数会期望输出三个值而不是一个。如何正确打印状态(以查看它们在训练和/或预测过程中如何变化)?
对于一个需要 2 个输入的模型,它们必须作为数组提供给 `fit()`。
嗨 Jason,问题是关于输出,而不是输入。问题是,如果我在 `Model()` 中设置 `outputs=[lstm1, state_h, state_c]`,那么 `fit()` 函数将期望三个数组作为目标数组。
嗨 Alex,你找到如何处理这种情况下的拟合了吗?
假设我有
model = Model(inputs=[input_x, h_one_in , h_two_in], outputs=[y1,y2,state_h,state_c])
我该如何编写我的 `mode.fit`? 在输入和输出中?
谢谢,
+1
我使用随机初始化,但结果令人失望。
还有其他想法吗?
看看这个 notebook,不是 LSTM,但训练和测试数据形状类似。
在 `inp_data_generator` 函数中,它产生类似的数据,匹配模型的输入和输出(输入和输出被组合在一起)。
即:`yield [np.array(inp_batch), np.array(ext_batch)], [np.array(touch_batch), np.array(cropped_batch)] # [x1, x2], [y1, y2]`
并且模型拟合调用如下:
`history = model.fit(train_data, validation_data = validation_data, validation_steps = validation_steps_per_epoch, steps_per_epoch = train_steps_per_epoch, epochs = epochs, callbacks = [early_stop])`
Jason,
一如既往的精彩博文。我也会购买您的 LSTM 书籍。
不过,我有一个关于 Keras LSTM 错误的问题,希望能得到您的帮助?
出现类似这样的错误:
“您必须为占位符张量 'embedding_layer_input' 提供值”
/usr/local/lib/python3.5/site-packages/tensorflow/python/framework/errors_impl.py in raise_exception_on_not_ok_status()
465 compat.as_text(pywrap_tensorflow.TF_Message(status)),
--> 466 pywrap_tensorflow.TF_GetCode(status))
467 finally
InvalidArgumentError: 您必须为占位符张量 'embedding_layer_input' 提供 dtype float 的值
[[Node: embedding_layer_input = Placeholder[dtype=DT_FLOAT, shape=[], _device=”/job:localhost/replica:0/task:0/gpu:0″]()]]
[[Node: output_layer_2/bias/read/_237 = _Recv[client_terminated=false, recv_device=”/job:localhost/replica:0/task:0/cpu:0″, send_device=”/job:localhost/replica:0/task:0/gpu:0″, send_device_incarnation=1, tensor_name=”edge_1546_output_layer_2/bias/read”, tensor_type=DT_FLOAT, _device=”/job:localhost/replica:0/task:0/cpu:0″]()]]
处理上述异常时,发生了另一个异常
这是我为此编写的代码:
def model_param(self)
# 执行深度学习的方法
来自 keras.models import Sequential
from keras.layers import Dense, Flatten, Dropout, Activation
from keras.layers import LSTM
from keras.layers.embeddings import Embedding
from keras.initializers import TruncatedNormal
tn=TruncatedNormal(mean=0.0, stddev=1/sqrt(self.x_train.shape[1]*self.x_train.shape[1]), seed=2)
self.model = Sequential()
self.model.add(Embedding(self.len_vocab,300,input_length=self.x_train.shape[1]))
# 添加 LSTM 单元
self.model.add(LSTM(self.num_units,dropout=0.30,kernel_initializer=tn,name=”lstm_1″))
# 添加用于输出的密集输出层
self.model.add(Dense(1,activation=”sigmoid”,name=”output_layer”))
#sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
self.model.compile(loss=’binary_crossentropy’,
optimizer=”adam”,
metrics=['accuracy'])
self.model.summary()
def fit(self)
# 在训练数据上训练深度学习网络
# 添加用于日志记录的回调
import keras
logger_tb=keras.callbacks.TensorBoard(
log_dir=”logs_sentiment_lstm”,
write_graph=True,
histogram_freq=5
)
self.model.fit(self.x_train, self.y_train,validation_split=0.20,
epochs=10,
batch_size=128,callbacks=[logger_tb]
)
哎呀,我之前没见过这个错误。
也许试试简化示例来找出原因?
`histogram_freq=5` 导致此错误,这是 Keras 中的一个 bug,将 `histogram_freq=0` 设置为 0 应该可以正常工作。
感谢分享。
这是另一篇很棒的博文 Jason!我是您所有 RNN 博文的粉丝。😉 谢谢!
如果有人想知道 LSTM 中的 c(内部状态)和 h(隐藏状态)之间的区别,这个回答对我很有帮助:
https://www.quora.com/What-is-the-difference-between-states-and-outputs-in-LSTM
说 GRU 和 SimpleRNN 中的 c = h 是否正确?
提前感谢!
谢谢 Julian。
嗨,Jason,
在 Keras 的编码器-解码器实现中,我们在编码器网络中执行 return state,这意味着我们在获取 `state_h` 和 `state_c` 之后,将 `[state_h,state_c]` 设置为解码器网络的初始状态。为 LSTM 网络设置初始状态意味着什么?它是否意味着解码器的 `state_h` = `[state_h,state_c]`?
提前感谢。
好问题,这是一个例子。
https://machinelearning.org.cn/develop-encoder-decoder-model-sequence-sequence-prediction-keras/
好的。我想我现在明白了。基本上,当我们为 LSTM 设置 `return_state=True` 时,LSTM 将接受三个输入,即 `decoder_actual_input`、`state_h`、`state_c`。在推理过程中,我们再次使用前一个预测的 `state_h` 和 `state_c` 重置 `state_c` 和 `state_h`。我的理解正确吗?
我仍然有点困惑为什么我们使用三个 Keras 模型(`model`、`encoder_model` 和 `decoder_model`)。
谢谢。
`return_state` 参数仅控制是否返回状态。在定义模型(例如使用函数式 API)时,使用另一个参数来初始化 LSTM 的状态。
明白了。是 `initial_state`。谢谢 Jason。
很高兴听到这个消息。
嗨,Jason,
我真的很喜欢读您的博客。我对于这篇博文有 2 个简短的问题,希望您能简要地解答一下。
1.我们能返回单元状态序列(类似于 *lstm1* 的一种变量)吗?
2.无论输入序列的维度(我的意思是特征数量)如何,只要我们在层中放置 1 个 LSTM 单元,隐藏状态和单元状态总是标量,对吗?因此,Keras 中每个门上的 `kernel_` 和 `recurrent_kernel_` 属性不是矩阵形式。但是,我认为您关于将每个 LSTM 单元视为具有 1 维隐藏状态/单元的观点在深度学习中的 dropout 情况是有道理的。
如果我误解了您的博文,请纠正我。谢谢。
不直接,也许可以通过递归调用模型来完成。
我想你说得对。
我对 Q1 有同样的问题,那么您是如何输出单元状态序列的?谢谢。
通常不行。您输出的是激活序列,在论文中称为 h。
嗨,非常好的解释。
一个问题,我认为 h = activation(o),对吗?(h:隐藏状态输出,o:隐藏单元)
但是 tanh(-0.19803026) 不等于 -0.09228823。(LSTM 的默认激活应该是 tanh)
非常感谢您,Jason。这消除了我的疑虑。
很高兴听到这个消息。
非常感谢您写下这篇博文。这确实非常有帮助。
谢谢,很高兴对您有帮助。
嘿 Jason,当使用双向包装器时,如何同时获取最终隐藏状态和序列?
上面的博文没有帮助吗?
嗨 Jason,我能否将一个密集层的输出连接到 LSTM 的 c 状态,以便在每个批次之前用该值初始化 c 状态?谢谢
我很确定你可以(这都只是代码),但这可能需要一些精心的编程。我没有别的建议,只能说多尝试、多出错。
告诉我进展如何。
第一个输入如果没有先前的隐藏状态或单元状态可以参考,那么它的隐藏状态和单元状态是什么?
它将是零。
当我使用基于双向 LSTM 的以下代码时,它会返回此错误
‘未连接,没有输入可以返回。’)
AttributeError: Layer sequential_1 is not connected, no input to return.
但当我运行普通的 LSTM(注释掉的代码)时,它返回正确。
self.model = Sequential()
# self.model.add(LSTM(input_shape=(None,self.num_encoder_tokens), units=self.n_hidden,
# return_sequences=True,name=’hidden’))
# self.model.add(LSTM(units=self.num_encoder_tokens, return_sequences=True))
# self.intermediate_layer = Model(inputs=self.model.input, outputs=self.model.get_layer(‘hidden’).output)
self.model.add(Bidirectional(LSTM(input_shape=(None,self.num_encoder_tokens), units=self.n_hidden,
return_sequences=True,name=’hidden’),merge_mode=’concat’))
self.model.add(Bidirectional(LSTM(units=self.num_encoder_tokens, return_sequences=True),merge_mode=’concat’))
self.intermediate_layer = Model(input=self.model.input,output=self.model.get_layer(‘hidden’).output)
为什么?
我在这里有一些建议
https://machinelearning.org.cn/faq/single-faq/why-does-the-code-in-the-tutorial-not-work-for-me
https://stackoverflow.com/questions/49313650/how-could-i-get-both-the-final-hidden-state-and-sequence-in-a-lstm-layer-when-us
This can help
对此没有回复吗?
非常感谢您的解释!
很高兴能帮到你,Sam!
Jason,你的工作太棒了。我一直以为最后一个隐藏状态等于单元状态。所以我错了,隐藏状态和单元状态永远不会相同吗?
谢谢你
是的,它们是不同的东西。
你好,
我只是想感谢你提供的整个网站。
每当我遇到代码或概念上的困难时,我都会访问你的网站,问题就会迎刃而解。
谢谢,很高兴能帮到你!
所以,在上面的例子中,我们的网络只包含一个 LSTM 节点或单元吗?
而且输出是逐个时间戳地馈入它,一次一个?
还是它为每个时间戳都有 3 个单元?
LSTM 中的节点数量与数据样本中的时间步长数量无关。
也许这会让你更清楚
https://machinelearning.org.cn/prepare-univariate-time-series-data-long-short-term-memory-networks/
“通常,我们不需要访问单元状态,除非我们正在开发复杂的模型,其中后续层需要以另一个层的最终单元状态来初始化其单元状态,例如在编码器-解码器模型中。”
在你另一篇博文中,编码器-解码器 LSTM 模型代码如下:
model.add(LSTM(200, activation='relu', input_shape=(n_timesteps, n_features)))
model.add(RepeatVector(n_outputs))
model.add(LSTM(200, activation=’relu’, return_sequences=True))
但 return_state = false?
正确。
你好 Jason,
感谢您的精彩博文。我有一个关于 LSTM 编码器中瓶颈的快速问题。据我所知,如果编码器有 50 个单元,那么 LSTM 编码器层的隐藏状态是否包含 50 个值,每个单元一个?
如果这是正确的,那么说如果原始数据有 50 个时间步长和 3 个维度/特征计数,那么拥有一个具有 20 个单元(会给出 20 个值的隐藏状态)的编码器 LSTM 可以被认为是某种压缩/降维(类似于自动编码器和压缩表示)是否准确?
最后,将一个具有某些非线性的全连接层应用于隐藏状态以进行降维是否有意义,即隐藏状态具有 50 个值 -> FFlayer 具有 10 个神经元,“压缩”50 个值到 10 个…?
再次感谢
是的,没错。
如果你想将隐藏状态用作学习到的特征,你可以将其馈入一个新的全连接模型。
太棒了,谢谢!
精彩的博文,如何在使用时保存状态,预测样本来自多个来源,就像这里的问题一样 https://stackoverflow.com/questions/54850854/keras-restore-lstm-hidden-state-for-a-specific-time-stamp ?
你可以通过从模型中检索状态并将其保存到文件来保存状态。
非常感谢您 🙂
亲爱的Jason
非常感谢您提供的精彩博文。我目前正在研究双流 LSTM 网络(图像序列),并且我尝试提取每个时间步长的两个 LSTM 的单元状态并计算平均值。然后用前一个时间步的平均值 + 现有的单元状态值来更新下一个时间步。并继续这个过程直到所有时间步。
如果您能向我解释如何按时间步更新 LSTM 单元状态(通过提供附加值),我将非常感激。非常感谢。
你为什么想要平均单元状态呢?
非常感谢您的回复。我正在这样做:
请注意,第二个 LSTM 用于光流流,不小心注释掉了 RGB 的两个 LSTM。谢谢。
为什么?你为什么想这样做?
我目前正在研究具有图像序列的双流网络。我想研究一下,与没有通信(就像正常的双流网络一样)相比,在两个流的每个时间步长之间通信单元状态是否有什么优势,作为我研究的一部分。感谢您的关心。
我目前正在研究具有图像序列的双流网络。我想研究一下,与没有通信(就像正常的双流网络一样)相比,在两个流的每个时间步长之间通信单元状态是否有什么优势,作为我研究的一部分。感谢您的关心。
有意思,让我知道你的进展。
非常棒的文章,非常感谢:)
谢谢。
它真的解决了我的困惑。谢谢 🙂
很高兴听到这个消息。
谢谢 Jason,
您能否告诉我如何在 LSTM 上使用 Bidirectional 包装器返回状态?输出解包时出错
代码
encoder = Bidirectional(LSTM(n_a, return_state=True))
encoder_outputs, state_h, state_c = encoder(encoder_inputs)
错误
ValueError: too many values to unpack (expected 3)
也许将其结果分配给一个变量并检查它以了解您拥有什么?
问题:LSTM 是否只将隐藏状态转发到上层,还是也将内存单元状态转发到上层?
或者内存单元状态只沿着时间序列转发?
谢谢!
只有隐藏状态被输出,内存状态保持在节点内部。
嗨,Jason,
感谢分享。我不确定我是否正确理解 Keras.LSTM。您能否帮助我澄清/纠正以下陈述?
1. Keras LSTM 默认是输出到隐藏的递归,例如,它将前一个输出发送到当前隐藏层;
2. 要创建隐藏到隐藏的 LSTM,我们可以这样做
lstm1, state_h, state_c = LSTM(1, return_sequences=True, return_state=True)(inputs1)
model = Model(inputs=(inputs1, state_h), outputs=lstm1)
3. Keras 使用教导强制还是 BPTT 来训练 LSTM?
我不确定。LSTM 有输出和隐藏状态。
抱歉造成混淆。我的输出到隐藏指的是 Goodfellow 的深度学习:第 10 章中的三种模式中的第二种
”
循环神经网络的一些重要设计模式包括以下内容:
• 循环网络在每个时间步生成输出,并且隐藏单元之间存在循环连接,如图 10.3 所示。
• 循环网络在每个时间步生成输出,并且隐藏单元之间仅存在从一个时间步的输出到下一个时间步的隐藏单元的循环连接,如图 10.4 所示。
• 具有隐藏单元之间循环连接的循环网络,它读取整个序列然后生成单个输出,如图 10.5 所示。
“
回到我的问题
1. Keras LSTM 默认是模式 2(前一个输出到当前隐藏)吗?
2. 我们可以使用 return_state 来创建一个模式 1(前一个隐藏到当前隐藏)模型吗?
3. Keras 使用 BPTT 进行训练吗?或者它可以根据模式在教导强制和 BPTT 之间进行选择?
如果你指的是层内的横向连接,那么不是。如果你指的是跨层连接,那么是。
是的,Keras 支持 BPTT 的一个版本,更多信息请参见此处(通用)
https://machinelearning.org.cn/gentle-introduction-backpropagation-time/
以及此处(Keras)
https://machinelearning.org.cn/truncated-backpropagation-through-time-in-keras/
谢谢你,Jason!
你好,Jason。
我想堆叠 2 个 GRU。第一个有 64 个隐藏层,第二个有 50 个隐藏层
我不确定如何定义它。
你能帮忙吗
encoder_inputs = Input(batch_shape=(32, 103, 1), name=’encoder_inputs’)
encoder_gru1 = GRU(64, return_sequences=True, return_state=True,name=’encoder_gru1′)
encoder_out1, encoder_state1 = encoder_gru1(encoder_inputs)
encoder_gru2 = GRU(50, return_sequences=True, name=’encoder_gru’) encoder_out, encoder_state = encoder_gru2(encoder_out1)
decoder_gru = GRU(50, return_sequences=True, name=’decoder_gru’)
decoder_out, decoder_state = decoder_gru(encoder_out)
但是我得到了以下错误
encoder_out, encoder_state = encoder_gru2(encoder_out1)
File “C:\Users\Harshula\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\framework\ops.py”, line 457, in __iter__
“Tensor objects are only iterable when eager execution is ”
TypeError: Tensor objects are only iterable when eager execution is enabled. To iterate over this tensor use tf.map_fn.
你可以使用这个教程作为起点,并将 LSTM 改为 GRU。
https://machinelearning.org.cn/stacked-long-short-term-memory-networks/
感谢这些易于理解的文章。我有一个问题,如何绘制预测?我的意思是,当我对代码应用正弦波以查看 LSTM 的三个输出时,我如何以连续信号的形式绘制输出?
你可以使用 matplotlib 和 plot() 函数。
我的意思是我想绘制 lstm1、state_h、state_c。但当我像这样写 model.fit 时
model.fit(trainX, trainY=[lstm1, state_h, state_c], epochs=10, batch_size=1, verbose=2)
我得到了这个错误
TypeError: Unrecognized keyword arguments: {‘trainY’: [, array([[]],
dtype=object), array([],
dtype=object)]}
lstm1、state_h、state_c 是否都应该具有三维?
这看起来真的很错误,例如,状态变量作为 fit 调用中的目标变量。
你具体想实现什么?
嗨 Jason
我的代码有三个 LSTM 输出:output、hidden_state、cell_state。
我想看到所有这些。
lstm, h, c = LSTM(units=20, batch_input_shape=(1,10, 2), return_sequences=True,
return_state=True)(inp)
dense = Dense(2)(lstm)
model = Model(inputs=inp, outputs=dense )
我想绘制我的所有三个输出。我可以绘制 lstm,但我无法绘制 h_state 和 c_state。
我该怎么做?
这很奇怪。
不过,你可以使用 matplotlib 来绘制任何你想绘制的东西。例如,plot(…)
你好 Jason,
感谢这篇好文章。
我有两个 Bi-LSTM 的两个隐藏状态,H1 和 H2,我想将它们用作两个 Dense 层的输入。我应该将这两个密集层与两个 Bi_LSTM 连接起来,然后就完成了?还是直接将它们连接到隐藏状态?
类似这样
hidden1 = Dense(100)(H1)
hidden2 = Dense(100)(H2)
再次感谢!
如果你所说的隐藏状态是指 LSTM 层内部的那些状态,那么我认为没有有效的方法可以将它们传递给密集层。
如果你指的是层的输出(这是常用含义),那么这样看起来是好的。
为了更清楚,我有两个文本输入,我使用 embedding 来编码它们,然后将 embedding 的输出放入两个 Bi-LSTMs 中。
所以我想使用这两个 Bi-LSTM 的隐藏状态来进行预测。第一个输入的隐藏状态如上返回
lstm, forward_h, forward_c, backward_h, backward_c= Bidirectional(..)(Embedding)
并且 H1 计算方式为:H1 = Concatenate()([forward_h, backward_h])。
我对第二个输入做了同样的事情,并计算了 H2。
数学上,我该如何实现上述公式
softmax(V tanh(W1*H1 + W2*H2))
其中 W 和 V 分别代表所有可训练的参数矩阵和向量。
Jason,感谢你的帮助。
干得好!
看起来你想做加权求和,也许是自定义层?
也许吧,但为了降低复杂性,我删除了两个 Bi-LSTM,所以只使用 embeddings 进行编码。
所以为了进行分类,使用这两个 embeddings,我可以使用这个数学公式:softmax(V tanh(W1*E1 + W2*E2))?如果是这样,上面的代码是否正确地表示了它?
input1 = Input(shape=(25,))
E1 = Embedding(vocab_size, 100, input_length=25,
weights=[embedding_matrix], trainable=False)(input1 )
input1_hidden1 = Dense(100)(E1)
input2 = Input(shape=(25,))
E2 = Embedding(vocab_size, 100, input_length=25,
weights=[embedding_matrix], trainable=False)(input2 )
input1_hidden2 = Dense(100)(E2 )
added = add([userQuestion_hidden1, tableShema_hidden1])
added = Activation(‘tanh’)(added)
output1 = Dense(1, activation=’softmax’)(added)
model = Model(inputs=[input1 , input2],outputs=output1)
我很乐意提供帮助,但我没有能力审查/调试你的代码。
也许可以试试在 Keras 用户组发帖?
https://machinelearning.org.cn/get-help-with-keras/
这很有趣,非常感谢 Jason
不客气。
请,我有一个错误
TypeError: `GRU` 只能接受 1 个位置参数(‘units’),但您传递了以下位置参数:[4, 200]
也许这能帮助你更好地理解输入形状
https://machinelearning.org.cn/faq/single-faq/what-is-the-difference-between-samples-timesteps-and-features-for-lstm-input
精彩的解释!
我只有一个困惑。
在第一个例子中,LSTM 定义为 LSTM(1)(inputs1),Input 定义为 Input(shape=(3,1))。
所以,你重塑数据的方式(1,3,1)意味着时间步值是 3(中间值),而 LSTM 中的单元数量是 1,即 LSTM(1)。
我对 1-LSTM 将如何处理 3 个时间步长值感到困惑。我的意思是,难道不应该有 3 个神经元/LSTM(3) 来处理(1,3,1)形状的数据吗?或者 LSTM 会逐个输入进行处理?
谢谢
谢谢。
更多关于时间步长与样本和特征的关系
https://machinelearning.org.cn/faq/single-faq/what-is-the-difference-between-samples-timesteps-and-features-for-lstm-input
LSTM 单元的数量与时间步长/特征/样本无关。
完全清楚。这对我帮助很大。
谢谢,很高兴听到这个!
你好,
感谢清晰的讨论。我有一个关于略有不同的实现的问题。我有一个带有 LSTM 层的模型,其中最后一个时间步的隐藏层将传递给 softmax 以创建情感。有没有办法在我向模型传递新序列时访问这些隐藏状态?
是的,你可以使用函数式 API 定义模型,将隐藏状态作为模型的单独输出。
你好,
感谢清晰的解释。我正在尝试构建一个编码器-解码器模型,但这个模型将有两个解码器(d1和d2)和一个编码器。一个解码器(d1)只从编码器获取输入,而另一个解码器(d2)将从编码器和其他解码器(d1)获取输入。d2应该只在d1做出特定类型的预测时才从d1获取隐藏状态。两个解码器有不同的词汇表。假设d1有“a,b,c,d”,d2有“P,Q,R,S”。我想在d1预测“b”时将隐藏状态从d1传递到d2。
我希望我的陈述能让你理解我正在做什么。谢谢!
这听起来很复杂。不确定我能为你做些什么,抱歉。
也许可以尝试不同的原型,直到达到你的要求?
亲爱的 Jason,
我经常来你的网站查找问题。你所有的文章都非常简洁,这篇关于返回序列和返回状态的文章也是如此。没有复杂的代码,直击要点。感谢你所做的出色工作。
我有一个问题。如果在上面的例子中,我们不使用LSTM(1),而是使用LSTM(5)呢?
inputs1 = Input(shape=(3, 1))
lstm1 = LSTM(5, return_sequences=True)(inputs1)
那么我的输出将是一个3D数组。但我很好奇LSTM在每个时间步是如何生成5个隐藏状态的。
每个LSTM不是有1个隐藏状态和1个单元状态吗?
你能否解释一下我的问题?
好问题,请看这个
https://machinelearning.org.cn/faq/single-faq/how-is-data-processed-by-an-lstm
[[[0.1]
[0.2]
[0.3]]] 是输入到LSTM的数据。但是,LSTM的输入可以是[[0.1 0.2 0.3]]吗?
好的,我找到了答案。LSTM层只接受3D格式的输入。
https://machinelearning.org.cn/reshape-input-data-long-short-term-memory-networks-keras/
Jason,
一个快速的问题。
当你输出一个单一的隐藏状态时,这是否意味着基于数据集[t1, t2, t3]的t4的预测?还是t3的预测?
同样,在输出三个时间步的隐藏状态时,这是否意味着对[t1, t2, t3]或[t2, t3, t4]的预测?
另外,如果我们想获得一个提前n步的单一隐藏状态输出(t+n),我们应该如何在你的例子中指定它?
谢谢,并希望尽快得到你的回复!
这是个愚蠢的问题。
这里没有基于时间步的预测设置,包括数据准备和相应的训练。数据准备和训练。
我会字面理解隐藏状态输出为携带从t1到t3的信息的输出。
谢谢
当你使用return state时,你只获得最后一个时间步的状态。
谢谢你,Jason!
您的材料对我学习非常有帮助。
您的简单清晰的解释是新手真正需要的。
不客气!
我的LSTM是这样的
def _get_model(input_shape, latent_dim, num_classes)
inputs = Input(shape=input_shape)
lstm_lyr,state_h,state_c = LSTM(latent_dim,dropout=0.1,return_state = True)(inputs)
fc_lyr = Dense(num_classes)(lstm_lyr)
soft_lyr = Activation(‘relu’)(fc_lyr)
model = Model(inputs, [soft_lyr,state_h,state_c])
model.compile(optimizer=’adam’, loss=’mse’, metrics=[‘accuracy’])
return model
model =_get_model((n_steps_in, n_features),latent_dim ,n_steps_out)
history = model.fit(X_train,Y_train)
print (history.history.keys)
dict_keys(['loss', 'activation_26_loss', 'lstm_151_loss', 'activation_26_accuracy', 'lstm_151_accuracy', 'val_loss', 'val_activation_26_loss', 'val_lstm_151_loss', 'val_activation_26_accuracy', 'val_lstm_151_accuracy'])
我得到了2个损失和3个准确率,如下所示
Epoch 1/2000
1/1 [==============================] – 1s 698ms/step – loss: 0.2338 – activation_26_loss: 0.1153 – lstm_151_loss: 0.1185 – activation_26_accuracy: 0.0000e+00 – lstm_151_accuracy: 0.0000e+00 – val_loss: 0.2341 – val_activation_26_loss: 0.1160 – val_lstm_151_loss: 0.1181 – val_activation_26_accuracy: 0.0000e+00 – val_lstm_151_accuracy: 0.0000e+00
如何解读这些损失和准确率?
如果您使用MSE损失,那么计算准确率是无效的。您可以在这里了解更多信息
https://machinelearning.org.cn/faq/single-faq/how-do-i-calculate-accuracy-for-regression
在《Long short term memory network with python》这本书的第102页和第104页。
我发现当我运行列表8.25中的程序时,我发现
Sequential对象没有predict_classes方法
请看
https://tensorflowcn.cn/api_docs/python/tf/keras/Sequential
请注意,只有“predict, predict_on_batch, predict_step”方法。\[***不再使用predict_classes了]
在《Long short term memory network with python》这本书的第102页和第104页。
我发现当我运行列表8.25中的程序时,我发现
# 预测新数据
X, y = generate_examples(size, 1)
yhat = model.predict_classes(X, verbose=0) // 问题出在这里
expected = “Right” if y[0]==1 else “Left”
predicted = “Right” if yhat[0]==1 else “Left”
print(‘Expected: %s, Predicted: %s’ % (expected, predicted)
来自compile的错误
有一个错误消息:“Sequencial对象在其类中没有***属性‘predict_classes’”
并且从互联网上得到一些信息,
model.predict_classes方法已弃用。它已在2021-01-01之后删除。
这意味着我们不能再使用predict_classes了。
解决办法
然后我通过替换“yhat”为以下两行来解决:
“ from numpy as np ”
“yhat = np.argmax( model.predict(X), axis= -1)”
在我替换并添加了两行之后
一切都可以成功运行。
我这样做对吗?
请回答我
你是对的。你做得非常完美。
尊敬的Jason博士,
感谢您的教程。
在“Return Sequences”部分,你有一个序列
请问:
* 我原以为序列中的下一个值会是0.4左右,但在例子中以及我自己尝试时,如上例所示,它是
然而,在https://machinelearning.org.cn/how-to-develop-lstm-models-for-time-series-forecasting/ 中,序列是
输出接近100
换句话说,在第一个输入为[0.1,0.2,0.3]的例子中,为什么我们得到-0.09而不是接近0.4的东西?同样,对于[70,80,90]的序列,我们得到了接近100的东西,即101?
谢谢你
悉尼的Anthony
正如所说,“您的具体输出值将因LSTM权重和单元状态的随机初始化而异。”
这个预测是来自一个未经训练的模型,因此是随机的,取决于LSTM层的初始化。如果您执行了model.fit(),您应该会看到更好的结果(前提是您有足够的数据进行训练,而在此特定示例中,我们没有)。
尊敬的 Adrian 博士,
关键概念是模型是“未经训练的”,模型构建中的关键陈述是“model.fit()”,而这个还没有实现来训练模型。
感谢您的澄清。
来自悉尼的Anthony。
不客气!
尊敬的Jason博士,
在“Return States”子标题下,
当你使用return_states = True在
请澄清最后两个数字。
在本教程的文本中,它说“…运行示例将返回一个包含3个值的序列,每个输入时间步的隐藏状态输出,以及层中的单个LSTM单元…”
如果第一个值是预测值,那么你有一个“一个隐藏状态输出”,那么第三个输出-0.11是什么,例如在以下输出中。
谢谢你,
悉尼的Anthony
LSTM有一个单元状态、一个隐藏状态和一个输出。您引用的三个数字都是输出,每个输入[0.1, 0.2, 0.3]各一个。
请参阅此Stack Overflow问题的图示:https://stackoverflow.com/a/50235563
尊敬的 Adrian 博士,
谢谢你的回复。
在LSTM模型中,您提到它有一个单元状态、一个隐藏状态和一个输出。
请澄清以下来自示例模型的3D数组中数字的顺序。
问题是3D数组中的数字顺序,单元状态、隐藏状态和输出?
然后我尝试使用以下代码进行model.fit()
我想要一个提前一步的预测x。
但我收到了一个错误。
“split_sequence”是基于“Vanilla LSTM”子标题下的https://machinelearning.org.cn/how-to-develop-lstm-models-for-time-series-forecasting/。
谢谢你,
悉尼的Anthony
您的模型期望输入形状为(3,1),但您调用了“x, y = split_sequence(data,1)”来生成输入形状为(1,1)——因此,将其更改为“x, y = split_sequence(data,3)”应该可以解决问题。
尊敬的 Adrian 博士,
不幸的是,修改并未奏效。我仍然遇到了运行时错误。
所以我做了的是复制“Return Sequences”子标题下的代码,并添加compile和fit。
结果:没有错误,也没有我期望的0.4这个数字。
但即使如此,我也无法预测下一个值会是0.4。
总结
* 我将x的形状设置为(1,3,1) = shape (samples, time_steps, features),如https://machinelearning.org.cn/reshape-input-data-long-short-term-memory-networks-keras/ 所示。
x = array([0.1, 0.2, 0.3]).reshape((1,3,1))
* 我将y的形状设置为(1,3) = shape (samples, time_steps)
y = array([0.2,0.3,0.4]).reshape((1,3))
* 添加了原始模型中没有的compile和fit。
* 目标是预测y的下一个值是0.5。
结果:我没有从预测中找到任何接近0.5的y的值。
谢谢你,
悉尼的Anthony
300 个 epoch,batch_size=1,数据集大小为 1,意味着你只有 300 次机会来更新网络权重。我尝试将其提高到 10000,似乎产生了更好的结果。另外,由于你没有使用也没有训练 return_state,可以尝试将其设置为 False。
尊敬的 Adrian 博士,
谢谢你的回复。
通过将 return_state 设置为 False,我遇到了以下运行时错误:
然而,保持 return_state=True,我没有遇到问题。尽管如此,我没有发现任何与预测值 0.4 匹配的结果。
当 epochs=1000 时。最后一个值接近 0.4,为 0.377
当 epochs = 2000 时,最后一个值是 0.345,更接近 0.4
当 epochs = 4000 时,最后一个值是 0.303,与 0.4 的偏差更大
当 epochs = 8000 时,最后一个值是 0.322,更接近 0.4
当 epochs = 16000 时,最后一个值是 0.308,与 0.4 的偏差更大
总结
* 设置 return_state=False 时,会发生运行时错误。
* 增加 epoch 的数量并不一定意味着更准确。在此实验中,将 epoch 增加到 16000 所产生的预测效果比 epoch 数量为 2000 时还要差。
* 我想了解为什么一个 LSTM 对于一个非常短的数组未能准确预测序列中的下一个值。
谢谢你,
悉尼的Anthony
如果您将 return_state 设置为 False,您的 LSTM 将只返回输出,而不返回状态。因此,您应该这样写:
尊敬的 Adrian 博士,
谢谢你的回复。
通过这个修改,结果似乎有了很大的改善。
epochs = 300,最终值 = 0.32
epochs = 1000,最终结果 = 0.417
epochs = 2000,最终结果 = 0.4
epochs = 4000,最终结果 = 0.391
这是最终的程序,然后我将进行总结和提问。
总结
* “简化”模型没有产生运行时错误。只对 lstm 输出感兴趣。
* 使用 return_state=False 得到更准确的结果。
* 增加 epoch 的数量也可能增加准确性,这从每个 epoch 的误差大小可以看出。但是,增加 epoch 的数量也可能导致误差增加。在这种情况下,epoch > 2000 导致误差增加且结果不准确。
* 为了获得最小误差,更准确的 epoch 数量可能在 1000 到 2000 之间。最优 epoch 数量可以通过图形化或使用早停机制来确定。
* 关于“return_states=True”和“return_states=False”的说明。当“return_states = True”时,结果不太准确。
还有更多问题请教。
* 为了获得最佳结果,epoch 的数量超过了 1000。这是一个如此简单的 AR(1) 过程,为什么需要这么多的 epoch 才能产生准确的结果?
* 我想用一个新的 x 来预测。
(i) 为什么我需要一个长度为 3 的数组 [0.2, 0.3, 0.4] – 为什么我不能用长度为 1 的数组 [0.4] 进行预测?
(ii) 为了让结果接近 0.5,我不得不将 epoch 的数量增加到 10000,但结果只有 0.45805833,而不是预期的 0.5。
(iii) 当我使用 return_states=True 时,结果不太准确。需要澄清 return_states=False 和 return_states=True,虽然有文档,但对于一个简单的模型,当 return_states = True 和 return_states = False 时,对最终结果的影响没有说明。
再次感谢您的帮助,它让我对这个概念有了更清晰的理解。
悉尼的Anthony
(i) 因为你设置了 return_sequence=True。
(ii) 因为你的数据太少了,LSTM 无法学习,这是规则。
(iii) 你可以凭经验看到效果。我没有深入研究代码来解释原因,但我猜 TensorFlow 的内部设计使得它不关心未使用的变量,从而更好地训练了网络,有点像增加了信号并减少了噪声。
尊敬的 Adrian 博士,
再次感谢您的回复,我很感激。
我理解了对 (ii) 和 (iii) 的回答,特别是关于需要更长的序列长度以及接受 TensorFlow 后端在处理 return_states=True 或 False 时的潜在怪癖。
尽管如此,对于 (i),即使设置了 return_sequences=False,我仍然不明白为什么在我没有的时候,我仍然需要 len(x) = 3 而不是 1。
我必须要有长度为 3 的 x 才能进行预测。
我无法拥有 x = array([0.4]).reshape((1,1,1)) 来进行预测。
我得到了一个运行时错误。
换句话说,如果我只想预测一个值,为什么我需要三个值作为输入?
无论如何,我很感激您的回复,因为它们帮助我更好地理解。
谢谢你,
悉尼的Anthony
您应该注意到您传递了一个输入层到 LSTM 层。在输入层,您已经指定了预期的形状。因此是 3,而不是 1。
尊敬的 Adrian 博士,
结论是,如果您想为 LSTM 模型进行预测,预测数据的形状必须与 LSTM 的输入层的 3D 形状相同。
再次非常感谢您的回复。
悉尼的Anthony
是的,这是正确的。我认为这部分是 Keras 设计强加的限制。
尊敬的 Adrian 博士,
谢谢,很感激。
悉尼的Anthony
你好 Adrian,
如果可以这样获得输出,是否也可以以某种方式更改 RNN 和 LSTM 层,以便可以使用几个隐藏状态作为输入和 LSTM 单元内部?
如果可以,RNN 层需要改变什么/可以使用什么?我认为先连接隐藏状态不起作用,因为我希望之后在单元内将它们分开。
感谢您的回答。
您好 Steffen……请将您的帖子内容精简为关于教程内容、代码列表或电子书的具体问题,以便我能更好地帮助您。
我对输入-隐藏-输出层感到困惑。默认情况下是否有一个输入层和一个输出层?当我们向模型添加层时,我们只是在更改隐藏层吗?
广告对于继续运行节目很重要,但不幸的是,它们确实令人烦恼,使我们在阅读内容时无法集中注意力。