作为对已接受答案的补充,此答案显示了keras行为以及如何获得每张照片。
一般Keras行为
标准keras内部处理总是如下图所示(其中我使用features=2
,压力和温度作为示例):
在此图中,我将步骤数增加到5,以避免与其他维度混淆。
对于此示例:
- 我们有N个油箱
- 我们每小时花费5个小时采取措施(时间步长)
- 我们测量了两个功能:
然后,我们的输入数组应为(N,5,2)
:
[ Step1 Step2 Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
....
Tank N: [[Pn1,Tn1], [Pn2,Tn2], [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
]
滑动窗输入
通常,LSTM层应该处理整个序列。划分窗口可能不是最好的主意。该层具有有关序列前进过程的内部状态。 Windows消除了学习长序列的可能性,从而将所有序列限制为窗口大小。
在窗口中,每个窗口都是一个较长的原始序列的一部分,但是Keras会将它们视为独立的序列:
[ Step1 Step2 Step3 Step4 Step5
Window A: [[P1,T1], [P2,T2], [P3,T3], [P4,T4], [P5,T5]],
Window B: [[P2,T2], [P3,T3], [P4,T4], [P5,T5], [P6,T6]],
Window C: [[P3,T3], [P4,T4], [P5,T5], [P6,T6], [P7,T7]],
....
]
请注意,在这种情况下,最初只有一个序列,但是您将其划分为许多序列以创建窗口。
“什么是序列”的概念是抽象的。重要的部分是:
- 您可以批量处理许多单独的序列
- 使序列成为序列的原因是它们是逐步演化的(通常是时间步长)
通过“单层”实现每种情况
实现许多标准:
您可以使用return_sequences=True
通过一个简单的LSTM层实现很多对很多:
outputs = LSTM(units, return_sequences=True)(inputs)
#output_shape -> (batch_size, steps, units)
实现多对一:
使用完全相同的图层,keras将执行完全相同的内部预处理,但是当您使用return_sequences=False
(或简单地忽略此参数)时,keras将自动放弃最后一步的步骤:
outputs = LSTM(units)(inputs)
#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned
实现一对多
现在,仅keras LSTM层不支持此功能。您将必须创建自己的策略来重复步骤。有两种好的方法:
- 通过重复张量创建恒定的多步输入
- 使用
stateful=True
重复执行一个步骤的输出,并将其用作下一步的输入(需要output_features == input_features
)
一对多与重复向量
为了适应喀拉拉邦的标准行为,我们需要分步进行输入,因此,我们只需重复输入所需的长度即可:
outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)
#output_shape -> (batch_size, steps, units)
了解有状态=真
现在出现stateful=True
一种可能用法(除了避免加载无法同时容纳计算机内存的数据)
有状态允许我们分阶段输入序列的“部分”。区别在于:
- 在
stateful=False
,第二批包含完整的新序列,与第一批无关
- 在
stateful=True
,第二批继续第一批,扩展了相同的序列。
这就像在Windows中划分序列一样,有两个主要区别:
- 这些窗户不叠加!
-
stateful=True
将看到这些窗口作为单个长序列连接
在stateful=True
,每个新批次将被解释为继续前一个批次(直到您调用model.reset_states()
)。
- 批次2中的序列1将继续批次1中的序列1。
- 批次2中的序列2将继续批次1中的序列2。
- 批次2中的序列n将继续批次1中的序列n。
输入示例,批次1包含步骤1和2,批次2包含步骤3至5:
BATCH 1 BATCH 2
[ Step1 Step2 | [ Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], | [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], | [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
.... |
Tank N: [[Pn1,Tn1], [Pn2,Tn2], | [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
] ]
注意批次1和批次2中的储罐对齐!这就是为什么我们需要shuffle=False
(当然,除非我们仅使用一个序列)。
您可以无限期地具有任意数量的批次。 (对于每批中具有可变长度,请使用input_shape=(None,features)
。
一对多与有状态= True
对于我们这里的情况,每批将仅使用1步,因为我们希望获得一个输出步并将其作为输入。
请注意,图片中的行为不是由stateful=True
引起的。我们将在下面的手动循环中强制执行该操作。在此示例中, stateful=True
是“允许”我们停止序列,操纵我们想要的并从我们停止的位置继续进行的操作。
老实说,对于这种情况,重复方法可能是更好的选择。但是由于我们要研究的是stateful=True
,所以这是一个很好的例子。最好的使用方法是下一个“多对多”案例。
层:
outputs = LSTM(units=features,
stateful=True,
return_sequences=True, #just to keep a nice output shape even with length 1
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
现在,我们将需要一个手动循环进行预测:
input_data = someDataWithShape((batch, 1, features))
#important, we're starting new sequences, not continuing old ones:
model.reset_states()
output_sequence = []
last_step = input_data
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
有状态=真对多对多
现在,在这里,我们得到了一个非常不错的应用程序:给定一个输入序列,尝试预测其未来未知的步骤。
我们使用的方法与上述“一对多”方法相同,不同之处在于:
- 我们将使用序列本身作为目标数据,向前迈出一步
- 我们知道序列的一部分(因此我们放弃了这部分结果)。
图层(与上面相同):
outputs = LSTM(units=features,
stateful=True,
return_sequences=True,
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
训练:
我们将训练模型来预测序列的下一步:
totalSequences = someSequencesShaped((batch, steps, features))
#batch size is usually 1 in these cases (often you have only one Tank in the example)
X = totalSequences[:,:-1] #the entire known sequence, except the last step
Y = totalSequences[:,1:] #one step ahead of X
#loop for resetting states at the start/end of the sequences:
for epoch in range(epochs):
model.reset_states()
model.train_on_batch(X,Y)
预测:
我们预测的第一阶段涉及“调整状态”。这就是为什么即使我们已经知道序列的这一部分,我们也要再次预测整个序列:
model.reset_states() #starting a new sequence
predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:] #the last step of the predictions is the first future step
现在我们像一对多情况一样进入循环。但是请不要在这里重置状态! 。我们希望模型知道序列的哪一步(并且由于上面我们所做的预测,它知道它在第一步)
output_sequence = [firstNewStep]
last_step = firstNewStep
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
在以下答案和文件中使用了这种方法:
实现复杂的配置
在上面的所有示例中,我展示了“一层”的行为。
当然,您可以在彼此之上堆叠许多层,而不必全部遵循相同的模式,然后创建自己的模型。
出现的一个有趣的例子是“自动编码器”,它具有“多对一个编码器”,后跟“一对多”解码器:
编码器:
inputs = Input((steps,features))
#a few many to many layers:
outputs = LSTM(hidden1,return_sequences=True)(inputs)
outputs = LSTM(hidden2,return_sequences=True)(outputs)
#many to one layer:
outputs = LSTM(hidden3)(outputs)
encoder = Model(inputs,outputs)
解码器:
使用“重复”方法;
inputs = Input((hidden3,))
#repeat to make one to many:
outputs = RepeatVector(steps)(inputs)
#a few many to many layers:
outputs = LSTM(hidden4,return_sequences=True)(outputs)
#last layer
outputs = LSTM(features,return_sequences=True)(outputs)
decoder = Model(inputs,outputs)
自动编码器:
inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)
autoencoder = Model(inputs,outputs)
fit(X,X)
训练fit(X,X)
补充说明
如果您想了解有关LSTM中如何计算步骤的详细信息,或者有关上述stateful=True
情况的详细信息,则可以在此答案中阅读更多内容: 对“了解Keras LSTM”的怀疑
0
我试图调和我对LSTM的理解,并在克里斯托弗·奥拉(Christopher Olah)在Keras中实现的这篇文章中指出了这一点 。我正在关注Jason Brownlee为Keras教程撰写的博客 。我主要感到困惑的是
[samples, time steps, features]
然后,让我们参考下面粘贴的代码专注于以上两个问题:
注意:create_dataset采用长度为N的序列,并返回一个
N-look_back
数组,其中每个元素都是一个look_back
长度序列。什么是时间步骤和功能?
可以看出TrainX是一个3D数组,其中Time_steps和Feature是最后两个维度(在此特定代码中为3和1)。对于下图,这是否意味着我们正在考虑粉盒数量为3的
many to one
情况?还是字面上的意思是链长为3(即仅考虑了3个绿色框)。当我们考虑多元序列时,features参数是否有意义?例如同时模拟两个金融股票?
有状态的LSTM
有状态LSTM是否意味着我们在批次运行之间保存单元内存值?如果是这种情况,
batch_size
为1,并且在两次运行之间重置内存,那么说它是有状态的是什么意思。我猜想这与训练数据没有被整理的事实有关,但是我不确定如何。有什么想法吗?图片参考: http : //karpathy.github.io/2015/05/21/rnn-efficiency/
编辑1:
@van对红色和绿色方框相等的评论有点困惑。因此,为了确认一下,以下API调用是否与展开的图表相对应?特别要注意第二张图(随意选择
batch_size
):编辑2:
对于已经完成Udacity深度学习课程但仍对time_step参数感到困惑的人,请查看以下讨论: https ://discussions.udacity.com/t/rnn-lstm-use-implementation/163169
更新:
原来是
model.add(TimeDistributed(Dense(vocab_len)))
是我想要的。这是一个示例: https : //github.com/sachinruk/ShakespeareBot更新2:
我在这里总结了我对LSTM的大部分理解: https : //www.youtube.com/watch?v= ywinX5wgdEU