了解 Keras 长短期记忆 (LSTM)

2024-12-19 09:23:00
admin
原创
66
摘要:问题描述:在尝试调和我对 Christopher Olah在 Keras 中实现的 LSTM 的理解以及遵循Jason Brownlee为 Keras 教程撰写的博客时,我对以下几点感到困惑:将数据系列重塑[samples, time steps, features]为有状态的 LSTM考虑以下代码引用的上述...

问题描述:

在尝试调和我对 Christopher Olah在 Keras 中实现的 LSTM 的理解以及遵循Jason Brownlee为 Keras 教程撰写的博客时,我对以下几点感到困惑:

  1. 将数据系列重塑[samples, time steps, features]

  2. 有状态的 LSTM

考虑以下代码引用的上述两个问题:

# reshape into X=t and Y=t+1
look_back = 3
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)

# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], look_back, 1))
testX = numpy.reshape(testX, (testX.shape[0], look_back, 1))
########################
# The IMPORTANT BIT
##########################
# create and fit the LSTM network
batch_size = 1
model = Sequential()
model.add(LSTM(4, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
for i in range(100):
    model.fit(trainX, trainY, nb_epoch=1, batch_size=batch_size, verbose=2, shuffle=False)
    model.reset_states()

注意:create_dataset 接受长度为 N 的序列并返回一个N-look_back数组,其中每个元素都是一个look_back长度序列。

时间步骤和特征有哪些?

可以看出,TrainX 是一个 3-D 数组,Time_steps 和 Feature 分别是最后两个维度(在此特定代码中分别为 3 和 1)。查看下图,这是否意味着我们正在考虑many to one粉色框数量为 3 的情况?还是意味着链长为 3(?。在此处输入图片描述

当我们考虑多元序列时,特征参数是否变得相关?例如同时对两只金融股票进行建模?

有状态的 LSTM

有状态 LSTM 是否意味着我们在批次运行之间保存单元内存值?如果是这样,batch_size那就是 1,并且内存在训练运行之间重置,那么说它是有状态的有什么意义呢?我猜这与训练数据没有被打乱的事实有关,但不确定是如何的。

有什么想法吗?图片参考: http: //karpathy.github.io/2015/05/21/rnn-effectiveness/

编辑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


解决方案 1:

作为已接受答案的补充,该答案展示了 keras 行为以及如何实现每张图片。

Keras 的一般行为

标准 keras 内部处理始终是多对多的,如下图所示(其中我使用了features=2压力和温度,仅作为示例):

多对多

在此图像中,我将步数增加到 5,以避免与其他尺寸混淆。

对于此示例:

  • 我们没有油罐

  • 我们花了 5 个小时每小时采取措施(时间步骤)

  • 我们测量了两个特征:

+ 压力P
+ 温度T

我们的输入数组应具有如下形状(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 层应该处理整个序列。划分窗口可能不是最好的主意。该层具有关于序列在前进过程中如何演变的内部状态。窗口消除了学习长序列的可能性,将所有序列限制在窗口大小内。

在窗口中,每个窗口都是一个长原始序列的一部分,但在 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]],
  ....
        ]

请注意,在这种情况下,您最初只有一个序列,但您将其分成多个序列来创建窗口。

“什么是序列”这个概念比较抽象,重要的部分有:

  • 你可以拥有包含许多单独序列的批次

  • 序列之所以成为序列,是因为它们逐步演变(通常是时间步骤)

用“单层”实现每一个案例

达到多对多标准:

标准多对多

您可以使用简单的 LSTM 层实现多对多,使用方法return_sequences=True

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 层本身不支持此功能。您必须创建自己的策略来增加步骤。有两种好方法:

  • 通过重复张量创建恒定的多步输入

  • 使用 astateful=True来循环获取一步的输出并将其作为下一步的输入(需要output_features == input_features

带有重复向量的一对多

为了适应 keras 标准行为,我们需要分步输入,因此,我们只需重复输入我们想要的长度:

一对多重复

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 允许我们分阶段输入序列的“部分”。区别在于:

  • 在中stateful=False,第二批包含全新的序列,独立于第一批

  • 在 中stateful=True,第二批延续第一批,扩展相同的序列。

这也类似于在窗口中划分序列,但主要有以下两个区别:

  • 这些窗口不重叠!!

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

一对多,stateful=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()

多对多,stateful=True

现在,这里我们得到一个非常好的应用:给定一个输入序列,尝试预测其未来未知的步骤。

我们使用的方法与上面的“一对多”相同,不同之处在于:

  • 我们将使用序列本身作为目标数据,领先一步

  • 我们知道序列的一部分(所以我们丢弃这部分结果)。

多对多状态

层(同上):

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)

其他说明

如果你想要了解有关 LSTM 中步骤计算方式的详细信息,或者有关stateful=True上述案例的详细信息,你可以在此答案中阅读更多内容:关于“理解 Keras LSTM”的疑问

解决方案 2:

首先,您选择精彩的教程(1、2)来开始。

Time-step 的含义Time-steps==3在 X.shape(描述数据形状)中表示有三个粉色框。由于在 Keras 中每个步骤都需要一个输入,因此绿色框的数量通常应等于红色框的数量。除非你破解了结构。

多对多 vs. 多对一return_sequences:在 keras 中,初始化LSTMGRU或时有一个参数SimpleRNN。当return_sequencesFalse(默认情况下)时,则为如图所示的多对一(batch_size, hidden_unit_length)。其返回形状为,代表最后的状态。当return_sequences为 时True,则为多对多。其返回形状为(batch_size, time_step, hidden_unit_length)

特征参数是否相关:特征参数表示“你的红框有多大”或每一步的输入维度是多少。如果你想从 8 种市场信息中进行预测,那么你可以用 生成数据feature==8

Stateful:可以去查源码,初始化状态的时候,如果stateful==True,就用上次训练的状态作为初始状态,否则就生成一个新的状态。我还没开启stateful,不过我不同意batch_size只有 时 才能为1 stateful==True

目前,您使用收集的数据生成数据。想象一下您的股票信息以流的形式出现,而不是等待一天来收集所有连续的数据,您希望在使用网络进行训练/预测时在线生成输入数据。如果您有 400 只股票共享同一个网络,那么您可以设置batch_size==400

解决方案 3:

当 RNN 的最后一层有 return_sequences 时,您不能使用简单的 Dense 层,而应该使用 TimeDistributed。

这是一个示例代码,可能会对其他人有所帮助。

words = keras.layers.Input(batch_shape=(None, self.maxSequenceLength), name = "input")

# Build a matrix of size vocabularySize x EmbeddingDimension 
# where each row corresponds to a "word embedding" vector.
# This layer will convert replace each word-id with a word-vector of size Embedding Dimension.
embeddings = keras.layers.embeddings.Embedding(self.vocabularySize, self.EmbeddingDimension,
    name = "embeddings")(words)
# Pass the word-vectors to the LSTM layer.
# We are setting the hidden-state size to 512.
# The output will be batchSize x maxSequenceLength x hiddenStateSize
hiddenStates = keras.layers.GRU(512, return_sequences = True, 
                                    input_shape=(self.maxSequenceLength,
                                    self.EmbeddingDimension),
                                    name = "rnn")(embeddings)
hiddenStates2 = keras.layers.GRU(128, return_sequences = True, 
                                    input_shape=(self.maxSequenceLength, self.EmbeddingDimension),
                                    name = "rnn2")(hiddenStates)

denseOutput = TimeDistributed(keras.layers.Dense(self.vocabularySize), 
    name = "linear")(hiddenStates2)
predictions = TimeDistributed(keras.layers.Activation("softmax"), 
    name = "softmax")(denseOutput)  

# Build the computational graph by specifying the input, and output of the network.
model = keras.models.Model(input = words, output = predictions)
# model.compile(loss='kullback_leibler_divergence', \nmodel.compile(loss='sparse_categorical_crossentropy', \n    optimizer = keras.optimizers.Adam(lr=0.009, \n        beta_1=0.9,\n        beta_2=0.999, \n        epsilon=None, \n        decay=0.01, \n        amsgrad=False))

解决方案 4:

有关动画 RNN、LSTM 和 GRU 的更多详细信息,请参阅此博客。

下图可以让你更好地了解 LSTM。这是一个 LSTM 单元。
这个数字

如你所见,X 有 3 features(绿色圆圈),所以这个单元的输入是一个维度为 3 的向量,而隐藏状态有 2 units(红色圆圈),所以这个单元的输出(以及单元状态)是一个维度为 2 的向量。

下图显示了一个具有 3 个时间步长(3 个 LSTM 单元)的 LSTM 层的示例:

这张图片

** 一个模型可以有多个 LSTM 层。

现在我再次使用Daniel Möller的例子以便更好地理解:我们有 10 个油罐。对于每个油罐,我们每小时测量 2 个特征:温度、压力,共 5 次。现在参数是:

  • batch_size = 一次前向/后向传递中使用的样本数(默认值 = 32) --> 例如,如果您有 1000 个样本,并且将 batch_size 设置为 100,则模型将进行 10 次迭代,将所有样本传递一次网络(1 个时期)。批处理大小越高,所需的内存空间就越大。由于此示例中的样本数量较少,我们认为 batch_size 等于所有样本 = 10

  • 时间步长= 5

  • 特征= 2

  • 单位= 它是一个正整数,决定了隐藏状态和单元状态的维度,或者换句话说,决定了传递给下一个 LSTM 单元的参数数量。它可以根据特征和时间步长任意或经验地选择。使用更多单位将获得更高的准确性和更多的计算时间。但这可能会导致过度拟合。

  • 输入形状= (批量大小、时间步长、特征)= (10,5,2)

  • 输出形状

    • (batch_size、时间步长、单位)如果return_sequences=True

    • (batch_size,单位)如果return_sequences=False

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   997  
  在项目管理领域,CDCP(Certified Data Center Professional)认证评审是一个至关重要的环节,它不仅验证了项目团队的专业能力,还直接关系到项目的成功与否。在这一评审过程中,沟通技巧的运用至关重要。有效的沟通不仅能够确保信息的准确传递,还能增强团队协作,提升评审效率。本文将深入探讨CDCP...
华为IPD流程   34  
  IPD(Integrated Product Development,集成产品开发)是一种以客户需求为核心、跨部门协同的产品开发模式,旨在通过高效的资源整合和流程优化,提升产品开发的成功率和市场竞争力。在IPD培训课程中,掌握关键成功因素是确保团队能够有效实施这一模式的核心。以下将从五个关键成功因素展开讨论,帮助企业和...
IPD项目流程图   40  
  华为IPD(Integrated Product Development,集成产品开发)流程是华为公司在其全球化进程中逐步构建和完善的一套高效产品开发管理体系。这一流程不仅帮助华为在技术创新和产品交付上实现了质的飞跃,还为其在全球市场中赢得了显著的竞争优势。IPD的核心在于通过跨部门协作、阶段性评审和市场需求驱动,确保...
华为IPD   39  
  华为作为全球领先的通信技术解决方案提供商,其成功的背后离不开一套成熟的管理体系——集成产品开发(IPD)。IPD不仅是一种产品开发流程,更是一种系统化的管理思想,它通过跨职能团队的协作、阶段评审机制和市场需求驱动的开发模式,帮助华为在全球市场中脱颖而出。从最初的国内市场到如今的全球化布局,华为的IPD体系在多个领域展现...
IPD管理流程   71  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用