我正在学习this post的时间差异学习。这里TD(0)的更新规则对我来说很清楚,但是在TD(λ)中,我不明白在一次更新中如何更新所有先前状态的效用值。
以下是用于比较机器人更新的图表:
上图解释如下:
在TD(λ)中,由于合格性迹线,结果传播回所有先前的状态。
我的问题是,即使我们使用具有资格跟踪的以下更新规则,如何将信息传播到单个更新中的所有先前状态?
在一次更新中,我们只更新单个状态Ut(s)
的实用程序,然后如何更新所有先前状态的实用程序?
编辑
根据答案,很明显,此更新适用于每一步,这就是传播信息的原因。如果是这种情况,那么它再次让我困惑,因为更新规则之间的唯一区别是资格跟踪。
因此,即使资格跟踪的值对于先前的状态不为零,在上述情况下delta的值将为零(因为最初的奖励和效用函数被初始化为0)。那么以前的状态如何在第一次更新中获得除零以外的其他效用值?
同样在给定的python实现中,在单次迭代后给出以下输出:
[[ 0. 0.04595 0.1 0. ]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]]
这里只更新了2个值而不是所有5个先前的状态,如图所示。我在这里缺少什么?
因此,即使资格跟踪的值对于先前的状态不为零,在上述情况下delta的值将为零(因为最初的奖励和效用函数被初始化为0)。那么以前的状态如何在第一次更新中获得除零以外的其他效用值?
你是对的,在第一次更新中,所有的奖励和更新仍然是0
(除非我们已经设法一步到达目标,然后奖励将不是0
)。
但是,资格跟踪e_t
将继续“记住”或“记住”我们之前访问过的所有州。因此,一旦我们设法达到目标状态并获得非零奖励,资格痕迹仍将记住我们经历的所有状态。这些状态在资格跟踪表中仍然会有非零条目,因此一旦您观察到您的第一个奖励,所有状态都会立即获得非零更新。
资格跟踪表确实每一步都会衰减(乘以gamma * lambda_
),因此很久以前访问过的状态更新幅度将小于我们最近访问过的状态更新幅度,但我们会继续要记住所有这些状态,他们将有非零条目(假设gamma > 0
和lambda_ > 0
)。这允许更新所有访问状态的值,而不是一旦我们到达那些状态,但是一旦我们观察到非零奖励(或者,在第一个时期之后的时期,一旦我们达到状态,我们已经在某个较早的时间点访问过它们之后已经存在非零预测值。
同样在给定的python实现中,在单次迭代后给出以下输出:
[[ 0. 0.04595 0.1 0. ] [ 0. 0. 0. 0. ] [ 0. 0. 0. 0. ]]
这里只更新了2个值而不是所有5个先前的状态,如图所示。我在这里缺少什么?
他们的代码的第一部分如下所示:
for epoch in range(tot_epoch):
#Reset and return the first observation
observation = env.reset(exploring_starts=True)
因此,每一个新纪元,他们都会首先使用exploring_starts
标志重置环境。如果我们看看the implementation of their environment,我们会看到这个标志的使用意味着我们总是从一个随机的初始位置开始。
因此,我怀疑,当运行代码生成该输出时,初始位置只是随机选择为目标左侧两步的位置,而不是左下角的位置。如果随机选择初始位置已经接近目标,则代理仅访问您看到非零更新的那两个状态,因此这些状态也将是资格表中具有非零条目的唯一状态跟踪因此是唯一具有非零更新的状态。
如果初始位置确实是左下角的位置,那么算法的正确实现确实会更新该路径上所有状态的值(假设没有添加额外的技巧,比如设置条目到0
,如果他们碰巧由于腐朽而与0
“足够接近”。
我还要注意,该页面上的代码实际上存在错误:在重置环境/开始新纪元时,它们不会将资格跟踪表的所有条目重置为0
。应该这样做。如果没有这样做,资格痕迹仍将记住在前一个时期内访问过的状态,并且仍然更新所有这些状态,即使它们在新纪元中没有再次访问过。这是不正确的。他们的代码的正确版本应该像这样开始:
for epoch in range(tot_epoch):
#Reset and return the first observation
observation = env.reset(exploring_starts=True)
trace_matrix = trace_matrix * 0.0 # IMPORTANT, added this
for step in range(1000):
...
您缺少一个小而重要的细节,更新规则适用于所有状态,而不仅仅是当前状态。因此,实际上,您正在更新e_t(s)
与零不同的所有状态。
编辑
delta
不为零,因为当剧集结束并且代理人获得+1的奖励时,计算当前状态。因此,在计算了不同于零的delta
之后,使用delta
和当前的合格性跟踪更新所有状态。
我不知道为什么在Python实现中(我没有仔细检查过)输出只更新了2个值,但请验证所有前5个状态的资格跟踪是否与0不同,如果不是这样的话,试着理解为什么。有时你不想将痕迹保持在很小的阈值(例如10e-5),因为它在学习过程中影响非常小,而且浪费了计算资源。
可以看出,δ用于计算状态效用。但是,δ使用下一个州的效用,如article所示。这意味着对于TD(0)它将更新所有状态,因为要计算Ut(s)我们需要计算下一个状态的U等等。
在TD(λ)中,在计算中添加合格性迹线时还会有额外的减少。上面得出的结论是,在第一次迭代中先前的值为0,因为所有实用程序在开始时为0,在更新时为TD(λ)他们通过资格追踪得到了更大的减少。你可以说它们非常小,太小而无法计算或考虑。