长短期记忆 (LSTM) 网络是一种能够学习长序列的循环神经网络。
这使它们不同于普通的没有记忆且只能学习输入和输出模式之间映射的多层神经网络。
了解像 LSTM 这样的复杂神经网络在小型人造问题上的能力很重要,因为这种理解将帮助您将网络扩展到大型甚至超大型问题。
在本教程中,您将发现 LSTM 记忆和回忆的能力。
完成本教程后,您将了解:
- 如何定义一个只有像 LSTM 这样的 RNN 才能通过记忆解决的小型序列预测问题。
- 如何转换问题表示,使其适合 LSTM 学习。
- 如何设计 LSTM 以正确解决问题。
通过我的新书《使用 Python 的长短期记忆网络》启动您的项目,包括分步教程和所有示例的 Python 源代码文件。
让我们开始吧。

长短期记忆网络中的内存演示
图片来自 crazlei,保留部分权利。
环境
本教程假设您有一个带有 SciPy、Keras 2.0 或更高版本以及 TensorFlow 或 Theano 后端的 Python 2 或 3 工作环境。
有关设置 Python 环境的帮助,请参阅以下帖子
序列问题描述
问题是逐个预测序列的值。
给定序列中的一个值,模型必须预测序列中的下一个值。例如,给定输入值“0”,模型必须预测值“1”。
模型必须学习并正确预测两个不同的序列。
一个难题是两个序列之间存在冲突信息,并且模型必须知道每个一步预测的上下文(例如,它当前正在预测的序列)才能正确预测每个完整序列。
这个难题很重要,可以防止模型记忆每个序列中的每个单步输入-输出值对,因为不了解序列的模型可能会倾向于这样做。
要学习的两个序列如下
- 3, 0, 1, 2, 3
- 4, 0, 1, 2, 4
我们可以看到序列的第一个值作为序列的最后一个值重复。这是为模型提供上下文的指示符,说明它正在处理哪个序列。
冲突是每个序列中倒数第二个项目之间的转换。在序列一中,输入为“2”,必须预测“3”,而在序列二中,输入为“2”,必须预测“4”。
这是一个多层感知器和其他非循环神经网络无法学习的问题。
这是 Hochreiter 和 Schmidhuber 1997 年论文长短期记忆 (PDF) 中用于演示 LSTM 长期记忆能力的“实验 2”的简化版本。
需要 LSTM 帮助进行序列预测吗?
参加我的免费7天电子邮件课程,了解6种不同的LSTM架构(附代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
问题表示
本节分为 3 个部分;它们是
- 独热编码
- 输入-输出对
- 重塑数据
独热编码
我们将使用独热编码来表示 LSTM 的学习问题。
也就是说,每个输入和输出值都将表示为具有 5 个元素的二进制向量,因为问题的字母表是 5 个唯一值。
例如,[0, 1, 2, 3, 4] 的 5 个值表示为以下 5 个二进制向量
1 2 3 4 5 |
0: [1, 0, 0, 0, 0] 1: [0, 1, 0, 0, 0] 2: [0, 0, 1, 0, 0] 3: [0, 0, 0, 1, 0] 4: [0, 0, 0, 0, 1] |
我们可以使用一个简单的函数来完成此操作,该函数将接受一个序列并返回序列中每个值的二进制向量列表。下面的函数 encode() 实现了此行为。
1 2 3 4 5 6 7 8 |
# 对输入模式进行二进制编码,返回二进制向量列表 def encode(pattern, n_unique): encoded = list() for value in pattern: row = [0.0 for x in range(n_unique)] row[value] = 1.0 encoded.append(row) return encoded |
我们可以在第一个序列上测试它并打印生成的二进制向量列表。完整的示例如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 对输入模式进行二进制编码,返回二进制向量列表 def encode(pattern, n_unique): encoded = list() for value in pattern: row = [0.0 for x in range(n_unique)] row[value] = 1.0 encoded.append(row) return encoded seq1 = [3, 0, 1, 2, 3] encoded = encode(seq1, 5) for vector in encoded: print(vector) |
运行示例会打印每个二进制向量。请注意,我们使用浮点值 0.0 和 1.0,因为它们将用作模型的输入和输出。
1 2 3 4 5 |
[0.0, 0.0, 0.0, 1.0, 0.0] [1.0, 0.0, 0.0, 0.0, 0.0] [0.0, 1.0, 0.0, 0.0, 0.0] [0.0, 0.0, 1.0, 0.0, 0.0] [0.0, 0.0, 0.0, 1.0, 0.0] |
输入-输出对
下一步是将编码值序列拆分为输入-输出对。
这是一个有监督的学习问题表示,以便机器学习问题可以学习如何将输入模式 (X) 映射到输出模式 (y)。
例如,第一个序列具有以下要学习的输入-输出对
1 2 3 4 5 |
X, y 3, 0 0, 1 1, 2 2, 3 |
我们必须从独热编码的二进制向量创建这些映射对,而不是原始数字。
例如,3->0 的第一个输入-输出对将是
1 2 |
X, y [0, 0, 0, 1, 0] [1, 0, 0, 0, 0] |
下面是一个名为 to_xy_pairs() 的函数,它将创建 X 和 y 模式列表,给定一个编码二进制向量列表。
1 2 3 4 5 6 7 |
# 创建编码向量的输入/输出对,返回 X, y def to_xy_pairs(encoded): X,y = list(),list() for i in range(1, len(encoded)): X.append(encoded[i-1]) y.append(encoded[i]) return X, y |
我们可以将其与上面的独热编码函数结合起来,并打印第一个序列的编码输入和输出对。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 对输入模式进行二进制编码,返回二进制向量列表 def encode(pattern, n_unique): encoded = list() for value in pattern: row = [0.0 for x in range(n_unique)] row[value] = 1.0 encoded.append(row) return encoded # 创建编码向量的输入/输出对,返回 X, y def to_xy_pairs(encoded): X,y = list(),list() for i in range(1, len(encoded)): X.append(encoded[i-1]) y.append(encoded[i]) 返回 X, y seq1 = [3, 0, 1, 2, 3] encoded = encode(seq1, 5) X, y = to_xy_pairs(encoded) for i in range(len(X)): print(X[i], y[i]) |
运行示例会打印序列中每个步骤的输入和输出对。
1 2 3 4 |
[0.0, 0.0, 0.0, 1.0, 0.0] [1.0, 0.0, 0.0, 0.0, 0.0] [1.0, 0.0, 0.0, 0.0, 0.0] [0.0, 1.0, 0.0, 0.0, 0.0] [0.0, 1.0, 0.0, 0.0, 0.0] [0.0, 0.0, 1.0, 0.0, 0.0] [0.0, 0.0, 1.0, 0.0, 0.0] [0.0, 0.0, 0.0, 1.0, 0.0] |
重塑数据
最后一步是重塑数据,使其可以直接被 LSTM 网络使用。
Keras LSTM 期望输入模式 (X) 为三维 NumPy 数组,维度为 [样本数, 时间步数, 特征数]。
对于一个输入数据序列,维度将是 [4, 1, 5],因为我们有 4 行数据,每行 1 个时间步,每行 5 列。
我们可以从我们的 X 模式列表中创建一个二维 NumPy 数组,然后将其重塑为所需的三维格式。例如
1 2 3 |
df = DataFrame(X) values = df.values array = values.reshape(4, 1, 5) |
我们还必须将输出模式列表 (y) 转换为二维 NumPy 数组。
下面是一个名为 to_lstm_dataset() 的函数,它以序列作为输入和序列字母表的大小,并返回一个 X 和 y 数据集,可用于 LSTM。它在重塑数据之前执行序列到独热编码以及到输入-输出对的所需转换。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 将序列转换为 x/y 对,可用于 LSTM def to_lstm_dataset(sequence, n_unique): # 独热编码 encoded = encode(sequence, n_unique) # 转换为输入/输出模式 X,y = to_xy_pairs(encoded) # 转换为 LSTM 友好格式 dfX, dfy = DataFrame(X), DataFrame(y) lstmX = dfX.values lstmX = lstmX.reshape(lstmX.shape[0], 1, lstmX.shape[1]) lstmY = dfy.values return lstmX, lstmY |
此函数可以按如下方式调用每个序列
1 2 3 4 5 6 |
seq1 = [3, 0, 1, 2, 3] seq2 = [4, 0, 1, 2, 4] n_unique = len(set(seq1 + seq2)) seq1X, seq1Y = to_lstm_dataset(seq1, n_unique) seq2X, seq2Y = to_lstm_dataset(seq2, n_unique) |
我们现在已经准备好所有数据以供 LSTM 使用。
使用 LSTM 学习序列
在本节中,我们将定义 LSTM 来学习输入序列。
本节分为 4 个部分
- LSTM 配置
- LSTM 训练
- LSTM 评估
- LSTM 完整示例
LSTM 配置
我们希望 LSTM 进行一步预测,这已在我们的数据集的格式和形状中定义。我们还希望 LSTM 在每个时间步之后用误差更新,这意味着我们需要使用批处理大小为一。
Keras LSTM 默认情况下在批处理之间不是有状态的。我们可以通过将 LSTM 层的 stateful 参数设置为 True 并手动管理训练 epoch 来使它们有状态,以确保 LSTM 的内部状态在每个序列之后重置。
我们必须使用 batch_input_shape 参数定义批处理的形状,该参数具有 3 个维度 [批处理大小, 时间步数, 特征数],它们将分别为 1、1 和 5。
网络拓扑将配置一个具有 20 个单元的隐藏 LSTM 层和一个具有 5 个输出的普通 Dense 层,用于输出模式中的 5 列。由于是二进制输出,输出层将使用 sigmoid(逻辑)激活函数,LSTM 层将使用默认的 tanh(双曲正切)激活函数。
由于是二进制输出,拟合网络时将优化对数(交叉熵)损失函数,并将使用所有默认参数的高效 ADAM 优化算法。
下面列出了用于此问题定义 LSTM 网络的 Keras 代码。
1 2 3 4 |
model = Sequential() model.add(LSTM(20, batch_input_shape=(1, 1, 5), stateful=True)) model.add(Dense(5, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam') |
LSTM 训练
我们必须手动逐个 epoch 拟合模型。
在一个 epoch 中,我们可以在每个序列上拟合模型,并确保在每个序列之后重置状态。
鉴于问题的简单性,模型不需要长时间训练;在这种情况下,只需 250 个 epoch。
下面是一个示例,说明如何跨所有 epoch 在每个序列上拟合模型。
1 2 3 4 5 6 |
# 训练 LSTM for i in range(250): model.fit(seq1X, seq1Y, epochs=1, batch_size=1, verbose=1, shuffle=False) model.reset_states() model.fit(seq2X, seq2Y, epochs=1, batch_size=1, verbose=0, shuffle=False) model.reset_states() |
我喜欢在拟合网络时看到损失函数的一些反馈,因此其中一个序列的详细输出已打开,但另一个序列未打开。
LSTM 评估
接下来,我们可以通过预测学习序列的每个步骤来评估拟合模型。
我们可以通过预测每个序列的输出来实现这一点。
predict_classes() 函数可用于 LSTM 模型,它将直接预测类别。它通过对输出二进制向量执行 argmax() 并返回具有最大输出的预测列的索引来实现这一点。输出索引完美地映射到序列中使用的整数(通过上面仔细的设计)。下面列出了进行预测的示例
1 |
result = model.predict_classes(seq1X, batch_size=1, verbose=0) |
我们可以进行预测,然后根据输入模式和序列中每个步骤的预期输出模式打印结果。
LSTM 完整示例
我们现在可以将整个教程联系起来。
完整的代码列表如下。
首先,准备数据,然后拟合模型并打印两个序列的预测。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
from pandas import DataFrame from keras.models import Sequential from keras.layers import Dense 来自 keras.层 导入 LSTM # 对输入模式进行二进制编码,返回二进制向量列表 def encode(pattern, n_unique): encoded = list() for value in pattern: row = [0.0 for x in range(n_unique)] row[value] = 1.0 encoded.append(row) return encoded # 创建编码向量的输入/输出对,返回 X, y def to_xy_pairs(encoded): X,y = list(),list() for i in range(1, len(encoded)): X.append(encoded[i-1]) y.append(encoded[i]) 返回 X, y # 将序列转换为 x/y 对,可用于 LSTM def to_lstm_dataset(sequence, n_unique): # 独热编码 encoded = encode(sequence, n_unique) # 转换为输入/输出模式 X,y = to_xy_pairs(encoded) # 转换为 LSTM 友好格式 dfX, dfy = DataFrame(X), DataFrame(y) lstmX = dfX.values lstmX = lstmX.reshape(lstmX.shape[0], 1, lstmX.shape[1]) lstmY = dfy.values return lstmX, lstmY # 定义序列 seq1 = [3, 0, 1, 2, 3] seq2 = [4, 0, 1, 2, 4] # 将序列转换为所需的数据格式 n_unique = len(set(seq1 + seq2)) seq1X, seq1Y = to_lstm_dataset(seq1, n_unique) seq2X, seq2Y = to_lstm_dataset(seq2, n_unique) # 定义 LSTM 配置 n_neurons = 20 n_batch = 1 n_epoch = 250 n_features = n_unique # 创建 LSTM model = Sequential() model.add(LSTM(n_neurons, batch_input_shape=(n_batch, 1, n_features), stateful=True)) model.add(Dense(n_unique, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam') # 训练 LSTM for i in range(n_epoch): model.fit(seq1X, seq1Y, epochs=1, batch_size=n_batch, verbose=1, shuffle=False) model.reset_states() model.fit(seq2X, seq2Y, epochs=1, batch_size=n_batch, verbose=0, shuffle=False) model.reset_states() # 在序列 1 上测试 LSTM print('序列 1') result = model.predict_classes(seq1X, batch_size=n_batch, verbose=0) model.reset_states() for i in range(len(result)): print('X=%.1f y=%.1f, yhat=%.1f' % (seq1[i], seq1[i+1], result[i])) # 在序列 2 上测试 LSTM print('序列 2') result = model.predict_classes(seq2X, batch_size=n_batch, verbose=0) model.reset_states() for i in range(len(result)): print('X=%.1f y=%.1f, yhat=%.1f' % (seq2[i], seq2[i+1], result[i])) |
运行示例会显示模型在每个 epoch 中第一个序列上的损失反馈。
注意:由于算法或评估过程的随机性,或者数值精度的差异,您的结果可能会有所不同。考虑多次运行示例并比较平均结果。
运行结束时,每个序列都会在预测的上下文中打印出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
... 4/4 [==============================] - 0s - 损失: 0.0930 纪元 1/1 4/4 [==============================] - 0s - 损失: 0.0927 纪元 1/1 4/4 [==============================] - 0s - 损失: 0.0925 序列 1 X=3.0 y=0.0, yhat=0.0 X=0.0 y=1.0, yhat=1.0 X=1.0 y=2.0, yhat=2.0 X=2.0 y=3.0, yhat=3.0 序列 2 X=4.0 y=0.0, yhat=0.0 X=0.0 y=1.0, yhat=1.0 X=1.0 y=2.0, yhat=2.0 X=2.0 y=4.0, yhat=4.0 |
结果显示了两个重要的事情
- LSTM 每次一步地正确学习了每个序列。
- LSTM 使用每个序列的上下文来正确解决冲突的输入对。
本质上,LSTM 能够记住 3 个时间步前序列开头的输入模式,从而正确预测序列中的最后一个值。
LSTM 这种记忆和关联远距离时间观测的能力是使其如此强大并广泛使用的关键能力。
尽管这个例子微不足道,但 LSTM 能够在数百甚至数千个时间步长上展示相同的能力。
扩展
本节列出了本教程中示例的扩展想法。
- 调优。LSTM 的配置(epoch、单元等)是在经过一些试错后选择的。很可能一个更简单的配置可以在这个问题上达到相同的效果。需要对参数进行一些搜索。
- 任意字母表。5 个整数的字母表是任意选择的。这可以更改为其他符号和更大的字母表。
- 长序列。本例中使用的序列非常短。LSTM 能够在数百甚至数千个时间步长的更长序列上展示相同的能力。
- 随机序列。本教程中使用的序列是线性递增的。可以创建新的随机值序列,让 LSTM 设计出通用解决方案,而不是针对本教程中使用的两个序列的专用解决方案。
- 批处理学习。在每个时间步之后对 LSTM 进行了更新。探索使用批处理更新以查看这是否能改善学习。
- 打乱周期。在训练期间和评估期间,序列在每个周期中都以相同的顺序显示。打乱序列的顺序,以便在周期内拟合序列 1 和序列 2,这可能会改善模型对具有相同字母表的新未见序列的泛化能力。
您是否探索过这些扩展?
请在下面的评论中分享您的结果。我很想看看您想出了什么。
进一步阅读
我强烈建议阅读 Hochreiter 和 Schmidhuber 1997 年的原始 LSTM 论文;它非常棒。
总结
在本教程中,您发现了 LSTM 在多个时间步长上记忆能力的关键能力。
具体来说,你学到了:
- 如何定义一个只有像 LSTM 这样的 RNN 才能通过记忆解决的小型序列预测问题。
- 如何转换问题表示,使其适合 LSTM 学习。
- 如何设计 LSTM 以正确解决问题。
你有什么问题吗?
请在下面的评论中提出您的问题,我将尽力回答。
感谢您的教程!如果您在每个输入序列后重置 LSTM,使其有状态有什么意义?
好问题,
我让 LSTM 有状态,以便我可以精确控制何时发生重置。您说得对,我也可以设计样本/批次数量,以便在适当的时候进行重置。
首先,感谢您提供如此精彩的教程和网站。
能否提供一个示例,说明在使用 stateful=false 时如何设计样本/批次数量,以便在适当的时候进行重置?
不客气。
感谢您的建议,也许将来会考虑。
嗨,Jason,
如果我们想要 num_lag = 2,即
x1,x2 -> y
————-
(3, 0) -> 1
(0, 1) -> 2
(1, 2) -> 3
to_xy_pairs 函数需要更新为
python
def to_xy_pairs(encoded):
X, y = list(), list()
for i in range(2, len(encoded)):
X.append(encoded[i - 2]) # <-- num_lag = 2
X.append(encoded[i - 1])
y.append(encoded[i])
return X, y
相应地,to_lstm_dataset() 更新为
`python
lstmX = lstmX.reshape(int(lstmX.shape[0] / 2), 2, lstmX.shape[1]) # 1.0 | 1.0
(0.0, 1.0) -> 2.0 | 2.0
(1.0, 2.0) -> 3.0 | 3.0
在预处理中,我们可以直接使用函数 series_to_supervised()(2017 年 5 月 8 日的帖子)吗?
我猜不能。
因为它生成的数据如下
-- var1(t-2) var1(t-1) var1(t)
你必须将它们组织成一个序列
-- X: [var1(t-2), var1(t-1), ...]
-- y: [var1(t), ...]
对吗?
所以函数 series_to_superviesed() 1) 用于演示,2) 产生中间结果?
也许吧,你可以试试。
在这种情况下,我们一次提供一个时间步的序列,而不是对整个序列进行 BPTT。这是对 LSTM 记忆能力的一次真正令人惊叹的演示。
同意:对于一步,没有 BPTT,但对于两步,LSTM 确实通过 BPTT 进行学习。
另外,对于网络拓扑
层(类型)输出形状参数 # 连接到
===================================================
ts_input (InputLayer) (None, 2, 18) 0
当 lag = 2 时,输入层的输出形状是 3D 张量(时间步长为 2),就像学习语言句子包含单词序列一样。
(继续 🙂
to_lstm_dataset()
现在继续
X = [[0.0, 0.0, 0.0, 1.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0, 0.0]]
y = [[0.0, 1.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0, 0.0]]
lstmX.shape = (3, 2, 5)
lstmY.shape = (3, 5)
– X:3 个批次,__每个批次包含 2 个时间步__,每个时间步输入一个 5 维向量
– y:3 个结果,对应。
所以我想
1) 对于单变量时间序列转换为有监督学习问题,to_xy_pairs() 就足够了。
2) 对于多变量时间序列转换为有监督学习问题,series_to_supervised() + to_xy_pairs() 就足够了。
好文章,谢谢。
对于有状态 LSTM,选择 batch_size > 1 是否有益?
如果可以,如何将任何 DataFrame (dfX) 重塑为适合有状态 LSTM 的 [batch_size, 1, num_features] 输入?
batch_size = 128
tsteps = 1
# X_train.shape = (107904, 10)
# Y_train.shape = (107904, 2)
# 107904 % 128 == 0
# X_train 和 Y_train 都是 DataFrames
model = Sequential()
model.add(LSTM(50,
input_shape=(tsteps, Y_train.shape[1]),
batch_size=batch_size,
return_sequences=True,
stateful=True))
model.add(LSTM(50,
return_sequences=False,
stateful=True))
model.add(Dense(X_train.shape[1]))
model.compile(loss='mse', optimizer='rmsprop')
我收到错误
ValueError: 检查输入时出错:预期 lstm_1_input 具有 3 个维度,但得到的数组形状为 (107904, 10)
批处理大小为 1 时不需要重塑,更多的是如何运行你的 epoch 的问题。
你好,Danil,
您需要将输入 x 重塑为 3D 张量,形状为 [样本数, 时间步数, 特征维度],然后您可以选择任何批处理大小
# 在序列 1 上测试 LSTM
print(‘序列 1’)
result = model.predict_classes(seq1X, batch_size=n_batch, verbose=0)
model.reset_states()
for i in range(len(result))
print(‘X=%.5f y=%.5f, yhat=%.5f’ % (seq1[i], seq1[i+1], result[i]))
“有没有办法让这个网络预测 result[i] 之后的下一个输出?” 这只预测它从训练集中已经知道的数据。
谢谢您。
是的,在所有数据上拟合模型,然后调用 model.predict()
感谢您的课程!如果 n_batch = 4 或 2,为什么它不收敛?在这个例子中有什么区别吗?
在这种情况下,我们受限于固定的批处理大小,因为模型是有状态的。
你好 Jason,谢谢你的回复
如果我们设置 n_batch = 4,它将不会收敛,并且对于两个序列都会导致 0123 或 0124。
它的行为就好像它没有保持状态……
我看到的唯一区别是,如果批处理大小 = 1,它会在进入第二个序列之前通过序列进行 4 次权重更新;如果批处理大小 = 4,它只会进行一次权重更新,然后重置状态并进入第二个序列。
我还尝试连接两个序列,这样我就可以运行 1 个 8 对的序列,但我仍然得到相同的结果,如果批处理大小 == 1,它会正确记忆所有序列(即 01230124),否则如果我设置批处理大小 = 4 或 8,它会导致 01230123 或 01240124(即不收敛)。
我这里错过了什么?
我还尝试了您课程中的其他示例,其中一个“使用 Keras 在 Python 中理解有状态 LSTM 循环神经网络”,其中它成功地学习了字母表,当批处理大小从 1 增加到训练数据集的批处理大小 = len(dataX) = 26 时。
如果能看到这个无状态模式的例子,那会非常有帮助。
输入形状会是什么样子?
这是一个无状态模式下 LSTM 的非常简单的例子,我们用一个非常简单的序列 [0->1] 和 [0->2] 对其进行训练。有没有人知道为什么它在无状态模式下不收敛?
我们有一个大小为 2 的批次,包含 2 个样本,它应该在批次内部保持状态。
来自 keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
import numpy
# 定义序列
seq = [0, 1, 0, 2]
# 将序列转换为所需的数据格式
seqX=numpy.array([[( 1. , 0. , 0.)], [( 1. , 0. , 0.)]])
seqY=numpy.array([( 0. , 1. , 0.) , ( 0. , 0. , 1.)])
# 定义 LSTM 配置
n_unique = len(set(seq))
n_neurons = 20
n_batch = 2
n_epoch = 300
n_features = n_unique
# 创建 LSTM
model = Sequential()
model.add(LSTM(n_neurons, input_shape=( 1, n_features) ))
model.add(Dense(n_unique, activation=’sigmoid’))
model.compile(loss=’binary_crossentropy’, optimizer=’Adam’)
# 训练 LSTM
model.fit(seqX, seqY, epochs=n_epoch, batch_size=n_batch, verbose=2, shuffle=False)
print(‘序列’)
result = model.predict_classes(seqX, batch_size=n_batch, verbose=0)
for i in range(2)
print(‘X=%.1f y=%.1f, yhat=%.1f’ % (0, i+1, result[i]))
嗨,Jason,
这是一个很棒的教程,但我里面有一些我无法理解的东西。
请参考您的代码中的以下片段。您能解释一下为什么您在循环中分别拟合 seq1X 和 seq2X,而不是联合拟合 [参见我接下来要说的]?
我在思考以下内容
我尝试了它并打印了 seq1、seq2 和 seq3。这是打印输出。我可以看到差异,但我不知道为什么。你能解释一下吗?请注意,打印输出不一致。
这是运行 #1 的打印输出
序列 1
X=3.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=3.0, yhat=2.0
序列 2
X=4.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=3.0
X=2.0 y=4.0, yhat=3.0
序列 3
X=3.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=3.0, yhat=2.0
X=3.0 y=4.0, yhat=4.0
X=4.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=4.0, yhat=4.0
运行 #2 的打印输出
序列 1
X=3.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=3.0, yhat=3.0
序列 2
X=4.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=4.0, yhat=3.0
序列 3
X=3.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=3.0, yhat=3.0
X=3.0 y=4.0, yhat=4.0
X=4.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=4.0, yhat=4.0
运行 #3 的打印输出
序列 1
X=3.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=3.0, yhat=3.0
序列 2
X=4.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=3.0
X=2.0 y=4.0, yhat=3.0
序列 3
X=3.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=3.0, yhat=3.0
X=3.0 y=4.0, yhat=4.0
X=4.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=4.0, yhat=4.0
谢谢
我不确定我是否理解,这是很久以前我写这篇东西的时候了——我几乎不记得细节了。
你到底想演示什么?
嗨,Jason,
长话短说,为什么要像这样在两个不同的 fit 语句中分别拟合 seq1X 和 seq2X?
为什么不将 seq1X 和 seq2X 连接起来,并在连接的训练数据集上拟合模型,在我的示例中,即 seq3X,如下所示
这归结于我如何定义测试问题。我想在样本之间重置状态,并演示模型可以在 n 个时间步中记住第一个时间步的值。
连接这两个序列是一个不同的问题。
也许重新阅读上面问题的定义?
很棒的教程。我只是想问一下,在每一步之后重置模型的重要性是什么。
谢谢
在这个例子中,我们只对一个样本的状态感兴趣。
是否可以使用 RNN 和 LSTM 动态记住聊天对话?如果可以,请给我一些文章建议
为什么模型需要记住整个聊天对话?
状态函数有什么作用?stateful=True 和 stateful=False 有什么区别?
当 stateful=True 时,LSTM 单元的内部状态不会重置,直到您手动重置它。
否则,单元的内部状态将在每个批处理结束时重置。
有没有办法使用模型权重计算 model.fit 的输出?我试过了,但结果大相径庭!
是的,它是输入和模型权重的加权和。
太棒了,不过请纠正我。
我得到了两层的权重,如下所示
看起来是个不错的开始。
然后我做了类似的事情
结果一样吗?
确实一样。问题在于权重矩阵的行实际上是列!
干得好!