关于“理解 Keras LSTMs”的疑问

     2023-02-23     169

关键词:

【中文标题】关于“理解 Keras LSTMs”的疑问【英文标题】:Doubts regarding `Understanding Keras LSTMs` 【发布时间】:2019-05-26 01:49:42 【问题描述】:

我是 LSTM 的新手,并且正在浏览 Understanding Keras LSTMs,并且对 Daniel Moller 的漂亮答案有一些愚蠢的疑问。

以下是我的一些疑问:

    Achieving one to many 部分指定了 2 种方法,其中写道,我们可以使用 stateful=True 循环获取一个步骤的输出并将其作为下一步的输入(需要 output_features == input_features)。

    One to many with repeat vector 图中,重复向量在所有时间步中作为输入提供,而在One to many with stateful=True 中,输出在下一个时间步中作为输入提供。那么,我们不是通过使用stateful=True 来改变层的工作方式吗?

    在构建 RNN 时应遵循上述两种方法中的哪一种(使用重复向量或将前一个时间步长输出作为下一个输入)?

    One to many with stateful=True部分下,要改变one to many的行为,在手动循环预测的代码中,我们如何知道steps_to_predict变量,因为我们事先不知道输出序列长度。

    我也不明白整个模型使用last_step output 生成next_step ouput 的方式。它让我对model.predict() 函数的工作感到困惑。我的意思是,model.predict() 不是同时预测整个输出序列,而不是循环通过要生成的no. of output sequences(我仍然不知道其值)并执行model.predict() 来预测特定的时间步长在给定的迭代中输出?

    我无法理解整个Many to many 案例。任何其他链接都会有所帮助。

    我了解我们使用model.reset_states() 来确保新批次独立于前一批。但是,我们是否手动创建序列批次,以便一个批次跟随另一批次,或者Kerasstateful=True 模式下自动将序列划分为这样的批次。

    如果是手动完成,为什么会有人将数据集分成这样的批次,其中一个序列的一部分在一个批次中,另一个在下一个批次中?

    最后,stateful=True 将被使用的实际实现或示例/用例是什么(因为这似乎很不寻常)?我正在学习 LSTM,这是我第一次被介绍给 Keras 中的stateful

谁能帮我解释一下我的愚蠢问题,以便我可以清楚地了解 Keras 中的 LSTM 实现吗?

编辑:询问其中一些是为了澄清当前的答案,还有一些是为了解决剩余的疑问

一个。所以,基本上有状态让我们keep OR reset 每批之后的内部状态。那么,如果我们在每批训练后一次又一次地重置内部状态,模型将如何学习?重置真的意味着重置参数(用于计算隐藏状态)吗?

B。在If stateful=False: automatically resets inner state, resets last output step 行中。重置最后一个输出步骤是什么意思?我的意思是,如果每个时间步都产生自己的输出,那么重置最后一个输出步骤意味着什么?也只有最后一个?

C。针对Question 2Question 4 的第二点,我仍然没有得到你的manipulate the batches between each iterationstateful((Question 2 的最后一行)的需要,它只重置了状态)。我的意思是,我们不知道时间步长中生成的每个输出的输入。

因此,您将序列分解为only one-step 的序列,然后使用new_step = model.predict(last_step),但是您怎么知道您需要一次又一次地执行此操作多长时间(循环必须有一个停止点) ?另外,请解释stateful 部分(在Question 2 的最后一行)。

D。在One to many with stateful=True 下的代码中,似乎 for 循环(手动循环)用于预测下一个单词仅在测试时使用。模型是否在训练时合并了该事物本身,还是我们manually 也需要在训练时使用此循环?

E。假设我们正在做一些 机器翻译 工作,我认为在整个输入(要翻译的语言)被输入到输入时间步然后生成输出(翻译的语言) 在每个时间步将通过manual loop 进行,因为现在我们结束了输入并开始使用迭代在每个时间步产生输出。我做对了吗?

F。由于 LSTM 的默认工作需要答案中提到的 3 件事,所以在序列中断的情况下,current_inputprevious_output 是否提供相同的向量,因为它们在没有当前输入可用的情况下的值是相同的?

G。在 Predicting: 部分下的 ma​​ny to many with stateful=True 下,代码如下:

predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:]

由于finding the very next word in the current sequence的手动循环到现在都没有用过,我怎么知道model.predict(totalSequences)已经预测的时间步长的count,以便预测的最后一步(predicted[:,-1:]) 稍后将用于生成其余的序列?我的意思是,我怎么知道predicted = model.predict(totalSequences)manual for loop之前已经产生了多少个序列(后面用到)。

编辑 2:

。在D 回答中,我仍然没有得到如何训练我的模型?我知道使用手动循环(在训练期间)可能会很痛苦,但是如果我不使用它,模型将如何在we want the 10 future steps, we cannot output them at once because we don't have the necessary 10 input steps 的情况下得到训练?只需使用model.fit() 就能解决我的问题吗?

D 答案的最后一段,You could train step by step using train_on_batch only in the case you have the expected outputs of each step. But otherwise I think it's very complicated or impossible to train.

你能详细解释一下吗?

step by step 是什么意思?如果我没有后面序列的输出,这将如何影响我的训练?在训练期间我还需要手动循环吗?如果没有,那么model.fit() 函数会按预期工作吗?

III。我将"repeat" option 解释为使用repeat vector。使用重复向量对one to many 的情况不是很好,不适合many to many 的情况,因为后者将有许多输入向量可供选择(用作单个重复向量)?您将如何将repeat vector 用于many to many 案例?

【问题讨论】:

请查看更新后的答案。 【参考方案1】:

问题 3

理解问题3是理解其他问题的关键,所以,让我们先尝试一下。

Keras 中的所有循环层都执行隐藏循环。这些循环对我们来说是完全不可见的,但我们可以在最后看到每次迭代的结果。

不可见的迭代次数等于time_steps 维度。因此,LSTM 的循环计算发生在步骤上。

如果我们通过 X 步传递输入,将会有 X 次不可见的迭代。

LSTM 中的每次迭代都需要 3 个输入:

此步骤的输入数据的相应切片 图层的内部状态 最后一次迭代的输出

因此,以下面的示例图像为例,我们的输入有 5 个步骤:

Keras 在一次预测中会做什么?

步骤 0: 采取输入的第一步,input_data[:,0,:] 一个形状为(batch, 2) 的切片 取内部状态(此时为零) 执行最后一个输出步骤(第一步不存在) 将计算传递给: 更新内部状态 创建一个输出步骤(输出 0) 第 1 步: 进行下一步的输入:input_data[:,1,:] 获取更新的内部状态 取上一步生成的输出(输出0) 通过相同的计算: 再次更新内部状态 再创建一个输出步骤(输出 1) 第 2 步: 拍下input_data[:,2,:] 获取更新的内部状态 取输出 1 通过: 更新内部状态 创建输出 2

依此类推,直到第 4 步。

最后:

如果stateful=False:自动重置内部状态,重置最后一个输出步骤 如果stateful=True:保持内部状态,保持上一步输出

您不会看到任何这些步骤。它看起来只是一次通过。

但您可以选择:

return_sequences = True:返回每个输出步骤,形状(batch, steps, units) 这正是多对多。输出中的步数与输入中的步数相同 return_sequences = False:只返回最后一个输出步骤,形状(batch, units) 这是多对一。您为整个输入序列生成单个结果。

现在,这回答了您问题 2 的第二部分:是的,predict 将在您不注意的情况下计算所有内容。但是:

输出步数将等于输入步数

问题 4

现在,在进行第 2 题之前,让我们先看看第 4 题,这实际上是答案的基础。

是的,批次划分应该手动完成。 Keras 不会更改您的批次。那么,我为什么要划分一个序列?

1、序列太大,一批放不下电脑或GPU的内存 2,您想做问题 2 上发生的事情:在每一步迭代之间操作批次。

问题 2

在问题 2 中,我们正在“预测未来”。那么,输出步数是多少?嗯,这是您想要预测的数字。假设您试图根据过去预测您将拥有的客户数量。您可以决定预测未来 1 个月或 10 个月。您的选择。

现在,您认为predict 会立即计算整个事情是正确的,但请记住上面我所说的问题 3

输出步数等于输入步数

还要记住,第一个输出步骤是第一个输入步骤的结果,第二个输出步骤是第二个输入步骤的结果,依此类推。

但我们想要的是未来,而不是与前面的步骤一一匹配。我们希望结果步骤遵循“最后”步骤。

所以,我们面临一个限制:如果我们没有各自的输入,如何定义固定数量的输出步骤? (遥远未来的输入也是未来,所以不存在)

这就是为什么我们将序列分解为只有一步的序列。所以predict 也会输出只有一步

当我们这样做时,我们就有能力在每次迭代之间操纵批次。而且我们有能力将输出数据(我们以前没有)作为输入数据。

有状态是必要的,因为我们希望这些步骤中的每一个都连接为一个序列(不要丢弃状态)。

问题 5

我所知道的stateful=True的最佳实际应用是问题2的答案。我们想要在步骤之间操作数据。

这可能是一个虚拟示例,但另一个应用程序是,例如,如果您要从 Internet 上的用户接收数据。用户每天使用您的网站,您都会向模型多提供一步数据(并且您希望以相同的顺序继续该用户以前的历史记录)。

问题 1

那么,最后是问题1。

我想说:除非您需要它,否则请始终避免使用stateful=True。 您不需要它来构建一对多网络,因此,最好不要使用它。

请注意,stateful=True 示例与 预测未来 示例相同,但您从一个步骤开始。这很难实现,由于手动循环,它的速度会更差。但是您可以控制输出步骤的数量,这在某些情况下可能是您想要的。

计算也会有所不同。在这种情况下,如果一个比另一个更好,我真的无法回答。但我不相信会有很大的不同。但网络是某种“艺术”,测试可能会带来有趣的惊喜。

编辑答案:

一个

我们不应将“状态”与“权重”混淆。它们是两个不同的变量。

权重:可学习的参数,它们永远不会重置。 (如果你重置权重,你会失去模型学到的所有东西) 状态:当前一批序列的记忆(与我现在在序列上的哪个步骤以及我“从这批中的特定序列”到这一步所学到的知识有关)。

想象你正在看一部电影(一个序列)。每一秒都会让你建立起记忆,比如角色的名字,他们做了什么,他们的关系是什么。

现在想象一下,您拿到了一部以前从未看过的电影,然后开始观看电影的最后一秒。你不会明白电影的结局,因为你需要这部电影的前一个故事。 (各州)

现在,您已看完整部电影。现在您将开始观看新电影(新序列)。你不需要记住你看过的上一部电影中发生了什么。如果你试图“加入电影”,你会感到困惑。

在这个例子中:

权重:理解和解释电影的能力,记住重要名称和动作的能力 状态:在暂停的电影中,状态是从开始到现在发生的事情的记忆

因此,状态是“未学习的”。状态是“计算的”,关于批次中的每个单独序列逐步构建。这就是为什么:

重置状态意味着从第 0 步开始新序列(开始新电影) 保持状态意味着继续上一步的相同序列(继续暂停的电影,或观看该故事的第 2 部分)

状态正是使循环网络像具有“过去步骤的记忆”一样工作的原因。

B

在 LSTM 中,最后一个输出步骤是“状态”的一部分。

一个 LSTM 状态包含:

通过计算每一步更新的内存矩阵 最后一步的输出

所以,是的:每一步都产生自己的输出,但每一步都使用最后一步的输出作为状态。这就是 LSTM 的构建方式。

如果你想“继续”相同的序列,你需要记忆最后一步的结果 如果您想“开始”一个新序列,您不希望记忆最后一步的结果(如果您不重置状态,这些结果将继续存储)

C

你想停就停。你想预测未来多少步?那是你的停止点。

假设我有一个包含 20 个步骤的序列。我想预测未来的 10 步。

在标准(非有状态)网络中,我们可以使用:

一次输入19步(从0到18) 一次输出 19 步(从 1 到 19)

这是“预测下一步”(注意 shift = 1 步)。我们可以这样做,因为我们拥有所有可用的输入数据。

但是当我们想要 10 个未来的步骤时,我们不能一次输出它们,因为我们没有必要的 10 个输入步骤(这些输入步骤是未来的,我们需要模型先预测它们)。

因此,我们需要根据现有数据预测未来的一个步骤,然后将此步骤用作下一步的输入。

但我希望这些步骤都是相互关联的。如果我使用stateful=False,模型会看到很多“长度为 1 的序列”。不,我们想要一个长度为 30 的序列。

D

这是一个非常好的问题,你得到了我......

有状态的一对多是我在写这个答案时的一个想法,但我从未使用过这个。我更喜欢“重复”选项。

只有在每个步骤都有预期输出的情况下,您才能使用train_on_batch 逐步训练。但除此之外,我认为训练非常复杂或不可能。

E

这是一种常见的方法。

使用网络生成压缩向量(该向量可以是结果,也可以是生成的状态,或两者兼而有之) 将此压缩向量用作另一个网络的初始输入/状态,手动逐步生成,并在模型生成“句末”单词或字符时停止。

也有没有手动循环的固定尺寸模型。您假设您的句子的最大长度为 X 个单词。比这更短的结果句子用“句子结尾”或“空”字/字符完成。 Masking 层在这些模型中非常有用。

F

您只提供输入。其他两件事(最后的输出和内部状态)已经存储在有状态层中。

我之所以输入=最后一个输出,只是因为我们的特定模型预测下一步。这就是我们希望它做的事情。对于每个输入,下一步。

我们在训练中使用移位序列来教授这一点。

G

没关系。我们只想要最后一步。

序列数由第一个: 保存。 -1: 只考虑最后一步。

但如果你想知道,你可以打印predicted.shape。在此模型中,它等于totalSequences.shape

编辑 2

首先,我们不能使用“一对多”模型来预测未来,因为我们没有这方面的数据。如果您没有序列步骤的数据,就不可能理解“序列”。

因此,这种类型的模型应该用于其他类型的应用程序。正如我之前所说,我对这个问题真的没有很好的答案。最好先有一个“目标”,然后我们决定哪种模型更适合该目标。

“逐步”是指手动循环。

如果你没有后面步骤的输出,我认为是不可能训练的。它可能根本不是一个有用的模型。 (但我不是什么都知道的人)

如果您有输出,是的,您可以使用 fit 训练整个序列,而无需担心手动循环。

III

关于 III,你是对的。您不会在多对多中使用重复向量,因为您有不同的输入数据。

“一对多”和“多对多”是两种不同的技术,各有优缺点。一种适用于某些应用程序,另一种适用于其他应用程序。

【讨论】:

又一个精彩的答案,但在阅读您的答案后,我在 EDIT 下提出了一些问题。 1+ 此答案应作为短论文提交:) @DanielMöller 更多问题在另一个 EDIT 部分下。 @DanielMöller 所以,在C 中,它仅仅意味着在不同的手动迭代中使用model.predict()stateful=False 将仅仅意味着我们使用不同的独立序列作为输入(我们不这样做'不希望 bcz 它只是遵循相同的序列)所以我们使用stateful=True 使模型将每个输入视为同一序列的一部分。这是否正确理解?嘿,等着这个!! 是的。正是这样。

关于video.js的一些普遍疑问[关闭]

】关于video.js的一些普遍疑问[关闭]【英文标题】:Somegeneraldoubtsaboutvideo.js[closed]【发布时间】:2012-12-0119:44:10【问题描述】:我对播放器有一些普遍的疑问。我会列出它们:video.js是否支持HLS视频格式?如果是这样,在什么平台... 查看详情

关于python的一些疑问(代码片段)

1.在默认unicode情况下,tuple中不能输出中文:如图hobby1=u‘篮球‘t_h=(hobby1,)printt_h输出:(u‘\u7bee\u7403‘,)  查看详情

关于 ARM NEON 周期的一些疑问

】关于ARMNEON周期的一些疑问【英文标题】:somedoubtsregardingcyclesofARMNEON【发布时间】:2014-06-1306:33:22【问题描述】:我在汇编中编写了一些霓虹灯代码,旨在最大限度地优化。尽管由于寄存器冲突和流水线导致的延迟减少了,但... 查看详情

关于可序列化交易的一些疑问?

】关于可序列化交易的一些疑问?【英文标题】:Somequeriesregardingserializabletransactions?【发布时间】:2011-10-1417:59:09【问题描述】:我已经读过,提交的隔离可以提供比可序列化隔离级别更多的并发性。我的问题是已提交的读隔离... 查看详情

95-38-030-buffer-javanio中-关于directbuffer,heapbuffer的疑问

...本文摘要:https://www.zhihu.com/question/573740682.疑问JavaNIO中,关于DirectBuffer,HeapBuffer的疑问?DirectBuffer属于堆外存,那应该还是属于用户内存,而不是内核内存?FileChannel的read(ByteBufferdst)函数,write(ByteBuf 查看详情

关于react的一些疑问点

1、refs  <inputtype="text"ref="input">  <divref="div">222</div>  <divref={this.refHandle.bind(this)}>3333</div>  则打印出来的   console.log(this.refs)  //object{input: 查看详情

关于顶功输入的疑问

...===========================以下是我针对他的问题所作的回答。关于cfeilong先 查看详情

关于 RNN 中的批大小和时间步长的疑问

】关于RNN中的批大小和时间步长的疑问【英文标题】:doubtsregardingbatchsizeandtimestepsinRNN【发布时间】:2017-11-0623:10:03【问题描述】:在TensorFlow的RNN教程中:https://www.tensorflow.org/tutorials/recurrent.它提到了两个参数:批量大小和时间... 查看详情

关于决策树和随机森林分类器(scikit)的疑问

】关于决策树和随机森林分类器(scikit)的疑问【英文标题】:Doubtsregardingdecisiontreesandrandomforestclassifier(scikit)【发布时间】:2016-03-2403:46:47【问题描述】:我是决策树的新手,所以这些问题可能是微不足道的。决策树:根据sciki... 查看详情

关于 C Linux 中命名信号量的疑问

】关于CLinux中命名信号量的疑问【英文标题】:DoubtsregardingNamedSemaphoreinCLinux【发布时间】:2013-06-1210:44:07【问题描述】:我正在使用namedsemaphoreinCinLinux来控制跨多个进程对共享内存的访问。到目前为止,我还没有向信号量sem_clos... 查看详情

mysql关于changebuffer的疑问

什么是merge将changebuffer中的操作应用到原数据页,得到最新结果的过程称为merge。除了访问这个数据页会触发merge外,系统有后台线程会定期merge。在数据库正常关闭(shutdown)的过程中,也会执行merge操作。为什么changebuffer适用于... 查看详情

关于socket的疑问

一直感觉一端发送数据,另一端接受数据很不可思议的事情,如果不能即时地读走会导致什么后果呢?其实socket读出来的数据,你自己看着办,里面的数据是什么格式你自己去解析,用户可以基于TCP去实现你自己的协议【其... 查看详情

关于伪造ip地址的疑问

1、使用火狐浏览器的ModifyHeaders插件可以伪造IP,,Add,Headername=X_FORWARDED_FOR,Value=IP;   然后确定,刷新页面即可;  问题就是这个Headername为什么只能是X_FORWARDED_FOR,而不能是HTTP_CLIENT_IP(客户端ip)或者REMOTE_ADDR,&n... 查看详情

关于 Angular 2 中的事件发出的一些疑问。这个例子究竟是如何工作的?

】关于Angular2中的事件发出的一些疑问。这个例子究竟是如何工作的?【英文标题】:SomedoubtsabouttheeventemitinAngular2.Howexactlythisexampleworks?【发布时间】:2017-11-2008:13:31【问题描述】:我是Angular2的绝对初学者,我对这个与框架如何... 查看详情

关于叛逆的疑问和感想

《硅谷之谜》中反复提及硅谷人的“叛逆”,而且把“叛逆和宽容”作为硅谷的独特之处的第一条。我理解他其实想表达的含义,应该是“叛逆”能激发“创新”?而“创新”应作为第一要素。应做N+1的“叛逆”(潜台词其实就... 查看详情

关于defer.promise.then异步的一个疑问

疑问:感觉会报错,因为执行到defer.promise.then这时候还没到defer.resolve,因为异步读文件,总归会慢解答:先执行defer.promise.then,是给callback赋值,函数的赋值会比较抽象,callback得到函数的赋值后,是函数就该等待执行,等待reso... 查看详情

一个关于java泛型的疑问(代码片段)

之前对如下代码的区别不了解Stack<Integer>stack=newStack<Integer>();Stackstack1=newStack();现在写个demo理解下,主要区别为是否指定了泛型。importjava.util.ArrayList;importjava.util.Stack;/***@Description:TOD 查看详情

关于易语言采用加壳软件加壳的疑问

我有一款易语言软件,用了几款加壳软件加密之后都不能使用,这是因为什么原因引起的?参考技术A代码加壳加错乱了,有些加壳软件直接把代码加错乱导致软件不能运行。主要就是你加壳的方法不对。 参考技术B最好只加1个... 查看详情