diff --git a/docs/chapter6/chapter6.md b/docs/chapter6/chapter6.md index b4af686..13fb33c 100644 --- a/docs/chapter6/chapter6.md +++ b/docs/chapter6/chapter6.md @@ -20,7 +20,7 @@ $$ 举例来说,有一种评论家叫做 `state value function(状态价值函数)`。状态价值函数的意思就是说,假设演员叫做 $\pi$,拿 $\pi$ 跟环境去做互动。假设 $\pi$ 看到了某一个状态 s,如果在玩 Atari 游戏的话,状态 s 是某一个画面,看到某一个画面的时候,接下来一直玩到游戏结束,期望的累积奖励有多大。所以 $V^{\pi}$ 是一个函数,这个函数输入一个状态,然后它会输出一个标量( scalar)。这个标量代表说,$\pi$ 这个演员看到状态 s 的时候,接下来预期到游戏结束的时候,它可以得到多大的值。 -![](img/6.1.png) +![](img/6.1.png ':size=550') 举个例子,假设你是玩 space invader 的话, @@ -44,11 +44,11 @@ $$ 但是实际上,你不可能把所有的状态通通都扫过。如果你是玩 Atari 游戏的话,状态是图像,你没有办法把所有的状态通通扫过。所以实际上 $V^{\pi}(s)$ 是一个网络。对一个网络来说,就算输入状态是从来都没有看过的,它也可以想办法估测一个值的值。 -![](img/6.2.png) +![](img/6.2.png ':size=550') 怎么训练这个网络呢?因为如果在状态 $s_a$,接下来的累积奖励就是 $G_a$。也就是说,对这个价值函数来说,如果输入是状态 $s_a$,正确的输出应该是 $G_a$。如果输入状态 $s_b$,正确的输出应该是值 $G_b$。**所以在训练的时候, 它就是一个 `回归问题(regression problem)`。**网络的输出就是一个值,你希望在输入 $s_a$ 的时候,输出的值跟 $G_a$ 越近越好,输入 $s_b$ 的时候,输出的值跟 $G_b$ 越近越好。接下来把网络训练下去,就结束了。这是 MC-based 的方法。 -![](img/6.3.png) +![](img/6.3.png ':size=550') **第二个方法是`Temporal-difference(时序差分)` 的方法, `即 TD-based ` 的方法。** @@ -80,7 +80,7 @@ $$ 如果用 TD 的话,你是要去最小化这样的一个式子: -![](img/6.5.png ':size=450') +![](img/6.5.png ':size=550') 在这中间会有随机性的是 r。因为计算你在 $s_t$ 采取同一个动作,你得到的奖励也不一定是一样的,所以 r 是一个随机变量。但这个随机变量的方差会比 $G_a$ 还要小,因为 $G_a$ 是很多 r 合起来,这边只是某一个 r 而已。$G_a$ 的方差会比较大,r 的方差会比较小。但是这边你会遇到的**一个问题是你这个 V 不一定估得准**。假设你的这个 V 估得是不准的,那你使用这个式子学习出来的结果,其实也会是不准的。所以 MC 跟 TD 各有优劣。**今天其实 TD 的方法是比较常见的,MC 的方法其实是比较少用的。** @@ -121,7 +121,7 @@ $$ Q-function 有一个需要注意的问题是,这个演员 $\pi$,在看到状态 s 的时候,它采取的动作不一定是 a。Q-function 假设在状态 s 强制采取动作 a。不管你现在考虑的这个演员 $\pi$, 它会不会采取动作 a,这不重要。在状态 s 强制采取动作 a。接下来都用演员 $\pi$ 继续玩下去,就只有在状态 s,我们才强制一定要采取动作 a,接下来就进入自动模式,让演员 $\pi$ 继续玩下去,得到的期望奖励才是 $Q^{\pi}(s,a)$ 。 -![](img/6.7.png) +![](img/6.7.png ':size=550') Q-function 有两种写法: @@ -132,7 +132,7 @@ Q-function 有两种写法: 那你要注意的事情是,上图右边的函数只有离散动作才能够使用。如果动作是无法穷举的,你只能够用上图左边这个式子,不能够用右边这个式子。 -![](img/6.8.png) +![](img/6.8.png ':size=550') 上图是文献上的结果,你去估计 Q-function 的话,看到的结果可能如上图所示。假设我们有 3 个动作:原地不动、向上、向下。 @@ -146,7 +146,7 @@ Q-function 有两种写法: 这是状态-动作价值的一个例子。 -![](img/6.9.png) +![](img/6.9.png ':size=550') 虽然表面上我们学习一个 Q-function,它只能拿来评估某一个演员$\pi$ 的好坏,但只要有了这个 Q-function,我们就可以做强化学习。有了这个 Q-function,我们就可以决定要采取哪一个动作,我们就可以进行`策略改进(Policy Improvement)`。 @@ -267,21 +267,23 @@ $$ ### Intuition -![](img/6.13.png) +![](img/6.13.png ':size=550') 我们可以通过猫追老鼠的例子来直观地理解为什么要 fix target network。猫是 `Q estimation`,老鼠是 `Q target`。一开始的话,猫离老鼠很远,所以我们想让这个猫追上老鼠。 -![](img/6.14.png) +![](img/6.14.png ':size=550') 因为 Q target 也是跟模型参数相关的,所以每次优化后,Q target 也会动。这就导致一个问题,猫和老鼠都在动。 -![](img/6.15.png) +![](img/6.15.png ':size=550') 然后它们就会在优化空间里面到处乱动,就会产生非常奇怪的优化轨迹,这就使得训练过程十分不稳定。所以我们可以固定 Q target,让老鼠动得不是那么频繁,可能让它每 5 步动一次,猫则是每一步都在动。如果老鼠每 5 次动一步的话,猫就有足够的时间来接近老鼠。然后它们之间的距离会随着优化过程越来越小,最后它们就可以拟合,拟合过后就可以得到一个最好的Q 网络。 ## Exploration -![](img/6.16.png)**第二个 tip 是`探索(Exploration)`。**当我们使用 Q-function 的时候,policy 完全取决于 Q-function。给定某一个状态,你就穷举所有的 a, 看哪个 a 可以让 Q 值最大,它就是采取的动作。这个跟策略梯度不一样,在做策略梯度的时候,输出其实是随机的。我们输出一个动作的分布,根据这个动作的分布去做采样, 所以在策略梯度里面,你每次采取的动作是不一样的,是有随机性的。 +![](img/6.16.png) + +**第二个 tip 是`探索(Exploration)`。**当我们使用 Q-function 的时候,policy 完全取决于 Q-function。给定某一个状态,你就穷举所有的 a, 看哪个 a 可以让 Q 值最大,它就是采取的动作。这个跟策略梯度不一样,在做策略梯度的时候,输出其实是随机的。我们输出一个动作的分布,根据这个动作的分布去做采样, 所以在策略梯度里面,你每次采取的动作是不一样的,是有随机性的。 像这种 Q-function, 如果你采取的动作总是固定的,会有什么问题呢?你会遇到的问题就是这不是一个好的收集数据的方式。因为假设我们今天真的要估某一个状态,你可以采取动作 $a_{1}$, $a_{2}$, $a_{3}$。你要估测在某一个状态采取某一个动作会得到的 Q 值,你一定要在那一个状态采取过那一个动作,才估得出它的值。如果你没有在那个状态采取过那个动作,你其实估不出那个值的。如果是用深的网络,就你的 Q-function 是一个网络,这种情形可能会没有那么严重。但是一般而言,假设 Q-function 是一个表格,没有看过的 state-action pair,它就是估不出值来。网络也是会有一样的问题,只是没有那么严重。所以今天假设你在某一个状态,动作 $a_{1}$, $a_{2}$, $a_{3}$ 你都没有采取过,那你估出来的 $Q(s,a_{1})$, $Q(s,a_{2})$, $Q(s,a_{3})$ 的值可能都是一样的,就都是一个初始值,比如说 0,即 $$ @@ -314,7 +316,7 @@ A: 因为 Q 值是有正有负的,所以可以它弄成一个概率,你先 这边要注意是 replay buffer 里面的经验可能是来自于不同的策略,你每次拿 $\pi$ 去跟环境互动的时候,你可能只互动 10000 次,然后接下来你就更新你的 $\pi$ 了。但是这个 buffer 里面可以放 5 万笔资料,所以 5 万笔资料可能是来自于不同的策略。Buffer 只有在它装满的时候,才会把旧的资料丢掉。所以这个 buffer 里面它其实装了很多不同的策略的经验。 -![](img/6.18.png) +![](img/6.18.png ':size=550') 有了这个 buffer 以后,你是怎么训练这个 Q 的模型呢,怎么估 Q-function?你的做法是这样:你会迭代地去训练这个 Q-function,在每次迭代里面,你从这个 buffer 里面随机挑一个 batch 出来,就跟一般的网络训练一样,你从那个训练集里面,去挑一个 batch 出来。你去采样一个 batch 出来,里面有一把的经验,根据这把经验去更新你的 Q-function。就跟 TD learning 要有一个目标网络是一样的。你去采样一堆 batch,采样一个 batch 的数据,采样一堆经验,然后再去更新你的 Q-function。