diff --git a/docs/chapter1/chapter1.md b/docs/chapter1/chapter1.md index e057858..95814f0 100644 --- a/docs/chapter1/chapter1.md +++ b/docs/chapter1/chapter1.md @@ -380,7 +380,7 @@ Learning 和 Planning 是序列决策的两个基本问题。 ### K-armed Bandit  -与一般监督学习不同,强化学习任务的最终奖赏是在多步动作之后才能观察到,这里我们不妨先考虑比较简单的情形:最大化单步奖赏,即仅考虑一步操作。需注意的是,即便在这样的简化情形下,强化学习仍与监督学习有显著不同,因为机器需通过尝试来发现各个动作产生的结果,而没有训练数据告诉机器应当做哪个动作。 +与监督学习不同,强化学习任务的最终奖赏是在多步动作之后才能观察到,这里我们不妨先考虑比较简单的情形:最大化单步奖赏,即仅考虑一步操作。需注意的是,即便在这样的简化情形下,强化学习仍与监督学习有显著不同,因为机器需通过尝试来发现各个动作产生的结果,而没有训练数据告诉机器应当做哪个动作。 想要最大化单步奖赏需考虑两个方面:一是需知道每个动作带来的奖赏,二是要执行奖赏最大的动作。若每个动作对应的奖赏是一个确定值,那么尝试遍所有的动作便能找出奖赏最大的动作。然而,更一般的情形是,一个动作的奖赏值是来自于一个概率分布,仅通过一次尝试并不能确切地获得平均奖赏值。 @@ -404,11 +404,11 @@ Learning 和 Planning 是序列决策的两个基本问题。  -你可以直接调用现有的包来实践。现在有很多深度学习的包可以用,熟练使用这里面的两三种,其实已经可以实现非常多的功能。所以你并不需要从头去去造轮子,就直接调用它里面的函数去实现你想实现的功能。 +你可以直接调用现有的包来实践。现在有很多深度学习的包可以用,熟练使用这里面的两三种,就可以实现非常多的功能。所以你并不需要从头去造轮子。  - [ OpenAI](https://openai.com/) 是一个非盈利的人工智能研究公司。Open AI 公布了非常多的学习资源以及这个算法资源,他们之所以叫 Open AI,就是他们把所有开发的算法都 open source 出来。 + [ OpenAI](https://openai.com/) 是一个非盈利的人工智能研究公司。Open AI 公布了非常多的学习资源以及算法资源,他们之所以叫 Open AI,就是他们把所有开发的算法都 open source 出来。 ### Gym @@ -449,7 +449,11 @@ $python  -这里我们看一下 CartPole 的这个环境。对于这个环境,有两个动作,Cart 往左移还是往右移。这里得到了观测:这个车当前的位置,Cart 当前的往左往右移的速度,这个杆的角度以及它的杆的最高点的速度。 +这里我们看一下 CartPole 的这个环境。对于这个环境,有两个动作,Cart 往左移还是往右移。这里得到了观测: + +* 这个车当前的位置, +* Cart 当前往左往右移的速度, +* 这个杆的角度以及杆的最高点的速度。 如果 observation 越详细,就可以更好地描述当前这个所有的状态。这里有 reward 的定义,如果能多保留一步,你就会得到一个奖励,所以你需要在尽可能多的时间存活来得到更多的奖励。当这个杆的角度大于某一个角度(没能保持平衡)或者这个车已经出到外面的时候,游戏就结束了,你就输了。所以这个 agent 的目的就是为了控制木棍,让它尽可能地保持平衡以及尽可能保持在这个环境的中央。 diff --git a/docs/chapter2/chapter2.md b/docs/chapter2/chapter2.md index dc9248e..7720160 100644 --- a/docs/chapter2/chapter2.md +++ b/docs/chapter2/chapter2.md @@ -573,7 +573,7 @@ $$  - + 我们再来看一个动态的例子,首先推荐斯坦福大学的一个网站:[GridWorld: Dynamic Programming Demo](https://cs.stanford.edu/people/karpathy/reinforcejs/gridworld_dp.html) ,这个网站模拟了单步更新的过程中,所有格子的一个状态价值的变化过程。 @@ -581,14 +581,15 @@ $$ 在这样的环境里面,我们想计算它每一个状态的价值。我们也定义了它的 reward function,你可以看到有些状态上面有一个 R 的值。比如我们这边有些值是为负的,我们可以看到格子里面有几个 -1 的 reward,只有一个 +1 reward 的格子。在这个棋盘的中间这个位置,可以看到有一个 R 的值是 1.0,为正的一个价值函数。 所以每个状态对应了一个值,然后有一些状态没有任何值,就说明它的这个 reward function,它的奖励是为零的。 - + + 我们开始做这个 policy evaluation,policy evaluation 是一个不停迭代的过程。当我们初始化的时候,所有的 $v(s)$ 都是 0。我们现在迭代一次,迭代一次过后,你发现有些状态上面,值已经产生了变化。比如有些状态的值的 R 为 -1,迭代一次过后,它就会得到 -1 的这个奖励。对于中间这个绿色的,因为它的奖励为正,所以它是 +1 的状态。 - + 所以当迭代第一次的时候,$v(s)$ 某些状态已经有些值的变化。 - + * 我们再迭代一次(one sweep),然后发现它就从周围的状态也开始有值。因为周围状态跟之前有值的状态是临近的,所以它就相当于把旁边这个状态转移过来。所以当我们逐渐迭代的话,你会发现这个值一直在变换。 @@ -784,41 +785,41 @@ $$  - + **我们来看一个 MDP control 的 Demo。** * 首先来看 policy iteration。之前的例子在每个状态都是采取固定的随机策略,就每个状态都是 0.25 的概率往上往下往左往右,没有策略的改变。 * 但是我们现在想做 policy iteration,就是每个状态的策略都进行改变。Policy iteration 的过程是一个迭代过程。 - + 我们先在这个状态里面 run 一遍 policy evaluation,就得到了一个 value function,每个状态都有一个 value function。 - + * **现在进行 policy improvement,按 policy update。**按这个 policy update 过后,你可以发现有些格子里面的 policy 已经产生变化。 * 比如说对于中间这个 -1 的这个状态,它的最佳策略是往下走。当你到达这个状态后,你应该往下,这样就会得到最佳的这个值。 * 绿色右边的这个方块的策略也改变了,它现在选取的最佳策略是往左走,也就是说在这个状态的时候,最佳策略应该是往左走。 - + 我们再 run 下一轮的 policy evaluation,你发现它的值又被改变了,很多次过后,它会收敛。 - + 我们再 run policy update,你发现每个状态里面的值基本都改变,它不再是上下左右随机在变了,它会选取一个最佳的策略。 - + 我们再 run 这个 policy evaluation,它的值又在不停地变化,变化之后又收敛了。 - + 我们再来 run 一遍 policy update。现在它的值又会有变化,就在每一个状态,它的这个最佳策略也会产生一些改变。 - + 再来在这个状态下面进行改变,现在你看基本没有什么变化,就说明整个 MDP 已经收敛了。所以现在它每个状态的值就是它当前最佳的 value function 的值以及它当前状态对应的这个 policy 就是最佳的 policy。 @@ -826,7 +827,7 @@ $$ 这个 Demo 说明了 policy iteration 可以把 gridworld 解决掉。解决掉的意思是说,不管在哪个状态,都可以顺着状态对应的最佳的策略来到达可以获得最多奖励的一个状态。 - + **我们再用 value iteration 来解 MDP,点第 3 个 value iteration。** diff --git a/docs/chapter3/chapter3.md b/docs/chapter3/chapter3.md index ddbe495..c4b9870 100644 --- a/docs/chapter3/chapter3.md +++ b/docs/chapter3/chapter3.md @@ -225,7 +225,7 @@ MC 是通过 empirical mean return (实际得到的收益)来更新它,对 **为了让大家更加直观感受下一个状态影响上一个状态**,我们推荐这个网站:[Temporal Difference Learning Gridworld Demo](https://cs.stanford.edu/people/karpathy/reinforcejs/gridworld_td.html)。 - + * 我们先初始化一下,然后开始时序差分的更新过程。 * 在训练的过程中,你会看到这个小黄球在不断地试错,在探索当中会先迅速地发现有 reward 的地方。最开始的时候,只是这些有 reward 的格子才有价值。当不断地重复走这些路线的时候,这些有价值的格子可以去慢慢地影响它附近的格子的价值。 @@ -411,6 +411,11 @@ $\varepsilon\text{-greedy}$ 的意思是说,我们有 $1-\varepsilon$ 的概 所以我们可以把 TD 也放到 control loop 里面去估计 Q-table,再采取这个 $\varepsilon$-greedy improvement。这样就可以在 episode 没结束的时候来更新已经采集到的状态价值。 + + +>* **偏差(bias):**描述的是预测值(估计值)的期望与真实值之间的差距。偏差越大,越偏离真实数据,如上图第二行所示。 +>* **方差(variance):**描述的是预测值的变化范围,离散程度,也就是离其期望值的距离。方差越大,数据的分布越分散,如上图右列所示。 + ### Sarsa: On-policy TD Control  @@ -548,6 +553,9 @@ Sarsa 是用自己的策略产生了 S,A,R,S',A' 这一条轨迹。然后拿着 * 比较 Q-learning 和 Sarsa 的更新公式可以发现,Sarsa 并没有选取最大值的 max 操作,因此, * Q-learning 是一个非常激进的算法,希望每一步都获得最大的利益; * 而 Sarsa 则相对非常保守,会选择一条相对安全的迭代路线。 + + + ## Summary  @@ -561,6 +569,7 @@ Sarsa 是用自己的策略产生了 S,A,R,S',A' 这一条轨迹。然后拿着 * [百面深度学习](https://book.douban.com/subject/35043939/) * [神经网络与深度学习](https://nndl.github.io/) * [机器学习](https://book.douban.com/subject/26708119//) +* [Understanding the Bias-Variance Tradeoff](http://scott.fortmann-roe.com/docs/BiasVariance.html) diff --git a/docs/chapter3/img/bias_variance.png b/docs/chapter3/img/bias_variance.png new file mode 100644 index 0000000..1014685 Binary files /dev/null and b/docs/chapter3/img/bias_variance.png differ diff --git a/docs/chapter4/chapter4.md b/docs/chapter4/chapter4.md index 8fbc0ed..5253e07 100644 --- a/docs/chapter4/chapter4.md +++ b/docs/chapter4/chapter4.md @@ -3,7 +3,7 @@  -在 reinforcement learning 中有 3 个components,一个`actor`,一个`environment`,一个`reward function`。 +在 reinforcement learning 中有 3 个 components:`actor`、`environment` 和 `reward function`。 让机器玩 video game 时, @@ -76,9 +76,11 @@ $$  +在 reinforcement learning 里面,除了 environment 跟 actor 以外, 还有`reward function`。 -在 reinforcement learning 里面,除了 environment 跟 actor 以外, 还有`reward function`。Reward function 根据在某一个 state 采取的某一个 action 决定说现在这个行为可以得到多少的分数。 它是一个 function,给它 $s_1$,$a_1$,它告诉你得到 $r_1$。给它 $s_2$ ,$a_2$,它告诉你得到 $r_2$。 把所有的 $r$ 都加起来,我们就得到了 $R(\tau)$ ,代表某一个 trajectory $\tau$ 的 reward。在某一场游戏里面, 某一个 episode 里面,我们会得到 R。**我们要做的事情就是调整 actor 内部的参数 $\theta$, 使得 R 的值越大越好。** 但实际上 reward 并不只是一个 scalar,reward 其实是一个 random variable,R 其实是一个 random variable。 因为 actor 在给定同样的 state 会做什么样的行为,这件事情是有随机性的。environment 在给定同样的 observation 要采取什么样的 action,要产生什么样的 observation,本身也是有随机性的。所以 R 是一个 random variable,你能够计算的,是它的期望值。你能够计算的是说,在给定某一组参数 $\theta$ 的情况下,我们会得到的 R 的期望值是多少。 +Reward function 根据在某一个 state 采取的某一个 action 决定说现在这个行为可以得到多少的分数。 它是一个 function,给它 $s_1$,$a_1$,它告诉你得到 $r_1$。给它 $s_2$ ,$a_2$,它告诉你得到 $r_2$。 把所有的 $r$ 都加起来,我们就得到了 $R(\tau)$ ,代表某一个 trajectory $\tau$ 的 reward。 +在某一场游戏里面, 某一个 episode 里面,我们会得到 R。**我们要做的事情就是调整 actor 内部的参数 $\theta$, 使得 R 的值越大越好。** 但实际上 reward 并不只是一个 scalar,reward 其实是一个 random variable。R 其实是一个 random variable,因为 actor 在给定同样的 state 会做什么样的行为,这件事情是有随机性的。Environment 在给定同样的 observation 要采取什么样的 action,要产生什么样的 observation,本身也是有随机性的。所以 R 是一个 random variable,你能够计算的,是它的期望值。你能够计算的是说,在给定某一组参数 $\theta$ 的情况下,我们会得到的 R 的期望值是多少。 $$ \bar{R}_{\theta}=\sum_{\tau} R(\tau) p_{\theta}(\tau) $$ @@ -112,7 +114,7 @@ $$ \end{aligned} $$ -实际上这个 expected value 没有办法算,所以你是用 sample 的方式来 sample 一大堆的 $\tau$。你 sample $N$ 笔 $\tau$, 然后你去计算每一笔的这些 value,然后把它全部加起来,最后你就得到你的 gradient。你就可以去 update 你的参数,你就可以去 update 你的 agent,如下式所示。 +实际上这个 expected value 没有办法算,所以你是用 sample 的方式来 sample 一大堆的 $\tau$。你 sample $N$ 笔 $\tau$, 然后你去计算每一笔的这些 value,然后把它全部加起来,就可以得到你的 gradient。你就可以去 update 你的参数,你就可以去 update 你的 agent,如下式所示。 $$ \begin{aligned} E_{\tau \sim p_{\theta}(\tau)}\left[R(\tau) \nabla \log p_{\theta}(\tau)\right] &\approx \frac{1}{N} \sum_{n=1}^{N} R\left(\tau^{n}\right) \nabla \log p_{\theta}\left(\tau^{n}\right) \\ @@ -143,7 +145,7 @@ $$ 你就可以把 sample 到的东西代到这个 gradient 的式子里面,把 gradient 算出来。也就是把这边的每一个 s 跟 a 的 pair 拿进来,算一下它的 log probability 。你计算一下在某一个 state 采取某一个 action 的 log probability,然后对它取 gradient,然后这个 gradient 前面会乘一个 weight,weight 就是这场游戏的 reward。 有了这些以后,你就会去 update 你的 model。 -Update 完你的 model 以后。你要重新去收集 data,再 update model。这边要注意一下,一般 policy gradient sample 的 data 就只会用一次。你把这些 data sample 起来,然后拿去 update 参数,这些 data 就丢掉了。接着再重新 sample data,才能够去 update 参数, 等一下我们会解决这个问题。 +Update 完你的 model 以后。你要重新去收集 data,再 update model。这边要注意一下,一般 `policy gradient(PG) ` sample 的 data 就只会用一次。你把这些 data sample 起来,然后拿去 update 参数,这些 data 就丢掉了。接着再重新 sample data,才能够去 update 参数, 等一下我们会解决这个问题。  @@ -158,13 +160,12 @@ Update 完你的 model 以后。你要重新去收集 data,再 update model。  -做 classification 的时候,objective function 就是 maximize 或 minimize 的对象, 因为我们现在是 maximize likelihood 所以其实是 maximize, 你要 maximize 的对象,如下式所示: +做 classification 的时候,objective function 就是 maximize 或 minimize 的对象, 因为我们现在是 maximize likelihood,所以其实是 maximize, 你要 maximize 的对象,如下式所示: $$ \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}} \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right) $$ -像这种 loss function,你可在 TensorFlow 里调用现成的 function,它就会自动帮你算。 -然后你就可以把 gradient 计算出来,这是一般的分类问题。RL 唯一不同的地方是 loss 前面乘上一个 weight,这个是整场游戏的时候得到的 total reward R, 它并不是在 state s 采取 action a 的时候得到的 reward。 你要把你的每一笔 training data,都 weighted by 这个 R。然后你用 TensorFlow 或 PyTorch 去帮你算 gradient 就结束了,跟一般 classification 差不多。 +像这种 loss function,你可在 TensorFlow 里调用现成的 function,它就会自动帮你算,然后你就可以把 gradient 计算出来。这是一般的分类问题,RL 唯一不同的地方是 loss 前面乘上一个 weight,这个是整场游戏的时候得到的 total reward R, 它并不是在 state s 采取 action a 的时候得到的 reward。 你要把你的每一笔 training data,都 weighted by 这个 R。然后你用 TensorFlow 或 PyTorch 去帮你算 gradient 就结束了,跟一般 classification 差不多。 ## Tips 这边有一些在实现的时候,你也许用得上的 tip。 @@ -183,7 +184,7 @@ $$  -这个是一个理想上的状况,但是实际上,我们是在做 sampling 就本来这边应该是一个 expectation, summation over 所有可能的 s 跟 a 的 pair。 但你真正在学的时候,当然不可能是这么做的,你只是 sample 了少量的 s 跟 a 的 pair 而已。 因为我们做的是 sampling,有一些 action 可能从来都没有 sample 到。在某一个 state1,虽然可以执行的 action 有 a/b/c 3 个,但你可能只 sample 到 action b,你可能只 sample 到 action c,你没有 sample 到 action a。但现在所有 action 的 reward 都是正的,所以根据这个式子,它的每一项的概率都应该要上升。你会遇到的问题是,因为 a 没有被 sample 到,其它 action 的概率如果都要上升,a 的概率就下降。 所以 a 不一定是一个不好的 action, 它只是没被 sample 到。但只是因为它没被 sample 到, 它的概率就会下降,这个显然是有问题的,要怎么解决这个问题呢?你会希望你的 reward 不要总是正的。 +这是一个理想上的状况,但是实际上,我们是在做 sampling 就本来这边应该是一个 expectation, summation over 所有可能的 s 跟 a 的 pair。 但你真正在学的时候,当然不可能是这么做的,你只是 sample 了少量的 s 跟 a 的 pair 而已。 因为我们做的是 sampling,有一些 action 可能从来都没有 sample 到。在某一个 state1,虽然可以执行的 action 有 a/b/c 3 个,但你可能只 sample 到 action b,你可能只 sample 到 action c,你没有 sample 到 action a。但现在所有 action 的 reward 都是正的,所以根据这个式子,它的每一项的概率都应该要上升。你会遇到的问题是,因为 a 没有被 sample 到,其它 action 的概率如果都要上升,a 的概率就下降。 所以 a 不一定是一个不好的 action, 它只是没被 sample 到。但只是因为它没被 sample 到, 它的概率就会下降,这个显然是有问题的,要怎么解决这个问题呢?你会希望你的 reward 不要总是正的。  @@ -284,11 +285,16 @@ REINFORCE 的伪代码主要看最后四行,先产生一个 episode 的数据  -类似地,policy gradient 预测每一个状态下面应该要输出的这个行动的概率,就是输入状态 $s_t$,然后输出动作的概率,比如 0.02,0.08,0.09。实际上输出给环境的动作是随机选了一个 action,比如说我选了右这个 action,它的 one-hot 向量就是 0,0,1。我们把神经网络的输出和实际动作带入 cross entropy 的公式就可以求出输出的概率和实际的动作之间的差距。但这个实际的动作 $a_t$ 只是我们输出的真实的 action,它并不一定是正确的 action,它不能像手写数字识别一样作为一个正确的标签来去指导神经网络朝着正确的方向去更新,所以我们在这里会需要乘以一个奖励回报 $G_t$。这个奖励回报相当于是对这个真实 action 的评价,$G_t$ 具体越大,未来总收益越大,说明当前输出的这个真实的 action 就越好,这个 loss 就越需要重视。如果 $G_t$ 越小,那就说明做这个 action $a_t$ 并没有那么的好,loss 的权重就要小一点,优化力度就小一点。通过这个和那个手写输入识别的一个对比,我们就知道为什么 loss 会构造成这个样子。 +* 类似地,policy gradient 预测每一个状态下面应该要输出的这个行动的概率,就是输入状态 $s_t$,然后输出动作的概率,比如 0.02,0.08,0.09。实际上输出给环境的动作是随机选了一个 action,比如说我选了右这个 action,它的 one-hot 向量就是 0,0,1。 +* 我们把神经网络的输出和实际动作带入 cross entropy 的公式就可以求出输出的概率和实际的动作之间的差距。 +* 但这个实际的动作 $a_t$ 只是我们输出的真实的 action,它并不一定是正确的 action,它不能像手写数字识别一样作为一个正确的标签来去指导神经网络朝着正确的方向去更新,所以我们需要乘以一个奖励回报 $G_t$。这个奖励回报相当于是对这个真实 action 的评价。 + * 如果 $G_t$ 越大,未来总收益越大,那就说明当前输出的这个真实的 action 就越好,这个 loss 就越需要重视。 + * 如果 $G_t$ 越小,那就说明做这个 action $a_t$ 并没有那么的好,loss 的权重就要小一点,优化力度就小一点。 +* 通过这个和那个手写输入识别的一个对比,我们就知道为什么 loss 会构造成这个样子。  -实际上我们在计算这个 loss 的时候,我们要拿到那个 $\ln \pi(A_t|S_t,\theta)$。我就拿我实际执行的这个动作,先取个 one-hot 向量,然后再拿到神经网络预测的动作概率,这两个一相乘,我就可以拿到算法里面的那个 $\ln \pi(A_t|S_t,\theta)$。这个就是我们要构造的 loss。因为我们会拿到整个 episode 的所有的轨迹,所以我们可以对这一条整条轨迹里面的每个 action 都去计算一个 loss。把所有的 loss 加起来之后,我们再扔给那个 adam 的优化器去自动更新参数就好了。 +实际上我们在计算这个 loss 的时候,我们要拿到那个 $\ln \pi(A_t|S_t,\theta)$。我就拿实际执行的这个动作,先取个 one-hot 向量,然后再拿到神经网络预测的动作概率,这两个一相乘,我就可以拿到算法里面的那个 $\ln \pi(A_t|S_t,\theta)$。这个就是我们要构造的 loss。因为我们会拿到整个 episode 的所有的轨迹,所以我们可以对这一条整条轨迹里面的每个 action 都去计算一个 loss。把所有的 loss 加起来之后,我们再扔给 adam 的优化器去自动更新参数就好了。  diff --git a/docs/index.html b/docs/index.html index 6c7d333..a635088 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,6 +7,7 @@ +
@@ -24,5 +25,6 @@ +