diff --git a/README.md b/README.md index 5e35bd8..98b0239 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ ## 使用说明 * 第 3 章到第 10 章为李宏毅《深度强化学习》课程的部分; -* 第 1 章根据[《强化学习纲要》](https://github.com/zhoubolei/introRL)整理而来; -* 第 2 章和第 11 章根据[《百度强化学习》](https://aistudio.baidu.com/aistudio/education/group/info/1335) 整理而来。 +* 第 1 章和第 2 章根据[《强化学习纲要》](https://github.com/zhoubolei/introRL)整理而来; +* 第 3 章和第 12 章根据[《百度强化学习》](https://aistudio.baidu.com/aistudio/education/group/info/1335) 整理而来。 ## 笔记在线阅读地址 @@ -17,16 +17,17 @@ ## 目录 - [P1 强化学习概述](https://datawhalechina.github.io/leedeeprl-notes/#/chapter1/chapter1) -- [P2 表格型方法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter2/chapter2) -- [P3 策略梯度](https://datawhalechina.github.io/leedeeprl-notes/#/chapter3/chapter3) -- [P4 近端策略优化 (PPO) 算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter4/chapter4) -- [P5 Q 学习 (基本概念)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter5/chapter5) -- [P6 Q 学习 (进阶技巧)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter6/chapter6) -- [P7 Q 学习 (连续动作)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter7/chapter7) -- [P8 演员-评论员算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter8/chapter8) -- [P9 稀疏奖励](https://datawhalechina.github.io/leedeeprl-notes/#/chapter9/chapter9) -- [P10 模仿学习](https://datawhalechina.github.io/leedeeprl-notes/#/chapter10/chapter10) -- [P11 深度确定性策略梯度 (DDPG) 算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter11/chapter11) +- [P2 马尔科夫决策过程 (MDP)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter2/chapter2) +- [P3 表格型方法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter3/chapter3) +- [P4 策略梯度](https://datawhalechina.github.io/leedeeprl-notes/#/chapter4/chapter4) +- [P5 近端策略优化 (PPO) 算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter5/chapter5) +- [P6 Q 学习 (基本概念)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter6/chapter6) +- [P7 Q 学习 (进阶技巧)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter7/chapter7) +- [P8 Q 学习 (连续动作)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter8/chapter8) +- [P9 演员-评论员算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter9/chapter9) +- [P10 稀疏奖励](https://datawhalechina.github.io/leedeeprl-notes/#/chapter10/chapter10) +- [P11 模仿学习](https://datawhalechina.github.io/leedeeprl-notes/#/chapter11/chapter11) +- [P12 深度确定性策略梯度 (DDPG) 算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter12/chapter12) ## 主要贡献者 diff --git a/docs/README.md b/docs/README.md index 268d55b..0d77cfe 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,8 +3,8 @@ ## 使用说明 * 第 3 章到第 10 章为李宏毅《深度强化学习》课程的部分; -* 第 1 章根据[《强化学习纲要》](https://github.com/zhoubolei/introRL)整理而来; -* 第 2 章和第 11 章根据[《百度强化学习》](https://aistudio.baidu.com/aistudio/education/group/info/1335) 整理而来。 +* 第 1 章和第 2 章根据[《强化学习纲要》](https://github.com/zhoubolei/introRL)整理而来; +* 第 3 章和第 12 章根据[《百度强化学习》](https://aistudio.baidu.com/aistudio/education/group/info/1335) 整理而来。 ## 笔记在线阅读地址 在线阅读地址:https://datawhalechina.github.io/leedeeprl-notes/ @@ -14,17 +14,17 @@ ## 目录 - [P1 强化学习概述](https://datawhalechina.github.io/leedeeprl-notes/#/chapter1/chapter1) -- [P2 表格型方法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter2/chapter2) -- [P3 策略梯度](https://datawhalechina.github.io/leedeeprl-notes/#/chapter3/chapter3) -- [P4 近端策略优化 (PPO) 算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter4/chapter4) -- [P5 Q 学习 (基本概念)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter5/chapter5) -- [P6 Q 学习 (进阶技巧)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter6/chapter6) -- [P7 Q 学习 (连续动作)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter7/chapter7) -- [P8 演员-评论员算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter8/chapter8) -- [P9 稀疏奖励](https://datawhalechina.github.io/leedeeprl-notes/#/chapter9/chapter9) -- [P10 模仿学习](https://datawhalechina.github.io/leedeeprl-notes/#/chapter10/chapter10) -- [P11 深度确定性策略梯度 (DDPG) 算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter11/chapter11) - +- [P2 马尔科夫决策过程 (MDP)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter2/chapter2) +- [P3 表格型方法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter3/chapter3) +- [P4 策略梯度](https://datawhalechina.github.io/leedeeprl-notes/#/chapter4/chapter4) +- [P5 近端策略优化 (PPO) 算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter5/chapter5) +- [P6 Q 学习 (基本概念)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter6/chapter6) +- [P7 Q 学习 (进阶技巧)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter7/chapter7) +- [P8 Q 学习 (连续动作)](https://datawhalechina.github.io/leedeeprl-notes/#/chapter8/chapter8) +- [P9 演员-评论员算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter9/chapter9) +- [P10 稀疏奖励](https://datawhalechina.github.io/leedeeprl-notes/#/chapter10/chapter10) +- [P11 模仿学习](https://datawhalechina.github.io/leedeeprl-notes/#/chapter11/chapter11) +- [P12 深度确定性策略梯度 (DDPG) 算法](https://datawhalechina.github.io/leedeeprl-notes/#/chapter12/chapter12) ## 主要贡献者 diff --git a/docs/chapter10/chapter10.md b/docs/chapter10/chapter10.md index c3b22e0..7643fb8 100644 --- a/docs/chapter10/chapter10.md +++ b/docs/chapter10/chapter10.md @@ -1,100 +1,81 @@ -# Imitation Learning +# Sparse Reward +实际上用 reinforcement learning learn agent 的时候,多数的时候 agent 都是没有办法得到 reward 的。那在没有办法得到 reward 的情况下,对 agent 来说它的训练是非常困难的。举例来说,假设你今天要训练一个机器手臂,然后桌上有一个螺丝钉跟螺丝起子,那你要训练它用螺丝起子把螺丝钉栓进去,那这个很难,为什么?因为你知道一开始你的 agent 是什么都不知道的,它唯一能够做不同的 action 的原因是 exploration。举例来说,你在做 Q-learning 的时候,会有一些随机性,让它去采取一些过去没有采取过的 action,那你要随机到说它把螺丝起子捡起来,再把螺丝栓进去,然后就会得到 reward 1,这件事情是永远不可能发生的。所以,不管你的 actor 做了什么事情,它得到 reward 永远都是 0,对它来说不管采取什么样的 action 都是一样糟或者是一样得好。所以,它最后什么都不会学到。如果环境中的 reward 非常的 sparse,reinforcement learning 的问题就会变得非常的困难。但是人类可以在非常 sparse 的 reward 上面去学习,我们的人生通常多数的时候,我们就只是活在那里,都没有得到什么 reward 或是 penalty。但是,人还是可以采取各种各式各样的行为。所以,一个真正厉害的 AI 应该能够在 sparse reward 的情况下也学到要怎么跟这个环境互动。 + +怎么解决 sparse reward 的这件事情呢?我们等一下会讲三个方向。 +## Reward Shaping ![](img/10.1.png) -`Imitation learning` 讨论的问题是,假设我们连 reward 都没有,那要怎么办呢?Imitation learning 又叫做 `learning from demonstration(示范学习)` ,`apprenticeship learning(学徒学习)`,`learning by watching(观察学习)`。在 Imitation learning 里面,你有一些 expert 的 demonstration,那 machine 也可以跟环境互动,但它没有办法从环境里面得到任何的 reward,它只能看着 expert 的 demonstration 来学习什么是好,什么是不好。其实,多数的情况,我们都没有办法真的从环境里面得到非常明确的 reward。举例来说,如果是棋类游戏或者是电玩,你有非常明确的 reward。但是其实多数的任务,都是没有 reward 的。以 chat-bot 为例,机器跟人聊天,聊得怎么样算是好,聊得怎么样算是不好,你无法给出明确的 reward。所以很多 task 是根本就没有办法给出 reward 的。 -虽然没有办法给出 reward,但是收集 expert 的 demonstration 是可以做到的。举例来说,在自动驾驶汽车里面,虽然你没有办法给出自动驾驶汽车的 reward,但你可以收集很多人类开车的纪录。在 chat-bot 里面,你可能没有办法定义什么叫做好的对话,什么叫做不好的对话。但是收集很多人的对话当作范例,这一件事情也是可行的。所以 imitation learning 的使用性非常高。假设你不知道该怎么定义 reward,你就可以收集到 expert 的 demonstration,你可以收集到一些范例的话,你可以收集到一些很厉害的 agent,比如说人跟环境实际上的互动的话,那你就可以考虑 imitation learning 这个技术。在 imitation learning 里面,我们介绍两个方法。第一个叫做 `Behavior Cloning`,第二个叫做 `Inverse Reinforcement Learning` 或者又叫做 `Inverse Optimal Control`。 +第一个方向叫做 `reward shaping`,reward shaping 的意思是说环境有一个固定的 reward,它是真正的 reward,但是我们为了让 agent 学出来的结果是我们要的样子,我们刻意地设计了一些 reward 来引导我们的 agent。举例来说,如果是把小孩当成一个 agent 的话。那一个小孩,他可 以take 两个 actions,一个action 是他可以出去玩,那他出去玩的话,在下一秒钟它会得到 reward 1。但是他在月考的时候,成绩可能会很差。所以在100 个小时之后呢,他会得到 reward -100。然后,他也可以决定要念书,然后在下一个时间,因为他没有出去玩,所以他觉得很不爽,所以他得到 reward -1。但是在 100 个小时后,他可以得到 reward 100。但对一个小孩来说,他可能就会想要 take play 而不是 take study。我们计算的是 accumulated reward,但也许对小孩来说,他的 discount factor 会很大,所以他就不太在意未来的reward。而且因为他是一个小孩,他还没有很多 experience,所以他的 Q-function estimate 是非常不精准的。所以要他去 estimate 很远以后会得到的 accumulated reward,他其实是预测不出来的。所以这时候大人就要引导他,怎么引导呢?就骗他说,如果你坐下来念书我就给你吃一个棒棒糖。所以,对他来说,下一个时间点会得到的 reward 就变成是positive 的。所以他就觉得说,也许 take 这个 study 是比 play 好的。虽然这并不是真正的 reward,而是其他人骗他的reward,告诉他说你采取这个 action 是好的。Reward shaping 的概念是一样的,简单来说,就是你自己想办法 design 一些 reward,它不是环境真正的 reward。在玩 Atari 游戏里面,真的 reward 是游戏主机给你的 reward,但你自己去设计一些 reward 好引导你的 machine,做你想要它做的事情。 -## Behavior Cloning ![](img/10.2.png) -其实 `Behavior Cloning` 跟 supervised learning 是一模一样的。我们以自动驾驶汽车为例,你可以收集到人开自动驾驶汽车的所有资料,比如说可以通过行车记录器进行收集。看到这样子的 observation 的时候,人会决定向前。机器就采取跟人一样的行为,也向前,就结束了,这个就叫做 Behavior Cloning。Expert 做什么,机器就做一模一样的事,怎么让机器学会跟 expert 一模一样的行为呢?就把它当作一个 supervised learning 的问题,你去收集很多行车纪录器。然后再收集人在那个情境下会采取什么样的行为。你知道说人在 state $s_1$ 会采取action $a_1$,人在state $s_2$ 会采取action $a_2$。人在state, $s_3$ 会采取action $a_3$。接下来,你就learn 一个 network。这个 network 就是你的 actor,他input $s_i$ 的时候,你就希望他的output 是$a_i$,就这样结束了。它就是一个的 supervised learning 的problem。 +举例来说,这个例子是 Facebook 玩 VizDoom 的 agent。VizDoom 是一个第一人射击游戏,在这个射击游戏中,杀了敌人就得到 positive reward,被杀就得到 negative reward。他们设计了一些新的 reward,用新的 reward 来引导 agent 让他们做得更好,这不是游戏中真正的 reward。 +比如说掉血就扣 0.05 的分数,弹药减少就扣分,捡到补给包就加分,呆在原地就扣分,移动就加分。 活着会扣一个很小的分数,因为不这样做的话,machine 会只想活着,一直躲避敌人,这样会让 machine 好战一点。表格中的参数都是调出来的。 + +Reward shaping是有问题的,因为我们需要 domain knowledge,举例来说,机器人想要学会的事情是把蓝色的板子从这个柱子穿过去。机器人很难学会,我们可以做 Reward Shaping。一个貌似合理的说法是,蓝色的板子离柱子越近,reward 越大。但是 machine 靠近的方式会有问题,它会用蓝色的板子打柱子。而我们要把蓝色板子放在柱子上面去,才能把蓝色板子穿过柱子。 这种 reward shaping的方式是没有帮助的,那至于什么 reward shaping 有帮助,什么 reward shaping 没帮助,会变成一个 domain knowledge,你要去调的。 + +## Curiosity ![](img/10.3.png) -Behavior Cloning 虽然非常简单,但它的问题是如果你只收集expert 的资料,你可能看过的 observation 会是非常 limited。举例来说,假设你要 learn 一部自动驾驶汽车,自动驾驶汽车就是要过这个弯道。如果是 expert 的话,他就是把车顺着这个红线就开过去了。但假设你的 agent 很笨,他今天开着开着,就开到撞墙了,他永远不知道撞墙这种状况要怎么处理,为什么?因为 training data 里面从来没有撞过墙,所以他根本就不知道撞墙这一种 case 要怎么处理。或是打电玩,电玩也是一样,让人去玩 Mario,那 expert 可能非常强,他从来不会跳不上水管,所以机器根本不知道跳不上水管时要怎么处理。人从来不会跳不上水管,但是机器如果跳不上水管时,就不知道要怎么处理。所以光是做Behavior Cloning 是不够的。只观察 expert 的行为是不够的,需要一个招数,这个招数叫作`Dataset Aggregation`。 +接下来就是介绍各种你可以自己加进去,in general 看起来是有用的 reward。举例来说,一个技术是给 machine 加上 curiosity,所以叫 `curiosity driven reward`。上图是我们之前讲 Actor-Critic 的时候看过的图。我们有一个 reward function,它给你某一个s tate,给你某一个 action,它就会评断说在这个 state 采取 这个action 得到多少的 reward。那我们当然希望 total reward 越大越好。在 curiosity driven 的这种技术里面,你会加上一个新的 reward function。这个新的 reward function 叫做 `ICM(intrinsic curiosity module)`,它就是要给机器加上好奇心。ICM 会吃 3 个东西,它会吃 state $s_1$、action $a_1$ 和 state $s_2$。根据$s_1$ 、$a_1$、 $a_2$,它会 output 另外一个 reward,我们这边叫做 $r_1^i$。对 machine 来说,total reward 并不是只有 r 而已,还有 $r^i$。它不是只有把所有的 r 都加起来,它还把所有 $r^i$ 加起来当作total reward。所以,它在跟环境互动的时候,它不是只希望 r 越大越好,它还同时希望 $r^i$ 越大越好,它希望从 ICM 的 module 里面得到的 reward 越大越好。ICM 就代表了一种curiosity。 + ![](img/10.4.png) -我们会希望收集更多样性的 data,而不是只收集 expert 所看到的 observation。我们会希望能够收集 expert 在各种极端的情况下,他会采取什么样的行为。以自动驾驶汽车为例的话,假设一开始,你的actor 叫作 $\pi_1$,你让 $\pi_1$去开这个车。但车上坐了一个 expert。这个 expert 会不断地告诉machine 说,如果在这个情境里面,我会怎么样开。所以 $\pi_1$ 自己开自己的,但是expert 会不断地表示他的想法。比如说,在这个时候,expert 可能说那就往前走。这个时候,expert 可能就会说往右转。但 $\pi_1$ 是不管 expert 的指令的,所以他会继续去撞墙。虽然 expert 说往右转,但是不管他怎么下指令都是没有用的。$\pi_1$ 会自己做自己的事情,因为我们要做的记录的是说,今天expert 在 $\pi_1$ 看到这种observation 的情况下,他会做什么样的反应。这个方法显然是有一些问题的,因为每次你开一次自动驾驶汽车都会牺牲一个人。那你用这个方法,你牺牲一个expert 以后,你就会得到说,人类在这样子的 state 下,在快要撞墙的时候,会采取什么样的反应。再把这个data 拿去train 新的 $\pi_2$。这个process 就反复继续下去,这个方法就叫做`Dataset Aggregation`。 - +怎么设计这个 ICM ?这个是最原始的设计。这个设计是这样。curiosity module 就是 input 3 个东西,input 现在的 state,input 在这个 state 采取的 action,然后接 input 下一个 state $s_{t+1}$。接下来会 output 一个 reward $r^i_t$。那这个 $r^i_t$ 是怎么算出来的呢?在 ICM 里面,你有一个 network,这个 network 会 take $a_t$ 跟$s_t$,然后去 output $\hat{s}_{t+1}$,也就是这个 network 根据 $a_t$ 和 $s_t$ 去 predict $\hat{s}_{t+1}$ 。接下来再看说,这个 network 的预测 $\hat{s}_{t+1}$ 跟真实的情况 $s_{t+1}$ 像不像,越不像那得到的 reward 就越大。所以这个 reward $r_t^i$ 的意思是说,如果未来的 state 越难被预测的话,那得到的 reward 就越大。这就是鼓励 machine 去冒险,现在采取这个 action,未来会发生什么事越没有办法预测的话,这个 action 的 reward 就大。所以如果有这样子的 ICM,machine 就会倾向于采取一些风险比较大的 action,它想要去探索未知的世界,它想要去看看说,假设某一个 state 是它没有办法预测,它会特别去想要采取那个 state,这可以增加 machine exploration 的能力。 +这个 network 1 其实是另外 train 出来的。Training 的时候,这个network 1,你会给它 $a_t$、 $s_t$、 $s_{t+1}$,然后让这个network 1 去学说 given $a_t, s_t$,怎么 predict $\hat{s}_{t+1}$。Apply 到 agent 互动的时候,其实要把 ICM module fix 住。其实,这一整个想法里面是有一个问题的。这个问题是某一些 state它很难被预测并不代表它就是好的,它就应该要去被尝试的。举例来说,俄罗斯轮盘的结果也是没有办法预测的,并不代表说,人应该每天去玩俄罗斯轮盘这样子。所以只是鼓励 machine 去冒险是不够的,因为如果光是只有这个 network 的架构,machine 只知道说什么东西它无法预测。如果在某一个 state 采取某一个 action,它无法预测接下来结果,它就会采取那个action,但并不代表这样的结果一定是好的。举例来说,可能在某个游戏里面,背景会有风吹草动,会有树叶飘动。那也许树叶飘动这件事情,是很难被预测的,对 machine 来说它在某一个 state 什么都不做,看着树叶飘动,然后,发现这个树叶飘动是没有办法预测的,接下来它就会一直站在那边,看树叶飘动。所以说,光是有好奇心是不够的,还要让它知道说,什么事情是真正重要的。 ![](img/10.5.png) -Behavior Cloning 还有一个 issue 是说,机器会完全 copy expert 的行为,不管 expert 的行为是否有道理,就算没有道理,没有什么用的,这是expert 本身的习惯,机器也会硬把它记下来。如果机器确实可以记住所有 expert 的行为,那也许还好,为什么呢?因为如果 expert 这么做,有些行为是多余的。但是没有问题,假设机器的行为可以完全仿造 expert 行为,那也就算了,那他是跟 expert 一样得好,只是做一些多余的事。但问题就是它是一个 machine,它是一个 network,network 的capacity 是有限的。就算给 network training data,它在training data 上得到的正确率往往也不是100%,他有些事情是学不起来的。这个时候,什么该学,什么不该学就变得很重要。 +怎么让 machine 知道说什么事情是真正重要的?你要加上另外一个 module,我们要 learn 一个`feature extractor`,黄色的格子代表 feature extractor,它是 input 一个 state,然后 output 一个feature vector 来代表这个state,那我们期待这个 feature extractor 可以把那种没有意义的画面,state 里面没有意义的东西把它过滤掉,比如说风吹草动、白云的飘动、树叶的飘动这种没有意义的东西直接把它过滤掉, -举例来说,在学习中文的时候,你的老师,他有语音,他也有行为,他也有知识,但其实只有语音部分是重要的,知识的部分是不重要的。也许 machine 只能够学一件事,也许他就只学到了语音,那没有问题。如果他只学到了手势,这样子就有问题了。所以让机器学习什么东西是需要 copy,什么东西是不需要 copy,这件事情是重要的。而单纯的 Behavior Cloning 就没有把这件事情学进来,因为机器只是复制 expert 所有的行为而已,它不知道哪些行为是重要,是对接下来有影响的,哪些行为是不重要的,是对接下来是没有影响的。 +假设这个 feature extractor 真的可以把无关紧要的东西过滤掉以后,network 1 实际上做的事情是,给它一个 actor,给它一个state $s_t$ 的feature representation,让它预测 state $s_{t+1}$ 的feature representation。接下来我们再看说,这个预测的结果跟真正的 state $s_{t+1}$ 的 feature representation 像不像,越不像,reward 就越大。怎么 learn 这个 feature extractor 呢?让这个feature extractor 可以把无关紧要的事情滤掉呢?这边的 learn 法就是 learn 另外一个network 2。这个 network 2 是吃 $\phi(s_t)$、$\phi(s_{t+1})$ 这两个 vector 当做 input,然后接下来它要predict action a 是什么,然后它希望呢这个 action a 跟真正的 action a 越接近越好。这个network 2 会 output 一个 action,它output 说,从 state $s_t$ 跳到 state $s_{t+1}$,要采取哪一个 action 才能够做到,那希望这个 action 跟真正的 action 越接近越好。加上这个 network 2 的好处就是因为要用 $\phi(s_t)$、$\phi(s_{t+1})$ 预测action。所以,今天我们抽出来的 feature 跟预测action 这件事情是有关的。所以风吹草动等与 machine 要采取的 action 无关的东西就会被滤掉,就不会被放在抽出来的 vector representation 里面。 + +## Curriculum Learning + ![](img/10.6.png) +接下来讲 `curriculum learning` ,curriculum learning 不是 reinforcement learning 所独有的概念。其实在 machine learning,尤其是 deep learning 里面,你都会用到 curriculum learning 的概念。举例来说,curriculum learning 的意思是说,你为机器的学习做规划,你给他喂 training data 的时候,是有顺序的,通常都是由简单到难。就好比说,假设你今天要交一个小朋友作微积分,他做错就打他一巴掌,这样他永远都不会做对,太难了。你要先教他九九乘法,然后才教他微积分。所以curriculum learning 的意思就是在教机器的时候,从简单的题目教到难的题目。就算不是 reinforcement learning,一般在 train deep network 的时候,你有时候也会这么做。举例来说,在 train RNN 的时候,已经有很多的文献都 report 说,你给机器先看短的 sequence,再慢慢给它长的 sequence,通常可以学得比较好。那用在reinforcement learning 里面,你就是要帮机器规划一下它的课程,从最简单的到最难的。 举例来说,在 Facebook 玩 VizDoom 的 agent 里面,Facebook 玩 VizDoom 的 agent 蛮强的。他们在参加这个 VizDoom 的比赛,机器的 VizDoom 比赛是得第一名的,他们是有为机器规划课程的。先从课程 0 一直上到课程 7。在这个课程里面,怪物的速度跟血量是不一样的。所以,在越进阶的课程里面,怪物的速度越快,然后他的血量越多。在 paper 里面也有讲说,如果直接上课程 7,machine 是学不起来的。你就是要从课程 0 一路玩上去,这样 machine 才学得起来。 -Behavior Cloning 还有什么样的问题呢?在做 Behavior Cloning 的时候,training data 跟 testing data 是 mismatch 的。我们可以用 Dataset Aggregation 的方法来缓解这个问题。这个问题是,在 training 跟 testing 的时候,data distribution 其实是不一样的。因为在 reinforcement learning 里面,action 会影响到接下来所看到的 state。我们是先有 state $s_1$,然后采取 action $a_1$,action $a_1$ 其实会决定接下来你看到什么样的 state $s_2$。所以在 reinforcement learning 里面有一个很重要的特征,就是你采取了 action 会影响你接下来所看到的 state。如果做了Behavior Cloning 的话,我们只能观察到 expert 的一堆 state 跟 action 的pair。然后我们希望可以 learn 一个 $\pi^*$,我们希望 $\pi^*$ 跟 $\hat{\pi}$ 越接近越好。如果 $\pi^*$ 可以跟 $\hat{\pi}$ 一模一样的话,你 training 的时候看到的 state 跟 testing 的时候所看到的 state 会是一样的。因为虽然 action 会影响我们看到的 state,但假设两个 policy 一模一样, 在同一个 state 都会采取同样的 action,那你接下来所看到的 state 都会是一样的。但问题就是你很难让你的 learn 出来的 policy 跟expert 的 policy 一模一样。Expert 可是一个人,network 要跟人一模一样,感觉很难吧。 +再举个例子,把蓝色的板子穿过柱子,怎么让机器一直从简单学到难呢? -如果你的 $\pi^*$ 跟 $\hat{\pi}$ 有一点误差。这个误差在一般 supervised learning problem 里面,每一个 example 都是 independent 的,也许还好。但对 reinforcement learning 的 problem 来说,你可能在某个地方就是失之毫厘,差之千里。可能在某个地方,也许 machine 没有办法完全复制 expert 的行为,它只复制了一点点,差了一点点,也许最后得到的结果就会差很多这样。所以 Behavior Cloning 并不能够完全解决 Imatation learning 这件事情。所以就有另外一个比较好的做法叫做 `Inverse Reinforcement Learning`。 +如第一张图所示,也许一开始机器初始的时候,它的板子就已经在柱子上了。这个时候,机器要做的事情只有把蓝色的板子压下去,就结束了。这比较简单,它应该很快就学的会。它只有往上跟往下这两个选择嘛,往下就得到 reward,就结束了,他也不知道学的是什么。 +如第二张图所示,这边就是把板子挪高一点,挪高一点,所以它有时候会很笨的往上拉,然后把板子拿出来了。如果它压板子学得会的话,拿板子也比较有机会学得会。假设它现在学的到说,只要板子接近柱子,它就可以把这个板子压下去的话。接下来,你再让它学更 general 的 case。 -## Inverse RL +如第三张图所示,一开始,让板子离柱子远一点。然后,板子放到柱子上面的时候,它就会知道把板子压下去,这个就是Curriculum Learning 的概念。当然 curriculum learning 有点 ad hoc(特别),就是需要人去为机器设计它的课程。 ![](img/10.7.png) -为什么叫 Inverse Reinforcement Learning,因为原来的 Reinforcement Learning 里面,有一个环境和一个 reward function。根据环境和 reward function,通过 Reinforcement Learning 这个技术,你会找到一个 actor,你会 learn 出一个optimal actor。但 Inverse Reinforcement Learning 刚好是相反的,你没有 reward function,你只有一堆 expert 的 demonstration。但你还是有环境的。IRL 的做法是说假设我们现在有一堆 expert 的demonstration,我们用 $\hat{\tau}$ 来代表expert 的demonstration。如果是在玩电玩的话,每一个 $\tau$ 就是一个很会玩电玩的人玩一场游戏的纪录,如果是自动驾驶汽车的话,就是人开自动驾驶汽车的纪录。这一边就是 expert 的 demonstration,每一个 $\tau$ 是一个 trajectory。 - -把所有 expert demonstration 收集起来,然后,使用Inverse Reinforcement Learning 这个技术。使用 Inverse Reinforcement Learning 技术的时候,机器是可以跟环境互动的。但他得不到reward。他的 reward 必须要从 expert 那边推出来,有了环境和 expert demonstration 以后,去反推出 reward function 长什么样子。之前 reinforcement learning 是由 reward function 反推出什么样的 action、actor 是最好的。Inverse Reinforcement Learning 是反过来,我们有expert 的demonstration,我们相信他是不错的,我就反推说,expert 是因为什么样的 reward function 才会采取这些行为。你有了reward function 以后,接下来,你就可以套用一般的 reinforcement learning 的方法去找出 optimal actor。所以 Inverse Reinforcement Learning 是先找出 reward function,找出 reward function 以后,再去用 Reinforcement Learning 找出 optimal actor。 - -把这个 reward function learn 出来,相较于原来的 Reinforcement Learning 有什么样好处。一个可能的好处是也许 reward function 是比较简单的。也许,虽然这个 expert 的行为非常复杂,但也许简单的 reward function 就可以导致非常复杂的行为。一个例子就是也许人类本身的 reward function 就只有活着这样,每多活一秒,你就加一分。但人类有非常复杂的行为,但是这些复杂的行为,都只是围绕着要从这个 reward function 里面得到分数而已。有时候很简单的 reward function 也许可以推导出非常复杂的行为。 +有一个比较 general 的方法叫做 `Reverse Curriculum Generation`。你可以用一个比较通用的方法来帮机器设计课程,这个比较通用的方法是怎么样呢?假设你现在一开始有一个state $s_g$,这是你的gold state,也就是最后最理想的结果。如果拿刚才那个板子和柱子的实验作为例子的话,就把板子放到柱子里面,这样子叫做 gold state。你就已经完成了,或者你让机器去抓东西,你训练一个机器手臂抓东西,抓到东西以后叫做 gold state。接下来你根据你的 gold state 去找其他的 state,这些其他的 state 跟 gold state 是比较接近的。举例来说,如果是让机器抓东西的例子里面,你的机器手臂可能还没有抓到东西。假设这些跟 gold state 很近的 state 叫做 $s_1$。你的机械手臂还没有抓到东西,但它离 gold state 很近,那这个叫做$s_1$。至于什么叫做近,这是 case dependent,你要根据你的 task 来 design 说怎么从 $s_g$ sample 出 $s_1$。如果是机械手臂的例子,可能就比较好想。其他例子可能就比较难想。接下来呢,你再从这些 $s_1$ 开始做互动,看它能不能够达到gold state $s_g$,那每一个state,你跟环境做互动的时候,你都会得到一个reward R。 ![](img/10.8.png) -Inverse Reinforcement Learning 实际上是怎么做的呢?首先,我们有一个 expert $\hat{\pi}$,这个 expert 去跟环境互动,给我们很多 $\hat{\tau_1}$ 到 $\hat{\tau_n}$。如果是玩游戏的话,就让某一个电玩高手,去玩 n 场游戏。把 n 场游戏的 state 跟 action 的 sequence 都记录下来。接下来,你有一个actor $\pi$,一开始actor 很烂,这个 actor 也去跟环境互动。他也去玩了n 场游戏,他也有 n 场游戏的纪录。接下来,我们要反推出 reward function。怎么推出 reward function 呢?**原则就是 expert 永远是最棒的,是先射箭,再画靶的概念。** - -Expert 去玩一玩游戏,得到这一些游戏的纪录,你的 actor 也去玩一玩游戏,得到这些游戏的纪录。接下来,你要定一个 reward function,这个 reward function 的原则就是 expert 得到的分数要比 actor 得到的分数高,先射箭,再画靶。所以我们就 learn 出一个 reward function。你就找出一个 reward function。这个 reward function 会使 expert 所得到的 reward 大过于 actor 所得到的reward。你有了新的 reward function 以后,就可以套用一般 Reinforcement Learning 的方法去learn 一个actor,这个actor 会针对 reward function 去 maximize 他的reward。他也会采取一大堆的action。但是,今天这个 actor 虽然可以 maximize 这个 reward function,采取一大堆的行为,得到一大堆游戏的纪录。 - -但接下来,我们就改 reward function。这个 actor 就会很生气,它已经可以在这个reward function 得到高分。但是他得到高分以后,我们就改 reward function,仍然让 expert 可以得到比 actor 更高的分数。这个就是 `Inverse Reinforcement learning`。有了新的 reward function 以后,根据这个新的 reward function,你就可以得到新的 actor,新的 actor 再去跟环境做一下互动,他跟环境做互动以后, 你又会重新定义你的 reward function,让 expert 得到的 reward 比 actor 大。 - -怎么让 expert 得到的 reward 大过 actor 呢?其实你在 learning 的时候,你可以很简单地做一件事就是,reward function 也许就是 neural network。这个 neural network 就是吃一个 $\tau$,output 就是应该要给这个 $\tau$ 多少的分数。或者说,你假设觉得 input 整个$\tau$ 太难了。因为$\tau$ 是 s 和 a 的一个很强的sequence。也许他就是 input 一个 s 和 a 的 pair,然后 output 一个real number。把整个 sequence,整个$\tau$ 会得到的 real number 都加起来就得到 $R(\tau)$。在training 的时候,对于 $\left\{\hat{\tau}_{1}, \hat{\tau}_{2}, \cdots, \hat{\tau}_{N}\right\}$,我们希望它 output 的 R 越大越好。对于 $\left\{\tau_{1}, \tau_{2}, \cdots, \tau_{N}\right\}$,我们就希望它 R 的值越小越好。 - -什么叫做一个最好的 reward function。最后你 learn 出来的 reward function 应该就是 expert 和 actor 在这个 reward function 都会得到一样高的分数。最终你的 reward function 没有办法分辨出谁应该会得到比较高的分数。 - -通常在 train 的时候,你会 iterative 的去做。那今天的状况是这样,最早的 Inverse Reinforcement Learning 对 reward function 有些限制,他是假设 reward function 是 linear 的。如果reward function 是 linear 的话,你可以 prove 这个algorithm 会 converge。但是如果不是 linear 的,你就没有办法 prove 说它会 converge。你有没有觉得这个东西,看起来还挺熟悉呢?其实你只要把他换个名字,说 actor 就是 generator,然后说 reward function 就是discriminator,它就是GAN。所以它会不会收敛这个问题就等于是问说 GAN 会不会收敛。如果你已经实现过,你会知道不一定会收敛。但除非你对 R 下一个非常严格的限制,如果你的 R 是一个 general 的network 的话,你就会有很大的麻烦。 +接下来,我们把 reward 特别极端的 case 去掉,reward 特别极端的 case 的意思就是说那些 case 太简单或是太难了。如果 reward 很大,代表说这个 case 太简单了,就不用学了,因为机器已经会了,它可以得到很大的 reward。如果 reward 太小,代表这个 case 太难了,依照机器现在的能力这个课程太难了,它学不会,所以就不要学这个,所以只找一些 reward 适中的 case。那当然什么叫做适中,这个就是你要调的参数,找一些 reward 适中的 case。接下来,再根据这些 reward 适中的 case 去 sample 出更多的 state。就假设你一开始,你机械手臂在这边,可以抓的到以后。接下来,就再离远一点,看看能不能够抓得到,又抓的到以后,再离远一点,看看能不能抓得到。这是一个有用的方法,它叫做`Reverse Curriculum learning`。刚才讲的是 Curriculum learning,就是你要为机器规划它学习的顺序。而 reverse curriculum learning 是从 gold state 去反推,就是说你原来的目标是长这个样子,我们从我们的目标去反推,所以这个叫做 reverse。 +## Hierarchical RL ![](img/10.9.png) -那怎么说它像是一个GAN,我们来跟GAN 比较一下。GAN 里面,你有一堆很好的图。然后你有一个generator,一开始他根本不知道要产生什么样的图,他就乱画。然后你有一个discriminator,discriminator 的工作就是给画的图打分,expert 画的图就是高分,generator 画的图就是低分。你有discriminator 以后,generator 会想办法去骗过 discriminator。Generator 会希望 discriminator 也会给它画的图高分。整个 process 跟 Inverse Reinforcement Learning 是一模一样的。 +那最后一个 tip 叫做 `Hierarchical Reinforcement learning`,分层的 reinforcement learning。 +所谓分层的Reinforcement learning 是说,我们有好几个 agent。然后,有一些agent 负责比较high level 的东西,它负责订目标,然后它订完目标以后,再分配给其他的 agent,去把它执行完成。这样的想法其实也是很合理的。因为我们知道说,我们人在一生之中,并不是时时刻刻都在做决定。举例来说,假设你想要写一篇paper,你会说就我先想个梗这样子,然后想完梗以后,你还要跑个实验。跑完实验以后,你还要写。写完以后呢,你还要这个去发表。每一个动作下面又还会再细分,比如说怎么跑实验呢?你要先 collect data,collect 完data 以后,你要再 label,你要弄一个network,然后又 train 不起来,要 train 很多次。然后重新 design network 架构好几次,最后才把network train 起来。 -* 画的图就是 expert 的 demonstration。generator 就是actor,generator 画很多图,actor 会去跟环境互动,产生很多 trajectory。这些 trajectory 跟环境互动的记录,游戏的纪录其实就是等于 GAN 里面的这些图。 -* 然后你 learn 一个reward function。Reward function 就是 discriminator。Rewards function 要给 expert 的 demonstration 高分,给 actor 互动的结果低分。 -* 接下来,actor 会想办法,从这个已经 learn 出来的 reward function 里面得到高分,然后 iterative 地去循环。跟GAN 其实是一模一样的,我们只是换个说法来而已。 +所以,我们要完成一个很大的 task 的时候,我们并不是从非常底层的那些 action 开始想起,我们其实是有个 plan。我们先想说,如果要完成这个最大的任务,那接下来要拆解成哪些小任务。每一个小任务要再怎么拆解成小小的任务。举例来说,叫你直接写一本书可能很困难,但叫你先把一本书拆成好几个章节,每个章节拆成好几段,每一段又拆成好几个句子,每一个句子又拆成好几个词汇,这样你可能就比较写得出来,这个就是分层的 Reinforcement learning 的概念。 +这边是举一个例子,就是假设校长、教授和研究生通通都是 agent。那今天假设我们的reward 就是只要进入百大就可以得到 reward。假设进入百大的话,校长就要提出愿景告诉其他的agent 说,现在你要达到什么样的目标。那校长的愿景可能就是说教授每年都要发三篇期刊。然后接下来这些agent 都是有分层的,所以上面的 agent,他的动作就是提出愿景这样。那他把他的愿景传给下一层的agent,下一层的 agent 就把这个愿景吃下去。如果他下面还有其他人的话,它就会提出新的愿景。比如说,校长要教授发期刊,但其实教授自己也是不做实验的。所以,教授也只能够叫下面的研究生做实验。所以教授就提出愿景,就做出实验的规划,然后研究生才是真的去执行这个实验的人。然后,真的把实验做出来,最后大家就可以得到reward。那现在是这样子的,在 learn 的时候,其实每一个 agent 都会 learn。那他们的整体的目标就是要达到最后的reward。那前面的这些 agent,他提出来的 actions 就是愿景这样。你如果是玩游戏的话,他提出来的就是,我现在想要产生这样的游戏画面。但是,假设他提出来的愿景是下面的 agent 达不到的,那就会被讨厌。举例来说,教授对研究生都一直逼迫研究生做一些很困难的实验,研究生都做不出来的话,研究生就会跑掉,所以他就会得到一个penalty。所以如果今天下层的 agent 没有办法达到上层 agent 所提出来的 goal 的话,上层的 agent 就会被讨厌,它就会得到一个 negative reward。所以他要避免提出那些愿景是底下的agent 所做不到的。那每一个agent 都是把上层的 agent 所提出来的愿景当作输入,然后决定他自己要产生什么输出。 +但是你知道说,就算你看到上面的的愿景说,叫你做这一件事情。你最后也不一定能做成这一件事情。假设本来教授目标是要写期刊,但是不知道怎么回事,他就要变成一个YouTuber。这个paper 里面的 solution,我觉得非常有趣。给大家做一个参考,这其实本来的目标是要写期刊,但却变成 YouTuber,那怎么办呢? 把原来的愿景改成变成 YouTuber 就行了,在paper 里面就是这么做的,为什么这么做呢? 因为虽然本来的愿景是要写期刊,但是后来变成YouTuber,难道这些动作都浪费了吗? 不是,这些动作是没有被浪费的。我们就假设说,本来的愿景其实就是要成为YouTuber,那你就知道成为 YouTuber 要怎做了。这个是分层 RL,是可以做得起来的 tip。 ![](img/10.10.png) -IRL 有很多的application,举例来说,可以用开来自动驾驶汽车。然后,有人用这个技术来学开自动驾驶汽车的不同风格,每个人在开车的时候,其实你会有不同风格。举例来说,能不能够压到线,能不能够倒退,要不要遵守交通规则等等。每个人的风格是不同的,然后用 Inverse Reinforcement Learning 可以让自动驾驶汽车学会各种不同的开车风格。 -![](img/10.11.png) +上图是真实的例子。实际上呢,这里面就做了一些比较简单的游戏,这个是走迷宫,蓝色是 agent,蓝色的 agent 要走到黄色的目标。这边也是,这个单摆要碰到黄色的球。那愿景是什么呢? -上图是文献上真实的例子,在这个例子里面, Inverse Reinforcement Learning 有一个有趣的地方,通常你不需要太多的 training data,因为 training data 往往都是个位数。因为 Inverse Reinforcement Learning 只是一种 demonstration,只是一种范例,实际上机器可以去跟环境互动非常多次。所以在 Inverse Reinforcement Learning 的文献, 往往会看到说只用几笔 data 就训练出一些有趣的结果。 +在这个 task 里面,它只有两个 agent ,下层的一个 agent 负责决定说要怎么走,上层的 agent 就负责提出愿景。虽然,实际上你可以用很多层,但 paper 就用了两层。 -比如说,在这个例子里面是要让自动驾驶汽车学会在停车场里面停。这边的demonstration 是这样,蓝色是终点,自动驾驶汽车要开到蓝色终点停车。给机器只看一行的四个 demonstration,然后让他去学怎么样开车,最后他就可以学出,在红色的终点位置,如果他要停车的话,他会这样开。今天给机器看不同的demonstration,最后他学出来开车的风格就会不太一样。举例来说,上图第二行是不守规矩的开车方式,因为他会开到道路之外,这边,他会穿过其他的车,然后从这边开进去。所以机器就会学到说,不一定要走在道路上,他可以走非道路的地方。上图第三行是倒退来停车,机器也会学会说,他可以倒退, - -![](img/10.12.png) - -这种技术也可以拿来训练机器人。你可以让机器人,做一些你想要他做的动作,过去如果你要训练机器人,做你想要他做的动作,其实是比较麻烦的。怎么麻烦呢?过去如果你要操控机器的手臂,你要花很多力气去写 program 才让机器做一件很简单的事看。假设你有 Imitation Learning 的技术,你可以让人做一下示范,然后机器就跟着人的示范来进行学习,比如学会摆盘子,拉着机器人的手去摆盘子,机器自己动。让机器学会倒水,人只教他20 次,杯子每次放的位置不太一样。用这种方法来教机械手臂。 - -## Third Person lmitation Learning -![](img/10.13.png) - -其实还有很多相关的研究,举例来说,你在教机械手臂的时候,要注意就是也许机器看到的视野跟人看到的视野是不太一样的。在刚才那个例子里面,人跟机器的动作是一样的。但是在未来的世界里面,也许机器是看着人的行为学的。刚才是人拉着,假设你要让机器学会打高尔夫球,在刚才的例子里面就是人拉着机器人手臂去打高尔夫球,但是在未来有没有可能机器就是看着人打高尔夫球,他自己就学会打高尔夫球了呢?但这个时候,要注意的事情是机器的视野跟他真正去采取这个行为的时候的视野是不一样的。机器必须了解到当他是第三人的视角的时候,看到另外一个人在打高尔夫球,跟他实际上自己去打高尔夫球的时候,看到的视野显然是不一样的。但他怎么把他是第三人的时间所观察到的经验把它 generalize 到他是第一人称视角的时候所采取的行为,这就需要用到`Third Person Imitation Learning`的技术。 - -![](img/10.14.png) - -这个怎么做呢?它的技术其实也是不只是用到 Imitation Learning,他用到了 `Domain-Adversarial Training`。我们在讲 Domain-Adversarial Training 的时候,我们有讲说这也是一个GAN 的技术。那我们希望今天有一个 extractor,有两个不同 domain 的image,通过 feature extractor 以后,没有办法分辨出他来自哪一个 domain。其实第一人称视角和第三人称视角,Imitation Learning 用的技术其实也是一样的,希望 learn 一个 Feature Extractor,机器在第三人称的时候跟他在第一人称的时候看到的视野其实是一样的,就是把最重要的东西抽出来就好了。 - -## Recap: Sentence Generation & Chat-bot -![](img/10.15.png) - -在讲 Sequence GAN 的时候,我们有讲过 Sentence Generation 跟 Chat-bot。那其实 Sentence Generation 或 Chat-bot 也可以想成是 Imitation Learning。机器在 imitate 人写的句子,你在写句子的时候,你写下去的每一个 word 都想成是一个 action,所有的 word 合起来就是一个 episode。举例来说, sentence generation 里面,你会给机器看很多人类写的文字。你要让机器学会写诗,那你就要给他看唐诗三百首。人类写的文字其实就是 expert 的 demonstration。每一个词汇其实就是一个 action。今天,你让机器做Sentence Generation 的时候其实就是在 imitate expert 的trajectory。Chat-bot 也是一样,在Chat-bot 里面你会收集到很多人互动对话的纪录,那些就是 expert 的 demonstration。 - -如果我们今天单纯用 maximum likelihood 这个技术来 maximize 会得到 likelihood,这个其实就是behavior cloning。我们今天做 behavior cloning 就是看到一个 state,接下来预测我们会得到什么样的 action。看到一个state,然后有一个 ground truth 告诉机器说什么样的 action 是最好的。在做 likelihood 的时候也是一样,given sentence 已经产生的部分。接下来 machine 要 predict 说接下来要写哪一个word 才是最好的。所以,其实 maximum likelihood 在做Sequence generation 的时候,它对应到 Imitation Learning 里面就是 behavior cloning。只有 maximum likelihood 是不够的,我们想要用 Sequence GAN,其实 Sequence GAN 就是对应到 Inverse Reinforcement Learning,Inverse Reinforcement Learning 就是一种 GAN 的技术。你把 Inverse Reinforcement Learning 的技术放在 Sentence generation,放到 Chat-bot 里面,其实就是 Sequence GAN 跟它的种种的变形。 +走迷宫的例子是说粉红色的这个点代表的就是愿景。上层这个 agent,它告诉蓝色的这个 agent 说,你现在的第一个目标是先走到这个地方,蓝色的 agent 走到以后,再说你的新的目标是走到这里。蓝色的 agent 再走到以后,新的目标在这里。接下来又跑到这边,最后希望蓝色的 agent 就可以走到黄色的这个位置。 +单摆的例子也一样,就是粉红色的这个点代表的是上层的 agent 所提出来的愿景,所以这个agent 先摆到这边,接下来,新的愿景又跑到这边,所以它又摆到这里。然后,新的愿景又跑到上面。然后又摆到上面,最后就走到黄色的位置了。这个就是 hierarchical 的 Reinforcement Learning。 diff --git a/docs/chapter10/img/10.1.png b/docs/chapter10/img/10.1.png index a8c236a..f394ac0 100644 Binary files a/docs/chapter10/img/10.1.png and b/docs/chapter10/img/10.1.png differ diff --git a/docs/chapter10/img/10.10.png b/docs/chapter10/img/10.10.png index ab8570f..8a4edbc 100644 Binary files a/docs/chapter10/img/10.10.png and b/docs/chapter10/img/10.10.png differ diff --git a/docs/chapter10/img/10.2.png b/docs/chapter10/img/10.2.png index eb17190..e1dda19 100644 Binary files a/docs/chapter10/img/10.2.png and b/docs/chapter10/img/10.2.png differ diff --git a/docs/chapter10/img/10.3.png b/docs/chapter10/img/10.3.png index 10e6e56..1d4b264 100644 Binary files a/docs/chapter10/img/10.3.png and b/docs/chapter10/img/10.3.png differ diff --git a/docs/chapter10/img/10.4.png b/docs/chapter10/img/10.4.png index e833118..5e1d209 100644 Binary files a/docs/chapter10/img/10.4.png and b/docs/chapter10/img/10.4.png differ diff --git a/docs/chapter10/img/10.5.png b/docs/chapter10/img/10.5.png index 5d15de7..487f858 100644 Binary files a/docs/chapter10/img/10.5.png and b/docs/chapter10/img/10.5.png differ diff --git a/docs/chapter10/img/10.6.png b/docs/chapter10/img/10.6.png index 313329c..50599e9 100644 Binary files a/docs/chapter10/img/10.6.png and b/docs/chapter10/img/10.6.png differ diff --git a/docs/chapter10/img/10.7.png b/docs/chapter10/img/10.7.png index 6bb3c56..1c08fad 100644 Binary files a/docs/chapter10/img/10.7.png and b/docs/chapter10/img/10.7.png differ diff --git a/docs/chapter10/img/10.8.png b/docs/chapter10/img/10.8.png index ed6afd4..e9a38f5 100644 Binary files a/docs/chapter10/img/10.8.png and b/docs/chapter10/img/10.8.png differ diff --git a/docs/chapter10/img/10.9.png b/docs/chapter10/img/10.9.png index 1a160cf..813ebfb 100644 Binary files a/docs/chapter10/img/10.9.png and b/docs/chapter10/img/10.9.png differ diff --git a/docs/chapter11/chapter11.md b/docs/chapter11/chapter11.md index 439b2d2..642af7a 100644 --- a/docs/chapter11/chapter11.md +++ b/docs/chapter11/chapter11.md @@ -1,81 +1,100 @@ -# DDPG - -## 离散动作 vs. 连续动作 - +# Imitation Learning ![](img/11.1.png) -离散动作与连续动作是相对的概念,一个是可数的,一个是不可数的。 在 CartPole 环境中,可以有向左推小车、向右推小车两个动作。在 Frozen Lake 环境中,小乌龟可以有上下左右四个动作。在 Atari 的 Pong 游戏中,游戏有6个按键的动作可以输出。 +`Imitation learning` 讨论的问题是,假设我们连 reward 都没有,那要怎么办呢?Imitation learning 又叫做 `learning from demonstration(示范学习)` ,`apprenticeship learning(学徒学习)`,`learning by watching(观察学习)`。在 Imitation learning 里面,你有一些 expert 的 demonstration,那 machine 也可以跟环境互动,但它没有办法从环境里面得到任何的 reward,它只能看着 expert 的 demonstration 来学习什么是好,什么是不好。其实,多数的情况,我们都没有办法真的从环境里面得到非常明确的 reward。举例来说,如果是棋类游戏或者是电玩,你有非常明确的 reward。但是其实多数的任务,都是没有 reward 的。以 chat-bot 为例,机器跟人聊天,聊得怎么样算是好,聊得怎么样算是不好,你无法给出明确的 reward。所以很多 task 是根本就没有办法给出 reward 的。 -但在实际情况中,经常会碰到连续动作空间的情况,也就是输出的动作是不可数的。比如说推小车力的大小, 选择下一时刻方向盘的转动角度或者四轴飞行器的四个螺旋桨给的电压的大小等等。 +虽然没有办法给出 reward,但是收集 expert 的 demonstration 是可以做到的。举例来说,在自动驾驶汽车里面,虽然你没有办法给出自动驾驶汽车的 reward,但你可以收集很多人类开车的纪录。在 chat-bot 里面,你可能没有办法定义什么叫做好的对话,什么叫做不好的对话。但是收集很多人的对话当作范例,这一件事情也是可行的。所以 imitation learning 的使用性非常高。假设你不知道该怎么定义 reward,你就可以收集到 expert 的 demonstration,你可以收集到一些范例的话,你可以收集到一些很厉害的 agent,比如说人跟环境实际上的互动的话,那你就可以考虑 imitation learning 这个技术。在 imitation learning 里面,我们介绍两个方法。第一个叫做 `Behavior Cloning`,第二个叫做 `Inverse Reinforcement Learning` 或者又叫做 `Inverse Optimal Control`。 +## Behavior Cloning ![](img/11.2.png) -对于这些连续的动作控制空间,Q-learning、DQN 等算法是没有办法处理的。那我们怎么输出连续的动作呢,这个时候,万能的神经网络又出现了。在上面这个离散动作的场景下,比如说我输出上下或是停止这几个动作。有几个动作,神经网络就输出几个概率值。我们用 $\pi_\theta(a_t|s_t)$ 来表示这个随机性的策略。 - -然后在连续的动作场景下,比如说我要输出这个机器人手臂弯曲的角度,这样子的一个动作,我们就输出一个具体的浮点数。我们用 $\mu_{\theta}(s_t)$ 来代表这个确定性的策略。 - -我们再解释一下随机性策略跟确定性策略。 - -* 对随机性的策略来说,我们输入某一个状态 s,采取某一个 action 的可能性并不是百分之百,而是有一个概率 P 的,就好像抽奖一样,根据概率随机抽取一个动作。 -* 而对于确定性的策略来说,它没有概率的影响。当神经网络的参数固定下来了之后,输入同样的state,必然输出同样的 action,这就是确定性的策略。 +其实 `Behavior Cloning` 跟 supervised learning 是一模一样的。我们以自动驾驶汽车为例,你可以收集到人开自动驾驶汽车的所有资料,比如说可以通过行车记录器进行收集。看到这样子的 observation 的时候,人会决定向前。机器就采取跟人一样的行为,也向前,就结束了,这个就叫做 Behavior Cloning。Expert 做什么,机器就做一模一样的事,怎么让机器学会跟 expert 一模一样的行为呢?就把它当作一个 supervised learning 的问题,你去收集很多行车纪录器。然后再收集人在那个情境下会采取什么样的行为。你知道说人在 state $s_1$ 会采取action $a_1$,人在state $s_2$ 会采取action $a_2$。人在state, $s_3$ 会采取action $a_3$。接下来,你就learn 一个 network。这个 network 就是你的 actor,他input $s_i$ 的时候,你就希望他的output 是$a_i$,就这样结束了。它就是一个的 supervised learning 的problem。 ![](img/11.3.png) -* 要输出离散动作的话,我们就是加一层 softmax 层来确保说所有的输出是动作概率,而且所有的动作概率加和为 1。 -* 要输出连续的动作的话,一般我们可以在输出层这里加一层 tanh。tanh 的图像的像右边这样子,它的作用就是可以把输出限制到 [-1,1] 之间。我们拿到这个输出后,就可以根据实际动作的一个范围再做一下缩放,然后再输出给环境。比如神经网络输出一个浮点数是 2.8,然后经过 tanh 之后,它就可以被限制在 [-1,1] 之间,它输出 0.99。然后假设说小车的一个速度的那个动作范围是 [-2,2] 之间,那我们就按比例从 [-1,1] 扩放到 [-2,2],0.99 乘 2,最终输出的就是1.98,作为小车的速度或者说推小车的力输出给环境。 - -## DDPG +Behavior Cloning 虽然非常简单,但它的问题是如果你只收集expert 的资料,你可能看过的 observation 会是非常 limited。举例来说,假设你要 learn 一部自动驾驶汽车,自动驾驶汽车就是要过这个弯道。如果是 expert 的话,他就是把车顺着这个红线就开过去了。但假设你的 agent 很笨,他今天开着开着,就开到撞墙了,他永远不知道撞墙这种状况要怎么处理,为什么?因为 training data 里面从来没有撞过墙,所以他根本就不知道撞墙这一种 case 要怎么处理。或是打电玩,电玩也是一样,让人去玩 Mario,那 expert 可能非常强,他从来不会跳不上水管,所以机器根本不知道跳不上水管时要怎么处理。人从来不会跳不上水管,但是机器如果跳不上水管时,就不知道要怎么处理。所以光是做Behavior Cloning 是不够的。只观察 expert 的行为是不够的,需要一个招数,这个招数叫作`Dataset Aggregation`。 ![](img/11.4.png) -在连续控制领域,比较经典的强化学习算法就是 `DDPG(Deep Deterministic Policy Gradient)`。DDPG 的特点可以从它的名字当中拆解出来,拆解成 Deep、Deterministic 和 Policy Gradient。 +我们会希望收集更多样性的 data,而不是只收集 expert 所看到的 observation。我们会希望能够收集 expert 在各种极端的情况下,他会采取什么样的行为。以自动驾驶汽车为例的话,假设一开始,你的actor 叫作 $\pi_1$,你让 $\pi_1$去开这个车。但车上坐了一个 expert。这个 expert 会不断地告诉machine 说,如果在这个情境里面,我会怎么样开。所以 $\pi_1$ 自己开自己的,但是expert 会不断地表示他的想法。比如说,在这个时候,expert 可能说那就往前走。这个时候,expert 可能就会说往右转。但 $\pi_1$ 是不管 expert 的指令的,所以他会继续去撞墙。虽然 expert 说往右转,但是不管他怎么下指令都是没有用的。$\pi_1$ 会自己做自己的事情,因为我们要做的记录的是说,今天expert 在 $\pi_1$ 看到这种observation 的情况下,他会做什么样的反应。这个方法显然是有一些问题的,因为每次你开一次自动驾驶汽车都会牺牲一个人。那你用这个方法,你牺牲一个expert 以后,你就会得到说,人类在这样子的 state 下,在快要撞墙的时候,会采取什么样的反应。再把这个data 拿去train 新的 $\pi_2$。这个process 就反复继续下去,这个方法就叫做`Dataset Aggregation`。 -* Deep 是因为用了神经网络。 -* Deterministic 表示 DDPG 输出的是一个确定性的动作,可以用于连续动作的一个环境。 -* Policy Gradient 代表的是它用到的是策略网络。REINFORCE 算法每隔一个 episode 就更新一次,但 DDPG 网络是每个 step 都会更新一次 policy 网络,也就是说它是一个单步更新的 policy 网络。 -DDPG 是 DQN 的一个扩展的版本。在 DDPG 的训练中,它借鉴了 DQN 的技巧:目标网络和经验回放。经验回放这一块跟 DQN 是一样的。但是 target network 这一块的更新跟 DQN 有点不一样。 ![](img/11.5.png) -提出 DDPG 是为了让 DQN 可以扩展到连续的动作空间,就是我们刚才提到的小车速度、角度和电压的电流量这样的连续值。所以 DDPG 直接在 DQN 基础上加了一个策略网络,就是蓝色的这个,用来直接输出动作值。所以 DDPG 需要一边学习 Q网络,一边学习策略网络。Q网络的参数用 $w$ 来表示。策略网络的参数用 $\theta$ 来表示。我们称这样的结构为 `Actor-Critic` 的结构。 + +Behavior Cloning 还有一个 issue 是说,机器会完全 copy expert 的行为,不管 expert 的行为是否有道理,就算没有道理,没有什么用的,这是expert 本身的习惯,机器也会硬把它记下来。如果机器确实可以记住所有 expert 的行为,那也许还好,为什么呢?因为如果 expert 这么做,有些行为是多余的。但是没有问题,假设机器的行为可以完全仿造 expert 行为,那也就算了,那他是跟 expert 一样得好,只是做一些多余的事。但问题就是它是一个 machine,它是一个 network,network 的capacity 是有限的。就算给 network training data,它在training data 上得到的正确率往往也不是100%,他有些事情是学不起来的。这个时候,什么该学,什么不该学就变得很重要。 + +举例来说,在学习中文的时候,你的老师,他有语音,他也有行为,他也有知识,但其实只有语音部分是重要的,知识的部分是不重要的。也许 machine 只能够学一件事,也许他就只学到了语音,那没有问题。如果他只学到了手势,这样子就有问题了。所以让机器学习什么东西是需要 copy,什么东西是不需要 copy,这件事情是重要的。而单纯的 Behavior Cloning 就没有把这件事情学进来,因为机器只是复制 expert 所有的行为而已,它不知道哪些行为是重要,是对接下来有影响的,哪些行为是不重要的,是对接下来是没有影响的。 + ![](img/11.6.png) -通俗的去解释一下这个 Actor-Critic 的结构,策略网络扮演的就是 actor 的角色,它负责对外展示输出,输出舞蹈动作。Q网络就是评论家(critic),它会在每一个 step 都对 actor 输出的动作做一个评估,打一个分,估计一下它做一次的 action 未来能有多少收益,也就是去估计这个 actor 输出的这个 action 的 Q值大概是多少,即 $Q_w(s,a)$。 Actor 就需要根据舞台目前的状态来做出一个 action。 -评论家就是评委,它需要根据舞台现在的状态和演员输出的 action 这两个值对 actor 刚刚的表现去打一个分数 $Q_w(s,a)$。所以 actor 就是要根据评委的打分来调整自己的策略。也就是更新 actor 的神经网络参数 $\theta$, 争取下次可以做得更好。而 critic 就是要根据观众的反馈,也就是环境的反馈 reward 来调整自己的打分策略,也就是要更新 critic 的神经网络的参数 $w$ ,它的目标是要让每一场表演都获得观众尽可能多的欢呼声跟掌声,也就是要最大化未来的总收益。其实最开始训练的时候,这两个神经网络参数是随机的。所以 critic 最开始是随机打分的,然后 actor 也跟着乱来,就随机表演,随机输出动作。但是由于我们有环境反馈的 reward 存在,所以 critic 的评分会越来越准确,也会评判的那个 actor 的表现会越来越好。既然 actor 是一个神经网络,是我们希望训练好的这个策略网络,那我们就需要计算梯度来去更新优化它里面的参数 $\theta$ 。简单的说,我们希望调整 actor 的网络参数,使得评委打分尽可能得高。注意,这里的 actor 是不管观众的,它只关注评委,它就是迎合评委的打分,打的这个 $Q_w(s,a)$ 而已。 +Behavior Cloning 还有什么样的问题呢?在做 Behavior Cloning 的时候,training data 跟 testing data 是 mismatch 的。我们可以用 Dataset Aggregation 的方法来缓解这个问题。这个问题是,在 training 跟 testing 的时候,data distribution 其实是不一样的。因为在 reinforcement learning 里面,action 会影响到接下来所看到的 state。我们是先有 state $s_1$,然后采取 action $a_1$,action $a_1$ 其实会决定接下来你看到什么样的 state $s_2$。所以在 reinforcement learning 里面有一个很重要的特征,就是你采取了 action 会影响你接下来所看到的 state。如果做了Behavior Cloning 的话,我们只能观察到 expert 的一堆 state 跟 action 的pair。然后我们希望可以 learn 一个 $\pi^*$,我们希望 $\pi^*$ 跟 $\hat{\pi}$ 越接近越好。如果 $\pi^*$ 可以跟 $\hat{\pi}$ 一模一样的话,你 training 的时候看到的 state 跟 testing 的时候所看到的 state 会是一样的。因为虽然 action 会影响我们看到的 state,但假设两个 policy 一模一样, 在同一个 state 都会采取同样的 action,那你接下来所看到的 state 都会是一样的。但问题就是你很难让你的 learn 出来的 policy 跟expert 的 policy 一模一样。Expert 可是一个人,network 要跟人一模一样,感觉很难吧。 + +如果你的 $\pi^*$ 跟 $\hat{\pi}$ 有一点误差。这个误差在一般 supervised learning problem 里面,每一个 example 都是 independent 的,也许还好。但对 reinforcement learning 的 problem 来说,你可能在某个地方就是失之毫厘,差之千里。可能在某个地方,也许 machine 没有办法完全复制 expert 的行为,它只复制了一点点,差了一点点,也许最后得到的结果就会差很多这样。所以 Behavior Cloning 并不能够完全解决 Imatation learning 这件事情。所以就有另外一个比较好的做法叫做 `Inverse Reinforcement Learning`。 + + +## Inverse RL ![](img/11.7.png) +为什么叫 Inverse Reinforcement Learning,因为原来的 Reinforcement Learning 里面,有一个环境和一个 reward function。根据环境和 reward function,通过 Reinforcement Learning 这个技术,你会找到一个 actor,你会 learn 出一个optimal actor。但 Inverse Reinforcement Learning 刚好是相反的,你没有 reward function,你只有一堆 expert 的 demonstration。但你还是有环境的。IRL 的做法是说假设我们现在有一堆 expert 的demonstration,我们用 $\hat{\tau}$ 来代表expert 的demonstration。如果是在玩电玩的话,每一个 $\tau$ 就是一个很会玩电玩的人玩一场游戏的纪录,如果是自动驾驶汽车的话,就是人开自动驾驶汽车的纪录。这一边就是 expert 的 demonstration,每一个 $\tau$ 是一个 trajectory。 -接下来就是类似 DQN。DQN 的最佳策略是想要学出一个很好的 Q网络。 学好这个网络之后,我们希望选取的那个动作使你的 Q值最大。DDPG 的目的也是为了求解让 Q值最大的那个 action。Actor 只是为了迎合评委的打分而已,所以用来优化策略网络的梯度就是要最大化这个 Q 值,所以构造的 loss 函数就是让 Q 取一个负号。我们写代码的时候要做的就是把这个 loss 函数扔到优化器里面,它就会自动最小化 loss,也就是最大化这个 Q。然后这里注意,除了策略网络要做优化,DDPG 还有一个 Q网络也要优化。评委一开始其实也不知道怎么评分,它也是在一步一步的学习当中,慢慢地去给出准确的打分。那我们优化 Q网络的方法其实跟 DQN 优化 Q网络的方法是一模一样的。我们用真实的 reward $r$ 和下一步的 Q 即 Q' 来去拟合未来的收益也就是 Q_target。 -然后让 Q网络的输出去逼近这个 Q_target。所以构造的 loss function 就是直接求这两个值的均方差。构造好loss 后,之后我们就扔进去那个优化器,让它自动去最小化 loss 就好了。 +把所有 expert demonstration 收集起来,然后,使用Inverse Reinforcement Learning 这个技术。使用 Inverse Reinforcement Learning 技术的时候,机器是可以跟环境互动的。但他得不到reward。他的 reward 必须要从 expert 那边推出来,有了环境和 expert demonstration 以后,去反推出 reward function 长什么样子。之前 reinforcement learning 是由 reward function 反推出什么样的 action、actor 是最好的。Inverse Reinforcement Learning 是反过来,我们有expert 的demonstration,我们相信他是不错的,我就反推说,expert 是因为什么样的 reward function 才会采取这些行为。你有了reward function 以后,接下来,你就可以套用一般的 reinforcement learning 的方法去找出 optimal actor。所以 Inverse Reinforcement Learning 是先找出 reward function,找出 reward function 以后,再去用 Reinforcement Learning 找出 optimal actor。 + +把这个 reward function learn 出来,相较于原来的 Reinforcement Learning 有什么样好处。一个可能的好处是也许 reward function 是比较简单的。也许,虽然这个 expert 的行为非常复杂,但也许简单的 reward function 就可以导致非常复杂的行为。一个例子就是也许人类本身的 reward function 就只有活着这样,每多活一秒,你就加一分。但人类有非常复杂的行为,但是这些复杂的行为,都只是围绕着要从这个 reward function 里面得到分数而已。有时候很简单的 reward function 也许可以推导出非常复杂的行为。 ![](img/11.8.png) -那我们把两个网络的 loss function 就可以构造出来。我们可以看到策略网络的 loss function 是一个复合函数。我们把那个 $a = \mu_\theta(s)$ 代进去,最终策略网络要优化的是策略网络的参数 $\theta$ 。 +Inverse Reinforcement Learning 实际上是怎么做的呢?首先,我们有一个 expert $\hat{\pi}$,这个 expert 去跟环境互动,给我们很多 $\hat{\tau_1}$ 到 $\hat{\tau_n}$。如果是玩游戏的话,就让某一个电玩高手,去玩 n 场游戏。把 n 场游戏的 state 跟 action 的 sequence 都记录下来。接下来,你有一个actor $\pi$,一开始actor 很烂,这个 actor 也去跟环境互动。他也去玩了n 场游戏,他也有 n 场游戏的纪录。接下来,我们要反推出 reward function。怎么推出 reward function 呢?**原则就是 expert 永远是最棒的,是先射箭,再画靶的概念。** -Q 网络要优化的是那个 Q 的输出 $Q_w(s,a)$ 和那个 Q_target 之间的一个均方差。但是 Q网络的优化存在一个和 DQN 一模一样的问题就是它后面的这个 Q_target 是不稳定的。这个在之前的 DQN 有讲过。后面的 $Q_{\bar{w}}\left(s^{\prime}, a^{\prime}\right)$ 也是不稳定的。因为 $Q_{\bar{w}}\left(s^{\prime}, a^{\prime}\right)$ 也是一个预估的值。为了稳定这个 Q_target。DDPG 分别给 Q网络和策略网络都搭建了 target network,专门就是为了用来稳定这个 Q_target。 +Expert 去玩一玩游戏,得到这一些游戏的纪录,你的 actor 也去玩一玩游戏,得到这些游戏的纪录。接下来,你要定一个 reward function,这个 reward function 的原则就是 expert 得到的分数要比 actor 得到的分数高,先射箭,再画靶。所以我们就 learn 出一个 reward function。你就找出一个 reward function。这个 reward function 会使 expert 所得到的 reward 大过于 actor 所得到的reward。你有了新的 reward function 以后,就可以套用一般 Reinforcement Learning 的方法去learn 一个actor,这个actor 会针对 reward function 去 maximize 他的reward。他也会采取一大堆的action。但是,今天这个 actor 虽然可以 maximize 这个 reward function,采取一大堆的行为,得到一大堆游戏的纪录。 + +但接下来,我们就改 reward function。这个 actor 就会很生气,它已经可以在这个reward function 得到高分。但是他得到高分以后,我们就改 reward function,仍然让 expert 可以得到比 actor 更高的分数。这个就是 `Inverse Reinforcement learning`。有了新的 reward function 以后,根据这个新的 reward function,你就可以得到新的 actor,新的 actor 再去跟环境做一下互动,他跟环境做互动以后, 你又会重新定义你的 reward function,让 expert 得到的 reward 比 actor 大。 + +怎么让 expert 得到的 reward 大过 actor 呢?其实你在 learning 的时候,你可以很简单地做一件事就是,reward function 也许就是 neural network。这个 neural network 就是吃一个 $\tau$,output 就是应该要给这个 $\tau$ 多少的分数。或者说,你假设觉得 input 整个$\tau$ 太难了。因为$\tau$ 是 s 和 a 的一个很强的sequence。也许他就是 input 一个 s 和 a 的 pair,然后 output 一个real number。把整个 sequence,整个$\tau$ 会得到的 real number 都加起来就得到 $R(\tau)$。在training 的时候,对于 $\left\{\hat{\tau}_{1}, \hat{\tau}_{2}, \cdots, \hat{\tau}_{N}\right\}$,我们希望它 output 的 R 越大越好。对于 $\left\{\tau_{1}, \tau_{2}, \cdots, \tau_{N}\right\}$,我们就希望它 R 的值越小越好。 + +什么叫做一个最好的 reward function。最后你 learn 出来的 reward function 应该就是 expert 和 actor 在这个 reward function 都会得到一样高的分数。最终你的 reward function 没有办法分辨出谁应该会得到比较高的分数。 + +通常在 train 的时候,你会 iterative 的去做。那今天的状况是这样,最早的 Inverse Reinforcement Learning 对 reward function 有些限制,他是假设 reward function 是 linear 的。如果reward function 是 linear 的话,你可以 prove 这个algorithm 会 converge。但是如果不是 linear 的,你就没有办法 prove 说它会 converge。你有没有觉得这个东西,看起来还挺熟悉呢?其实你只要把他换个名字,说 actor 就是 generator,然后说 reward function 就是discriminator,它就是GAN。所以它会不会收敛这个问题就等于是问说 GAN 会不会收敛。如果你已经实现过,你会知道不一定会收敛。但除非你对 R 下一个非常严格的限制,如果你的 R 是一个 general 的network 的话,你就会有很大的麻烦。 -target Q 网络就为了来计算 Q_target 里面的 $Q_{\bar{w}}\left(s^{\prime}, a^{\prime}\right)$。然后 $Q_{\bar{w}}\left(s^{\prime}, a^{\prime}\right)$ 里面的需要的 next action $a'$ 就是通过 target_P 网络来去输出,即 $a^{\prime}=\mu_{\bar{\theta}}\left(s^{\prime}\right)$。 +![](img/11.9.png) -为了区分前面的 Q网络和策略网络以及后面的 target_Q 网络和 target_p 策略网络。前面的网络的参数是 $w$,后面的网络的参数是 $\bar{w}$。这就是为什么我们去看一些 DDPG 的文章,会发现 DDPG 会有四个网络。策略网络的 target 网络 和 Q网络的 target 网络就是颜色比较深的这两个。它只是为了让计算 Q_target 的时候能够更稳定一点而已。因为这两个网络也是固定一段时间的参数之后再跟评估网络同步一下最新的参数。 +那怎么说它像是一个GAN,我们来跟GAN 比较一下。GAN 里面,你有一堆很好的图。然后你有一个generator,一开始他根本不知道要产生什么样的图,他就乱画。然后你有一个discriminator,discriminator 的工作就是给画的图打分,expert 画的图就是高分,generator 画的图就是低分。你有discriminator 以后,generator 会想办法去骗过 discriminator。Generator 会希望 discriminator 也会给它画的图高分。整个 process 跟 Inverse Reinforcement Learning 是一模一样的。 -这里面训练需要用到的数据就是 $s,a,r,s'$。我们只需要用到这四个数据,我们就用 Replay Memory 把这些数据存起来,然后再 sample 进来训练就好了。这个经验回放的技巧跟 DQN 是一模一样的。注意,因为 DDPG 使用了经验回放这个技巧,所以 DDPG 是一个 `off-policy` 的算法。 - -## Exploration vs. Exploitation -DDPG 通过 off-policy 的方式来训练一个确定性策略。因为策略是确定的,如果 agent 使用同策略来探索,在一开始的时候,它会很可能不会尝试足够多的 action 来找到有用的学习信号。为了让 DDPG 的策略更好地探索,我们在训练的时候给它们的 action 加了噪音。DDPG 的原作者推荐使用时间相关的 [OU noise](https://en.wikipedia.org/wiki/Ornstein–Uhlenbeck_process),但最近的结果表明不相关的、均值为 0 的 Gaussian noise 的效果非常好。由于后者更简单,因此我们更喜欢使用它。为了便于获得更高质量的训练数据,你可以在训练过程中把噪声变小。 - -在测试的时候,为了查看策略利用它学到的东西的表现,我们不会在 action 中加噪音。 - -## References - -* [百度强化学习课](https://aistudio.baidu.com/aistudio/education/lessonvideo/460292) - -* [OpenAI Spinning Up ](https://spinningup.openai.com/en/latest/algorithms/ddpg.html#) - - +* 画的图就是 expert 的 demonstration。generator 就是actor,generator 画很多图,actor 会去跟环境互动,产生很多 trajectory。这些 trajectory 跟环境互动的记录,游戏的纪录其实就是等于 GAN 里面的这些图。 +* 然后你 learn 一个reward function。Reward function 就是 discriminator。Rewards function 要给 expert 的 demonstration 高分,给 actor 互动的结果低分。 +* 接下来,actor 会想办法,从这个已经 learn 出来的 reward function 里面得到高分,然后 iterative 地去循环。跟GAN 其实是一模一样的,我们只是换个说法来而已。 +![](img/11.10.png) +IRL 有很多的application,举例来说,可以用开来自动驾驶汽车。然后,有人用这个技术来学开自动驾驶汽车的不同风格,每个人在开车的时候,其实你会有不同风格。举例来说,能不能够压到线,能不能够倒退,要不要遵守交通规则等等。每个人的风格是不同的,然后用 Inverse Reinforcement Learning 可以让自动驾驶汽车学会各种不同的开车风格。 + +![](img/11.11.png) + +上图是文献上真实的例子,在这个例子里面, Inverse Reinforcement Learning 有一个有趣的地方,通常你不需要太多的 training data,因为 training data 往往都是个位数。因为 Inverse Reinforcement Learning 只是一种 demonstration,只是一种范例,实际上机器可以去跟环境互动非常多次。所以在 Inverse Reinforcement Learning 的文献, 往往会看到说只用几笔 data 就训练出一些有趣的结果。 + +比如说,在这个例子里面是要让自动驾驶汽车学会在停车场里面停。这边的demonstration 是这样,蓝色是终点,自动驾驶汽车要开到蓝色终点停车。给机器只看一行的四个 demonstration,然后让他去学怎么样开车,最后他就可以学出,在红色的终点位置,如果他要停车的话,他会这样开。今天给机器看不同的demonstration,最后他学出来开车的风格就会不太一样。举例来说,上图第二行是不守规矩的开车方式,因为他会开到道路之外,这边,他会穿过其他的车,然后从这边开进去。所以机器就会学到说,不一定要走在道路上,他可以走非道路的地方。上图第三行是倒退来停车,机器也会学会说,他可以倒退, + +![](img/11.12.png) + +这种技术也可以拿来训练机器人。你可以让机器人,做一些你想要他做的动作,过去如果你要训练机器人,做你想要他做的动作,其实是比较麻烦的。怎么麻烦呢?过去如果你要操控机器的手臂,你要花很多力气去写 program 才让机器做一件很简单的事看。假设你有 Imitation Learning 的技术,你可以让人做一下示范,然后机器就跟着人的示范来进行学习,比如学会摆盘子,拉着机器人的手去摆盘子,机器自己动。让机器学会倒水,人只教他20 次,杯子每次放的位置不太一样。用这种方法来教机械手臂。 + +## Third Person lmitation Learning +![](img/11.13.png) + +其实还有很多相关的研究,举例来说,你在教机械手臂的时候,要注意就是也许机器看到的视野跟人看到的视野是不太一样的。在刚才那个例子里面,人跟机器的动作是一样的。但是在未来的世界里面,也许机器是看着人的行为学的。刚才是人拉着,假设你要让机器学会打高尔夫球,在刚才的例子里面就是人拉着机器人手臂去打高尔夫球,但是在未来有没有可能机器就是看着人打高尔夫球,他自己就学会打高尔夫球了呢?但这个时候,要注意的事情是机器的视野跟他真正去采取这个行为的时候的视野是不一样的。机器必须了解到当他是第三人的视角的时候,看到另外一个人在打高尔夫球,跟他实际上自己去打高尔夫球的时候,看到的视野显然是不一样的。但他怎么把他是第三人的时间所观察到的经验把它 generalize 到他是第一人称视角的时候所采取的行为,这就需要用到`Third Person Imitation Learning`的技术。 + +![](img/11.14.png) + +这个怎么做呢?它的技术其实也是不只是用到 Imitation Learning,他用到了 `Domain-Adversarial Training`。我们在讲 Domain-Adversarial Training 的时候,我们有讲说这也是一个GAN 的技术。那我们希望今天有一个 extractor,有两个不同 domain 的image,通过 feature extractor 以后,没有办法分辨出他来自哪一个 domain。其实第一人称视角和第三人称视角,Imitation Learning 用的技术其实也是一样的,希望 learn 一个 Feature Extractor,机器在第三人称的时候跟他在第一人称的时候看到的视野其实是一样的,就是把最重要的东西抽出来就好了。 + +## Recap: Sentence Generation & Chat-bot +![](img/11.15.png) + +在讲 Sequence GAN 的时候,我们有讲过 Sentence Generation 跟 Chat-bot。那其实 Sentence Generation 或 Chat-bot 也可以想成是 Imitation Learning。机器在 imitate 人写的句子,你在写句子的时候,你写下去的每一个 word 都想成是一个 action,所有的 word 合起来就是一个 episode。举例来说, sentence generation 里面,你会给机器看很多人类写的文字。你要让机器学会写诗,那你就要给他看唐诗三百首。人类写的文字其实就是 expert 的 demonstration。每一个词汇其实就是一个 action。今天,你让机器做Sentence Generation 的时候其实就是在 imitate expert 的trajectory。Chat-bot 也是一样,在Chat-bot 里面你会收集到很多人互动对话的纪录,那些就是 expert 的 demonstration。 + +如果我们今天单纯用 maximum likelihood 这个技术来 maximize 会得到 likelihood,这个其实就是behavior cloning。我们今天做 behavior cloning 就是看到一个 state,接下来预测我们会得到什么样的 action。看到一个state,然后有一个 ground truth 告诉机器说什么样的 action 是最好的。在做 likelihood 的时候也是一样,given sentence 已经产生的部分。接下来 machine 要 predict 说接下来要写哪一个word 才是最好的。所以,其实 maximum likelihood 在做Sequence generation 的时候,它对应到 Imitation Learning 里面就是 behavior cloning。只有 maximum likelihood 是不够的,我们想要用 Sequence GAN,其实 Sequence GAN 就是对应到 Inverse Reinforcement Learning,Inverse Reinforcement Learning 就是一种 GAN 的技术。你把 Inverse Reinforcement Learning 的技术放在 Sentence generation,放到 Chat-bot 里面,其实就是 Sequence GAN 跟它的种种的变形。 diff --git a/docs/chapter11/img/11.1.png b/docs/chapter11/img/11.1.png index d2d8b08..a8c236a 100644 Binary files a/docs/chapter11/img/11.1.png and b/docs/chapter11/img/11.1.png differ diff --git a/docs/chapter11/img/11.10.png b/docs/chapter11/img/11.10.png new file mode 100644 index 0000000..ab8570f Binary files /dev/null and b/docs/chapter11/img/11.10.png differ diff --git a/docs/chapter10/img/10.11.png b/docs/chapter11/img/11.11.png similarity index 100% rename from docs/chapter10/img/10.11.png rename to docs/chapter11/img/11.11.png diff --git a/docs/chapter10/img/10.12.png b/docs/chapter11/img/11.12.png similarity index 100% rename from docs/chapter10/img/10.12.png rename to docs/chapter11/img/11.12.png diff --git a/docs/chapter10/img/10.13.png b/docs/chapter11/img/11.13.png similarity index 100% rename from docs/chapter10/img/10.13.png rename to docs/chapter11/img/11.13.png diff --git a/docs/chapter10/img/10.14.png b/docs/chapter11/img/11.14.png similarity index 100% rename from docs/chapter10/img/10.14.png rename to docs/chapter11/img/11.14.png diff --git a/docs/chapter10/img/10.15.png b/docs/chapter11/img/11.15.png similarity index 100% rename from docs/chapter10/img/10.15.png rename to docs/chapter11/img/11.15.png diff --git a/docs/chapter11/img/11.2.png b/docs/chapter11/img/11.2.png index bc14e58..eb17190 100644 Binary files a/docs/chapter11/img/11.2.png and b/docs/chapter11/img/11.2.png differ diff --git a/docs/chapter11/img/11.3.png b/docs/chapter11/img/11.3.png index be0f3f7..10e6e56 100644 Binary files a/docs/chapter11/img/11.3.png and b/docs/chapter11/img/11.3.png differ diff --git a/docs/chapter11/img/11.4.png b/docs/chapter11/img/11.4.png index 7760c5b..e833118 100644 Binary files a/docs/chapter11/img/11.4.png and b/docs/chapter11/img/11.4.png differ diff --git a/docs/chapter11/img/11.5.png b/docs/chapter11/img/11.5.png index 4e6802a..5d15de7 100644 Binary files a/docs/chapter11/img/11.5.png and b/docs/chapter11/img/11.5.png differ diff --git a/docs/chapter11/img/11.6.png b/docs/chapter11/img/11.6.png index 76a90fe..313329c 100644 Binary files a/docs/chapter11/img/11.6.png and b/docs/chapter11/img/11.6.png differ diff --git a/docs/chapter11/img/11.7.png b/docs/chapter11/img/11.7.png index 825e6b8..6bb3c56 100644 Binary files a/docs/chapter11/img/11.7.png and b/docs/chapter11/img/11.7.png differ diff --git a/docs/chapter11/img/11.8.png b/docs/chapter11/img/11.8.png index ade74f6..ed6afd4 100644 Binary files a/docs/chapter11/img/11.8.png and b/docs/chapter11/img/11.8.png differ diff --git a/docs/chapter11/img/11.9.png b/docs/chapter11/img/11.9.png new file mode 100644 index 0000000..1a160cf Binary files /dev/null and b/docs/chapter11/img/11.9.png differ diff --git a/docs/chapter12/chapter12.md b/docs/chapter12/chapter12.md new file mode 100644 index 0000000..b9d3864 --- /dev/null +++ b/docs/chapter12/chapter12.md @@ -0,0 +1,81 @@ +# DDPG + +## 离散动作 vs. 连续动作 + +![](img/12.1.png) +离散动作与连续动作是相对的概念,一个是可数的,一个是不可数的。 在 CartPole 环境中,可以有向左推小车、向右推小车两个动作。在 Frozen Lake 环境中,小乌龟可以有上下左右四个动作。在 Atari 的 Pong 游戏中,游戏有6个按键的动作可以输出。 + +但在实际情况中,经常会碰到连续动作空间的情况,也就是输出的动作是不可数的。比如说推小车力的大小, 选择下一时刻方向盘的转动角度或者四轴飞行器的四个螺旋桨给的电压的大小等等。 + +![](img/12.2.png) + +对于这些连续的动作控制空间,Q-learning、DQN 等算法是没有办法处理的。那我们怎么输出连续的动作呢,这个时候,万能的神经网络又出现了。在上面这个离散动作的场景下,比如说我输出上下或是停止这几个动作。有几个动作,神经网络就输出几个概率值。我们用 $\pi_\theta(a_t|s_t)$ 来表示这个随机性的策略。 + +然后在连续的动作场景下,比如说我要输出这个机器人手臂弯曲的角度,这样子的一个动作,我们就输出一个具体的浮点数。我们用 $\mu_{\theta}(s_t)$ 来代表这个确定性的策略。 + +我们再解释一下随机性策略跟确定性策略。 + +* 对随机性的策略来说,我们输入某一个状态 s,采取某一个 action 的可能性并不是百分之百,而是有一个概率 P 的,就好像抽奖一样,根据概率随机抽取一个动作。 +* 而对于确定性的策略来说,它没有概率的影响。当神经网络的参数固定下来了之后,输入同样的state,必然输出同样的 action,这就是确定性的策略。 + +![](img/12.3.png) + +* 要输出离散动作的话,我们就是加一层 softmax 层来确保说所有的输出是动作概率,而且所有的动作概率加和为 1。 +* 要输出连续的动作的话,一般我们可以在输出层这里加一层 tanh。tanh 的图像的像右边这样子,它的作用就是可以把输出限制到 [-1,1] 之间。我们拿到这个输出后,就可以根据实际动作的一个范围再做一下缩放,然后再输出给环境。比如神经网络输出一个浮点数是 2.8,然后经过 tanh 之后,它就可以被限制在 [-1,1] 之间,它输出 0.99。然后假设说小车的一个速度的那个动作范围是 [-2,2] 之间,那我们就按比例从 [-1,1] 扩放到 [-2,2],0.99 乘 2,最终输出的就是1.98,作为小车的速度或者说推小车的力输出给环境。 + +## DDPG + +![](img/12.4.png) + +在连续控制领域,比较经典的强化学习算法就是 `DDPG(Deep Deterministic Policy Gradient)`。DDPG 的特点可以从它的名字当中拆解出来,拆解成 Deep、Deterministic 和 Policy Gradient。 + +* Deep 是因为用了神经网络。 +* Deterministic 表示 DDPG 输出的是一个确定性的动作,可以用于连续动作的一个环境。 + +* Policy Gradient 代表的是它用到的是策略网络。REINFORCE 算法每隔一个 episode 就更新一次,但 DDPG 网络是每个 step 都会更新一次 policy 网络,也就是说它是一个单步更新的 policy 网络。 + +DDPG 是 DQN 的一个扩展的版本。在 DDPG 的训练中,它借鉴了 DQN 的技巧:目标网络和经验回放。经验回放这一块跟 DQN 是一样的。但是 target network 这一块的更新跟 DQN 有点不一样。 +![](img/12.5.png) +提出 DDPG 是为了让 DQN 可以扩展到连续的动作空间,就是我们刚才提到的小车速度、角度和电压的电流量这样的连续值。所以 DDPG 直接在 DQN 基础上加了一个策略网络,就是蓝色的这个,用来直接输出动作值。所以 DDPG 需要一边学习 Q网络,一边学习策略网络。Q网络的参数用 $w$ 来表示。策略网络的参数用 $\theta$ 来表示。我们称这样的结构为 `Actor-Critic` 的结构。 + +![](img/12.6.png) +通俗的去解释一下这个 Actor-Critic 的结构,策略网络扮演的就是 actor 的角色,它负责对外展示输出,输出舞蹈动作。Q网络就是评论家(critic),它会在每一个 step 都对 actor 输出的动作做一个评估,打一个分,估计一下它做一次的 action 未来能有多少收益,也就是去估计这个 actor 输出的这个 action 的 Q值大概是多少,即 $Q_w(s,a)$。 Actor 就需要根据舞台目前的状态来做出一个 action。 + +评论家就是评委,它需要根据舞台现在的状态和演员输出的 action 这两个值对 actor 刚刚的表现去打一个分数 $Q_w(s,a)$。所以 actor 就是要根据评委的打分来调整自己的策略。也就是更新 actor 的神经网络参数 $\theta$, 争取下次可以做得更好。而 critic 就是要根据观众的反馈,也就是环境的反馈 reward 来调整自己的打分策略,也就是要更新 critic 的神经网络的参数 $w$ ,它的目标是要让每一场表演都获得观众尽可能多的欢呼声跟掌声,也就是要最大化未来的总收益。其实最开始训练的时候,这两个神经网络参数是随机的。所以 critic 最开始是随机打分的,然后 actor 也跟着乱来,就随机表演,随机输出动作。但是由于我们有环境反馈的 reward 存在,所以 critic 的评分会越来越准确,也会评判的那个 actor 的表现会越来越好。既然 actor 是一个神经网络,是我们希望训练好的这个策略网络,那我们就需要计算梯度来去更新优化它里面的参数 $\theta$ 。简单的说,我们希望调整 actor 的网络参数,使得评委打分尽可能得高。注意,这里的 actor 是不管观众的,它只关注评委,它就是迎合评委的打分,打的这个 $Q_w(s,a)$ 而已。 + +![](img/12.7.png) + +接下来就是类似 DQN。DQN 的最佳策略是想要学出一个很好的 Q网络。 学好这个网络之后,我们希望选取的那个动作使你的 Q值最大。DDPG 的目的也是为了求解让 Q值最大的那个 action。Actor 只是为了迎合评委的打分而已,所以用来优化策略网络的梯度就是要最大化这个 Q 值,所以构造的 loss 函数就是让 Q 取一个负号。我们写代码的时候要做的就是把这个 loss 函数扔到优化器里面,它就会自动最小化 loss,也就是最大化这个 Q。然后这里注意,除了策略网络要做优化,DDPG 还有一个 Q网络也要优化。评委一开始其实也不知道怎么评分,它也是在一步一步的学习当中,慢慢地去给出准确的打分。那我们优化 Q网络的方法其实跟 DQN 优化 Q网络的方法是一模一样的。我们用真实的 reward $r$ 和下一步的 Q 即 Q' 来去拟合未来的收益也就是 Q_target。 + +然后让 Q网络的输出去逼近这个 Q_target。所以构造的 loss function 就是直接求这两个值的均方差。构造好loss 后,之后我们就扔进去那个优化器,让它自动去最小化 loss 就好了。 + +![](img/12.8.png) + +那我们把两个网络的 loss function 就可以构造出来。我们可以看到策略网络的 loss function 是一个复合函数。我们把那个 $a = \mu_\theta(s)$ 代进去,最终策略网络要优化的是策略网络的参数 $\theta$ 。 + +Q 网络要优化的是那个 Q 的输出 $Q_w(s,a)$ 和那个 Q_target 之间的一个均方差。但是 Q网络的优化存在一个和 DQN 一模一样的问题就是它后面的这个 Q_target 是不稳定的。这个在之前的 DQN 有讲过。后面的 $Q_{\bar{w}}\left(s^{\prime}, a^{\prime}\right)$ 也是不稳定的。因为 $Q_{\bar{w}}\left(s^{\prime}, a^{\prime}\right)$ 也是一个预估的值。为了稳定这个 Q_target。DDPG 分别给 Q网络和策略网络都搭建了 target network,专门就是为了用来稳定这个 Q_target。 + + +target Q 网络就为了来计算 Q_target 里面的 $Q_{\bar{w}}\left(s^{\prime}, a^{\prime}\right)$。然后 $Q_{\bar{w}}\left(s^{\prime}, a^{\prime}\right)$ 里面的需要的 next action $a'$ 就是通过 target_P 网络来去输出,即 $a^{\prime}=\mu_{\bar{\theta}}\left(s^{\prime}\right)$。 + +为了区分前面的 Q网络和策略网络以及后面的 target_Q 网络和 target_p 策略网络。前面的网络的参数是 $w$,后面的网络的参数是 $\bar{w}$。这就是为什么我们去看一些 DDPG 的文章,会发现 DDPG 会有四个网络。策略网络的 target 网络 和 Q网络的 target 网络就是颜色比较深的这两个。它只是为了让计算 Q_target 的时候能够更稳定一点而已。因为这两个网络也是固定一段时间的参数之后再跟评估网络同步一下最新的参数。 + +这里面训练需要用到的数据就是 $s,a,r,s'$。我们只需要用到这四个数据,我们就用 Replay Memory 把这些数据存起来,然后再 sample 进来训练就好了。这个经验回放的技巧跟 DQN 是一模一样的。注意,因为 DDPG 使用了经验回放这个技巧,所以 DDPG 是一个 `off-policy` 的算法。 + +## Exploration vs. Exploitation +DDPG 通过 off-policy 的方式来训练一个确定性策略。因为策略是确定的,如果 agent 使用同策略来探索,在一开始的时候,它会很可能不会尝试足够多的 action 来找到有用的学习信号。为了让 DDPG 的策略更好地探索,我们在训练的时候给它们的 action 加了噪音。DDPG 的原作者推荐使用时间相关的 [OU noise](https://en.wikipedia.org/wiki/Ornstein–Uhlenbeck_process),但最近的结果表明不相关的、均值为 0 的 Gaussian noise 的效果非常好。由于后者更简单,因此我们更喜欢使用它。为了便于获得更高质量的训练数据,你可以在训练过程中把噪声变小。 + +在测试的时候,为了查看策略利用它学到的东西的表现,我们不会在 action 中加噪音。 + +## References + +* [百度强化学习课](https://aistudio.baidu.com/aistudio/education/lessonvideo/460292) + +* [OpenAI Spinning Up ](https://spinningup.openai.com/en/latest/algorithms/ddpg.html#) + + + + + + + diff --git a/docs/chapter12/img/12.1.png b/docs/chapter12/img/12.1.png new file mode 100644 index 0000000..d2d8b08 Binary files /dev/null and b/docs/chapter12/img/12.1.png differ diff --git a/docs/chapter12/img/12.2.png b/docs/chapter12/img/12.2.png new file mode 100644 index 0000000..bc14e58 Binary files /dev/null and b/docs/chapter12/img/12.2.png differ diff --git a/docs/chapter12/img/12.3.png b/docs/chapter12/img/12.3.png new file mode 100644 index 0000000..be0f3f7 Binary files /dev/null and b/docs/chapter12/img/12.3.png differ diff --git a/docs/chapter12/img/12.4.png b/docs/chapter12/img/12.4.png new file mode 100644 index 0000000..7760c5b Binary files /dev/null and b/docs/chapter12/img/12.4.png differ diff --git a/docs/chapter12/img/12.5.png b/docs/chapter12/img/12.5.png new file mode 100644 index 0000000..4e6802a Binary files /dev/null and b/docs/chapter12/img/12.5.png differ diff --git a/docs/chapter12/img/12.6.png b/docs/chapter12/img/12.6.png new file mode 100644 index 0000000..76a90fe Binary files /dev/null and b/docs/chapter12/img/12.6.png differ diff --git a/docs/chapter12/img/12.7.png b/docs/chapter12/img/12.7.png new file mode 100644 index 0000000..825e6b8 Binary files /dev/null and b/docs/chapter12/img/12.7.png differ diff --git a/docs/chapter12/img/12.8.png b/docs/chapter12/img/12.8.png new file mode 100644 index 0000000..ade74f6 Binary files /dev/null and b/docs/chapter12/img/12.8.png differ diff --git a/docs/chapter2/chapter2.md b/docs/chapter2/chapter2.md index 14bc7f0..ae9ab02 100644 --- a/docs/chapter2/chapter2.md +++ b/docs/chapter2/chapter2.md @@ -1,246 +1,333 @@ -# 表格型方法 - -这节课我们通过最简单的`表格型的方法`来讲解如何使用 value-based 方法去求解强化学习。 - -## Sarsa - -### MDP +# MDP ![](img/2.1.png) -强化学习的三个重要的要素:状态、动作和奖励。强化学习智能体跟环境是一步一步交互的,就是我先观察一下状态,然后再输入动作。再观察一下状态,再输出动作,拿到这些 reward 。它是一个跟时间相关的一个序列决策的问题。 - -举个例子,在 $t-1$ 时刻,我看到了熊对我招手,那我下意识的可能输出的动作就是赶紧跑路。熊看到了有人跑了,可能就觉得发现猎物,开始发动攻击。而在 $t$ 时刻的话,我如果选择装死的动作,可能熊咬了咬我那个摔了几下就发现就觉得挺无趣的,可能会走开。这个时候,我再跑路的话可能就跑路成功了,就是这样子的一个序列决策的过程。 - -当然在输出每一个动作之前,其实你都是可以选择不同的动作。比如说在 $t$ 时刻,我选择跑路的时候,熊已经追上来了,如果说 $t$ 时刻,我没有选择装死,而我是选择跑路的话,这个时候熊已经追上了,那这个时候,其实我有两种情况转移到不同的状态去,就我有一定的概率可以逃跑成功,也有很大的概率我会逃跑失败。那我们就用状态转移概率 $p\left[s_{t+1}, r_{t} \mid s_{t}, a_{t}\right]$ 来表述说在 $s_t$ 的状态选择了 $a_t$ 的动作的时候,转移到 $s_{t+1}$ ,而且拿到 $r_t$ 的概率是多少。 - -这样子的一个状态转移概率是具有`马尔可夫性质(Markov Property)`的(系统下一时刻的状态仅由当前时刻的状态决定,不依赖于以往任何状态)。因为这个状态转移概率,它是下一时刻的状态是取决于当前的状态,它和之前的 $s_{t-1}$ 和 $s_{t-2}$ 都没有什么关系。然后再加上说这个过程也取决于智能体跟环境交互的这个$a_t$ ,所以有一个决策的一个过程在里面。我们就称这样的一个过程为`马尔可夫决策过程(Markov Decision Process, MDP)`。 - - -MDP 就是序列决策这样一个经典的表达方式。MDP 也是强化学习里面一个非常基本的学习框架。状态、动作、状态转移概率和奖励 $(S,A,P,R)$,这四个合集就构成了强化学习 MDP 的四元组,后面也可能会再加个衰减因子构成五元组。 - +这节课我会给大家介绍马尔可夫决策过程。在介绍马尔可夫决策过程之前,我会给大家介绍它的简化版本:马尔可夫链以及马尔可夫奖励过程,通过跟这两种过程的比较,我们可以更生动地理解马尔可夫决策过程。第二部分我会给大家介绍马尔可夫决策过程中的 policy evaluation,就是当给定一个决策过后我们怎么去计算它的价值函数。第三部分,我会给大家介绍马尔可夫决策过程的控制,具体有两种算法:`policy iteration` 和 `value iteration`。 ![](img/2.2.png) - - - -我们把这些可能的动作和可能的状态转移的关系画成这样子的一个树状图。它们之间的关系就是一个从 $s_t$ 到 $a_t$ ,再到 $s_{t+1}$ ,再到 $a_{t+1}$,再到 $s_{t+2}$ 这样子的一个过程。 - -我们去跟环境交互,我们只能走完整的一条通路。这里面产生了一系列的一个决策的过程,就是我们跟环境交互产生了一个经验。然后我们会使用 P 函数和 R 函数来去描述环境。P 函数就是状态转移的概率,R 函数就是 Reward function。P 函数实际上反映的是环境的一个随机性。比方说,在熊发怒的情况下,我如果选择装死,假设熊看到人装死就一定会走的话,我们就称在这里面的这个状态转移概率就是百分之百。但如果说在熊发怒的情况下,我选择跑路而导致说我有可能跑成功以及跑失败,出现这两种情况。那我们就可以用概率去表达一下说转移到其中一种情况的概率大概 10%,另外一种情况的概率大概是 90% 会跑失败。**如果我们知道这些状态转移概率和奖励函数的话,我们就说这个环境是已知的,因为我们是用这两个函数去描述环境的。**如果是已知的话,我们其实可以用动态规划去计算说,我如果要逃脱熊,那么能够逃脱熊概率最大的最优策略是什么。很多强化学习的经典的算法都是 model-free 的,就是环境是未知的这样子的一个情况下,我们强化学习怎么去解决。 +上图介绍了在强化学习里面 agent 跟 environment 之间的交互,agent 在得到环境的状态过后,它会采取行为,它会把这个采取的行为返还给环境。环境在得到 agent 的行为过后,它会进入下一个状态,把下一个状态传回 agent。在强化学习中,agent 跟环境就是这样进行交互的,这个交互过程其实是可以通过马尔可夫决策过程来表示,所以马尔可夫决策过程是强化学习里面的一个基本框架。在马尔可夫决策过程中,它的环境是 fully observable ,就是全部可以观测的,但是很多时候在环境里面有些量是不可观测的,但是在这个部分观测的问题也可以转换成一个 MDP 的问题。 ![](img/2.3.png) -因为现实世界中人类第一次遇到熊之前,我们根本不知道我们能不能跑得过熊。所以刚刚那个10%、90%的概率也就是虚构出来的概率,熊到底在什么时候会往什么方向去转变的话,我们经常是不知道的。我们是处在一个未知的环境里的,也就是这一系列的决策的 P 函数和 R 函数是未知的。这就是 model-based 跟 model-free 的一个最大的区别。强化学习就是可以用来解决用完全未知的和随机的环境。 -强化学习要像人类一样去学习了,人类学习的话就是一条路一条路的去尝试一下,先走一条路,我看看结果到底是什么。多试几次,只要能活命的,我们其实可以慢慢的了解哪个状态会更好。我们用价值函数 $V(s)$ 来代表这个状态是好的还是坏的。然后用这个 Q 函数来判断说在什么状态下做什么动作能够拿到最大奖励,我们用 Q 函数来表示这个状态-动作值。 +在介绍马尔可夫决策过程之前,我会给大家首先梳理一下马尔可夫、马尔可夫奖励过程。这两个过程是马尔可夫决策过程的一个基础。 -![](img/2.4.png) +## Markov Processes -接下来就会介绍 Q 函数。在经过多次尝试和那个熊打交道之后,人类就可以对熊的不同的状态去做出判断,我们可以用状态动作价值的来表达说在某个状态下,为什么动作 1 会比动作 2 好。因为动作 1 的价值比动作 2 要高。这个价值就叫 Q 函数。如果说这个 Q 表格是一张已经训练好的表格的话,那这一张表格就像是我们的一本生活手册。我们就知道在熊发怒的时候,装死的价值会高一点。在熊离开的时候,我们可能偷偷逃跑的会比较容易获救。这张表格里面 Q 函数的物理意义就是我选择了这个动作之后我最后面能不能成功,就是我需要去计算我在这个状态下,我选择了这个动作,后续能够一共拿到多少总收益。如果我可以预估未来的总收益的大小,我们当然知道在当前的这个状态下选择哪个动作,价值更高。我选择某个动作是因为我未来一共可以拿到的那个价值会更高一点。所以强化学习它的目标导向性很强,环境给了这个 reward 是一个非常重要的反馈,它就是根据环境的 reward 的反馈来去做选择。 +![](img/2.4.png)如果一个状态转移是符合马尔可夫的,那我们就是说一个状态的下一个状态只取决于它当前状态,而跟它当前状态之前的状态都没有关系。比如说我们这里有一个 $h_t$,它包含了之前的所有状态,但是我们这里的转移从当前 $s_t$ 转到 $s_{t+1}$ 这个状态,他是直接就等于它之前所有的状态,这一个我们说某一个过程,它是满足马尔可夫特征的,就是再说未来的转移跟过去是独立的,它只取决于现在。这个马尔可夫特征其实是所有马尔可夫过程的一个基础。 -![](img/2.5.png)未来的总收益是一个什么样的概念,为什么可以用这个来评价当前这个动作是好是坏。举个例子,假设说一辆车在路上,当前是红灯,我们直接走的那个收益就很低,因为违反交通规则,这是就是当前的单步收益。可是如果我们这是一辆救护车,我们正在运送病人,把病人快速送达医院的收益非常的高,而且越快你的收益越大。很可能是我们这个时候应该要闯红灯,因为未来的远期收益太高了。这也是为什么说强化学习需要去学习远期的收益,因为现实世界当中这个奖励往往是延迟的,是有delay 的。 +![](img/2.5.png) -所以我们一般会从当前状态开始,后续有可能会收到所有收益加起来计算。当前动作的 Q 的价值,让 Q 的价值可以真正的代表当前这个状态动作的真正的价值。 +让我们首先来看一看马尔可夫链。举个例子,这个图里面有四个状态,这四个状态从 $s_1,s_2,s_3,s_4$ 之间互相转移。比如说从 $s_1$ 开始, $s_1$ 有 0.1 的概率继续存活在 $s_1$ 状态,另外,它有0.2的概率转移到 $s_2$ 。另外有 0.7 的概率转移到 $s_4$ 。如果 $s_4$ 是我们当前状态的话,那么它有 0.3 的概率转移到 $s_2$ ,有 0.2 的概率转移到 $s_3$ ,有另外有 0.5 的概率留在这里,所以描述这样的状态转移,我们可以用这一个状态转移矩阵。状态转移矩阵类似于一个 conditional probability。当我们知道当前我们在 $s_t$ 这个状态过后,到达下面所有状态的一个概念。所以它每一行其实描述了是从一个节点到达所有其它节点的这个概念。 ![](img/2.6.png) +上图是一个马尔可夫链的例子,我们这里有七个状态。比如说从 $s_1$ 开始到 $s_2$ ,它有 0.4 的概率,然后另外它有 0.6 的概率继续存活在它当前的状态。 $s_2$ 有 0.4 的概率到左边,另外有 0.4 的概率到 $s_3$ 。另外有 0.2 的概率存活在它现在的状态,所以当我们给定了这个状态转移的马尔可夫链过后,我们可以对这个链进行采样,这样就会得到一串的轨迹。下面我们这里有三个轨迹,都是从同一个起始点开始。假设我们从还是 $s_3$ 这个状态开始。比如说第一条链,它先到了 $s_4$ ,然后又到了 $s_5$,然后又往右到了 $s_6$ ,然后继续存活在 $s_6$ 状态。另外,第二条链说的是它从 $s_3$ 开始,先往左走到了 $s_2$ 。然后它又往右走,又回到了$s_3$ ,然后它又往左走,然后再往左走到了 $s_1$ 。通过对这个状态的采样,我们就可以生成了很多这样的轨迹。 -但是有的时候你目光放的太长远不好,因为如果说事情很快就结束的话,你考虑到最后一步的收益无可厚非,。如果说是一个持续的没有尽头的任务,即`持续式任务(Continuing Task)`。你把所有未来的收益全部相加,作为当前的状态价值就很不合理。股票的例子就很典型了,我们要关注的是累积的收益。可是如果说十年之后才有一次大涨大跌,你要把十年后的收益也作为当前动作的考虑因素,显然我们不会这么做。那我们会怎么办呢,就有句俗话说得好,就对远一点的东西呢,我们就当做近视就不需要看得太清楚,我们就可以适当引入这个衰减因子 $\gamma$ 来去计算这个未来总收益。$\gamma \in [0,1]$ 。越往后 $\gamma^n$ 就会越小,也就是说越后面的收益对当前价值的影响就会越小。 +## Markov Reward Process(MRP) ![](img/2.7.png) - -举个具体的例子来看看这些计算出来的是什么效果。这是一个悬崖问题。这个问题是需要智能体从出发点 S 出发,然后到达目的地 G,同时避免掉进悬崖(cliff),掉进悬崖的话就会有负一百分的惩罚,但游戏不会结束,它会被直接拖回起点,游戏继续。为了到达目的地的话,我们可以沿着蓝线和红线走。 +这里我们再来看一看马尔可夫奖励过程,马尔可夫奖励过程是马尔可夫链再加上了一个奖励函数。我们在定义马尔可夫奖励过程之中,这个转移矩阵跟它的这个状态都是跟马尔可夫链一样的,这里多了一个是这个奖励函数。奖励函数是一个期望,它说当你当到达某一个状态的时候,可以获得多大的奖励,然后这里另外定义了一个这个 discount factor $\gamma$ 。 ![](img/2.8.png) -在这个环境当中,我们去怎么去计算状态动作价值,就是未来的总收益的话。假设我走一条路,然后这条路的话,我从这个状态出发,在这里选择是向上,这里选择向右,选择向右。 - -如果 $\gamma = 0$,然后用这个公式去计算的话,它相当于考虑的就是一个单步的收益。我们可以认为它是一个目光短浅的一个计算的方法。 - -但 $\gamma = 1$ 的话,那就等于是说把后续所有的收益可能都全部加起来。在这里悬崖问题,你每走一步都会拿到一个 -1 分的 reward。只有到了终点之后,它才会停止。如果说 $\gamma =1 $的话,我们用这个公式去计算,就这里是 -1。然后这里的话,未来的总收益就是 $-1+-1=-2$ 。 - -如果让 $\gamma = 0.6$ 的话,就是目光没有放得那么的长远,计算出来是这个样子的。 - - -利用 $G_{t}=R_{t+1}+\gamma G_{t+1}$ 这个公式从后往前推。 -$$ -\begin{array}{l} -G_{7}=R+\gamma G_{8}=-1+0.6 *(-2.176)=-2.3056 \approx-2.3 \\ -G_{8}=R+\gamma G_{9}=-1+0.6 *(-1.96)=-2.176 \approx-2.18 \\ -G_{9}=R+\gamma G_{10}=-1+0.6 *(-1.6)=-1.96 \\ -G_{10}=R+\gamma G_{11}=-1+0.6 *(-1)=-1.6 \\ -G_{12}=R+\gamma G_{13}=-1+0.6 * 0=-1 \\ -G_{13}=0 -\end{array} -$$ - - -这里的计算是我们选择了一条路,走完这条路径上每一个状态动作的价值,我们可以看一下右下角这个图,如果说我走的不是这条路,我走的是这一条路,那我算出来那个状态动作价值的 Q 值可能是这样。那我们就知道,当小乌龟在 -12 这个点的时候,往右边走是 -11,往上走是 -15。它自然就知道往右走的价值更大,小乌龟就会往右走 +这里是我们刚才看的马尔可夫链,如果把奖励也放上去的话,就是说到达每一个状态,我们都会获得一个奖励。这里我们可以定义比如说它 $s_1$ 状态的时候可以获得 5 的奖励,到达 $s_7$ 的时候,它有 10 的奖励,其它状态它没有任何奖励。因为我们这里状态是有限的,所以我们可以用一个向量来表示这个奖励函数。这个向量就是表示了每个点的奖励的大小。我们可以通过一个形象的例子来理解马尔代夫奖励过程,你其实可以把它看成一个纸船,就是当我们把一个纸船放到一个河流之中去,那么它就会随着这个河流而流动,它自身其实是没有动力,所以你可以把这个马尔可夫奖励过程看成是一个随波逐流的例子,当我们从某一个点开始的时候,这个纸船它就会随着这个我们事先定义好的状态转移进行流动,然后它到达每个状态过后,我们就有可能获得一些奖励。 ![](img/2.9.png) -最后我们要求解的就是类似于这样子的一张 Q 表格。就是它的行数是所有的状态数量,一般可以用坐标来表示表示格子的状态,也可以用 1、2、3、4、5、6、7 来表示不同的位置。Q 表格一共四列的话就代表说是上下左右四个动作。最开始这张 Q 表格会全部初始化为零,然后在 agent 不断地去和环境交互得到不同的轨迹,当交互的次数足够多的时候,我们就可以估算出每一个状态下,每个行动的平均总收益去更新这个 Q 表格。怎么去更新 Q 表格就是我们接下来要引入的强化学习的强化概念。 -强化概念的就是我们可以用下一个状态的价值来更新当前状态的价值。其实就是强化学习里面有一个bootstrap(自助)的概念。在强化学习里面,你可以每走一步更新一下 Q 表格,然后用下一个状态的 Q 值来更新这个状态的 Q 值。 +这里我们进一步定义一些概念,第一个是这个 Horizon 的概念,它说明了我们同一个 episode 或者是整个一个轨迹的长度。然后它是由有限个步数决定的。另外,这里我们再定一个 return。Return 说的是我们把奖励进行折扣,然后获得的这个收益。这个 return 的定义你可以看到它是从你后面得到的 return 逐步叠加起来,然后这里有一个叠加系数,就是越往后的得到的奖励,我们折扣的越多,就说明我们其实更希望得到现有的奖励,未来我们的奖励的话就要把它打折扣。当我们有了这个 return 过后,我们就可以正式定义一个状态的价值了,就是 state value function。然后对于这个马尔可夫奖励过程,它里面定义成是关于这个 return 的期望, $G_t$ 是我们之前定义的 discounted return。然后我们这里取了一个期望,期望就是说从这个状态开始,你有可能获得多大的价值,所以这个期望也可以看成是一个对未来可能获得奖励的一个它的当前价值的一个表现。就是当你进入某一个状态过后,你现在就有多大的价值。 ![](img/2.10.png) -这种单步更新的方法叫做`时序差分`的更新方法。为了让大家更好理解强化学习里面时序差分的这种更新方法。我这里就找了一下它的的物理意义。我们先理解一下巴普洛夫的条件反射实验了。这个实验讲的是什么呢?就是小狗对盆里面的食物,它会产生无条件刺激分泌唾液。一开始小狗对于铃声这种中性刺激是没有反应的。可是我们把这个铃声和这个食物结合起来,每次先给它响一下铃,再给它喂食物。多次重复之后,当铃声响起的时候,小狗也会开始流口水。盆里的肉可以认为是强化学习里面最后面的那个延迟的 reward。声音的刺激可以认为是有 reward 的那个状态之前的一个状态。多次重复实验之后,最后的这个 reward 会强化小狗对于这个声音的条件反射,它会让小狗知道说这个声音代表着有食物,这个声音对于小狗来说也就有了价值,它听到这个声音也会也会流口水。 +这里我们简短地解释一下为什么需要 discounted factor。这第一点是我们是想避免在有些马尔可夫过程,它是自己是带环的,就像它没有并没有终结,然后我们想避免这个无穷的奖励。另外,我们是想把这个不确定性也表示出来,希望尽可能快地得到奖励,而不是在未来某一个点得到奖励。然后另外如果这个奖励是它是有实际价值的了,我们可能是更希望立刻就得到奖励,而不是我们后面再得到奖励。在人的行为里面来说的话,其实也是大家也是想得到立刻奖励了。另外,在有些状态的时候,我们这个系数也可以把它设为 0。比如说,当我们设为 0 过后,然后我们就只关注了它当前的奖励。另外,我们也可以把它设为 1,设为 1 的话就是对未来并没有折扣,未来获得的奖励跟我们当前获得的奖励是一样的。价值是一样的,这个系数其实是应该可以作为强化学习 agent 的一个 hyper parameter 来进行调整,然后就会得到不同行为的 agent。 ![](img/2.11.png) -巴普洛夫效应揭示的是中性刺激(铃声)跟无条件刺激(食物)紧紧挨着反复出现的时候,条件刺激也可以引起无条件刺激引起的唾液分泌,然后形成这个条件刺激。这种中性刺激跟无条件刺激在时间上面的结合,我们就称之为强化。 强化的次数越多,条件反射就会越巩固。小狗原本不觉得铃声有价值的,经过强化之后,小狗就会慢慢地意识到铃声也是有价值的,它可能带来带来食物。更重要是一种条件反射巩固之后,我们再用另外一种新的刺激和条件反射去结合,还可以形成第二级条件反射,同样还可以形成第三级条件反射。在人的身上是可以建立多级的条件反射的。举个例子,比如说一般我们遇到熊都是这样一个顺序,看到树上有熊瓜,然后看到熊之后,突然熊发怒,扑过来了。经历这个过程之后,我们可能最开始看到熊才会瑟瑟发抖,后面就是看到树上有熊爪就已经有害怕的感觉了。也就说在不断的重复试验之后,下一个状态的价值,它是可以不断地去强化影响上一个状态的价值的。 +这里我们再来看一看,在这个马尔可夫奖励过程里面,它如何计算它的价值。这个马尔可夫奖励过程依旧是这个状态转移。它的奖励函数是定义成这样,它在进入第一个状态的时候,他会得到 5 的奖励,进入第七个状态的时候会得到 10 的奖励,其它状态都没有奖励。我们现在可以计算每一个轨迹得到的奖励,比如我们这里对于这个 $s_4,s_5,s_6,s_7$ 整个轨迹的奖励进行计算,我们这里折扣系数是0.5。那么我们在 $s_4$ 的时候,我们并没有任何奖励,所以这里是零。下一个状态 $s_5$ 的时候,因为我们已经到了下一步了,所以我们要把 $s_5$ 进行一个折扣,$s_5$ 本身也是没有奖励的。然后是到$s_6$ ,然后也没有任何奖励。折扣系数应该是下两步,所以我们要再乘以 $\frac{1}{2}$ 。然后这里终于我们到达$s_7$ ,然后我们获得了一个奖励。但是因为 $s_7$ 这个状态是我们试过以后的未来我们才获得的奖励,所以我们要进行三次折扣。所以对于这个轨迹,它的 return 就是一个1.25,类似地,我们可以得到其它轨迹的 return 。 + +这里就自然而然引出了一个问题,当我们有了一些轨迹的实际 return。那我们怎么计算它的价值函数。比如说我们现在想知道 $s_4$ 状态的价值。就是当你进入 $s_4$ 后,它的价值到底如何。 + +那么一个可行的做法,就是说我们可以产生很多轨迹,然后把这里的轨迹都叠加起来。比如我们现在可以从 $s_4$ 开始,然后采样生成很多轨迹,然后我们都把它的 return 计算出来,然后可以直接把它取一个平均,然后作为你进入 $s_4$ 它的价值,这其实是一种计算价值函数的一个办法,通过这个蒙特卡罗采样的办法计算 $s_4$ 的状态,我们接下来会进一步介绍这个蒙特卡洛算法 ![](img/2.12.png) -为了让大家更加直观感受下一个状态影响上一个状态效果,这里推荐斯坦福大学的一个网站:[Temporal Difference Learning Gridworld Demo](https://cs.stanford.edu/people/karpathy/reinforcejs/gridworld_td.html)。这个网站模拟了就是这种单步更新的过程中,所有格子的一个状态价值的变化过程。我们可以看到格子里面有几个 -1的 reward。只有一个 +1 reward 的那个格子。 +但是这里我们采取了另外一种计算方法,我们通过一定的推导就可以从这个价值函数里面推导出 `Bellman Equation(贝尔曼等式)`。Bellman Equation 定义了你当前状态跟未来状态之间的这个关系。比如 $s'$ 我们可以把它看成未来的所有状态。然后这里有一个转移 $P(s'|s)$ ,就是我们从当前状态转移到未来状态,那么它之间是满足于这个关系,然后我们可以把第二部分这部分看成是一个 Discounted sum of future reward。$V(s')$ 代表的是未来某一个状态的价值,那么我们从当前这个位置开始有一定的概率去到未来的所有状态,所以我们要把这个概率也写上去,这个转移矩阵也写上去,然后我们就得到了未来状态。然后再乘以一个 $\gamma$。这样就可以把未来为折扣,然后再加上我们当前立刻可以得到的这个奖励,这样就组成了这个 Bellman Equation。这个推导过程,大家其实可以去练习练习,就从这个定义出发,然后把它分解开,我们就可以得到 Bellman Equation。 ![](img/2.13.png) -玩起来是这样的,先初始化一下,然后开始时序差分的更新过程,训练的过程你会看到这个小黄球不断的在试错。但探索当中会先迅速地发现有 reward 的地方。最开始的时候,只是这些有 reward 的格子 才有价值,当不断的重复走这些路线的时候,这些有价值的格子,它可以去慢慢的影响它附近的格子的价值。反复训练之后,有 reward 的这些格子周围的格子的状态就会慢慢的被强化,然后强化就是当它收敛到最后一个最优的状态了,就是把这些价值最终收敛到一个最优的情况之后,那个小黄球就会自动地知道,就是我一直往价值高的地方走,我就能够走到能够拿到 reward 的地方。 - -### Temporal Difference +Bellman Equation 定义了状态之间迭代关系。假设我们现在有一个马尔可夫转移矩阵是右边这个样子。然后 Bellman Equation 描述的就是当前状态到未来状态的一个转移,你可以发现,从假设我们当前是在 $s_1$, 那么它只可能去到三个未来的状态。一个是它有 0.1 的概率留在它当前这个位置,另外有 0.2 的概率,它去到才 $s_2$ 状态。另外 0.7 的概率去到 $s_4$ 的状态,所以我们要把这个转移乘以它的这个未来的状态,再加上它的 immediate reward 就会得到它当前状态的价值。所以 Bellman Equation 定义的就是当前状态跟未来状态的一个迭代的关系。 ![](img/2.14.png) -这种强化方式其实在数学上面一行公式就表达出来了。这种更新的方式叫做`时序差分(Temporal Difference)`。这个公式就是说可以拿下一步的 Q 值 $Q(S_{t+_1},A_{t+1})$ 来更新我这一步的 Q 值 $Q(S_t,A_t)$ 。 +另外我们可以把 Bellman Equation 写成一种矩阵的形式,这下面就是矩阵的一个具体形式。我们首先有这个转移矩阵。我们当前这个状态是一个向量 $[V(s_1),V(s_2),\cdots,V(s_N)]^T$。我们可以写成迭代的形式。我们每一行来看的话,V 这个向量乘以了转移矩阵里面的某一行,然后再加上它当前的这个可以得到的 reward,然后就会回到它当前的这个价值。 -为了理解这个公式,如图所示,我们先把 $R_{t+1}+\gamma Q\left(S_{t+1}, A_{t+1}\right.)$ 当作是一个目标值,就是 $Q(S_t,A_t)$ 想要去逼近的一个目标值。我们想要计算的就是这个 $Q(S_t,A_t)$ 。因为最开始 Q 值都是随机初始化或者是初始化为零。它需要不断的去逼近它理想中真实的Q 值,我们就叫 target 。Target 就是未来收益的总和大概有多少,而且是带衰减的那个。 - -我们用 $G_t$ 来表示未来收益总和(return),我们对 return 做一下简单的数学变化,可以知道 +当我们写成如下的矩阵形式后 $$ -G_t = R_{t+1}+ \gamma G_{t+1} +V = R+ \gamma PV $$ -也就是说,我们拿 $Q(S_t,A_t)$ 来逼近这个 $G_t$ , 那 $Q(S_{t+1},A_{t+1})$ 其实就是近似这个 $G_{t+1}$ ,那我们可以把 $G_{t+1}$ 放到这个目标值这里。$Q(S_t,A_t)$ 就是要逼近这个目标值。我们用软更新的方式来逼近。 - -软更新的方式就是 $\alpha$ ,每次我只更新一点点。这个 $\alpha$ 有点类似于像学习率一样的东西。最终的话,Q 值都是可以慢慢地逼近到真实的 target 值的。这样我们的更新公式只需要用到当前时刻的 $S_{t},A_t$ ,然后还有拿到的 $R_{t+1}, S_{t+1},A_{t+1}$ 。 - -该算法由于每次更新值函数需要知道前一步的状态(state),前一步的动作(action)、奖励(reward)、当前状态(state)、将要执行的动作(action),即 $(S_{t}, A_{t}, R_{t+1}, S_{t+1}, A_{t+1})$ 这几个值 ,由此得名 `Sarsa` 算法。因为它走了一步之后,拿到了 $(S_{t}, A_{t}, R_{t+1}, S_{t+1}, A_{t+1})$ 之后,就可以做一次更新。 +让我们可以直接得到一个`解析解(analytic solution)`,就通过矩阵求逆的过程,就可以把这个 V 的这个价值直接求出来。但是一个问题是这个矩阵求逆的过程的复杂度是 $O(N^3)$。所以就当我们状态非常多的时候,比如说从我们现在十个状态到一千个状态,到一百万个状态。那么当我们有一百万个状态的时候,这个转移矩阵就会是个一百万乘以一百万的一个矩阵。这样一个大矩阵的话求逆是非常困难的,所以这种通过解析解去解,只能对于很小量的马尔可夫奖励过程。 ![](img/2.15.png) -我们看看用代码去怎么去实现。了解单步更新的一个基本公式之后,代码实现就很简单了。这个是环境,这个是 agent 。我们每次跟环境交互一次之后呢,就可以 learn 一下。我们向环境输出 action, +另外求解这个价值函数,我们有这个迭代的方法来解这种状态非常多的这个马尔可夫奖励过程,这里迭代的方法就有几种。比如说我们可以通过动态规划(Dynamic Programming)的方法,然后也可以通过蒙特卡罗的办法,就通过采样的办法去计算它。另外我们也可以通过 Temporal-Difference Learning 的那个办法。这个 Temporal-Difference Learning 叫 TD Leanring,就是动态规划和蒙特卡罗的一个结合。 -然后从环境当中拿到那 state 和 reward。Agent 主要实现两个方法,一个就是根据 Q 表格去选择动作,输出 action。另外一个就是拿到 $(S_{t}, A_{t}, R_{t+1}, S_{t+1}, A_{t+1})$ 这几个值去更新我们的 Q 表格。 +![](img/2.16.png) -![](img/2.16.png)我们直接看这个框框里面的更新公式, 和之前的公式是一模一样的。$S'$ 就是 $S_{t+1}$ 。我们就是拿下一步的 Q 值来更新这一步的 Q 值,不断地强化每一个 Q。这边我们给出 [Sarsa 的 Python 实现](https://github.com/datawhalechina/leedeeprl-notes/tree/master/codes/Sarsa)。 +这里首先我们来看一个蒙特卡罗的一个办法来计算它的一个价值函数,这个蒙特卡罗就跟我们之前采用的这个方法是很类似,就说我们当得到一个马尔可夫奖励过程过后,我们可以从某一个状态开始,然后让它让把这个小船放进去,让它随波逐流,这样就会产生一个轨迹。产生了一个轨迹过后,人们就会得到一个奖励,那么就直接把它的 Discounted 的奖励 $g$ 直接算出来。算出来过后就可以把它积累起来,当积累到一定的轨迹数量过后,然后直接除以这个轨迹,然后就会得到它的这个价值。 -## Sarsa(λ) +比如说我们要算 $s_4$ 状态的一个价值,就可以从 $s_4$ 状态开始,然后随机产生很多轨迹,就产生很多小船,然后扔到这个转移矩阵里面去,然后它就会随波逐流,然后产生轨迹。每个轨迹,我们可以算到它的这个 return 。那么每个轨迹都会得到一个 return,让我们得到大量的 return 。比如说一百个、一千个的 return ,然后直接取一个平均,那么就可以等价于它现在这个 $s_4$ 这个价值。因为 $s_4$ 的价值 $V(s_4)$ 就是定义了你未来可能得到多少的这个奖励。这就是蒙特卡罗采样的方法。 -Sarsa 属于单步更新法,也就是说每执行一个动作,就会更新一次价值和策略。如果不进行单步更新,而是采取 $n$ 步更新或者回合更新,即在执行 $n$ 步之后再来更新价值和策略,这样就得到了 $n$ 步 Sarsa。具体来说,对于 Sarsa,在 $t$ 时刻其价值的计算公式为 -$$ -q_{t}=r_{t}+\gamma Q\left(s_{t+1}, a_{t+1}\right) -$$ -而对于 $n$ 步 Sarsa,它的 $n$ 步 Q 收获为 -$$ -q_{t}^{(n)}=r_{t}+\gamma r_{t+1}+\cdots+\gamma^{n-1} r_{t+n-1}+\gamma^{n} Q\left(s_{t+n}, a_{t+n}\right) -$$ -如果给 $q_t^{(n)}$ 加上衰减因子 $\lambda$ 并进行求和,即可得到 Sarsa($\lambda$) 的 Q 收获: -$$ -q_{t}^{\lambda}=(1-\lambda) \sum_{n=1}^{\infty} \lambda^{n-1} q_{t}^{(n)} -$$ -因此,$n$ 步 Sarsa($\lambda$)的更新策略可以表示为 -$$ -Q\left(s_{t}, a_{t}\right) \leftarrow Q\left(s_{t}, a_{t}\right)+\alpha\left(q_{t}^{\lambda}-Q\left(s_{t}, a_{t}\right)\right) -$$ -总的来说,Sarsa 和 Sarsa($\lambda$) 的差别主要体现在价值的更新上。 +![](img/2.17.png)我们也可以用这个动态规划的一个办法,就通过这种一直去迭代它的 Bellman Equation ,然后让它最后收敛,我们就可以得到它的一个状态。所以在这里算法二就是一个迭代的一个算法,通过这个 bootstraping 的一个办法,然后去不停地迭代这个 Bellman Equation。然后当这个最后更新的状态跟你上一个状态变化并不大的时候,这个更新就可以停止。那么我们就可以输出这个最新的这个 $V'(s)$ 作为它当前的状态。所以这里就是利用到了 Bellman Equation,就把 Bellman Equation 变成一个 Bellman Update。这样就可以得到它的一个价值。 - - -## Q-learning - -![](img/2.17.png) - -Sarsa 是一种 on-policy 策略。Sarsa 优化的是它实际执行的策略。它直接拿下一步会执行的 action 来去优化 Q 表格,所以 on-policy 在学习的过程中,只存在一种策略,它用一种策略去做 action 的选取,也用一种策略去做优化。所以 Sarsa 知道它下一步的动作有可能会跑到悬崖那边去,所以它就会在优化它自己的策略的时候,会尽可能的离悬崖远一点。这样子就会保证说,它下一步哪怕是有随机动作,它也还是在安全区域内。 - -而 off-policy 在学习的过程中,有两种不同的策略。第一个策略是我们希望学到一个最佳的目标策略,另外一个策略是探索环境的策略,它可以大胆地去探索到所有可能的轨迹,然后喂给这个目标策略去学习。而且喂给目标策略的数据中并不需要 $a_{t+1}$ ,而 Sarsa 是有 $a_{t+1}$ 的。比如说目标策略优化时候,Q-learning 才不管你下一步去往哪里探索,会不会掉悬崖,我就只选我收益最大一个最优的策略。探索环境的策略,我们叫做 `behavior policy(行为策略)`,它像是一个战士,可以在环境里面探索所有的动作和轨迹和经验,然后把这些经验的交给目标策略去学习。`Target policy(目标策略)`就像是在后方指挥战术的一个军师,它可以根据自己的经验来学习最优的策略,不需要去和环境交互。 +## Markov Decision Process(MDP) ![](img/2.18.png) - 我们通过对比的方式来去理解 `Q-learning`。Q-learning 是 off-policy 的时序差分学习方法,Sarsa 是 on-policy 的时序差分学习方法。 - -* Sarsa 在更新 Q 表格的时候,它用到的 A' 。我要获取下一个 Q 值的时候,A' 是下一个 step 一定会执行的 action 。这个 action 有可能是 $\varepsilon$-greddy 方法 sample 出来的值,也有可能是 max Q 对应的 action,也有可能是随机动作。但是就是它实实在在执行了的那个动作。 - -* 但是 Q-learning 在更新 Q 表格的时候,它用到这个的 Q 值 $Q(S',a')$ 对应的那个 action ,它不一定是下一个 step 会执行的实际的 action,因为你下一个实际会执行的那个 action 可能会探索。Q-learning 默认的 action 不是通过 behavior policy 来选取的,它是默认 A' 为最优策略选的动作,所以 Q-learning 在学习的时候,不需要传入 A',即 $a_{t+1}$ 的值。 - -在Q-learning 中,Q函数的估计方法为 -$$ -Q(s, a) \leftarrow Q(s, a)+\alpha\left(r+\gamma \max _{a^{\prime}} Q\left(s^{\prime}, a^{\prime}\right)-Q(s, a)\right) -$$ -相当于让 $Q(s,a)$ 直接去估计最优状态值函数 $Q^*(s,a)$。 - -> 事实上,Q-learning 算法被提出的时间更早,Sarsa 算法是 Q-learning 算法的改进。 - +相对于马尔可夫奖励过程,马尔可夫决策过程多了一个 action,就是它多了一个 decision,其它的定义跟马尔可夫奖励过程都是类似的。这里我们多了一个决策,多了一个 action ,那么这个状态转移也多了一个 condition,就是它多了一个你采取某一种行为,然后你未来的状态会不同,它不仅是依赖于你当前的状态,也依赖于在当前状态你这个 agent 它采取的这个行为会决定它未来的这个状态走向。对于这个价值函数,它也是多了一个条件,多了一个你当前的这个行为,就说你可以得到的奖励是基于你当前的状态以及当年你采取的行为会决定你在当前可能得到的奖励多少。 ![](img/2.19.png) -Sarsa 和 Q-learning 的更新公式都是一样的,区别只在 target 计算的这一部分, - -* Sarsa 是 $R_{t+1}+\gamma Q(S_{t+1}, A_{t+1})$ ; -* Q-learning 是$R_{t+1}+\gamma \underset{a}{\max} Q\left(S_{t+1}, a\right)$ 。 - -Sarsa 实际上都是用自己的策略产生了 S,A,R,S',A' 这一条轨迹。然后拿着 $Q(S_{t+1},A_{t+1})$ 去更新原本的 Q 值 $Q(S_t,A_t)$。 但是 Q-learning 并不需要知道,我实际上选择哪一个 action ,它默认下一个动作就是 Q 最大的那个动作。Q-learning 知道实际上 behavior policy 可能会有 10% 的概率去选择别的动作,但是 Q-learning 并不担心受到探索的影响,它默认了就按照最优的策略来去优化我的目标策略,所以它可以更大胆地去寻找最优的路径,它其实会表现的比 Sarsa 大胆非常多。 - -然后 Q-learning 的这个逐步的一个拆解的话,跟 Sarsa 唯一一点不一样就是我并不需要提前知道我 $A_2$ ,我就能更新 $Q(S_1,A_1)$ 。在训练一个 episode 这个流程图当中,Q-learning 在 learn 之前它也不需要去拿到 next action A',它只需要前面四个 $(S,A,R,S')$也就可以了,这一点就是跟 Sarsa 有一个很明显的区别。这边我们给出[ Q-learning 的 Python实现](https://github.com/datawhalechina/leedeeprl-notes/tree/master/codes/Q-learning)。 - -### Q-function Bellman Equation - -记策略 $\pi $ 的状态-动作值函数为 $Q^{\pi}(s_t,a_t)$,它表示在状态 $s_t$ 下,执行动作 $a_t$ 会带来的累积奖励 $G_t$ 的期望,具体公式为: -$$ -\begin{aligned} Q ^ { \pi } \left( s _ { t } , a _ { t } \right) & = \mathbb { E } \left[ G _ { t } \mid s _ { t } , a _ { t } \right] \\ & = \mathbb { E } \left[ r _ { t } + \gamma r _ { t + 1 } + \gamma ^ { 2 } r _ { t + 2 } + \cdots \mid s _ { t } , a _ { t } \right] \\ & = \mathbb { E } \left[ r _ { t } + \gamma \left( r _ { t + 1 } + \gamma r _ { t + 2 } + \cdots \right) \mid s _ { t } , a _ { t } \right] -\\ & =\mathbb { E } [ r _ { t }|s_t,a_t] + \gamma \mathbb{E}[r_{t+1}+ \gamma r_{t+2}+\cdots|s_t,a_t] \\ -& = \mathbb{E}[ r _ { t }|s_t,a_t]+ \gamma \mathbb{E}[G_{t+1}|s_t,a_t] -\\ &= \mathbb { E } \left[ r _ { t } + \gamma Q ^ { \pi } \left( s _ { t + 1 } , a _ { t + 1 } \right) \mid s _ { t } , a _ { t } \right] \end{aligned} -$$ -上式是 MDP 中 Q-function 的 Bellman 方程的基本形式。累积奖励 $G_t$ 的计算,不仅考虑当下 $t$ 时刻的动作 $a_t$ 的奖励 $r_t$,还会累积计算对之后決策带来的影响(公式中的 $\gamma$ 是后续奖励的衰减因子)。从上式可以看出,当前状态的动作价值 $Q^{\pi}(s_t,a_t)$ ,与当前动作的奖励 $r_t$ 以及下一状态的动作价值 $Q^{\pi}(s_{t+1},a_{t+1})$ 有关,因此,状态-动作值函数的计算可以通过动态规划算法来实现。 - ->Bellman Equation 就是当前状态与未来状态的迭代关系,表示当前状态的值函数可以通过下个状态的值函数来计算。Bellman Equation 因其提出者、动态规划创始人 Richard Bellman 而得名 ,也 叫作“动态规划方程”。 - -从另一方面考虑,在计算 $t$ 时刻的动作价值 $Q^{\pi}(s_t,a_t)$ 时,需要知道在 $t$、$t+1$、$t+2 \cdots \cdots$ 时刻的奖励,这样就不仅需要知道某一状态的所有可能出现的后续状态以及对应的奖励值,还要进行全宽度的回溯来更新状态的价值。这种方法无法在状态转移函数未知或者大规模问题中使用。因此,Q-learning 采用了浅层的时序差分采样学习,在计算累积奖励时,基于当前策略 $\pi$ 预测接下来发生的 $n$ 步动作($n$ 可以取 1 到 $+\infty$)并计算其奖励值。 - -具体来说,假设在状态 $s_t$ 下选择了动作 $a_t$,并得到了奖励 $r_t$ ,此时状态转移到 $s_{t+1}$,如果在此状态下根据同样的策略选择了动作 $a_{t+1}$ ,则 $Q^{\pi}(s_t,a_t)$ 可以表示为 -$$ -Q^{\pi}\left(s_{t}, a_{t}\right)=\mathbb{E}_{s_{t+1}, a_{t+1}}\left[r_{t}+\gamma Q^{\pi}\left(s_{t+1}, a_{t+1}\right) \mid s_{t}, a_{t}\right] -$$ - -Q-learning 算法在使用过程中,可以根据获得的累积奖励来选择策略,累积奖励的期望值越高,价值也就越大,智能体越倾向于选择这个动作。因此,最优策略 $\pi^*$ 对应的状态-动作值函数 $Q^*(s_t,a_t)$ 满足如下关系式: - -$$ -Q^{*}\left(s_{t}, a_{t}\right)=\max _{\pi} Q^{\pi}\left(s_{t}, a_{t}\right)=\mathbb{E}_{s_{t+1}}\left[r_{t}+\gamma \max _{a_{t+1}} Q\left(s_{t+1}, a_{t+1}\right) \mid s_{t}, a_{t}\right] -$$ - -Q-learning 算法在学习过程中会不断地更新 Q 值,但它并没有直接采用上式中的项进行更新,而是采用类似于梯度下降法的更新方式,即状态 $s_t$ 下的动作价值 $Q^*(s_t,a_t)$ 会朝着状态 $s_{t+1}$ 下的动作价值 $r_{t}+\gamma \max _{a_{t+1}} Q^{*}\left(s_{t+1}, a_{t+1}\right)$ 做一定比例的更新: -$$ -\begin{aligned} -Q^{*}\left(s_{t}, a_{t}\right) \leftarrow Q^{*}\left(s_{t}, a_{t}\right)+\alpha\left(r_{t}+\gamma \max _{a_{t+1}} Q^{*}\left(s_{t+1}, a_{t+1}\right)-Q^{*}\left(s_{t}, a_{t}\right)\right) -\end{aligned} -$$ -其中 $\alpha$ 是更新比例(学习速率)。这种渐进式的更新方式,可以减少策略估计造成的影响,并且最终会收敛至最优策略。 +policy 定义了我们在某一个步骤某一个状态的时候应该采取什么样的行为,当我们知道当前状态过后,我们可以带入这个策函数(policy function),那我们会得到一个概率,概率就象征了在所有可能的行为里面怎样去采取行动。就可能有 0.7 的概率往左走,有 0.3 的概率往右走,这样是一个概率的一个表示。另外这个策略也可能是确定的,它有可能是直接输出一个值,或者就直接告诉你当前应该采取什么样的行为,而不是一个行为的概率。然后这里我们有一个假设,就这个概率函数,它应该是静态的(stationary),不同时间点,你采取的行为其实都是对这个 policy function 进行采样。 ![](img/2.20.png) -下面讲一下 on-policy 和 off-policy 的区别。 - -* Sarsa 就是一个典型的 on-policy 策略,它只用一个 $\pi$ ,为了兼顾探索和利用,所以它训练的时候会显得有点胆小怕事。它在解决悬崖问题的时候,会尽可能地离悬崖边上远远的,确保说哪怕自己不小心探索了一点了,也还是在安全区域内不不至于跳进悬崖。 - -* Q-learning 是一个比较典型的 off-policy 的策略,它有目标策略 target policy,一般用 $\pi$ 来表示。然后还有行为策略 behavior policy,用 $\mu$ 来表示。它分离了目标策略跟行为策略。Q-learning 就可以大胆地用 behavior policy 去探索得到的经验轨迹来去优化我的目标策略。这样子我更有可能去探索到最优的策略。 -* 比较 Q-learning 和 Sarsa 的更新公式可以发现,Sarsa 并没有选取最大值的 max 操作。因此,Q-learning 是一个非常激进的算法,希望每一步都获得最大的利益;而 Sarsa 则相对非常保守,会选择一条相对安全的迭代路线。 +这里说明了马尔可夫决策过程跟马尔可夫奖励过程的之间的一个转换,就是当我们已知一个马尔可夫决策过程以及我们已知一个 policy $\pi$ 的时候,那我们可以把马尔可夫决策过程转换成马尔可夫奖励过程。我们这里在马尔可夫决策过程里面,它的转移函数 $P(s'|s,a)$ 是基于它当前状态以及它当前的 action,因为我们现在已经已知它的这个 policy function,就是说在每一个状态,我们知道它可能采取的行为的概率,那么就可以直接把这个 action 进行加和,直接把这个 a 去掉,那我们就可以得到一个对于马尔可夫奖励过程的一个转移。这里就并没有 action 在这个里面,对于这个奖励函数,我们也可以把这个 action 拿掉,这样就会得到一个类似于马尔可夫奖励过程的一个奖励函数。 ![](img/2.21.png) -总结如上图所示。 + + +这里我们再来看一看,马尔科夫决策过程里面它状态转移跟之前马尔可夫奖励过程以及马尔可夫链的一个差异。对于之前的马尔可夫链的过程,它的转移是直接就决定,就从你当前是S,那么就直接通过这个转移概率就直接决定了你下一个状态会是什么。但是对于马尔可夫决策过程,它的中间多了一层这个行为 a ,就是说在你当前这个状态的时候,你首先要决定的是采取某一种行为。那么你会到了某一个黑色的这个节点,到了这个黑色的节点,因为你有一定的不确定性,当你当前状态决定过后以及你当前采取的行为过后,你到未来的状态其实也是一个概率分布。所以你采取行为以及你决定,然后你可能有有多大的概率到达某一个未来状态,以及另外有多大概率到达另外一个状态。所以在这个当前状态跟未来状态转移过程中这里多了一层决策性,这里是马尔可夫决策过程跟之前的马尔可夫过程很不同的一个地方。这里这个行为是由 agent 决定,所以这里我们多了一个 component,agent 会采取这个行为来决定这个未来的状态转移。 + +![](img/2.22.png) + +顺着马尔可夫决策过程的定义,我们可以把 state-value function,就是在马尔可夫决策过程里面的价值函数也进行一个定义,它的定义是跟马尔可夫奖励过程是类似的,但是这里我们的一个期望 expectation over policy,就是这个期望是基于这个你采取的这个 policy ,就当你的 policy 决定过后,让我们通过对这个 policy 进行采样,然后我们可以得到一个期望。那么就可以计算出它的这个价值函数。这里我们另外引入了一个 Q 函数,action-value function。 + +这个 Q 函数定义的是某一个状态某一个行为,然后它有可能得到的这个 return 的一个期望,这里期望其实也是 over 这个 policy function。所以你需要对这个 policy function 进行一个加和。然后最后得到它的这个价值。第三步,这里导出了价值函数跟Q函数之间的一个关系。价值函数跟 Q 函数的关系,就是直接对价值函数中的行为函数进行加和,就可以得到这个价值。 + +![](img/2.23.png) + +我们这里会得到一个 `Bellman Expectation Equation`,通过对它价值函数的定义,然后我们可以对它进行一个分解,我们就可以直接又得到一个这个类似于我们之前马尔可夫奖励过程的 Bellman Equation,这里叫 Bellman Expectation Equation。 因为这里期望是期望于它所有的这个 policy 所有可能的行为都把它 marginalize 掉,然后得到 return。那么对于 Q 函数,我们也可以做类似的分解,那么也可以得到对于 Q 函数的这个 Bellman Expectation Equation。 + +Bellman Expectation Equation 定义了你当前状态跟未来状态之间的一个关联。 + +![](img/2.24.png) + +那我们进一步进行一个简单的一个分解。等式 8 和等式 9 象征了价值函数跟 Q 函数之间的一个关联。我们把等式 8 插入到等式 9,然后可以得到等式 11,它象征了你当前时刻的 Q 函数跟未来时刻的 Q 函数之间的一个关联。也可以吧 等式9插入等式 8 中,然后我们可以得到等式 10。等式 10 象征了我们当前状态的价值跟未来状态价值之间的一个关联。 + +![](img/2.25.png) + +这里有一个概念叫 `Backup`。Backup 类似于 bootstraping(拔靴自助) 之间这个迭代关系,就对于某一个状态,它的当前这个价值是跟它未来价值线性相关的,你可以看到我们这里有两层加和。第一层加和就是这个叶子节点,然后往上走一层的话,我们就可以把未来的这个价值,$s'$ 的这个价值 backup 到黑色的节点。然后再有一层加和,第二层加和,这个加和是把 action 进行加和。得到黑色节点的价值过后,再往上 backup 一层,然后就会推到根节点的价值,根节点就是我们当前状态。所以这个 Backup Diagram 定义了你未来下一时刻的状态跟你上一时刻的状态之间的一个关联。 -## References +![](img/2.26.png) -* [百面深度学习](https://book.douban.com/subject/35043939/) +同样对于 Q 函数,我们也可以进行这样的一个推导,就我们现在的根节点是这个Q函数的一个节点。这个 Q 函数是对于黑色的这个节点。我们下一时刻的这个Q函数是叶子节点,有四个黑色结点。那么我们这里也有两个加和。 -* [神经网络与深度学习](https://nndl.github.io/) +第一层加和是我们先把这个叶子节点从黑节点推到这个白色的这个节点,进了它的这个状态,就当我们到达某一个状态过后,这个白色极点,然后再进行一个加和,这样就把它重新推回到当前节点的一个Q函数,所以这个等式就决定了未来 Q 函数跟当前 Q 函数之间的这个关联。 + +![](img/2.27.png) + +这里一个概念是 policy evaluation。Policy evaluation 的概念是说当我们知道一个马尔可夫决策过程以及我们要采取的策略 $\pi$ ,那我们计算价值函数的过程。这个就是叫 policy evaluation,就像我们在评估这个策略,我们会得到多大的这个奖励。这个 policy evaluation 在有些地方也是被 叫做 prediction,也就是在预测你当前采取的这个策略最终会产生多少的价值。 + +![](img/2.28.png) + +这个马尔可夫决策过程,你其实可以把它想象成一个摆渡的一个人,就在这个船上面,其实有一个人它可以控制这个船的移动,这样就避免了这个船随波逐流。因为你在每一个时刻,这个人会决定采取什么样的一个行为,这样会把这个船进行导向。这样就相对于马尔可夫奖励过程跟马尔可夫链的过程的话,这个纸的小船只在一个随波逐流,然后产生轨迹。这里MDP 的这个不同就是我们有一个主体,这个 agent 去控制这个船,然后这样我们就可以尽可能多的获得奖励。 + +![](img/2.29.png) + +这里我们再来进一步把这个例子,看一看它这个怎么做 policy evaluation,怎么在这个决策过程里面计算它每一个状态的价值。现在我们假设环境里面它有两种行为,就是往左走跟往右走的行为。然后我们这里 reward 的定义。因为其实这个现在的奖励函数应该是关于行为以及状态两个变量的一个函数,但我们这里就说,对于所有行为不管你采取什么行为,然后你只要是到达状态一了,然后都有五的奖励。只要是你到达状态 $s_7$ 了,然后你有十的奖励,然后中间没有任何奖励。那么假设我们现在采取的一个策略,这个策略我们说我们不管在任何状态,我们采取的策略都是往左走,我们也这里假设我们的价值这个折扣因子是零,那么直接就可以得到对于这样一个 deterministic policy,那么最后估算出的价值函数是是一致的。怎么得到这个结果,其实我们就可以直接在去 run 这个 iterative Equation,就把这个 Bellman Expectation Equation 拿到这个里面来,然后不停的迭代,最后它会收敛。收敛过后,然后它的值就是它每一个状态的价值。 + +![](img/2.30.png) + +我们再来看另外一个情况,就是如果我们这里有折扣了,这个折扣因子是 0.5,我们就可以通过这个等式进行迭代 +$$ +v_{t}^{\pi}(s)=\sum_{a} P(\pi(s)=a)\left(r(s, a)+\gamma \sum_{s^{\prime} \in S} P\left(s^{\prime} \mid s, a\right) v_{t-1}^{\pi}\left(s^{\prime}\right)\right) +$$ +然后就会得到它的状态。另外一个练习的一个例子,就是说我们现在采取的 policy 在每个状态,我们有 0.5 的概率往左走。另外有 0.5 的概率往右走,那么放到这个状态里面去如何计算。其实也是把这个 Bellman Expectation Equation 拿出来,然后进行迭代就可以算出来了,就当我们开始的时候,我们可以初始化。初始化这个不同的 $v(s')$ 都会有一个值,那么放到这个里面去迭代,最后它的 $v$ ,然后就会算出来。 + +![](img/2.31.png) + +接下来我会给大家介绍马尔可夫决策过程的预测跟控制。这两个问题是马尔可夫决策过程里面的核心问题。对于 prediction,它的意思是说当我们给定一个马尔可夫决策过程以及一个给定的 policy $\pi$ ,那我们去计算它的 value function,就等于每个状态它的价值函数是多少。control 这个问题是说我们去寻找一个最佳的一个策略,它的 input 就是马尔可夫决策过程,输出是通过去寻找它的最佳策略,然后同时输出它的最佳价值函数(optimal value function)以及它的这个最佳策略(optimal policy)。在 MDP 里面,Prediction 和 control 都可以通过这个动态规划去解决。 + +![](img/2.32.png) + +首先我们来看一下这个动态规划。动态规划是说的是我们把可以把一个问题分解成一个最佳的一个子结构,当我们可以把一些子结构都可以解决的话,那么它总共就可以组成一个最优的一个解。马尔可夫决策过程是满足这个动态规划的要求的。就是在 Bellman Equation 里面,大家都看到了,我们其实把它分解成一个递归的一个结构,当我们把它分解成一个递归的结构的时候,如果我们的子问题子状态,然后能得到一个值,那么它的未来状态因为跟子状态是直接相连的。那我们也可以继续推算出来。所以这个价值函数就可以储存它以及重用它的最佳的解。所以动态规划是解 MDP prediction 和 control 一个非常有效的一个方式。 + +![](img/2.33.png) + +首先我们来看一下 policy evaluation,就是当我们给定一个 MDP 的时候,我们有一个事先定好的一个 policy。那么我们可以获得多少的价值,就对于当前这个策略,我们可以得到多大的这个 value function。这里一个方法是说,我们直接把这个 Bellman Expectation Backup,这个等式拿出来,然后变成一个迭代的一个过程,这样反复迭代直到收敛。这样就可以计算它的一个过程。这个迭代过程是可以看作是 synchronous backup 的一个过程,这里大家可以看到这个等式14说的就是这个 Bellman Expectation Backup,我们把这个转换成一个动态规划的一个迭代。当我们得到上一时刻的这个 $v_t$ 的时候,那我们下一时刻就通过这个递归的一个关系,我们可以推出下一时刻的这个值,那么反复去迭代它,最后它的值就是从 $v_1,v_2$,到最后收敛过后这个值。这个值就是我们当前给定的 policy 对应的价值函数。 + +![](img/2.34.png) + +Policy evaluation 的核心思想就是直接把这个 Bellman expectation backup,把如下的等式拿出来, +$$ +v_{t+1}(s)=\sum_{a \in \mathcal{A}} \pi(a \mid s)\left(R(s, a)+\gamma \sum_{s^{\prime} \in \mathcal{S}} P\left(s^{\prime} \mid s, a\right) v_{t}\left(s^{\prime}\right)\right) +$$ +然后反复迭代,然后就会得到一个收敛的价值函数的值,这个函数因为我们已经给定了它的这个 policy function,那我们可以直接把它简化成一个马尔可夫奖励过程的一个表达形式,那么它的形式就更简洁一些,就相当于我们把这个 $a$ 去掉。然后这样它就只有价值函数跟转移函数了。那我们通过去迭代这个更简化的一个函数,这样我们也可以得到它每个状态的价值,因为不管是在马尔可夫奖励过程以及马尔可夫决策过程,它的这个价值函数包含的这个变量都是只跟这个状态有关就相当于进入某一个状态,未来可能得到多大的价值。 + +![](img/2.35.png) + +比如现在这个环境是一个 small gridworld 的一个例子,就在我们这个环境非常简单。然后这个 agent 的目的是从某一个状态开始,它为了出去这个状态,它的终止状态就是左上角跟右上角,然后这里总共有14个状态,因为我们把每个位置就是用一个状态来表示。然后这个 agent 它采取的行为,我们说它的这个 policy function 就直接先给定了。我们说它在每一个状态都是随机游走。你说它们在每一个状态就是上下左右行走,它在边缘状态的时候,比如说在第四号状态的时候,它往左走的话,它是依然存在现在这个第四号状态,我们加了这个限制。然后这里我们给的奖励函数就是说你在这个每走一步,然后你就会得到一个负的奖励。所以这个 agent 需要尽快地到达这个终止状态。转态之间的转移也是确定的。比如我们从第六号状态往上走,它就会直接到达第二状态,因为很多时候有些环境是 probabilistic 的话,就是说 agent 在第六号状态,它选择往上走的时候,有可能地板是滑的,然后它可能滑到第三号状态或者第一号状态去,这就是有概率的一个转移。但我们这里说这个环境把它简化,从六号往上走,然后它就到了二号或者往右走然后它就到达七号。所以直接把这个迭代来解它。因为我们已经知道每一个概率以及它的这个概率转移,那么就直接可以进行一个简短的迭代,然后就会算出它每一个状态的一个价值。 + +![](img/2.36.png) + +![](img/2.37.png) + +我们再来看一个动态的一个例子,就你可以看见这里有很多格子。每个格子都代表了一个状态。然后在每个格子里面,你可以发现它初始有一个值,我们开始的时候它的所有值都是零。然后在每一个状态,你可以看下它还有一些箭头,这个箭头就是说它当前这个状态的时候,它应该采取什么样的策略,我们这里采取一个随机的一个策略,不管它在哪一个状态,然后它上下左右的概率都是相同的。就是比如在某个状态,它都有上下左右 0.25 的概率采取某一个行为,所以它是一个完全随机的一个行为。 + +![](img/2.38.png) + +在这样的环境里面,现在我们想计算它每一个状态的价值。然后这里我们也定义了它的 reward function。你可以看到有些状态上面有一个 R 的这个值。比如我们这边有些值是为负的,然后在这个棋盘的中间这个位置,可以能看到有一个 R 1.0,为正的一个价值函数。 所以每个状态对应了一个值,然后有一些状态没有任何值,就说明它的这个 reward function,它的奖励是为零的。 + +所以,当我们开始做这个 policy evaluation,policy evaluation是一个不停迭代的过程。当我们初始化的时候,所有的 $v(s)$ 都是0。我们现在迭代一次,迭代一次过后,你发现有些状态上面,值已经产生了变化。比如说那些有奖励的值,比如有些状态的值的 R 为 -1,迭代一次过后,它就会得到 -1 的这个奖励。对于中间这个绿色的,因为它的奖励为正,所以它是 + 1的状态。 + +![](img/2.39.png) + +所以当迭代第一次的时候,然后我们 $v(s)$ 某些状态已经有些值的变化。 + +![](img/2.40.png) + +然后我们再迭代一次(one sweep),然后发现它就从周围的状态也开始有值。因为周围状态跟之前有值的状态是临近的,所以它就相当于把旁边这个状态转移过来。所以当我们逐渐迭代的话,你会发现这个值一直在变换。等迭代了很多次过后,然后很远的这些状态的价值函数已经有些值了,而且你可以发现它这里整个过程呈现这个逐渐扩散开的一个过程,这其实也是 policy evaluation 的一个可视化。当我们每一步在进行迭代的时候,就远的状态就会得到了一些值,就逐渐从一些已经有奖励的这些状态,逐渐扩散,当你 run 很多次过后,然后它就逐渐稳定下来,最后值就会确定不变,这样收敛过后,每个状态上面的值就是它目前得到的这个 value function 的值。 + +![](img/2.41.png) + +policy evaluation 是说我们给定一个 MDP 以及给定一个 policy,然后我们可以估算出它的价值函数。那么这个问题的另外一方面是说如果我们只有一个 MDP,如何去寻找一个最佳的策略,然后可以得到一个最佳的一个价值函数(Optimal Value Function)。这里 Optimal Value Function的定义是说,我们去搜索一种 policy $\pi$ ,然后我们会得到每个状态它的状态值最大的一个情况,$v^*$ 就是到达每一个状态,它的值的极大化情况。在这种极大化情况上面,我们得到的策略就可以说它是最佳策略(optimal policy)。optimal policy 使得每个状态,它的状态函数都取得最大值。所以当我们说某一个 MDP 的环境被解了过后,就是说我们可以得到一个 optimal value function,然后我们就说它被解了。在这种情况下面,然后我们它的最佳的价值函数是一致的,就它达到了这个 upper bound,它的值是一致的,但是这里可能有多个最佳的 policy,多个 policy 可以取得相同的最佳价值。 + +![](img/2.42.png) + +怎么去寻找这个最佳的 policy ,这里一个隐含条件是当我们取得最佳的价值函数过后,我们其实可以通过对这个Q函数进行极大化,然后得到最佳的价值。就当所有东西都收敛过后,如果我们对于这个Q函数,因为Q函数是关于状态跟动作的一个函数,所以对某一个状态我们当采取一个行为,然后可以使得这个Q函数最大化。那么就这个行为就应该是最佳的行为。所以当我们能优化出一个 Q 函数。我们可以直接在这个Q 函数上面取一个关于这个动作 action 最大化的值,然后我们就可以直接提取出它的最佳策略。 + +![](img/2.43.png) + +这里一种策略搜索办法是我们可以去穷举。因为假设我们有有限多个状态、有限多个行为可能性,那么每个状态我们可以采取这个 A 种行为的策略,那么总共就是 $|A|^{|S|}$ 个可能的 policy。那么有一种方法是直接可以把这个把穷举一遍,然后算出每种策略的 value function,然后对比一下可以得到最佳策略。但是一个问题是这样的穷举是非常没有效率,所以我们要采取另外的一些办法,所以在解这个搜索最佳策略的方法有两种比较常用的方法:一种是叫 policy iteration,另外一种是叫 value iteration 的一个方法。 +![](img/2.44.png) + +所以我们在寻找这个最佳策略的过程就是 MDP 的控制过程,MDP Control 说的就是怎么去寻找一个最佳的策略,然后我们可以得到一个最大的价值函数。对于一个事先定好的 MDP 过程,当这个 agent 去采取策略的时候,我们可以说它这个最佳策略一般都是确定的。而且它是 stationary,它不会随着时间的变化。但是不一定是 unique,多种行为然后都会取得相同的这个这个价值。 + +![](img/2.45.png) + +首先我们来看一下 policy iteration,policy iteration 也是一个迭代算法。它主要由两个步骤组成,第一个步骤是 policy evaluation,就跟我们之前说的这个评价一个已有的这个价值函数的价值是一致的,就是我们当前我们在优化这个 policy $\pi$ ,所以在优化过程中得到一个最新的这个 policy 。让我们先保证这个 policy 不变,那么去估计它出来的这个价值。 + +给定当前的policy function,去估计这个 v 函数。取得 v 函数过后,我们可以进一步推算出它的 Q 函数。 + +得到 Q 函数过后,那我们就直接去取它的极大化。在 Q 函数上面取极大化,这样我们就有了第二步骤。第二步骤就是改进它的策略,通过在这个 Q 函数上面做一个贪心的一个搜索,这样就会进一步改进它的一个策略。这两个步骤就一直是在迭代进行,所以在这个 policy iteration 里面,在初始化的时候,我们有一个初始化的 $V$ 和 $\pi$ 。然后就是在这两个过程之间迭代,左边这幅图上面这根曲线就是我们当前这个 v 这个值,下面是 policy 的值。就跟踢皮球一样,我们先给定当前已有的这个 policy function,然后去算它的这个 v。算出 v 过后,我们会得到一个 Q 函数,Q 函数我们采取 greedy 的策略,这样我们有踢皮球,踢回这个 policy 。然后就会进一步改进那个 policy ,得到一个改进的 policy 过后,它还不是最佳的,我们再进行 policy evaluation,然后又会得到一个新的一个 value function,基于这个新的 value function 再进行 Q 函数的极大化 ,这样就逐渐迭代,然后就会得到收敛。 + +![](img/2.46.png) + +这里和我们再来看一下第二个步骤 policy improvement,我们是如何改进它的这个策略。当我们等到这个 v 值过后,我们就可以通过这个 reward function 以及状态转移把它的这个 Q-function 算出来。对于每一个状态,第二个步骤会得到它的一个新一轮的这个 policy ,就在每一个状态,我们去取使它得到最大值的 action。你可以把这个 Q 函数看成一个 Q-table。横轴是它的所有状态,纵轴是它的可能的 action。Q 函数得到过后,Q-table 就得到了。 + +那么对于某一个状态,每一列里面我们会取最大的那个值,最大值对应的那个 action 就是它现在应该采取了更佳的action。 + +所以你看这里下面这个 arg max 操作就说在每个状态里面,我们去采取一个 action,这个 action 就是能使这一列的 Q 最大化的那个动作。 + +![](img/2.47.png) + +当我们采取一直在采取这个 arg max这个操作的时候,我们会得到一个单调的递增。其实大致就是再说,我们通过采取这种 greedy ,这种 arg max 这个操作,然后是会得到更好的这个或者是不变的这个 policy,而不会使它这个价值函数变差。所以当这个改进停止过后,然后我们就会得到一个最佳的一个策略。 + +![](img/2.48.png) + +当改进停止过后,我们取它极大化的这个 action 之后,它直接就会变成它的这个价值函数。所以我们在这里有了一个新的一个等式,就叫 Bellman Optimality Equation。这个 Bellman Optimality Equation 满足的时候,是说整个 MDP 已经到达最佳的状态。 + +它到达最佳状态过后,对于我们这个Q函数,我们取它最大的 action 时候的那个值,就是直接等于它的最佳的这个 value function,这个条件只有当整个状态已经收敛过后,已经得到一个最佳的 policy 的时候,然后它是满足的。 + +![](img/2.49.png) + +最佳的价值函数到达过后,这个 Bellman Optimlity Equation 就会满足。我们满足过后,就有这个 max 操作,当我们取最大的这个 action 的时候对应的那个值就是当前那个状态的最佳的价值函数。 + +我们可以把第一个等式插入到第二个等式里面去,然后就会得到这个Q函数之间的这个转移。它下一步这个状态我们取了这个 max 这个值过后,就会也跟它下一个最佳的这个状态等价。 + +Q-learning 是基于 Bellman Optimality Equation 来进行的,当取它最大的这个状态的时候,它会满足下面这个等式: +$$ +q^{*}(s, a)=R(s, a)+\gamma \sum_{s^{\prime} \in S} P\left(s^{\prime} \mid s, a\right) \max _{a^{\prime}} q^{*}\left(s^{\prime}, a^{\prime}\right) +$$ + + +![](img/2.50.png) + +value iteration 说的是我们把 Bellman Optimality Equation 当成一个 update rule 来进行,之前我们是说上面这个等式只有当整个状态已经到达最佳状态的时候,然后才满足。但是我们这里可以把它转换成一个 backup 的一个等式。 Backup 就是说一个迭代的一个等式,我们不停地去迭代 Bellman Optimality Equation,就希望能不停的迭代,到了最后,它能逐渐趋向于最佳的策略,所以这也是 value iteration 这个算法的精髓。就是我们去为了得到最佳的这个 $v^*$ ,对于每个状态它的 $v^*$ 这个值,我们直接把这个 Bellman Optimality Equation 进行迭代,迭代了很多次,之后它就会收敛。 + +![](img/2.51.png) + +value iteration 这个算法目的是为了得到一个最佳的一个策略。一个解法是直接把这个 Bellman Optimallity backup, + +它这个等式拿进来进行迭代,迭代很多次,然后收敛过后得到的那个值就是它的最佳的那个值。所以你看这个算法,开始的时候,它是先把所有值初始化,通过每一个状态,然后它会进行这个迭代。把等式 22 插到 等式 23 里面,那就是Bellman Optimallity backup 的那个等式。有了这个等式过后,然后进行不停的迭代,迭代过后,然后收敛。然后就会得到这个 $V^*$ 。当我们有这个 $V^*$ 过后,一个问题是如何进一步推算出它的最佳策略。最佳策略的话,我们可以直接用这个arg max,就先把它的 Q 函数重构出来,重构出来过后,我们可以对每一个列对应的最大的那个 action 就是应该它现在的最佳策略,这样我们可以就可以把这个最佳策略从这个这个最佳价值函数里面推导出来。 + +![](img/2.52.png) + +这里是一个可视化的一个过程,其实也是一个 grid world ,我们希望能在这个棋盘里面,不管你在哪一个位置开始,我们都希望能够到 goal 的这个点,左上角的那个点。因为它是一个迭代过程,然后我这里可视化了从 $v_1$ 到 $v_7$ 上面每一个状态。它的这个值的变化,你发现它的这个值逐渐在变化,而且现在是因为它每走一步,让它会得到一个负的一个值,所以它需要尽快的到达左上角,可以发现离它越远的那个值就就越大。 + +$v_7$ 收敛过后,右下角那个值是-6,也就相当于它要走六步,才能到达最上面那个值。而且离这个目的地越近了,它的价值越大。 + + + +![](img/2.53.png) + +![](img/2.54.png) + +我们这里在可以来看一个 Demo,MDP 控制的过程。让我们首先来看这个 policy iteration。之前我给大家看的这个例子,它们在每个状态都是采取固定的随机策略,就到每个状态都是都是 0.25 的概率往上往下往左往右,这里并没有策略的改变。但是我们现在想做 policy iteration,就是想每个状态都进行改变。Policy iteration 的过程是一个迭代过程。 + +![](img/2.55.png) + +我们先在这个状态里面,我们先 run 一遍 policy evaluation,我们就得到了一个 value function,就每个状态都有一个value function。 + +![](img/2.56.png) + +现在我们进行第二个步骤 policy improvement,按 policy update,按这个 policy update 过后,你可以发现有些格子里面的这个 policy 已经产生变化。比如说现在对于中间这个-1的这个状态,然后它的最佳策略是往下走。当你到达这个状态过后,你应该往下,这样就会得到最佳的这个值。让旁边这个绿色旁边的这个方块,它的策略也改变了,它现在选取的最佳策略是往左走,你说你在当前状态的时候,最佳策略应该是往左走才对。 + + + +![](img/2.57.png) + +我们再 run 下一轮的 policy evaluation,你发现它的这个值又被改变,很多次过后,然后它会更新。 + +![](img/2.58.png) + +我们再 run policy update,你发现每个状态里面的值基本都改变,它不再是上下左右随机在变了,它会选取一个最佳的一个策略。 + +![](img/2.59.png) + +我们再 run 这个 policy evaluation。它的值又再不停地变换,变化之后现在又收敛了。 + +![](img/2.60.png) + + +我们再来 run 一遍这个 policy update。现在它的值又会有变化,就在每一个状态,它的这个最佳的这个策略也会产生一些改变。 + +![](img/2.61.png) + +再来在这个状态下面进行改变,现在就基本你看基本没有什么变化,就说明整个MDP他已经收敛了。所以对于现在它每个状态的值就是它当前最佳的 value function 的值以及它当前状态对应的这个 policy 已经是最佳的 policy。我们可以简单来看,比如说现在我们在右上角这个 0.38 的这个位置,现在我们直接就可以跟根据它每个状态的这个值,比如现在右上角,然后它说现在应该往下走,我们往下走一步。它又说往下走,然后再往下走。现在我们有两个选择,一个是往左走,一个往下走。我们现在往下走,随着这个箭头的指示,我们就会到达中间 1.20 的一个价值的一个状态。如果能达到这个状态的话,我们会得到很多 reward 。这个说明了 policy iteration 的一个过程,把这个 gridworld 解决掉。解决掉的意思是说,不管在哪个状态,都可以顺着它这个状态对应的最佳的这个策略,然后到达我们可以获得最多奖励的一个状态。 + + + +![](img/2.62.png) + +我们再来看用 value iteration 来解 MDP,点第 3 行 value iteration, 当它的这个值确定下来过后,然后它会产生它的最佳状态,这个最佳状态跟这个 policy iteration 得出来的最佳策略是一致的,就可以得到一个最佳的一个策略,然后在每个状态,我们跟着这个最佳策略走,然后就会到达最多可以得到奖励的一个状态。 + +![](img/2.63.png) + +这个 Demo 里面是一个代码,就是为了解一个叫 FrozenLake 的一个例子,这个例子是 OpenAI Gym里的一个环境,跟 gridworld 很像,不过它每一个状态转移是一个 probability。 + + + +![](img/2.64.png) + +然后我们再来看一下 policy iteration 和 value iteration 的一个对比,这两个算法都是为了解 MDP 的控制问题,policy iteration 是由两部分组成的:policy evaluation 和 policy improvement。它很清楚的把这个过程分成了两步,就首先对于当前的这个已经搜索到的策略函数,然后对它进行一个估值,得到估值过后,把 Q 函数算出来,我们进一步进行改进。 + +但对于 value iteration 的话,它是直接把 Bellman Optimality Equation 拿进来,然后直接去寻找最佳的 value function,这里没有 policy function 在这里面,当我们把这个 optimal value function 算出来过后,那我们可以在最后再执行一步这个提取过程,最佳策略提取过程。这样就可以把它的最佳策略抽取过来。 + + + +![](img/2.65.png) + +这里是一个总结,就对于 MDP 里面的 prediction 和 control 都是用动态规划来讲,然后我们这里其实采取了不同的这个 Bellman Equation。如果是一个 Prediction 的问题,就是说 policy evaluation 的问题,那么是直接是把这个 Bellman Expectation Equation 拿进来,就是不停地 run 这个 Bellman Expectation Equation,这样我们就可以去估计出给定的这个策略,然后可以得到的价值函数。对于这个control,如果我们的算法是 policy iteration 的话,那我们这里是直接是用的 Bellman Expectation Equation 。把它分成两步,先上它的这个价值函数,然后再去优化它的策略,然后不停迭代,然后这里用到的只是 Bellman Expectation Equation。如果我们这里采取的算法是 value iteration,那么我们这里用到的 Bellman Equation 就是 Bellman Optimality Equation,通过 arg max 这个过程,不停地去 arg max 它,最后它就会达到最优的状态。 + diff --git a/docs/chapter2/img/2.1.png b/docs/chapter2/img/2.1.png index eb28b9c..d7ca24c 100644 Binary files a/docs/chapter2/img/2.1.png and b/docs/chapter2/img/2.1.png differ diff --git a/docs/chapter2/img/2.10.png b/docs/chapter2/img/2.10.png index 6e666f9..d4aaf67 100644 Binary files a/docs/chapter2/img/2.10.png and b/docs/chapter2/img/2.10.png differ diff --git a/docs/chapter2/img/2.11.png b/docs/chapter2/img/2.11.png index e39171c..cb1ef21 100644 Binary files a/docs/chapter2/img/2.11.png and b/docs/chapter2/img/2.11.png differ diff --git a/docs/chapter2/img/2.12.png b/docs/chapter2/img/2.12.png index 1936a65..d2279d8 100644 Binary files a/docs/chapter2/img/2.12.png and b/docs/chapter2/img/2.12.png differ diff --git a/docs/chapter2/img/2.13.png b/docs/chapter2/img/2.13.png index c451a23..0e2dcea 100644 Binary files a/docs/chapter2/img/2.13.png and b/docs/chapter2/img/2.13.png differ diff --git a/docs/chapter2/img/2.14.png b/docs/chapter2/img/2.14.png index 63d6e04..58072bb 100644 Binary files a/docs/chapter2/img/2.14.png and b/docs/chapter2/img/2.14.png differ diff --git a/docs/chapter2/img/2.15.png b/docs/chapter2/img/2.15.png index 03d2c76..38f27af 100644 Binary files a/docs/chapter2/img/2.15.png and b/docs/chapter2/img/2.15.png differ diff --git a/docs/chapter2/img/2.16.png b/docs/chapter2/img/2.16.png index 6ca2f3f..0b80fbf 100644 Binary files a/docs/chapter2/img/2.16.png and b/docs/chapter2/img/2.16.png differ diff --git a/docs/chapter2/img/2.17.png b/docs/chapter2/img/2.17.png index 6c48225..2d6d83d 100644 Binary files a/docs/chapter2/img/2.17.png and b/docs/chapter2/img/2.17.png differ diff --git a/docs/chapter2/img/2.18.png b/docs/chapter2/img/2.18.png index cd0c6b7..eb28dcb 100644 Binary files a/docs/chapter2/img/2.18.png and b/docs/chapter2/img/2.18.png differ diff --git a/docs/chapter2/img/2.19.png b/docs/chapter2/img/2.19.png index cbd192b..640080c 100644 Binary files a/docs/chapter2/img/2.19.png and b/docs/chapter2/img/2.19.png differ diff --git a/docs/chapter2/img/2.2.png b/docs/chapter2/img/2.2.png index 2ef99ba..145f6d6 100644 Binary files a/docs/chapter2/img/2.2.png and b/docs/chapter2/img/2.2.png differ diff --git a/docs/chapter2/img/2.20.png b/docs/chapter2/img/2.20.png index c56a0ab..b8141b5 100644 Binary files a/docs/chapter2/img/2.20.png and b/docs/chapter2/img/2.20.png differ diff --git a/docs/chapter2/img/2.21.png b/docs/chapter2/img/2.21.png index d76d077..bdbadd0 100644 Binary files a/docs/chapter2/img/2.21.png and b/docs/chapter2/img/2.21.png differ diff --git a/docs/chapter2/img/2.22.png b/docs/chapter2/img/2.22.png new file mode 100644 index 0000000..4714825 Binary files /dev/null and b/docs/chapter2/img/2.22.png differ diff --git a/docs/chapter2/img/2.23.png b/docs/chapter2/img/2.23.png new file mode 100644 index 0000000..cb960ca Binary files /dev/null and b/docs/chapter2/img/2.23.png differ diff --git a/docs/chapter2/img/2.24.png b/docs/chapter2/img/2.24.png new file mode 100644 index 0000000..0ee4bc1 Binary files /dev/null and b/docs/chapter2/img/2.24.png differ diff --git a/docs/chapter2/img/2.25.png b/docs/chapter2/img/2.25.png new file mode 100644 index 0000000..feb50be Binary files /dev/null and b/docs/chapter2/img/2.25.png differ diff --git a/docs/chapter2/img/2.26.png b/docs/chapter2/img/2.26.png new file mode 100644 index 0000000..a6526fc Binary files /dev/null and b/docs/chapter2/img/2.26.png differ diff --git a/docs/chapter2/img/2.27.png b/docs/chapter2/img/2.27.png new file mode 100644 index 0000000..86805c6 Binary files /dev/null and b/docs/chapter2/img/2.27.png differ diff --git a/docs/chapter2/img/2.28.png b/docs/chapter2/img/2.28.png new file mode 100644 index 0000000..a0d4329 Binary files /dev/null and b/docs/chapter2/img/2.28.png differ diff --git a/docs/chapter2/img/2.29.png b/docs/chapter2/img/2.29.png new file mode 100644 index 0000000..c6bda08 Binary files /dev/null and b/docs/chapter2/img/2.29.png differ diff --git a/docs/chapter2/img/2.3.png b/docs/chapter2/img/2.3.png index ba0f7a7..6082bed 100644 Binary files a/docs/chapter2/img/2.3.png and b/docs/chapter2/img/2.3.png differ diff --git a/docs/chapter2/img/2.30.png b/docs/chapter2/img/2.30.png new file mode 100644 index 0000000..9dcb8a1 Binary files /dev/null and b/docs/chapter2/img/2.30.png differ diff --git a/docs/chapter2/img/2.31.png b/docs/chapter2/img/2.31.png new file mode 100644 index 0000000..eccc7a2 Binary files /dev/null and b/docs/chapter2/img/2.31.png differ diff --git a/docs/chapter2/img/2.32.png b/docs/chapter2/img/2.32.png new file mode 100644 index 0000000..e4bef9e Binary files /dev/null and b/docs/chapter2/img/2.32.png differ diff --git a/docs/chapter2/img/2.33.png b/docs/chapter2/img/2.33.png new file mode 100644 index 0000000..fda21ff Binary files /dev/null and b/docs/chapter2/img/2.33.png differ diff --git a/docs/chapter2/img/2.34.png b/docs/chapter2/img/2.34.png new file mode 100644 index 0000000..68328be Binary files /dev/null and b/docs/chapter2/img/2.34.png differ diff --git a/docs/chapter2/img/2.35.png b/docs/chapter2/img/2.35.png new file mode 100644 index 0000000..6bc5da2 Binary files /dev/null and b/docs/chapter2/img/2.35.png differ diff --git a/docs/chapter2/img/2.36.png b/docs/chapter2/img/2.36.png new file mode 100644 index 0000000..df03632 Binary files /dev/null and b/docs/chapter2/img/2.36.png differ diff --git a/docs/chapter2/img/2.37.png b/docs/chapter2/img/2.37.png new file mode 100644 index 0000000..0cdfae2 Binary files /dev/null and b/docs/chapter2/img/2.37.png differ diff --git a/docs/chapter2/img/2.38.png b/docs/chapter2/img/2.38.png new file mode 100644 index 0000000..e22b11c Binary files /dev/null and b/docs/chapter2/img/2.38.png differ diff --git a/docs/chapter2/img/2.39.png b/docs/chapter2/img/2.39.png new file mode 100644 index 0000000..89f2681 Binary files /dev/null and b/docs/chapter2/img/2.39.png differ diff --git a/docs/chapter2/img/2.4.png b/docs/chapter2/img/2.4.png index de654a2..11a4acd 100644 Binary files a/docs/chapter2/img/2.4.png and b/docs/chapter2/img/2.4.png differ diff --git a/docs/chapter2/img/2.40.png b/docs/chapter2/img/2.40.png new file mode 100644 index 0000000..585b1da Binary files /dev/null and b/docs/chapter2/img/2.40.png differ diff --git a/docs/chapter2/img/2.41.png b/docs/chapter2/img/2.41.png new file mode 100644 index 0000000..cc8be84 Binary files /dev/null and b/docs/chapter2/img/2.41.png differ diff --git a/docs/chapter2/img/2.42.png b/docs/chapter2/img/2.42.png new file mode 100644 index 0000000..b9c678b Binary files /dev/null and b/docs/chapter2/img/2.42.png differ diff --git a/docs/chapter2/img/2.43.png b/docs/chapter2/img/2.43.png new file mode 100644 index 0000000..a1b445b Binary files /dev/null and b/docs/chapter2/img/2.43.png differ diff --git a/docs/chapter2/img/2.44.png b/docs/chapter2/img/2.44.png new file mode 100644 index 0000000..4a176d6 Binary files /dev/null and b/docs/chapter2/img/2.44.png differ diff --git a/docs/chapter2/img/2.45.png b/docs/chapter2/img/2.45.png new file mode 100644 index 0000000..e4b2145 Binary files /dev/null and b/docs/chapter2/img/2.45.png differ diff --git a/docs/chapter2/img/2.46.png b/docs/chapter2/img/2.46.png new file mode 100644 index 0000000..e365a9c Binary files /dev/null and b/docs/chapter2/img/2.46.png differ diff --git a/docs/chapter2/img/2.47.png b/docs/chapter2/img/2.47.png new file mode 100644 index 0000000..1378e2c Binary files /dev/null and b/docs/chapter2/img/2.47.png differ diff --git a/docs/chapter2/img/2.48.png b/docs/chapter2/img/2.48.png new file mode 100644 index 0000000..ac675b2 Binary files /dev/null and b/docs/chapter2/img/2.48.png differ diff --git a/docs/chapter2/img/2.49.png b/docs/chapter2/img/2.49.png new file mode 100644 index 0000000..30771da Binary files /dev/null and b/docs/chapter2/img/2.49.png differ diff --git a/docs/chapter2/img/2.5.png b/docs/chapter2/img/2.5.png index 5877863..5243a81 100644 Binary files a/docs/chapter2/img/2.5.png and b/docs/chapter2/img/2.5.png differ diff --git a/docs/chapter2/img/2.50.png b/docs/chapter2/img/2.50.png new file mode 100644 index 0000000..0c98189 Binary files /dev/null and b/docs/chapter2/img/2.50.png differ diff --git a/docs/chapter2/img/2.51.png b/docs/chapter2/img/2.51.png new file mode 100644 index 0000000..05fad9f Binary files /dev/null and b/docs/chapter2/img/2.51.png differ diff --git a/docs/chapter2/img/2.52.png b/docs/chapter2/img/2.52.png new file mode 100644 index 0000000..05e348d Binary files /dev/null and b/docs/chapter2/img/2.52.png differ diff --git a/docs/chapter2/img/2.53.png b/docs/chapter2/img/2.53.png new file mode 100644 index 0000000..2edc639 Binary files /dev/null and b/docs/chapter2/img/2.53.png differ diff --git a/docs/chapter2/img/2.54.png b/docs/chapter2/img/2.54.png new file mode 100644 index 0000000..ce6ff06 Binary files /dev/null and b/docs/chapter2/img/2.54.png differ diff --git a/docs/chapter2/img/2.55.png b/docs/chapter2/img/2.55.png new file mode 100644 index 0000000..60d0c20 Binary files /dev/null and b/docs/chapter2/img/2.55.png differ diff --git a/docs/chapter2/img/2.56.png b/docs/chapter2/img/2.56.png new file mode 100644 index 0000000..9711e65 Binary files /dev/null and b/docs/chapter2/img/2.56.png differ diff --git a/docs/chapter2/img/2.57.png b/docs/chapter2/img/2.57.png new file mode 100644 index 0000000..fad4ab2 Binary files /dev/null and b/docs/chapter2/img/2.57.png differ diff --git a/docs/chapter2/img/2.58.png b/docs/chapter2/img/2.58.png new file mode 100644 index 0000000..0dd930b Binary files /dev/null and b/docs/chapter2/img/2.58.png differ diff --git a/docs/chapter2/img/2.59.png b/docs/chapter2/img/2.59.png new file mode 100644 index 0000000..7cf6aeb Binary files /dev/null and b/docs/chapter2/img/2.59.png differ diff --git a/docs/chapter2/img/2.6.png b/docs/chapter2/img/2.6.png index 402a395..fa5b184 100644 Binary files a/docs/chapter2/img/2.6.png and b/docs/chapter2/img/2.6.png differ diff --git a/docs/chapter2/img/2.60.png b/docs/chapter2/img/2.60.png new file mode 100644 index 0000000..2b25d01 Binary files /dev/null and b/docs/chapter2/img/2.60.png differ diff --git a/docs/chapter2/img/2.61.png b/docs/chapter2/img/2.61.png new file mode 100644 index 0000000..6e1384c Binary files /dev/null and b/docs/chapter2/img/2.61.png differ diff --git a/docs/chapter2/img/2.62.png b/docs/chapter2/img/2.62.png new file mode 100644 index 0000000..7464375 Binary files /dev/null and b/docs/chapter2/img/2.62.png differ diff --git a/docs/chapter2/img/2.63.png b/docs/chapter2/img/2.63.png new file mode 100644 index 0000000..72a8f5d Binary files /dev/null and b/docs/chapter2/img/2.63.png differ diff --git a/docs/chapter2/img/2.64.png b/docs/chapter2/img/2.64.png new file mode 100644 index 0000000..3a9eda9 Binary files /dev/null and b/docs/chapter2/img/2.64.png differ diff --git a/docs/chapter2/img/2.65.png b/docs/chapter2/img/2.65.png new file mode 100644 index 0000000..539a30a Binary files /dev/null and b/docs/chapter2/img/2.65.png differ diff --git a/docs/chapter2/img/2.7.png b/docs/chapter2/img/2.7.png index b6c4b12..13d4c8c 100644 Binary files a/docs/chapter2/img/2.7.png and b/docs/chapter2/img/2.7.png differ diff --git a/docs/chapter2/img/2.8.png b/docs/chapter2/img/2.8.png index d3127c5..8071a01 100644 Binary files a/docs/chapter2/img/2.8.png and b/docs/chapter2/img/2.8.png differ diff --git a/docs/chapter2/img/2.9.png b/docs/chapter2/img/2.9.png index 9710b0f..8dd6000 100644 Binary files a/docs/chapter2/img/2.9.png and b/docs/chapter2/img/2.9.png differ diff --git a/docs/chapter3/chapter3.md b/docs/chapter3/chapter3.md index 1d55a2d..9c0f93d 100644 --- a/docs/chapter3/chapter3.md +++ b/docs/chapter3/chapter3.md @@ -1,303 +1,246 @@ -# Policy Gradient -## Policy Gradient +# 表格型方法 + +这节课我们通过最简单的`表格型的方法`来讲解如何使用 value-based 方法去求解强化学习。 + +## Sarsa + +### MDP ![](img/3.1.png) -在 reinforcement learning 中有 3 个components,一个`actor`,一个`environment`,一个`reward function`。 +强化学习的三个重要的要素:状态、动作和奖励。强化学习智能体跟环境是一步一步交互的,就是我先观察一下状态,然后再输入动作。再观察一下状态,再输出动作,拿到这些 reward 。它是一个跟时间相关的一个序列决策的问题。 -让机器玩 video game 时, +举个例子,在 $t-1$ 时刻,我看到了熊对我招手,那我下意识的可能输出的动作就是赶紧跑路。熊看到了有人跑了,可能就觉得发现猎物,开始发动攻击。而在 $t$ 时刻的话,我如果选择装死的动作,可能熊咬了咬我那个摔了几下就发现就觉得挺无趣的,可能会走开。这个时候,我再跑路的话可能就跑路成功了,就是这样子的一个序列决策的过程。 -* actor 做的事情就是去操控游戏的摇杆, 比如说向左、向右、开火等操作; -* environment 就是游戏的主机, 负责控制游戏的画面负责控制说,怪物要怎么移动, 你现在要看到什么画面等等; -* reward function 就是当你做什么事情,发生什么状况的时候,你可以得到多少分数, 比如说杀一只怪兽得到 20 分等等。 +当然在输出每一个动作之前,其实你都是可以选择不同的动作。比如说在 $t$ 时刻,我选择跑路的时候,熊已经追上来了,如果说 $t$ 时刻,我没有选择装死,而我是选择跑路的话,这个时候熊已经追上了,那这个时候,其实我有两种情况转移到不同的状态去,就我有一定的概率可以逃跑成功,也有很大的概率我会逃跑失败。那我们就用状态转移概率 $p\left[s_{t+1}, r_{t} \mid s_{t}, a_{t}\right]$ 来表述说在 $s_t$ 的状态选择了 $a_t$ 的动作的时候,转移到 $s_{t+1}$ ,而且拿到 $r_t$ 的概率是多少。 -同样的概念用在围棋上也是一样的, +这样子的一个状态转移概率是具有`马尔可夫性质(Markov Property)`的(系统下一时刻的状态仅由当前时刻的状态决定,不依赖于以往任何状态)。因为这个状态转移概率,它是下一时刻的状态是取决于当前的状态,它和之前的 $s_{t-1}$ 和 $s_{t-2}$ 都没有什么关系。然后再加上说这个过程也取决于智能体跟环境交互的这个$a_t$ ,所以有一个决策的一个过程在里面。我们就称这样的一个过程为`马尔可夫决策过程(Markov Decision Process, MDP)`。 -* actor 就是 alpha Go,它要决定下哪一个位置; -* environment 就是对手; -* reward function 就是按照围棋的规则, 赢就是得一分,输就是负一分等等。 -在 reinforcement learning 里面,environment 跟 reward function 不是你可以控制的,environment 跟 reward function 是在开始学习之前,就已经事先给定的。你唯一能做的事情是调整 actor 里面的 policy,使得 actor 可以得到最大的 reward。Actor 里面会有一个 policy, 这个policy 决定了actor 的行为。Policy 就是给一个外界的输入,然后它会输出 actor 现在应该要执行的行为。 +MDP 就是序列决策这样一个经典的表达方式。MDP 也是强化学习里面一个非常基本的学习框架。状态、动作、状态转移概率和奖励 $(S,A,P,R)$,这四个合集就构成了强化学习 MDP 的四元组,后面也可能会再加个衰减因子构成五元组。 + ![](img/3.2.png) -**Policy 一般写成 $\pi$**。假设你是用 deep learning 的技术来做 reinforcement learning 的话,**policy 就是一个 network**。Network 里面就有一堆参数, 我们用 $\theta$ 来代表 $\pi$ 的参数。Network 的 input 就是现在 machine 看到的东西,如果让 machine 打电玩的话, 那 machine 看到的东西就是游戏的画面。Machine 看到什么东西,会影响你现在 training 到底好不好 train。 -举例来说,在玩游戏的时候, 也许你觉得游戏的画面,前后是相关的,也许你觉得说,你应该让你的 policy,看从游戏初始到现在这个时间点,所有画面的总和。你可能会觉得你要用到 RNN 来处理它,不过这样子,你会比较难处理。要让你的 machine,你的 policy 看到什么样的画面, 这个是你自己决定的。让你知道说给机器看到什么样的游戏画面,可能是比较有效的。Output 的就是今天机器要采取什么样的行为。 -上图就是具体的例子, -* policy 就是一个 network; -* input 就是游戏的画面,它通常是由 pixels 所组成的; -* output 就是看看说有那些选项是你可以去执行的,output layer 就有几个 neurons。 -假设你现在可以做的行为就是有 3 个,output layer 就是有 3 个 neurons。每个 neuron 对应到一个可以采取的行为。Input 一个东西后,network 就会给每一个可以采取的行为一个分数。接下来,你把这个分数当作是概率。 actor 就是看这个概率的分布,根据这个机率的分布,决定它要采取的行为。比如说 70% 会走 left,20% 走 right,10% 开火等等。概率分布不同,actor 采取的行为就会不一样。 +我们把这些可能的动作和可能的状态转移的关系画成这样子的一个树状图。它们之间的关系就是一个从 $s_t$ 到 $a_t$ ,再到 $s_{t+1}$ ,再到 $a_{t+1}$,再到 $s_{t+2}$ 这样子的一个过程。 + +我们去跟环境交互,我们只能走完整的一条通路。这里面产生了一系列的一个决策的过程,就是我们跟环境交互产生了一个经验。然后我们会使用 P 函数和 R 函数来去描述环境。P 函数就是状态转移的概率,R 函数就是 Reward function。P 函数实际上反映的是环境的一个随机性。比方说,在熊发怒的情况下,我如果选择装死,假设熊看到人装死就一定会走的话,我们就称在这里面的这个状态转移概率就是百分之百。但如果说在熊发怒的情况下,我选择跑路而导致说我有可能跑成功以及跑失败,出现这两种情况。那我们就可以用概率去表达一下说转移到其中一种情况的概率大概 10%,另外一种情况的概率大概是 90% 会跑失败。**如果我们知道这些状态转移概率和奖励函数的话,我们就说这个环境是已知的,因为我们是用这两个函数去描述环境的。**如果是已知的话,我们其实可以用动态规划去计算说,我如果要逃脱熊,那么能够逃脱熊概率最大的最优策略是什么。很多强化学习的经典的算法都是 model-free 的,就是环境是未知的这样子的一个情况下,我们强化学习怎么去解决。 ![](img/3.3.png) -接下来用一个例子来说明 actor 是怎么样跟环境互动的。 首先 actor 会看到一个游戏画面,我们用 $s_1$ 来表示这个游戏画面,它代表游戏初始的画面。接下来 actor 看到这个游戏的初始画面以后,根据它内部的 network,根据它内部的 policy 来决定一个 action。假设它现在决定的 action 是向右,它决定完 action 以后,它就会得到一个 reward ,代表它采取这个 action 以后得到的分数。 +因为现实世界中人类第一次遇到熊之前,我们根本不知道我们能不能跑得过熊。所以刚刚那个10%、90%的概率也就是虚构出来的概率,熊到底在什么时候会往什么方向去转变的话,我们经常是不知道的。我们是处在一个未知的环境里的,也就是这一系列的决策的 P 函数和 R 函数是未知的。这就是 model-based 跟 model-free 的一个最大的区别。强化学习就是可以用来解决用完全未知的和随机的环境。 -我们把一开始的初始画面,写作 $s_1$, 把第一次执行的动作叫做 $a_1$,把第一次执行动作完以后得到的 reward 叫做 $r_1$。不同的书会有不同的定义,有人会觉得说这边应该要叫做 $r_2$,这个都可以,你自己看得懂就好。Actor 决定一个的行为以后, 就会看到一个新的游戏画面,这边是 $s_2$。然后把这个 $s_2$ 输入给 actor,这个 actor 决定要开火,然后它可能杀了一只怪,就得到五分。然后这个 process 就反复地持续下去,直到今天走到某一个 timestamp 执行某一个 action,得到 reward 之后, 这个 environment 决定这个游戏结束了。比如说,如果在这个游戏里面,你是控制绿色的船去杀怪,如果你被杀死的话,游戏就结束,或是你把所有的怪都清空,游戏就结束了。 +强化学习要像人类一样去学习了,人类学习的话就是一条路一条路的去尝试一下,先走一条路,我看看结果到底是什么。多试几次,只要能活命的,我们其实可以慢慢的了解哪个状态会更好。我们用价值函数 $V(s)$ 来代表这个状态是好的还是坏的。然后用这个 Q 函数来判断说在什么状态下做什么动作能够拿到最大奖励,我们用 Q 函数来表示这个状态-动作值。 ![](img/3.4.png) -一场游戏叫做一个 `Episode(回合)` 或者 `Trial(试验)`。把这个游戏里面,所有得到的 reward 都总合起来,就是 `Total reward`,我们称其为`Return(回报)`,用 R 来表示它。Actor 要想办法去 maximize 它可以得到的 reward。 -![](img/3.5.png) -首先,`environment` 是一个`function`,游戏的主机也可以把它看作是一个 function,虽然它不一定是 neural network,可能是 rule-based 的规则,但你可以把它看作是一个 function。这个 function,一开始就先吐出一个 state,也就是游戏的画面,接下来你的 actor 看到这个游戏画面 $s_1$ 以后,它吐出 $a_1$,然后 environment 把 $a_1$ 当作它的输入,然后它再吐出 $s_2$,吐出新的游戏画面。Actor 看到新的游戏画面,再采取新的行为 $a_2$,然后 environment 再看到 $a_2$,再吐出 $s_3$。这个 process 会一直持续下去,直到 environment 觉得说应该要停止为止。 +接下来就会介绍 Q 函数。在经过多次尝试和那个熊打交道之后,人类就可以对熊的不同的状态去做出判断,我们可以用状态动作价值的来表达说在某个状态下,为什么动作 1 会比动作 2 好。因为动作 1 的价值比动作 2 要高。这个价值就叫 Q 函数。如果说这个 Q 表格是一张已经训练好的表格的话,那这一张表格就像是我们的一本生活手册。我们就知道在熊发怒的时候,装死的价值会高一点。在熊离开的时候,我们可能偷偷逃跑的会比较容易获救。这张表格里面 Q 函数的物理意义就是我选择了这个动作之后我最后面能不能成功,就是我需要去计算我在这个状态下,我选择了这个动作,后续能够一共拿到多少总收益。如果我可以预估未来的总收益的大小,我们当然知道在当前的这个状态下选择哪个动作,价值更高。我选择某个动作是因为我未来一共可以拿到的那个价值会更高一点。所以强化学习它的目标导向性很强,环境给了这个 reward 是一个非常重要的反馈,它就是根据环境的 reward 的反馈来去做选择。 -在一场游戏里面,我们把 environment 输出的 $s$ 跟 actor 输出的行为 $a$,把这个 $s$ 跟 $a$ 全部串起来, 叫做一个 `Trajectory`,如下式所示。 -$$ -\text { Trajectory } \tau=\left\{s_{1}, a_{1}, s_{2}, a_{2}, \cdots, s_{t}, a_{t}\right\} -$$ - -每一个 trajectory,你可以计算它发生的概率。假设现在 actor 的参数已经被给定了话,就是 $\theta$。根据 $\theta$,你其实可以计算某一个 trajectory 发生的概率,你可以计算某一个回合,某一个 episode 里面, 发生这样子状况的概率。 - -$$ -\begin{aligned} -p_{\theta}(\tau) -&=p\left(s_{1}\right) p_{\theta}\left(a_{1} | s_{1}\right) p\left(s_{2} | s_{1}, a_{1}\right) p_{\theta}\left(a_{2} | s_{2}\right) p\left(s_{3} | s_{2}, a_{2}\right) \cdots \\ -&=p\left(s_{1}\right) \prod_{t=1}^{T} p_{\theta}\left(a_{t} | s_{t}\right) p\left(s_{t+1} | s_{t}, a_{t}\right) -\end{aligned} -$$ - -怎么算呢,如上式所示。在假设你 actor 的参数就是 $\theta$ 的情况下,某一个 trajectory $\tau$ 的概率就是这样算的,你先算 environment 输出 $s_1$ 的概率,再计算根据 $s_1$ 执行 $a_1$ 的概率,这是由你 policy 里面的 network 参数 $\theta$ 所决定的, 它是一个概率,因为你的 policy 的 network 的 output 是一个 distribution,actor 是根据这个 distribution 去做 sample,决定现在实际上要采取的 action是哪一个。接下来 environment 根据 $a_1$ 跟 $s_1$ 产生 $s_2$,因为 $s_2$ 跟$s_1$ 还是有关系的,下一个游戏画面,跟前一个游戏画面通常还是有关系的,至少要是连续的, 所以给定前一个游戏画面 $s_1$ 和现在 actor 采取的行为 $a_1$,就会产生 $s_2$。 - -这件事情可能是概率,也可能不是概率,这个取决于 environment,就是主机它内部设定是怎样。看今天这个主机在决定,要输出什么样的游戏画面的时候,有没有概率。因为如果没有概率的话,这个游戏的每次的行为都一样,你只要找到一条 path 就可以过关了,这样感觉是蛮无聊的 。所以游戏里面,通常是还是有一些概率的,你做同样的行为,给同样的前一个画面, 下次产生的画面不见得是一样的。Process 就反复继续下去,你就可以计算一个 trajectory $s_1$,$a_1$, $s_2$ , $a_2$ 出现的概率有多大。 - -**这个概率取决于两部分**, - -* 一部分是 `environment 的行为`, environment 的 function 它内部的参数或内部的规则长什么样子。 $p(s_{t+1}|s_t,a_t)$这一项代表的是 environment, environment 这一项通常你是无法控制它的,因为那个是人家写好的,你不能控制它。 -* 另一部分是 `agent 的行为`。你能控制的是 $p_\theta(a_t|s_t)$。给定一个 $s_t$, actor 要采取什么样的 $a_t$ 会取决于你 actor 的参数 $\theta$, 所以这部分是 actor 可以自己控制的。随着 actor 的行为不同,每个同样的 trajectory, 它就会有不同的出现的概率。 +![](img/3.5.png)未来的总收益是一个什么样的概念,为什么可以用这个来评价当前这个动作是好是坏。举个例子,假设说一辆车在路上,当前是红灯,我们直接走的那个收益就很低,因为违反交通规则,这是就是当前的单步收益。可是如果我们这是一辆救护车,我们正在运送病人,把病人快速送达医院的收益非常的高,而且越快你的收益越大。很可能是我们这个时候应该要闯红灯,因为未来的远期收益太高了。这也是为什么说强化学习需要去学习远期的收益,因为现实世界当中这个奖励往往是延迟的,是有delay 的。 +所以我们一般会从当前状态开始,后续有可能会收到所有收益加起来计算。当前动作的 Q 的价值,让 Q 的价值可以真正的代表当前这个状态动作的真正的价值。 ![](img/3.6.png) -在 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 的期望值是多少。 - -$$ -\bar{R}_{\theta}=\sum_{\tau} R(\tau) p_{\theta}(\tau) -$$ -这个期望值的算法如上式所示,穷举所有可能的 trajectory $\tau$, 每一个 trajectory $\tau$ 都有一个概率。比如 $\theta$ 是一个很强的 model, 那它都不会死。如果有一个 episode 很快就死掉了, 它的概率就很小;如果有一个 episode 都一直没有死, 那它的概率就很大。根据你的 $\theta$, 你可以算出某一个 trajectory $\tau$ 出现的概率,接下来你计算这个 $\tau$ 的 total reward 是多少。 Total reward weighted by 这个 $\tau$ 出现的概率,对所有的 $\tau$ 进行求和,就是期望值。给定一个参数,你会得到的期望值。 -$$ -\bar{R}_{\theta}=\sum_{\tau} R(\tau) p_{\theta}(\tau)=E_{\tau \sim p_{\theta}(\tau)}[R(\tau)] -$$ -我们还可以写成上式那样,从 $p_{\theta}(\tau)$ 这个 distribution sample 一个 trajectory $\tau$,然后计算 $R(\tau)$ 的期望值,就是你的 expected reward。 我们要做的事情就是 maximize expected reward。 +但有的时候你把目光放得太长远不好,因为如果说事情很快就结束的话,你考虑到最后一步的收益无可厚非,。如果说是一个持续的没有尽头的任务,即`持续式任务(Continuing Task)`。你把所有未来的收益全部相加,作为当前的状态价值就很不合理。股票的例子就很典型了,我们要关注的是累积的收益。可是如果说十年之后才有一次大涨大跌,你要把十年后的收益也作为当前动作的考虑因素,显然我们不会这么做。那我们会怎么办呢,就有句俗话说得好,就对远一点的东西呢,我们就当做近视就不需要看得太清楚,我们就可以适当引入这个衰减因子 $\gamma$ 来去计算这个未来总收益。$\gamma \in [0,1]$ 。越往后 $\gamma^n$ 就会越小,也就是说越后面的收益对当前价值的影响就会越小。 ![](img/3.7.png) -怎么 maximize expected reward 呢?我们用的是 `gradient ascent`,因为要让它越大越好,所以是 gradient ascent。Gradient ascent 在 update 参数的时候要加。要进行 gradient ascent,我们先要计算 expected reward $\bar{R}$ 的 gradient 。我们对 $\bar{R}$ 取一个 gradient,这里面只有 $p_{\theta}(\tau)$ 是跟 $\theta$ 有关,所以 gradient 就放在 $p_{\theta}(\tau)$ 这个地方。$R(\tau)$ 这个 reward function 不需要是 differentiable,我们也可以解接下来的问题。举例来说,如果是在 GAN 里面,$R(\tau)$ 其实是一个 discriminator,它就算是没有办法微分,也无所谓,你还是可以做接下来的运算。 - -取 gradient之后,我们背一个公式, -$$ -\nabla f(x)=f(x)\nabla \log f(x) -$$ -我们可以对 $\nabla p_{\theta}(\tau)$ 使用这个公式,然后会得到 $\nabla p_{\theta}(\tau)=p_{\theta}(\tau) \nabla \log p_{\theta}(\tau)$。 - -接下来, 分子分母,上下同乘$p_{\theta}(\tau)$,然后我们可以得到下式: -$$ -\frac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)}=\log p_{\theta}(\tau) -$$ - - 然后如下式所示, 对 $\tau$ 进行求和,把 $R(\tau)$ 和 $\log p_{\theta}(\tau)$ 这两项 weighted by $ p_{\theta}(\tau)$, 既然有 weighted by $p_{\theta}(\tau)$,它们就可以被写成这个 expected 的形式。也就是你从 $p_{\theta}(\tau)$ 这个 distribution 里面 sample $\tau$ 出来, 去计算 $R(\tau)$ 乘上 $\nabla\log p_{\theta}(\tau)$,然后把它对所有可能的 $\tau$ 进行求和,就是这个 expected value 。 - -$$ -\begin{aligned} -\nabla \bar{R}_{\theta}&=\sum_{\tau} R(\tau) \nabla p_{\theta}(\tau)\\&=\sum_{\tau} R(\tau) p_{\theta}(\tau) \frac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)} \\&= -\sum_{\tau} R(\tau) p_{\theta}(\tau) \nabla \log p_{\theta}(\tau) \\ -&=E_{\tau \sim p_{\theta}(\tau)}\left[R(\tau) \nabla \log p_{\theta}(\tau)\right] -\end{aligned} -$$ - -实际上这个 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) \\ -&=\frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}} R\left(\tau^{n}\right) \nabla \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right) -\end{aligned} -$$ -注意 $p_{\theta}(\tau)$ 里面有两项,$p(s_{t+1}|s_t,a_t)$ 来自于 environment,$p_\theta(a_t|s_t)$ 是来自于 agent。 $p(s_{t+1}|s_t,a_t)$ 由环境决定从而与 $\theta$ 无关,因此 $\nabla \log p(s_{t+1}|s_t,a_t) =0 $。因此 $\nabla p_{\theta}(\tau)= -\nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)$。 - -你可以非常直观的来理解这个部分,也就是在你 sample 到的 data 里面, 你 sample 到,在某一个 state $s_t$ 要执行某一个 action $a_t$, 这个 $s_t$ 跟 $a_t$ 它是在整个 trajectory $\tau$ 的里面的某一个 state and action 的 pair。 - -* 假设你在 $s_t$ 执行 $a_t$,最后发现 $\tau$ 的 reward 是正的, 那你就要增加这一项的概率,你就要增加在 $s_t$ 执行 $a_t$ 的概率。 -* 反之,在 $s_t$ 执行 $a_t$ 会导致$\tau$ 的 reward 变成负的, 你就要减少这一项的概率。 +举个具体的例子来看看这些计算出来的是什么效果。这是一个悬崖问题。这个问题是需要智能体从出发点 S 出发,然后到达目的地 G,同时避免掉进悬崖(cliff),掉进悬崖的话就会有负一百分的惩罚,但游戏不会结束,它会被直接拖回起点,游戏继续。为了到达目的地的话,我们可以沿着蓝线和红线走。 ![](img/3.8.png) -这个怎么实现呢? 你用 gradient ascent 来 update 你的参数,你原来有一个参数 $\theta$ ,把你的 $\theta$ 加上你的 gradient 这一项,那当然前面要有个 learning rate,learning rate 其实也是要调的,你可用 Adam、RMSProp 等方法对其进行调整。 -我们可以套下面这个公式来把 gradient 计算出来: +在这个环境当中,我们去怎么去计算状态动作价值,就是未来的总收益的话。假设我走一条路,然后这条路的话,我从这个状态出发,在这里选择是向上,这里选择向右,选择向右。 +如果 $\gamma = 0$,然后用这个公式去计算的话,它相当于考虑的就是一个单步的收益。我们可以认为它是一个目光短浅的一个计算的方法。 + +但 $\gamma = 1$ 的话,那就等于是说把后续所有的收益可能都全部加起来。在这里悬崖问题,你每走一步都会拿到一个 -1 分的 reward。只有到了终点之后,它才会停止。如果说 $\gamma =1 $的话,我们用这个公式去计算,就这里是 -1。然后这里的话,未来的总收益就是 $-1+-1=-2$ 。 + +如果让 $\gamma = 0.6$ 的话,就是目光没有放得那么的长远,计算出来是这个样子的。 + + +利用 $G_{t}=R_{t+1}+\gamma G_{t+1}$ 这个公式从后往前推。 $$ -\nabla \bar{R}_{\theta}=\frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}} R\left(\tau^{n}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right) +\begin{array}{l} +G_{7}=R+\gamma G_{8}=-1+0.6 *(-2.176)=-2.3056 \approx-2.3 \\ +G_{8}=R+\gamma G_{9}=-1+0.6 *(-1.96)=-2.176 \approx-2.18 \\ +G_{9}=R+\gamma G_{10}=-1+0.6 *(-1.6)=-1.96 \\ +G_{10}=R+\gamma G_{11}=-1+0.6 *(-1)=-1.6 \\ +G_{12}=R+\gamma G_{13}=-1+0.6 * 0=-1 \\ +G_{13}=0 +\end{array} $$ -实际上,要套上面这个公式, 首先你要先收集一大堆的 s 跟 a 的 pair,你还要知道这些 s 跟 a 在跟环境互动的时候,你会得到多少的 reward。 这些资料怎么收集呢?你要拿你的 agent,它的参数是 $\theta$,去跟环境做互动, 也就是拿你已经 train 好的 agent 先去跟环境玩一下,先去跟那个游戏互动一下, 互动完以后,你就会得到一大堆游戏的纪录,你会记录说,今天先玩了第一场,在第一场游戏里面,我们在 state $s_1$ 采取 action $a_1$,在 state $s_2$ 采取 action $a_2$ 。 - -玩游戏的时候是有随机性的,所以 agent 本身是有随机性的,在同样 state $s_1$,不是每次都会采取 $a_1$,所以你要记录下来。在 state $s_1^1$ 采取 $a_1^1$,在 state $s_2^1$ 采取 $a_2^1$。整场游戏结束以后,得到的分数是$R(\tau^1)$。你会 sample 到另外一笔 data,也就是另外一场游戏。在另外一场游戏里面,你在 state $s_1^2$ 采取 $a_1^2$,在 state $s_2^2$ 采取 $a_2^2$,然后你 sample 到的就是 $\tau^2$,得到的 reward 是 $R(\tau^2)$。 - -你就可以把 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 参数, 等一下我们会解决这个问题。 +这里的计算是我们选择了一条路,走完这条路径上每一个状态动作的价值,我们可以看一下右下角这个图,如果说我走的不是这条路,我走的是这一条路,那我算出来那个状态动作价值的 Q 值可能是这样。那我们就知道,当小乌龟在 -12 这个点的时候,往右边走是 -11,往上走是 -15。它自然就知道往右走的价值更大,小乌龟就会往右走 ![](img/3.9.png) +最后我们要求解的就是类似于这样子的一张 Q 表格。就是它的行数是所有的状态数量,一般可以用坐标来表示表示格子的状态,也可以用 1、2、3、4、5、6、7 来表示不同的位置。Q 表格一共四列的话就代表说是上下左右四个动作。最开始这张 Q 表格会全部初始化为零,然后在 agent 不断地去和环境交互得到不同的轨迹,当交互的次数足够多的时候,我们就可以估算出每一个状态下,每个行动的平均总收益去更新这个 Q 表格。怎么去更新 Q 表格就是我们接下来要引入的强化学习的强化概念。 -接下来讲一些实现细节。实现方法是这个样子,把它想成一个分类的问题,在 classification 里面就是 input 一个 image,然后 output 决定说是 10 个 class 里面的哪一个。在做 classification 时,我们要收集一堆 training data,要有 input 跟 output 的 pair。 - -在实现的时候,你就把 state 当作是 classifier 的 input。 你就当在做 image classification 的 problem,只是现在的 class 不是说 image 里面有什么 objects。 现在的 class 是说,看到这张 image 我们要采取什么样的行为,每一个行为就是一个 class。比如说第一个 class 叫做向左,第二个 class 叫做向右,第三个 class 叫做开火。 - -这些训练的数据从哪里来的呢? 做分类的问题时,要有 input 和正确的 output。 这些训练数据是从 sampling 的 process 来的。假设在 sampling 的 process 里面,在某一个 state,你 sample 到你要采取 action a, 你就把这个 action a 当作是你的 ground truth。你在这个 state,你 sample 到要向左。 本来向左这件事概率不一定是最高, 因为你是 sample,它不一定概率最高。假设你 sample 到向左,在 training 的时候 你叫告诉 machine 说,调整 network 的参数, 如果看到这个 state,你就向左。在一般的 classification 的 problem 里面,其实你在 implement classification 的时候, 你的 objective function 都会写成 minimize cross entropy,其实 minimize cross entropy 就是 maximize log likelihood。 - +强化概念的就是我们可以用下一个状态的价值来更新当前状态的价值。其实就是强化学习里面有一个bootstrap(自助)的概念。在强化学习里面,你可以每走一步更新一下 Q 表格,然后用下一个状态的 Q 值来更新这个状态的 Q 值。 ![](img/3.10.png) -做 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 里 call 现成的 function,它就会自动帮你算。 -然后你就可以把 gradient 计算出来,这是一般的分类问题。RL 唯一不同的地方是 loss 前面乘上一个 weight,这个是整场游戏的时候得到的 total reward R, 它并不是在 state s 采取 action a 的时候得到的 reward。 你要把你的每一笔 training data,都 weighted by 这个 R。然后你用 TensorFlow 或 PyTorch 去帮你算 gradient 就结束了,跟一般 classification 差不多。 - -## Tips -这边有一些在实现的时候,你也许用得上的 tip。 -### Tip 1: Add a Baseline +这种单步更新的方法叫做`时序差分`的更新方法。为了让大家更好理解强化学习里面时序差分的这种更新方法。我这里就找了一下它的的物理意义。我们先理解一下巴普洛夫的条件反射实验了。这个实验讲的是什么呢?就是小狗对盆里面的食物,它会产生无条件刺激分泌唾液。一开始小狗对于铃声这种中性刺激是没有反应的。可是我们把这个铃声和这个食物结合起来,每次先给它响一下铃,再给它喂食物。多次重复之后,当铃声响起的时候,小狗也会开始流口水。盆里的肉可以认为是强化学习里面最后面的那个延迟的 reward。声音的刺激可以认为是有 reward 的那个状态之前的一个状态。多次重复实验之后,最后的这个 reward 会强化小狗对于这个声音的条件反射,它会让小狗知道说这个声音代表着有食物,这个声音对于小狗来说也就有了价值,它听到这个声音也会也会流口水。 ![](img/3.11.png) -第一个 tip 是 add 一个 baseline。add baseline 是什么意思呢?如果 given state s 采取 action a 会给你整场游戏正面的 reward,就要增加它的概率。如果 state s 执行 action a,整场游戏得到负的 reward,就要减少这一项的概率。 +巴普洛夫效应揭示的是中性刺激(铃声)跟无条件刺激(食物)紧紧挨着反复出现的时候,条件刺激也可以引起无条件刺激引起的唾液分泌,然后形成这个条件刺激。这种中性刺激跟无条件刺激在时间上面的结合,我们就称之为强化。 强化的次数越多,条件反射就会越巩固。小狗原本不觉得铃声有价值的,经过强化之后,小狗就会慢慢地意识到铃声也是有价值的,它可能带来带来食物。更重要是一种条件反射巩固之后,我们再用另外一种新的刺激和条件反射去结合,还可以形成第二级条件反射,同样还可以形成第三级条件反射。在人的身上是可以建立多级的条件反射的。举个例子,比如说一般我们遇到熊都是这样一个顺序,看到树上有熊瓜,然后看到熊之后,突然熊发怒,扑过来了。经历这个过程之后,我们可能最开始看到熊才会瑟瑟发抖,后面就是看到树上有熊爪就已经有害怕的感觉了。也就说在不断的重复试验之后,下一个状态的价值,它是可以不断地去强化影响上一个状态的价值的。 -但在很多游戏里面, reward 总是正的,就是说最低都是 0。比如说打乒乓球游戏, 你的分数就是介于 0 到 21 分之间,所以这个 R 总是正的。假设你直接套用这个式子, 在 training 的时候,告诉 model 说,不管是什么 action 你都应该要把它的概率提升。 在理想上,这么做并不一定会有问题。因为虽然说 R 总是正的,但它正的量总是有大有小,你在玩乒乓球那个游戏里面,得到的 reward 总是正的,但它是介于 0~21分之间,有时候你采取某些 action 可能是得到 0 分,采取某些 action 可能是得到 20 分。 ![](img/3.12.png) -假设你有 3 个 action a/b/c 可以执行,在某一个 state 有 3 个 action a/b/c可以执行。根据这个式子,你要把这 3 项的概率, log probability 都拉高。 但是它们前面 weight 的这个 R 是不一样的。 R 是有大有小的,weight 小的,它上升的就少,weight 多的,它上升的就大一点。 因为这个 log probability,它是一个概率,所以action a、b、c 的和要是 0。 所以上升少的,在做完 normalize 以后, 它其实就是下降的,上升的多的,才会上升。 +为了让大家更加直观感受下一个状态影响上一个状态效果,这里推荐斯坦福大学的一个网站:[Temporal Difference Learning Gridworld Demo](https://cs.stanford.edu/people/karpathy/reinforcejs/gridworld_td.html)。这个网站模拟了就是这种单步更新的过程中,所有格子的一个状态价值的变化过程。我们可以看到格子里面有几个 -1的 reward。只有一个 +1 reward 的那个格子。 +![](img/3.13.png) - ![1](img/3.13.png) +玩起来是这样的,先初始化一下,然后开始时序差分的更新过程。训练的过程中你会看到这个小黄球在不断地试错。但探索当中会先迅速地发现有 reward 的地方。最开始的时候,只是这些有 reward 的格子 才有价值,当不断地重复走这些路线的时候,这些有价值的格子,它可以去慢慢地影响它附近的格子的价值。反复训练之后,有 reward 的这些格子周围的格子的状态就会慢慢的被强化,然后强化就是当它收敛到最后一个最优的状态了,就是把这些价值最终收敛到一个最优的情况之后,那个小黄球就会自动地知道,就是我一直往价值高的地方走,我就能够走到能够拿到 reward 的地方。 +### Temporal Difference -这个是一个理想上的状况,但是实际上,我们是在做 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 不要总是正的。 +![](img/3.14.png) -![1.](img/3.14.png) +这种强化方式其实在数学上面一行公式就表达出来了。这种更新的方式叫做`时序差分(Temporal Difference)`。这个公式就是说可以拿下一步的 Q 值 $Q(S_{t+_1},A_{t+1})$ 来更新我这一步的 Q 值 $Q(S_t,A_t)$ 。 -为了解决 reward 总是正的这个问题,你可以把 reward 减掉一项叫做 b,这项 b 叫做 baseline。你减掉这项 b 以后,就可以让 $R(\tau^n)-b$ 这一项, 有正有负。 所以如果得到的 total reward $R(\tau^n)$ 大于 b 的话,就让它的概率上升。如果这个 total reward 小于 b,就算它是正的,正的很小也是不好的,你就要让这一项的概率下降。 如果$R(\tau^n) 事实上,Q-learning 算法被提出的时间更早,Sarsa 算法是 Q-learning 算法的改进。 -如果大家可以接受这样子的话, 实际上就是这么 implement 的。这个 b 可以是 state-dependent 的,事实上 b 它通常是一个 network 估计出来的,它是一个 network 的 output。 ![](img/3.19.png) -把 $R-b$ 这一项合起来,我们统称为` advantage function`, 用 `A` 来代表 advantage function。Advantage function 是 dependent on s and a,我们就是要计算的是在某一个 state s 采取某一个 action a 的时候,advantage function 有多大。 +Sarsa 和 Q-learning 的更新公式都是一样的,区别只在 target 计算的这一部分, -在算 advantage function 时,你要计算$\sum_{t^{\prime}=t}^{T_{n}} r_{t^{\prime}}^{n}$ ,你会需要有一个互动的结果。你会需要有一个 model 去跟环境做互动,你才知道接下来得到的 reward 会有多少。这个 advantage function 的上标是 $\theta$,$\theta$ 就是代表说是用 $\theta$ 这个 model 跟环境去做互动,然后你才计算出这一项。从时间 t 开始到游戏结束为止,所有 r 的加和减掉 b,这个就叫 advantage function。 +* Sarsa 是 $R_{t+1}+\gamma Q(S_{t+1}, A_{t+1})$ ; +* Q-learning 是$R_{t+1}+\gamma \underset{a}{\max} Q\left(S_{t+1}, a\right)$ 。 -Advantage function 的意义就是,假设我们在某一个 state $s_t$ 执行某一个 action $a_t$,相较于其他可能的 action,它有多好。它在意的不是一个绝对的好,而是相对的好,即`相对优势(relative advantage)`。因为会减掉一个 b,减掉一个 baseline, 所以这个东西是相对的好,不是绝对的好。 $A^{\theta}\left(s_{t}, a_{t}\right)$ 通常可以是由一个 network estimate 出来的,这个 network 叫做 critic。 +Sarsa 实际上都是用自己的策略产生了 S,A,R,S',A' 这一条轨迹。然后拿着 $Q(S_{t+1},A_{t+1})$ 去更新原本的 Q 值 $Q(S_t,A_t)$。 但是 Q-learning 并不需要知道,我实际上选择哪一个 action ,它默认下一个动作就是 Q 最大的那个动作。Q-learning 知道实际上 behavior policy 可能会有 10% 的概率去选择别的动作,但是 Q-learning 并不担心受到探索的影响,它默认了就按照最优的策略来去优化我的目标策略,所以它可以更大胆地去寻找最优的路径,它其实会表现的比 Sarsa 大胆非常多。 -## REINFORCE +然后 Q-learning 的这个逐步的一个拆解的话,跟 Sarsa 唯一一点不一样就是我并不需要提前知道我 $A_2$ ,我就能更新 $Q(S_1,A_1)$ 。在训练一个 episode 这个流程图当中,Q-learning 在 learn 之前它也不需要去拿到 next action A',它只需要前面四个 $(S,A,R,S')$也就可以了,这一点就是跟 Sarsa 有一个很明显的区别。这边我们给出[ Q-learning 的 Python实现](https://github.com/datawhalechina/leedeeprl-notes/tree/master/codes/Q-learning)。 + +### Q-function Bellman Equation + +记策略 $\pi $ 的状态-动作值函数为 $Q^{\pi}(s_t,a_t)$,它表示在状态 $s_t$ 下,执行动作 $a_t$ 会带来的累积奖励 $G_t$ 的期望,具体公式为: +$$ +\begin{aligned} Q ^ { \pi } \left( s _ { t } , a _ { t } \right) & = \mathbb { E } \left[ G _ { t } \mid s _ { t } , a _ { t } \right] \\ & = \mathbb { E } \left[ r _ { t } + \gamma r _ { t + 1 } + \gamma ^ { 2 } r _ { t + 2 } + \cdots \mid s _ { t } , a _ { t } \right] \\ & = \mathbb { E } \left[ r _ { t } + \gamma \left( r _ { t + 1 } + \gamma r _ { t + 2 } + \cdots \right) \mid s _ { t } , a _ { t } \right] +\\ & =\mathbb { E } [ r _ { t }|s_t,a_t] + \gamma \mathbb{E}[r_{t+1}+ \gamma r_{t+2}+\cdots|s_t,a_t] \\ +& = \mathbb{E}[ r _ { t }|s_t,a_t]+ \gamma \mathbb{E}[G_{t+1}|s_t,a_t] +\\ &= \mathbb { E } \left[ r _ { t } + \gamma Q ^ { \pi } \left( s _ { t + 1 } , a _ { t + 1 } \right) \mid s _ { t } , a _ { t } \right] \end{aligned} +$$ +上式是 MDP 中 Q-function 的 Bellman 方程的基本形式。累积奖励 $G_t$ 的计算,不仅考虑当下 $t$ 时刻的动作 $a_t$ 的奖励 $r_t$,还会累积计算对之后決策带来的影响(公式中的 $\gamma$ 是后续奖励的衰减因子)。从上式可以看出,当前状态的动作价值 $Q^{\pi}(s_t,a_t)$ ,与当前动作的奖励 $r_t$ 以及下一状态的动作价值 $Q^{\pi}(s_{t+1},a_{t+1})$ 有关,因此,状态-动作值函数的计算可以通过动态规划算法来实现。 + +>Bellman Equation 就是当前状态与未来状态的迭代关系,表示当前状态的值函数可以通过下个状态的值函数来计算。Bellman Equation 因其提出者、动态规划创始人 Richard Bellman 而得名 ,也 叫作“动态规划方程”。 + +从另一方面考虑,在计算 $t$ 时刻的动作价值 $Q^{\pi}(s_t,a_t)$ 时,需要知道在 $t$、$t+1$、$t+2 \cdots \cdots$ 时刻的奖励,这样就不仅需要知道某一状态的所有可能出现的后续状态以及对应的奖励值,还要进行全宽度的回溯来更新状态的价值。这种方法无法在状态转移函数未知或者大规模问题中使用。因此,Q-learning 采用了浅层的时序差分采样学习,在计算累积奖励时,基于当前策略 $\pi$ 预测接下来发生的 $n$ 步动作($n$ 可以取 1 到 $+\infty$)并计算其奖励值。 + +具体来说,假设在状态 $s_t$ 下选择了动作 $a_t$,并得到了奖励 $r_t$ ,此时状态转移到 $s_{t+1}$,如果在此状态下根据同样的策略选择了动作 $a_{t+1}$ ,则 $Q^{\pi}(s_t,a_t)$ 可以表示为 +$$ +Q^{\pi}\left(s_{t}, a_{t}\right)=\mathbb{E}_{s_{t+1}, a_{t+1}}\left[r_{t}+\gamma Q^{\pi}\left(s_{t+1}, a_{t+1}\right) \mid s_{t}, a_{t}\right] +$$ + +Q-learning 算法在使用过程中,可以根据获得的累积奖励来选择策略,累积奖励的期望值越高,价值也就越大,智能体越倾向于选择这个动作。因此,最优策略 $\pi^*$ 对应的状态-动作值函数 $Q^*(s_t,a_t)$ 满足如下关系式: + +$$ +Q^{*}\left(s_{t}, a_{t}\right)=\max _{\pi} Q^{\pi}\left(s_{t}, a_{t}\right)=\mathbb{E}_{s_{t+1}}\left[r_{t}+\gamma \max _{a_{t+1}} Q\left(s_{t+1}, a_{t+1}\right) \mid s_{t}, a_{t}\right] +$$ + +Q-learning 算法在学习过程中会不断地更新 Q 值,但它并没有直接采用上式中的项进行更新,而是采用类似于梯度下降法的更新方式,即状态 $s_t$ 下的动作价值 $Q^*(s_t,a_t)$ 会朝着状态 $s_{t+1}$ 下的动作价值 $r_{t}+\gamma \max _{a_{t+1}} Q^{*}\left(s_{t+1}, a_{t+1}\right)$ 做一定比例的更新: +$$ +\begin{aligned} +Q^{*}\left(s_{t}, a_{t}\right) \leftarrow Q^{*}\left(s_{t}, a_{t}\right)+\alpha\left(r_{t}+\gamma \max _{a_{t+1}} Q^{*}\left(s_{t+1}, a_{t+1}\right)-Q^{*}\left(s_{t}, a_{t}\right)\right) +\end{aligned} +$$ +其中 $\alpha$ 是更新比例(学习速率)。这种渐进式的更新方式,可以减少策略估计造成的影响,并且最终会收敛至最优策略。 ![](img/3.20.png) -给大家区分一下什么是蒙特卡洛跟时序差分。形象去理解的话,蒙特卡洛可以简单的理解为算法完成一个 episode 之后,再拿这一个 episode 的数据来去 learn 一下,做一次更新。因为我们已经拿到了一整条 episode 的数据的话,也能够拿到每一个 step 的那个 reward,那我们也可以很方便的去计算每个 step 的未来总收益,就是我们的期望,就是我们的回报 $G_t$ 。$G_t$是我们的未来总收益,$G_t$代表是从这个 step 后面我能拿到的收益之和是多少。$G_1$是说我从第一步开始,往后能够拿到多少的收益。$G_2$ 的话也是说我从第二步这里开始,我往后能够拿到一共拿到多少的收益。 - -相比较蒙特卡洛还是一个 episode 更新一次这样子的方式,时序差分就是每个 step 都更新一下。我每走一步,我就更新下,这样的更新频率会更高一点。它拿的是 Q-function 来去近似地表示我的未来总收益 $G_t$。 - -举个例子来解释时序差分强化学习和蒙特卡洛强化学习的区别, - -* 时序差分强化学习是指在不清楚马尔可夫状态转移概率的情况下,以采样的方式得到不完整的状态序列,估计某状态在该状态序列完整后可能得到的收益,并通过不断地采样持续更新价值。 -* 蒙特卡洛强化学习则需要经历完整的状态序列后,再来更新状态的真实价值。 - -例如,你想获得开车去公司的时间,每天上班开车的经历就是一次采样。假设今天在路口 A 遇到了堵车, - -* 时序差分强化学习会在路口 A 就开始更新预计到达路口 B、路口 C $\cdots \cdots$, 以及到达公司的时间; -* 而蒙特卡洛强化学习并不会立即更新时间,而是在到达公司后,再修改到达每个路口和公司的时间。 - -时序差分强化学习能够在知道结果之前就开始学习,相比蒙特卡洛强化学习,其更快速、灵活。 +下面讲一下 on-policy 和 off-policy 的区别。 +* Sarsa 就是一个典型的 on-policy 策略,它只用一个 $\pi$ ,为了兼顾探索和利用,所以它训练的时候会显得有点胆小怕事。它在解决悬崖问题的时候,会尽可能地离悬崖边上远远的,确保说哪怕自己不小心探索了一点了,也还是在安全区域内不不至于跳进悬崖。 +* Q-learning 是一个比较典型的 off-policy 的策略,它有目标策略 target policy,一般用 $\pi$ 来表示。然后还有行为策略 behavior policy,用 $\mu$ 来表示。它分离了目标策略跟行为策略。Q-learning 就可以大胆地用 behavior policy 去探索得到的经验轨迹来去优化我的目标策略。这样子我更有可能去探索到最优的策略。 +* 比较 Q-learning 和 Sarsa 的更新公式可以发现,Sarsa 并没有选取最大值的 max 操作。因此,Q-learning 是一个非常激进的算法,希望每一步都获得最大的利益;而 Sarsa 则相对非常保守,会选择一条相对安全的迭代路线。 ![](img/3.21.png) -我们介绍下策略梯度最简单的也是最经典的一个算法 `REINFORCE`。REINFORCE 用的是回合更新的方式。它在代码上的处理上是先拿到每个 step 的 reward,然后计算每个 step 的未来总收益 $G_t$ 是多少,然后拿每个 $G_t$ 代入公式,去优化每一个 action 的输出。所以编写代码时会有这样一个函数,输入每个 step 拿到的 reward,然后把这些 reward 转成每一个 step 的未来总收益。因为未来总收益是这样计算的: -$$ -\begin{aligned} -G_{t} &=\sum_{k=t+1}^{T} \gamma^{k-t-1} r_{k} \\ -&=r_{t+1}+\gamma G_{t+1} -\end{aligned} -$$ -上一个 step 和下一个 step 的未来总收益可以有这样子的一个关系。所以在代码的计算上,我们就是从后往前推,一步一步地往前推,先算 $G_T$,然后往前推,一直算到 $G_1$ 。 +总结如上图所示。 -![](img/3.22.png) -REINFORCE 代码主要看最后四行,先产生一个 episode 的数据,比如 $(s_1,a_1,G_1),(s_2,a_2,G_2),\cdots,(s_T,a_T,G_T)$。然后针对每个 action 来计算梯度。 在代码上计算时,我们要拿到神经网络的输出。神经网络会输出每个 action 对应的概率值,然后我们还可以拿到实际的 action,把它转成 one-hot 向量乘一下,我们可以拿到 $\ln \pi(A_t|S_t,\theta)$ 。 - -![](img/3.23.png) - -手写数字识别的项目是很经典的一个多分类的问题,就是我们输入一张手写数字的图片,经过神经网络输出的是各个分类的一个概率。目的是希望我输出的这个概率的分布尽可能地去贴近真实值的概率分布。因为真实值只有一个数字 9,可是你用这个 one-hot 向量的形式去给他编码的话,也可以理解为这个真实值也是一个概率分布,9 的概率就是1,其他的概率就是 0。神经的网络输出一开始可能会比较平均,通过不断的迭代训练优化之后,我会希望 9 输出的概率可以远高于其他数字输出的概率。 - -![](img/3.24.png) - -如上图所示,就是提高 9 对应的概率,降低其他数字对应的概率。让神经网络输出的概率能够更贴近这个真实值的概率分布。那我们可以用交叉熵(Cross Entropy)来去表示两个概率分布之间的差距。 - -![](img/3.25.png) - -我们看一下它的优化流程,就是怎么让这个输出去逼近这个真实值。它的优化流程就是将图片作为输入传给神经网络,然后神经网络会给这个图片属于哪一类数字,输出所有数字可能的概率。然后再计算这个交叉熵,就是神经网络的输出 $Y_i$ 和真实的标签值 $Y_i'$ 之间的距离 $-\sum Y_{i}^{\prime} \cdot \log \left(Y_{i}\right)$。我们希望尽可能地缩小这两个概率分布之间的差距,计算出来的 cross entropy 就可以作为这个 loss 函数传给神经网络里面的优化器去优化,去自动去做神经网络的参数更新。 - -![](img/3.26.png) - -那类似的,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 会构造成这个样子。 - -![](img/3.27.png) - -实际上我们在计算这个 loss 的时候,我们要拿到那个 $\ln \pi(A_t|S_t,\theta)$。我就拿我实际执行的这个动作,先取个 one-hot 向量,然后再拿到神经网络预测的动作概率,这两个一相乘,我就可以拿到算法里面的那个 $\ln \pi(A_t|S_t,\theta)$。这个就是我们要构造的 loss。因为我们会拿到整个 episode 的所有的轨迹,所以我们可以对这个这一条整条轨迹里面的每个 action 都去计算一个 loss。把所有的 loss 加起来之后,我们再扔给那个 adam 的优化器去自动更新参数就好了。 - -![](img/3.28.png) - -上图是 REINFORCE 的流程图。首先我们需要一个 policy model 来输出动作概率,输出动作概率后,我们用 sample 函数去得到一个具体的动作,然后跟环境交互过后,我们可以得到一整个 episode 的数据。拿到 episode 数据之后,我再去执行一下 learn() 函数,在 learn() 函数里面,我就可以拿这些数据去构造 loss function,扔给这个优化器去优化,去更新我的 policy model。 ## References -* [Intro to Reinforcement Learning (强化学习纲要)](https://github.com/zhoubolei/introRL) +* [百面深度学习](https://book.douban.com/subject/35043939/) + * [神经网络与深度学习](https://nndl.github.io/) + + + + diff --git a/docs/chapter3/img/3.1.png b/docs/chapter3/img/3.1.png index 6e8519f..eb28b9c 100644 Binary files a/docs/chapter3/img/3.1.png and b/docs/chapter3/img/3.1.png differ diff --git a/docs/chapter3/img/3.10.png b/docs/chapter3/img/3.10.png index 52d050b..6e666f9 100644 Binary files a/docs/chapter3/img/3.10.png and b/docs/chapter3/img/3.10.png differ diff --git a/docs/chapter3/img/3.11.png b/docs/chapter3/img/3.11.png index 4b4d507..e39171c 100644 Binary files a/docs/chapter3/img/3.11.png and b/docs/chapter3/img/3.11.png differ diff --git a/docs/chapter3/img/3.12.png b/docs/chapter3/img/3.12.png index e6ddcf4..1936a65 100644 Binary files a/docs/chapter3/img/3.12.png and b/docs/chapter3/img/3.12.png differ diff --git a/docs/chapter3/img/3.13.png b/docs/chapter3/img/3.13.png index 203d2a7..c451a23 100644 Binary files a/docs/chapter3/img/3.13.png and b/docs/chapter3/img/3.13.png differ diff --git a/docs/chapter3/img/3.14.png b/docs/chapter3/img/3.14.png index 3069eee..63d6e04 100644 Binary files a/docs/chapter3/img/3.14.png and b/docs/chapter3/img/3.14.png differ diff --git a/docs/chapter3/img/3.15.png b/docs/chapter3/img/3.15.png index 78b2c45..03d2c76 100644 Binary files a/docs/chapter3/img/3.15.png and b/docs/chapter3/img/3.15.png differ diff --git a/docs/chapter3/img/3.16.png b/docs/chapter3/img/3.16.png index 3a35bc3..6ca2f3f 100644 Binary files a/docs/chapter3/img/3.16.png and b/docs/chapter3/img/3.16.png differ diff --git a/docs/chapter3/img/3.17.png b/docs/chapter3/img/3.17.png index 770a694..6c48225 100644 Binary files a/docs/chapter3/img/3.17.png and b/docs/chapter3/img/3.17.png differ diff --git a/docs/chapter3/img/3.18.png b/docs/chapter3/img/3.18.png index 5e2caf8..cd0c6b7 100644 Binary files a/docs/chapter3/img/3.18.png and b/docs/chapter3/img/3.18.png differ diff --git a/docs/chapter3/img/3.19.png b/docs/chapter3/img/3.19.png index 488258f..cbd192b 100644 Binary files a/docs/chapter3/img/3.19.png and b/docs/chapter3/img/3.19.png differ diff --git a/docs/chapter3/img/3.2.png b/docs/chapter3/img/3.2.png index 6250af6..2ef99ba 100644 Binary files a/docs/chapter3/img/3.2.png and b/docs/chapter3/img/3.2.png differ diff --git a/docs/chapter3/img/3.20.png b/docs/chapter3/img/3.20.png index 8284e0a..c56a0ab 100644 Binary files a/docs/chapter3/img/3.20.png and b/docs/chapter3/img/3.20.png differ diff --git a/docs/chapter3/img/3.21.png b/docs/chapter3/img/3.21.png index 815c2f7..d76d077 100644 Binary files a/docs/chapter3/img/3.21.png and b/docs/chapter3/img/3.21.png differ diff --git a/docs/chapter3/img/3.3.png b/docs/chapter3/img/3.3.png index cca153f..ba0f7a7 100644 Binary files a/docs/chapter3/img/3.3.png and b/docs/chapter3/img/3.3.png differ diff --git a/docs/chapter3/img/3.4.png b/docs/chapter3/img/3.4.png index 9f0233f..de654a2 100644 Binary files a/docs/chapter3/img/3.4.png and b/docs/chapter3/img/3.4.png differ diff --git a/docs/chapter3/img/3.5.png b/docs/chapter3/img/3.5.png index d553434..5877863 100644 Binary files a/docs/chapter3/img/3.5.png and b/docs/chapter3/img/3.5.png differ diff --git a/docs/chapter3/img/3.6.png b/docs/chapter3/img/3.6.png index 825f92a..402a395 100644 Binary files a/docs/chapter3/img/3.6.png and b/docs/chapter3/img/3.6.png differ diff --git a/docs/chapter3/img/3.7.png b/docs/chapter3/img/3.7.png index 52de9f8..b6c4b12 100644 Binary files a/docs/chapter3/img/3.7.png and b/docs/chapter3/img/3.7.png differ diff --git a/docs/chapter3/img/3.8.png b/docs/chapter3/img/3.8.png index 62f994a..d3127c5 100644 Binary files a/docs/chapter3/img/3.8.png and b/docs/chapter3/img/3.8.png differ diff --git a/docs/chapter3/img/3.9.png b/docs/chapter3/img/3.9.png index 22a2c52..9710b0f 100644 Binary files a/docs/chapter3/img/3.9.png and b/docs/chapter3/img/3.9.png differ diff --git a/docs/chapter4/chapter4.md b/docs/chapter4/chapter4.md index dea583e..6eb2b2f 100644 --- a/docs/chapter4/chapter4.md +++ b/docs/chapter4/chapter4.md @@ -1,227 +1,306 @@ -# PPO -## From On-policy to Off-policy -在讲 PPO 之前,我们先讲一下 on-policy 和 off-policy 这两种 training 方法的区别。 -在 reinforcement learning 里面,我们要 learn 的就是一个agent。 - -* 如果要 learn 的 agent 跟和环境互动的 agent 是同一个的话, 这个叫做`on-policy(同策略)`。 -* 如果要 learn 的 agent 跟和环境互动的 agent 不是同一个的话, 那这个叫做`off-policy(异策略)`。 - -比较拟人化的讲法是如果要学习的那个 agent,一边跟环境互动,一边做学习这个叫 on-policy。 如果它在旁边看别人玩,通过看别人玩来学习的话,这个叫做 off-policy。 - -为什么我们会想要考虑 off-policy ?让我们来想想 policy gradient。Policy gradient 是 on-policy 的做法,因为在做 policy gradient 时,我们需要有一个 agent、一个 policy 和一个 actor。这个 actor 先去跟环境互动去搜集资料,搜集很多的 $\tau$,根据它搜集到的资料,会按照 policy gradient 的式子去 update policy 的参数。所以 policy gradient 是一个 on-policy 的 algorithm。 +# Policy Gradient +## Policy Gradient ![](img/4.1.png) -PPO 是 policy gradient 的一个变形,它是现在 OpenAI default reinforcement learning 的 algorithm。 +在 reinforcement learning 中有 3 个components,一个`actor`,一个`environment`,一个`reward function`。 -$$ -\nabla \bar{R}_{\theta}=E_{\tau \sim p_{\theta}(\tau)}\left[R(\tau) \nabla \log p_{\theta}(\tau)\right] -$$ +让机器玩 video game 时, + +* actor 做的事情就是去操控游戏的摇杆, 比如说向左、向右、开火等操作; +* environment 就是游戏的主机, 负责控制游戏的画面负责控制说,怪物要怎么移动, 你现在要看到什么画面等等; +* reward function 就是当你做什么事情,发生什么状况的时候,你可以得到多少分数, 比如说杀一只怪兽得到 20 分等等。 + +同样的概念用在围棋上也是一样的, + +* actor 就是 alpha Go,它要决定下哪一个位置; +* environment 就是对手; +* reward function 就是按照围棋的规则, 赢就是得一分,输就是负一分等等。 + +在 reinforcement learning 里面,environment 跟 reward function 不是你可以控制的,environment 跟 reward function 是在开始学习之前,就已经事先给定的。你唯一能做的事情是调整 actor 里面的 policy,使得 actor 可以得到最大的 reward。Actor 里面会有一个 policy, 这个policy 决定了actor 的行为。Policy 就是给一个外界的输入,然后它会输出 actor 现在应该要执行的行为。 -问题是上面这个 update 的式子中的 $E_{\tau \sim p_{\theta}(\tau)}$ 应该是你现在的 policy $\theta$ 所 sample 出来的 trajectory $\tau$ 做 expectation。一旦 update 了参数,从 $\theta$ 变成 $\theta'$ ,$p_\theta(\tau)$这个概率就不对了,之前sample 出来的 data 就变的不能用了。所以 policy gradient 是一个会花很多时间来 sample data 的 algorithm,你会发现大多数时间都在 sample data,agent 去跟环境做互动以后,接下来就要 update 参数。你只能 update 参数一次。接下来你就要重新再去 collect data, 然后才能再次update 参数,这显然是非常花时间的。所以我们想要从 on-policy 变成 off-policy。 这样做就可以用另外一个policy, 另外一个actor $\theta'$ 去跟环境做互动。用 $\theta'$ collect 到的data 去训练 $\theta$。假设我们可以用 $\theta'$ collect 到的data 去训练 $\theta$,意味着说我们可以把$\theta'$ collect 到的data 用非常多次。我们可以执行 gradient ascent 好几次,我们可以 update 参数好几次, 都只要用同一笔data 就好了。因为假设 $\theta$ 有能力学习另外一个actor $\theta'$ 所 sample 出来的 data 的话, 那$\theta'$ 就只要sample 一次,也许sample 多一点的data, 让$\theta$ 去update 很多次,这样就会比较有效率。 ![](img/4.2.png) +**Policy 一般写成 $\pi$**。假设你是用 deep learning 的技术来做 reinforcement learning 的话,**policy 就是一个 network**。Network 里面就有一堆参数, 我们用 $\theta$ 来代表 $\pi$ 的参数。Network 的 input 就是现在 machine 看到的东西,如果让 machine 打电玩的话, 那 machine 看到的东西就是游戏的画面。Machine 看到什么东西,会影响你现在 training 到底好不好 train。 -具体怎么做呢?这边就需要介绍 `important sampling` 的概念。假设你有一个function $f(x)$,你要计算从 p 这个 distribution sample x,再把 x 带到 f 里面,得到$f(x)$。你要该怎么计算这个 $f(x)$ 的期望值?假设你不能对 p 这个distribution 做积分的话,那你可以从 p 这个 distribution 去 sample 一些data $x^i$。把 $x^i$ 代到 $f(x)$ 里面,然后取它的平均值,就可以近似 $f(x)$ 的期望值。 +举例来说,在玩游戏的时候, 也许你觉得游戏的画面,前后是相关的,也许你觉得说,你应该让你的 policy,看从游戏初始到现在这个时间点,所有画面的总和。你可能会觉得你要用到 RNN 来处理它,不过这样子,你会比较难处理。要让你的 machine,你的 policy 看到什么样的画面, 这个是你自己决定的。让你知道说给机器看到什么样的游戏画面,可能是比较有效的。Output 的就是今天机器要采取什么样的行为。 -现在有另外一个问题,我们没有办法从 p 这个 distribution 里面 sample data。假设我们不能从 p sample data,只能从另外一个 distribution q 去 sample data,q 可以是任何 distribution。我们不能够从 p 去sample data,但可以从 q 去 sample $x$。我们从 q 去 sample $x^i$ 的话就不能直接套下面的式子。 -$$ -E_{x \sim p}[f(x)] \approx \frac{1}{N} \sum_{i=1}^N f(x^i) -$$ -因为上式是假设你的 $x$ 都是从 p sample 出来的。所以做一个修正,修正是这样子的。期望值$E_{x \sim p}[f(x)]$其实就是$\int f(x) p(x) dx$,我们对其做如下的变换: -$$ -\int f(x) p(x) d x=\int f(x) \frac{p(x)}{q(x)} q(x) d x=E_{x \sim q}[f(x){\frac{p(x)}{q(x)}}] -$$ -我们就可以写成对 q 里面所 sample 出来的 x 取期望值。我们从q 里面 sample x,然后再去计算$f(x) \frac{p(x)}{q(x)}$,再去取期望值。所以就算我们不能从 p 里面去 sample data,只要能够从 q 里面去sample data,然后代入上式,你就可以计算从 p 这个distribution sample x 代入 f 以后所算出来的期望值。 +上图就是具体的例子, -这边是从 q 做 sample,所以从 q 里 sample 出来的每一笔data,你需要乘上一个 weight 来修正这两个 distribution 的差异,weight 就是$\frac{p(x)}{q(x)}$。$q(x)$ 可以是任何 distribution,唯一的限制就是 $q(x)$ 的概率是 0 的时候,$p(x)$ 的概率不为 0,不然这样会没有定义。假设 $q(x)$ 的概率是 0 的时候,$p(x)$ 的概率也都是 0 的话,那这样 $p(x)$ 除以 $q(x)$是有定义的。所以这个时候你就可以 apply important sampling 这个技巧。你就可以从 p 做 sample 换成从 q 做 sample。 +* policy 就是一个 network; +* input 就是游戏的画面,它通常是由 pixels 所组成的; +* output 就是看看说有那些选项是你可以去执行的,output layer 就有几个 neurons。 + +假设你现在可以做的行为就是有 3 个,output layer 就是有 3 个 neurons。每个 neuron 对应到一个可以采取的行为。Input 一个东西后,network 就会给每一个可以采取的行为一个分数。接下来,你把这个分数当作是概率。 actor 就是看这个概率的分布,根据这个机率的分布,决定它要采取的行为。比如说 70% 会走 left,20% 走 right,10% 开火等等。概率分布不同,actor 采取的行为就会不一样。 ![](img/4.3.png) +接下来用一个例子来说明 actor 是怎么样跟环境互动的。 首先 actor 会看到一个游戏画面,我们用 $s_1$ 来表示这个游戏画面,它代表游戏初始的画面。接下来 actor 看到这个游戏的初始画面以后,根据它内部的 network,根据它内部的 policy 来决定一个 action。假设它现在决定的 action 是向右,它决定完 action 以后,它就会得到一个 reward ,代表它采取这个 action 以后得到的分数。 -Important sampling 有一些 issue。虽然理论上你可以把 p 换成任何的 q。但是在实现上, p 和 q 不能够差太多。差太多的话,会有一些问题。什么样的问题呢? +我们把一开始的初始画面,写作 $s_1$, 把第一次执行的动作叫做 $a_1$,把第一次执行动作完以后得到的 reward 叫做 $r_1$。不同的书会有不同的定义,有人会觉得说这边应该要叫做 $r_2$,这个都可以,你自己看得懂就好。Actor 决定一个的行为以后, 就会看到一个新的游戏画面,这边是 $s_2$。然后把这个 $s_2$ 输入给 actor,这个 actor 决定要开火,然后它可能杀了一只怪,就得到五分。然后这个 process 就反复地持续下去,直到今天走到某一个 timestamp 执行某一个 action,得到 reward 之后, 这个 environment 决定这个游戏结束了。比如说,如果在这个游戏里面,你是控制绿色的船去杀怪,如果你被杀死的话,游戏就结束,或是你把所有的怪都清空,游戏就结束了。 -$$ -E_{x \sim p}[f(x)]=E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] -$$ -虽然上式成立。但上式左边是$f(x)$ 的期望值,它的distribution 是 p,上式右边是$f(x) \frac{p(x)}{q(x)}$ 的期望值,它的distribution 是 q。如果不是算期望值,而是算 variance 的话。这两个variance 是不一样的。两个 random variable 的 mean 一样,并不代表它的 variance 一样。 +![](img/4.4.png) +一场游戏叫做一个 `Episode(回合)` 或者 `Trial(试验)`。把这个游戏里面,所有得到的 reward 都总合起来,就是 `Total reward`,我们称其为`Return(回报)`,用 R 来表示它。Actor 要想办法去 maximize 它可以得到的 reward。 -我们可以代一下方差的公式 +![](img/4.5.png) +首先,`environment` 是一个`function`,游戏的主机也可以把它看作是一个 function,虽然它不一定是 neural network,可能是 rule-based 的规则,但你可以把它看作是一个 function。这个 function,一开始就先吐出一个 state,也就是游戏的画面,接下来你的 actor 看到这个游戏画面 $s_1$ 以后,它吐出 $a_1$,然后 environment 把 $a_1$ 当作它的输入,然后它再吐出 $s_2$,吐出新的游戏画面。Actor 看到新的游戏画面,再采取新的行为 $a_2$,然后 environment 再看到 $a_2$,再吐出 $s_3$。这个 process 会一直持续下去,直到 environment 觉得说应该要停止为止。 + +在一场游戏里面,我们把 environment 输出的 $s$ 跟 actor 输出的行为 $a$,把这个 $s$ 跟 $a$ 全部串起来, 叫做一个 `Trajectory`,如下式所示。 $$ -\operatorname{Var}_{x \sim p}[f(x)]=E_{x \sim p}\left[f(x)^{2}\right]-\left(E_{x \sim p}[f(x)]\right)^{2} +\text { Trajectory } \tau=\left\{s_{1}, a_{1}, s_{2}, a_{2}, \cdots, s_{t}, a_{t}\right\} $$ +每一个 trajectory,你可以计算它发生的概率。假设现在 actor 的参数已经被给定了话,就是 $\theta$。根据 $\theta$,你其实可以计算某一个 trajectory 发生的概率,你可以计算某一个回合,某一个 episode 里面, 发生这样子状况的概率。 + $$ \begin{aligned} -\operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] &=E_{x \sim q}\left[\left(f(x) \frac{p(x)}{q(x)}\right)^{2}\right]-\left(E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]\right)^{2} \\ -&=E_{x \sim p}\left[f(x)^{2} \frac{p(x)}{q(x)}\right]-\left(E_{x \sim p}[f(x)]\right)^{2} +p_{\theta}(\tau) +&=p\left(s_{1}\right) p_{\theta}\left(a_{1} | s_{1}\right) p\left(s_{2} | s_{1}, a_{1}\right) p_{\theta}\left(a_{2} | s_{2}\right) p\left(s_{3} | s_{2}, a_{2}\right) \cdots \\ +&=p\left(s_{1}\right) \prod_{t=1}^{T} p_{\theta}\left(a_{t} | s_{t}\right) p\left(s_{t+1} | s_{t}, a_{t}\right) \end{aligned} $$ -$\operatorname{Var}_{x \sim p}[f(x)]$ 和 $\operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$ 的差别在第一项是不同的, $\operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$ 的第一项多乘了$\frac{p(x)}{q(x)}$,如果$\frac{p(x)}{q(x)}$ 差距很大的话, $\operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$的 variance 就会很大。所以虽然理论上它们的expectation 一样,也就是说,你只要对 p 这个distribution sample 够多次,q 这个distribution sample 够多,你得到的结果会是一样的。但是假设你sample 的次数不够多,因为它们的variance 差距是很大的,所以你就有可能得到非常大的差别。 +怎么算呢,如上式所示。在假设你 actor 的参数就是 $\theta$ 的情况下,某一个 trajectory $\tau$ 的概率就是这样算的,你先算 environment 输出 $s_1$ 的概率,再计算根据 $s_1$ 执行 $a_1$ 的概率,这是由你 policy 里面的 network 参数 $\theta$ 所决定的, 它是一个概率,因为你的 policy 的 network 的 output 是一个 distribution,actor 是根据这个 distribution 去做 sample,决定现在实际上要采取的 action是哪一个。接下来 environment 根据 $a_1$ 跟 $s_1$ 产生 $s_2$,因为 $s_2$ 跟$s_1$ 还是有关系的,下一个游戏画面,跟前一个游戏画面通常还是有关系的,至少要是连续的, 所以给定前一个游戏画面 $s_1$ 和现在 actor 采取的行为 $a_1$,就会产生 $s_2$。 -![](img/4.4.png) +这件事情可能是概率,也可能不是概率,这个取决于 environment,就是主机它内部设定是怎样。看今天这个主机在决定,要输出什么样的游戏画面的时候,有没有概率。因为如果没有概率的话,这个游戏的每次的行为都一样,你只要找到一条 path 就可以过关了,这样感觉是蛮无聊的 。所以游戏里面,通常是还是有一些概率的,你做同样的行为,给同样的前一个画面, 下次产生的画面不见得是一样的。Process 就反复继续下去,你就可以计算一个 trajectory $s_1$,$a_1$, $s_2$ , $a_2$ 出现的概率有多大。 -举个例子,当 $p(x)$ 和 $q(x)$ 差距很大的时候,会发生什么样的问题。假设蓝线是 $p(x)$ 的distribution,绿线是 $q(x)$ 的 distribution,红线是 $f(x)$。如果我们要计算$f(x)$的期望值,从 $p(x)$ 这个distribution 做 sample 的话,那显然 $E_{x \sim p}[f(x)]$ 是负的,因为左边那块区域 $p(x)$ 的概率很高,所以要 sample 的话,都会 sample 到这个地方,而 $f(x)$ 在这个区域是负的, 所以理论上这一项算出来会是负。 +**这个概率取决于两部分**, -接下来我们改成从 $q(x)$ 这边做 sample,因为 $q(x)$ 在右边这边的概率比较高,所以如果你sample 的点不够的话,那你可能都只sample 到右侧。如果你都只 sample 到右侧的话,你会发现说,算 $E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$这一项,搞不好还应该是正的。你这边sample 到这些点,然后你去计算它们的$f(x) \frac{p(x)}{q(x)}$都是正的,所以你sample 到这些点都是正的。 你取期望值以后,也都是正的。为什么会这样,因为你 sample 的次数不够多,因为假设你sample 次数很少,你只能sample 到右边这边。左边这边虽然概率很低,但也不是没有可能被 sample 到。假设你今天好不容易 sample 到左边的点,因为左边的点,$p(x)$ 和 $q(x)$ 是差很多的, 这边 $p(x)$ 很小,$q(x)$ 很大。今天 $f(x)$ 好不容易终于 sample 到一个负的,这个负的就会被乘上一个非常大的 weight ,这样就可以平衡掉刚才那边一直 sample 到 positive 的 value 的情况。最终你算出这一项的期望值,终究还是负的。但前提是你要sample 够多次,这件事情才会发生。但有可能sample 不够,$E_{x \sim p}[f(x)]$跟$E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$就有可能有很大的差距。这就是 importance sampling 的问题。 +* 一部分是 `environment 的行为`, environment 的 function 它内部的参数或内部的规则长什么样子。 $p(s_{t+1}|s_t,a_t)$这一项代表的是 environment, environment 这一项通常你是无法控制它的,因为那个是人家写好的,你不能控制它。 +* 另一部分是 `agent 的行为`。你能控制的是 $p_\theta(a_t|s_t)$。给定一个 $s_t$, actor 要采取什么样的 $a_t$ 会取决于你 actor 的参数 $\theta$, 所以这部分是 actor 可以自己控制的。随着 actor 的行为不同,每个同样的 trajectory, 它就会有不同的出现的概率。 -![](img/4.5.png) - -现在要做的事情就是把 importance sampling 用在 off-policy 的 case。把 on-policy training 的algorithm 改成 off-policy training 的 algorithm。怎么改呢,之前我们是拿 $\theta$ 这个policy 去跟环境做互动,sample 出trajectory $\tau$,然后计算$R(\tau) \nabla \log p_{\theta}(\tau)$。 - -现在我们不用$\theta$ 去跟环境做互动,假设有另外一个 policy $\theta'$,它就是另外一个actor。它的工作是他要去做demonstration,$\theta'$ 的工作是要去示范给$\theta$ 看。它去跟环境做互动,告诉 $\theta$ 说,它跟环境做互动会发生什么事。然后,借此来训练$\theta$。我们要训练的是$\theta$ ,$\theta'$ 只是负责做 demo,负责跟环境做互动。 - -我们现在的$\tau$ 是从 $\theta'$ sample 出来的,是拿 $\theta'$ 去跟环境做互动。所以sample 出来的 $\tau$ 是从 $\theta'$ sample 出来的,这两个distribution 不一样。但没有关系,假设你本来是从 p 做sample,但你发现你不能够从 p 做sample,所以我们不拿$\theta$ 去跟环境做互动。你可以把 p 换 q,然后在后面这边补上一个 importance weight。现在的状况就是一样,把 $\theta$ 换成 $\theta'$ 后,要补上一个importance weight $\frac{p_{\theta}(\tau)}{p_{\theta^{\prime}}(\tau)}$。这个 importance weight 就是某一个 trajectory $\tau$ 用 $\theta$ 算出来的概率除以这个 trajectory $\tau$,用$\theta'$ 算出来的概率。这一项是很重要的,因为今天你要learn 的是actor $\theta$ 和 $\theta'$ 是不太一样的。$\theta'$ 会见到的情形跟 $\theta$ 见到的情形不见得是一样的,所以中间要做一个修正的项。 - -现在的data 不是从$\theta$ sample 出来,是从 $\theta'$ sample 出来的。从$\theta$ 换成$\theta'$ 有什么好处呢?因为现在跟环境做互动是$\theta'$ 而不是$\theta$。所以 sample 出来的东西跟 $\theta$ 本身是没有关系的。所以你就可以让 $\theta'$ 做互动 sample 一大堆的data,$\theta$ 可以update 参数很多次。然后一直到 $\theta$ train 到一定的程度,update 很多次以后,$\theta'$ 再重新去做sample,这就是on-policy 换成off-policy 的妙用。 ![](img/4.6.png) -实际在做 policy gradient 的时候,我们并不是给整个 trajectory $\tau$ 都一样的分数,而是每一个state-action 的pair 会分开来计算。实际上 update gradient 的时候,我们的式子是长这样子的。 -$$ -=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta}}\left[A^{\theta}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] -$$ -我们用 $\theta$ 这个actor 去sample 出$s_t$ 跟$a_t$,sample 出state 跟action 的pair,我们会计算这个state 跟action pair 它的advantage, 就是它有多好。$A^{\theta}\left(s_{t}, a_{t}\right)$就是 accumulated 的 reward 减掉 bias,这一项就是估测出来的。它要估测的是,在state $s_t$ 采取action $a_t$ 是好的,还是不好的。那接下来后面会乘上$\nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)$,也就是说如果$A^{\theta}\left(s_{t}, a_{t}\right)$是正的,就要增加概率, 如果是负的,就要减少概率。 - -那现在用了 importance sampling 的技术把 on-policy 变成 off-policy,就从 $\theta$ 变成 $\theta'$。所以现在$s_t$、$a_t$ 是$\theta'$ ,另外一个actor 跟环境互动以后所 sample 到的data。 但是拿来训练要调整参数是 model $\theta$。因为 $\theta'$ 跟 $\theta$ 是不同的model,所以你要做一个修正的项。这项修正的项,就是用 importance sampling 的技术,把$s_t$、$a_t$ 用 $\theta$ sample 出来的概率除掉$s_t$、$a_t$ 用 $\theta'$ sample 出来的概率。 +在 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 的期望值是多少。 $$ -=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{P_{\theta}\left(s_{t}, a_{t}\right)}{P_{\theta^{\prime}}\left(s_{t}, a_{t}\right)} A^{\theta}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] +\bar{R}_{\theta}=\sum_{\tau} R(\tau) p_{\theta}(\tau) $$ - -这边 $A^{\theta}(s_t,a_t)$ 有一个上标 $\theta$,$\theta$ 代表说这个是 actor $\theta$ 跟环境互动的时候所计算出来的 A。但是实际上从 $\theta$ 换到 $\theta'$ 的时候,$A^{\theta}(s_t,a_t)$ 应该改成 $A^{\theta'}(s_t,a_t)$,为什么?A 这一项是想要估测说现在在某一个 state 采取某一个 action,接下来会得到 accumulated reward 的值减掉base line 。你怎么估 A 这一项,你就会看在 state $s_t$,采取 action $a_t$,接下来会得到的reward 的总和,再减掉baseline。之前是 $\theta$ 在跟环境做互动,所以你观察到的是 $\theta$ 可以得到的reward。但现在是 $\theta'$ 在跟环境做互动,所以你得到的这个advantage, 其实是根据 $\theta'$ 所estimate 出来的advantage。但我们现在先不要管那么多, 我们就假设这两项可能是差不多的。 - -那接下来,我们可以拆解 $p_{\theta}\left(s_{t}, a_{t}\right)$ 和 $p_{\theta'}\left(s_{t}, a_{t}\right)$,即 +这个期望值的算法如上式所示,穷举所有可能的 trajectory $\tau$, 每一个 trajectory $\tau$ 都有一个概率。比如 $\theta$ 是一个很强的 model, 那它都不会死。如果有一个 episode 很快就死掉了, 它的概率就很小;如果有一个 episode 都一直没有死, 那它的概率就很大。根据你的 $\theta$, 你可以算出某一个 trajectory $\tau$ 出现的概率,接下来你计算这个 $\tau$ 的 total reward 是多少。 Total reward weighted by 这个 $\tau$ 出现的概率,对所有的 $\tau$ 进行求和,就是期望值。给定一个参数,你会得到的期望值。 $$ -\begin{aligned} -p_{\theta}\left(s_{t}, a_{t}\right)&=p_{\theta}\left(a_{t}|s_{t}\right) p_{\theta}(s_t) \\ -p_{\theta'}\left(s_{t}, a_{t}\right)&=p_{\theta'}\left(a_{t}|s_{t}\right) p_{\theta'}(s_t) -\end{aligned} +\bar{R}_{\theta}=\sum_{\tau} R(\tau) p_{\theta}(\tau)=E_{\tau \sim p_{\theta}(\tau)}[R(\tau)] $$ -于是我们得到下式: -$$ -=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} \frac{p_{\theta}\left(s_{t}\right)}{p_{\theta^{\prime}}\left(s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] -$$ - - -然后这边需要做一件事情是,假设 model 是 $\theta$ 的时候,你看到$s_t$ 的概率,跟 model 是$\theta'$ 的时候,你看到$s_t$ 的概率是差不多的,即$p_{\theta}(s_t)=p_{\theta'}(s_t)$。因为它们是一样的,所以你可以把它删掉,即 -$$ -=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] \quad(1) -$$ - -为什么可以假设它是差不多的。举例来说,会看到什么state 往往跟你会采取什么样的action 是没有太大的关系的。比如说你玩不同的 Atari 的游戏,其实你看到的游戏画面都是差不多的,所以也许不同的 $\theta$ 对 $s_t$ 是没有影响的。但是有一个更直觉的理由就是这一项到时候真的要你算,你会算吗?因为想想看这项要怎么算,这一项你还要说我有一个参数$\theta$,然后拿$\theta$ 去跟环境做互动,算$s_t$ 出现的概率,这个你根本很难算。尤其是你如果 input 是image 的话, 同样的 $s_t$ 根本就不会出现第二次。你根本没有办法估这一项, 所以干脆就无视这个问题。 - -但是 $p_{\theta}(a_t|s_t)$很好算。你手上有$\theta$ 这个参数,它就是个network。你就把$s_t$ 带进去,$s_t$ 就是游戏画面,你把游戏画面带进去,它就会告诉你某一个state 的 $a_t$ 概率是多少。我们其实有个 policy 的network,把 $s_t$ 带进去,它会告诉我们每一个 $a_t$ 的概率是多少。所以 -$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)}$ 这一项,你只要知道$\theta$ 和 $\theta'$ 的参数就可以算。 - -现在我们得到一个新的objective function。 - -$$ -J^{\theta^{\prime}}(\theta)=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)\right] -$$ - - -式(1)是 gradient,其实我们可以从 gradient 去反推原来的 objective function。这边有一个公式 - -$$ -\nabla f(x)=f(x) \nabla \log f(x) -$$ - -我们可以用这个公式来反推objective function,要注意一点,对 $\theta$ 求梯度时,$p_{\theta^{\prime}}(a_{t} | s_{t})$ 和 $A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)$ 都是常数。 - - -所以实际上,当我们apply importance sampling 的时候,要去optimize 的那一个objective function 就长这样子,我们把它写作$J^{\theta^{\prime}}(\theta)$。为什么写成$J^{\theta^{\prime}}(\theta)$ 呢,这个括号里面那个$\theta$ 代表我们要去optimize 的那个参数。$\theta'$ 是说我们拿 $\theta'$ 去做demonstration,就是现在真正在跟环境互动的是$\theta'$。因为 $\theta$ 不跟环境做互动,是 $\theta'$ 在跟环境互动。 - -然后你用$\theta'$ 去跟环境做互动,sample 出$s_t$、$a_t$ 以后,你要去计算$s_t$ 跟$a_t$ 的advantage,然后你再去把它乘上$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)}$。$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)}$是好算的,$A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)$ 可以从这个 sample 的结果里面去估测出来的,所以 $J^{\theta^{\prime}}(\theta)$ 是可以算的。实际上在 update 参数的时候,就是按照式(1) 来 update 参数。 - - - -## PPO +我们还可以写成上式那样,从 $p_{\theta}(\tau)$ 这个 distribution sample 一个 trajectory $\tau$,然后计算 $R(\tau)$ 的期望值,就是你的 expected reward。 我们要做的事情就是 maximize expected reward。 ![](img/4.7.png) +怎么 maximize expected reward 呢?我们用的是 `gradient ascent`,因为要让它越大越好,所以是 gradient ascent。Gradient ascent 在 update 参数的时候要加。要进行 gradient ascent,我们先要计算 expected reward $\bar{R}$ 的 gradient 。我们对 $\bar{R}$ 取一个 gradient,这里面只有 $p_{\theta}(\tau)$ 是跟 $\theta$ 有关,所以 gradient 就放在 $p_{\theta}(\tau)$ 这个地方。$R(\tau)$ 这个 reward function 不需要是 differentiable,我们也可以解接下来的问题。举例来说,如果是在 GAN 里面,$R(\tau)$ 其实是一个 discriminator,它就算是没有办法微分,也无所谓,你还是可以做接下来的运算。 -我们可以把 on-policy 换成 off-policy,但 importance sampling 有一个 issue,如果 $p_{\theta}\left(a_{t} | s_{t}\right)$ 跟 $p_{\theta'}\left(a_{t} | s_{t}\right)$ 差太多的话,这两个 distribution 差太多的话,importance sampling 的结果就会不好。怎么避免它差太多呢?这个就是 `Proximal Policy Optimization (PPO) ` 在做的事情。它实际上做的事情就是这样,在 off-policy 的方法里要optimize 的是 $J^{\theta^{\prime}}(\theta)$。但是这个 objective function 又牵涉到 importance sampling。在做 importance sampling 的时候,$p_{\theta}\left(a_{t} | s_{t}\right)$ 不能跟 $p_{\theta'}\left(a_{t} | s_{t}\right)$差太多。你做 demonstration 的 model 不能够跟真正的 model 差太多,差太多的话 importance sampling 的结果就会不好。我们在 training 的时候,多加一个 constrain。这个constrain 是 $\theta$ 跟 $\theta'$ output 的 action 的 KL divergence,简单来说,这一项的意思就是要衡量说 $\theta$ 跟 $\theta'$ 有多像。 +取 gradient之后,我们背一个公式, +$$ +\nabla f(x)=f(x)\nabla \log f(x) +$$ +我们可以对 $\nabla p_{\theta}(\tau)$ 使用这个公式,然后会得到 $\nabla p_{\theta}(\tau)=p_{\theta}(\tau) \nabla \log p_{\theta}(\tau)$。 -然后我们希望在 training 的过程中,learn 出来的 $\theta$ 跟 $\theta'$ 越像越好。因为如果 $\theta$ 跟 $\theta'$ 不像的话,最后的结果就会不好。所以在 PPO 里面有两个式子,一方面是 optimize 本来要 optimize 的东西,但再加一个 constrain。这个 constrain 就好像那个 regularization 的 term 一样,在做 machine learning 的时候不是有 L1/L2 的regularization。这一项也很像 regularization,这样 regularization 做的事情就是希望最后 learn 出来的 $\theta$ 不要跟 $\theta'$ 太不一样。 +接下来, 分子分母,上下同乘$p_{\theta}(\tau)$,然后我们可以得到下式: +$$ +\frac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)}=\log p_{\theta}(\tau) +$$ + + 然后如下式所示, 对 $\tau$ 进行求和,把 $R(\tau)$ 和 $\log p_{\theta}(\tau)$ 这两项 weighted by $ p_{\theta}(\tau)$, 既然有 weighted by $p_{\theta}(\tau)$,它们就可以被写成这个 expected 的形式。也就是你从 $p_{\theta}(\tau)$ 这个 distribution 里面 sample $\tau$ 出来, 去计算 $R(\tau)$ 乘上 $\nabla\log p_{\theta}(\tau)$,然后把它对所有可能的 $\tau$ 进行求和,就是这个 expected value 。 -PPO 有一个前身叫做TRPO,TRPO 的式子如下式所示。 $$ \begin{aligned} -J_{T R P O}^{\theta^{\prime}}(\theta)=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)\right] \\ \\ -\mathrm{KL}\left(\theta, \theta^{\prime}\right)<\delta +\nabla \bar{R}_{\theta}&=\sum_{\tau} R(\tau) \nabla p_{\theta}(\tau)\\&=\sum_{\tau} R(\tau) p_{\theta}(\tau) \frac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)} \\&= +\sum_{\tau} R(\tau) p_{\theta}(\tau) \nabla \log p_{\theta}(\tau) \\ +&=E_{\tau \sim p_{\theta}(\tau)}\left[R(\tau) \nabla \log p_{\theta}(\tau)\right] \end{aligned} $$ -它与PPO不一样的地方 是 constrain 摆的位置不一样,PPO是直接把 constrain 放到你要 optimize 的那个式子里面,然后你就可以用 gradient ascent 的方法去 maximize 这个式子。但 TRPO 是把 KL divergence 当作constrain,它希望 $\theta$ 跟 $\theta'$ 的 KL divergence 小于一个$\delta$。如果你是用 gradient based optimization 时,有 constrain 是很难处理的。 +实际上这个 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) \\ +&=\frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}} R\left(\tau^{n}\right) \nabla \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right) +\end{aligned} +$$ +注意 $p_{\theta}(\tau)$ 里面有两项,$p(s_{t+1}|s_t,a_t)$ 来自于 environment,$p_\theta(a_t|s_t)$ 是来自于 agent。 $p(s_{t+1}|s_t,a_t)$ 由环境决定从而与 $\theta$ 无关,因此 $\nabla \log p(s_{t+1}|s_t,a_t) =0 $。因此 $\nabla p_{\theta}(\tau)= +\nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)$。 -PPO是很难处理的,因为它是把 KL divergence constrain 当做一个额外的 constrain,没有放 objective 里面,所以它很难算。所以不想搬石头砸自己的脚的话, 你就用PPO 不要用TRPO。看文献上的结果是,PPO 跟TRPO 可能 performance 差不多,但 PPO 在实现上比 TRPO 容易的多。 +你可以非常直观的来理解这个部分,也就是在你 sample 到的 data 里面, 你 sample 到,在某一个 state $s_t$ 要执行某一个 action $a_t$, 这个 $s_t$ 跟 $a_t$ 它是在整个 trajectory $\tau$ 的里面的某一个 state and action 的 pair。 + +* 假设你在 $s_t$ 执行 $a_t$,最后发现 $\tau$ 的 reward 是正的, 那你就要增加这一项的概率,你就要增加在 $s_t$ 执行 $a_t$ 的概率。 +* 反之,在 $s_t$ 执行 $a_t$ 会导致$\tau$ 的 reward 变成负的, 你就要减少这一项的概率。 -KL divergence 到底指的是什么?这边我是直接把 KL divergence 当做一个 function,input 是 $\theta$ 跟 $\theta'$,但我的意思并不是说把 $\theta$ 或 $\theta'$ 当做一个distribution,算这两个distribution 之间的距离,我不是这个意思。所谓的 $\theta$ 跟 $\theta'$ 的距离并不是参数上的距离,而是 behavior 上的距离。 -假设你有一个model,有一个actor 它是$\theta$,你有另外一个actor 的参数是$\theta'$ ,所谓参数上的距离就是你算这两组参数有多像。我今天所讲的不是参数上的距离, 而是它们行为上的距离。就是你先带进去一个state s,它会对这个 action 的 space output 一个 distribution。假设你有 3 个actions,3 个可能的 actions 就 output 3 个值。那今天所指的 distance 是behavior distance。也就是说,给同样的 state 的时候,输出 action 之间的差距。这两个 actions 的 distribution 都是一个概率分布。所以就可以计算这两个概率分布的 KL divergence。把不同的 state output 的这两个 distribution 的KL divergence 平均起来才是我这边所指的两个 actor 间的 KL divergence。你可能说怎么不直接算这个 $\theta$ 或 $\theta'$ 之间的距离,甚至不要用KL divergence 算,L1 跟 L2 的 norm 也可以保证 $\theta$ 跟 $\theta'$ 很接近啊。在做reinforcement learning 的时候,之所以我们考虑的不是参数上的距离,而是 action 上的距离,是因为很有可能对 actor 来说,参数的变化跟 action 的变化不一定是完全一致的。有时候你参数小小变了一下,它可能 output 的行为就差很多。或是参数变很多,但 output 的行为可能没什么改变。**所以我们真正在意的是这个actor 它的行为上的差距,而不是它们参数上的差距。**所以在做PPO 的时候,所谓的 KL divergence 并不是参数的距离,而是action 的距离。 ![](img/4.8.png) +这个怎么实现呢? 你用 gradient ascent 来 update 你的参数,你原来有一个参数 $\theta$ ,把你的 $\theta$ 加上你的 gradient 这一项,那当然前面要有个 learning rate,learning rate 其实也是要调的,你可用 Adam、RMSProp 等方法对其进行调整。 + +我们可以套下面这个公式来把 gradient 计算出来: + +$$ +\nabla \bar{R}_{\theta}=\frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}} R\left(\tau^{n}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right) +$$ +实际上,要套上面这个公式, 首先你要先收集一大堆的 s 跟 a 的 pair,你还要知道这些 s 跟 a 在跟环境互动的时候,你会得到多少的 reward。 这些资料怎么收集呢?你要拿你的 agent,它的参数是 $\theta$,去跟环境做互动, 也就是拿你已经 train 好的 agent 先去跟环境玩一下,先去跟那个游戏互动一下, 互动完以后,你就会得到一大堆游戏的纪录,你会记录说,今天先玩了第一场,在第一场游戏里面,我们在 state $s_1$ 采取 action $a_1$,在 state $s_2$ 采取 action $a_2$ 。 + +玩游戏的时候是有随机性的,所以 agent 本身是有随机性的,在同样 state $s_1$,不是每次都会采取 $a_1$,所以你要记录下来。在 state $s_1^1$ 采取 $a_1^1$,在 state $s_2^1$ 采取 $a_2^1$。整场游戏结束以后,得到的分数是$R(\tau^1)$。你会 sample 到另外一笔 data,也就是另外一场游戏。在另外一场游戏里面,你在 state $s_1^2$ 采取 $a_1^2$,在 state $s_2^2$ 采取 $a_2^2$,然后你 sample 到的就是 $\tau^2$,得到的 reward 是 $R(\tau^2)$。 + +你就可以把 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 参数, 等一下我们会解决这个问题。 -我们来看一下PPO1 的algorithm。它先initial 一个policy 的参数$\theta^0$。然后在每一个iteration 里面呢,你要用参数$\theta^k$,$\theta^k$ 就是你在前一个training 的iteration得到的actor 的参数,你用$\theta^k$ 去跟环境做互动,sample 到一大堆 state-action 的pair。 -然后你根据$\theta^k$ 互动的结果,估测一下$A^{\theta^{k}}\left(s_{t}, a_{t}\right)$。然后你就 apply PPO 的 optimization 的 formulation。但跟原来的policy gradient 不一样,原来的 policy gradient 只能 update 一次参数,update 完以后,你就要重新 sample data。但是现在不用,你拿 $\theta^k$ 去跟环境做互动,sample 到这组 data 以后,你可以让 $\theta$ update 很多次,想办法去 maximize objective function。这边 $\theta$ update 很多次没有关系,因为我们已经有做 importance sampling,所以这些experience,这些 state-action 的 pair 是从 $\theta^k$ sample 出来的没有关系。$\theta$ 可以 update 很多次,它跟 $\theta^k$ 变得不太一样也没有关系,你还是可以照样训练 $\theta$。 ![](img/4.9.png) -在PPO 的paper 里面还有一个 `adaptive KL divergence`,这边会遇到一个问题就是 $\beta$ 要设多少,它就跟那个regularization 一样。regularization 前面也要乘一个weight,所以这个 KL divergence 前面也要乘一个 weight,但 $\beta$ 要设多少呢?所以有个动态调整 $\beta$ 的方法。在这个方法里面呢,你先设一个 KL divergence,你可以接受的最大值。然后假设你发现说你 optimize 完这个式子以后,KL divergence 的项太大,那就代表说后面这个 penalize 的 term 没有发挥作用,那就把 $\beta$ 调大。那另外你定一个 KL divergence 的最小值。如果发现 optimize 完上面这个式子以后,KL divergence 比最小值还要小,那代表后面这一项的效果太强了,你怕他只弄后面这一项,那 $\theta$ 跟 $\theta^k$ 都一样,这不是你要的,所以你这个时候你叫要减少 $\beta$。所以 $\beta$ 是可以动态调整的。这个叫做 adaptive KL penalty。 +接下来讲一些实现细节。实现方法是这个样子,把它想成一个分类的问题,在 classification 里面就是 input 一个 image,然后 output 决定说是 10 个 class 里面的哪一个。在做 classification 时,我们要收集一堆 training data,要有 input 跟 output 的 pair。 + +在实现的时候,你就把 state 当作是 classifier 的 input。 你就当在做 image classification 的 problem,只是现在的 class 不是说 image 里面有什么 objects。 现在的 class 是说,看到这张 image 我们要采取什么样的行为,每一个行为就是一个 class。比如说第一个 class 叫做向左,第二个 class 叫做向右,第三个 class 叫做开火。 + +这些训练的数据从哪里来的呢? 做分类的问题时,要有 input 和正确的 output。 这些训练数据是从 sampling 的 process 来的。假设在 sampling 的 process 里面,在某一个 state,你 sample 到你要采取 action a, 你就把这个 action a 当作是你的 ground truth。你在这个 state,你 sample 到要向左。 本来向左这件事概率不一定是最高, 因为你是 sample,它不一定概率最高。假设你 sample 到向左,在 training 的时候 你叫告诉 machine 说,调整 network 的参数, 如果看到这个 state,你就向左。在一般的 classification 的 problem 里面,其实你在 implement classification 的时候, 你的 objective function 都会写成 minimize cross entropy,其实 minimize cross entropy 就是 maximize log likelihood。 + ![](img/4.10.png) -如果你觉得算 KL divergence 很复杂。有一个PPO2。PPO2 要去 maximize 的 objective function 如下式所示,它的式子里面就没有 KL divergence 。 +做 classification 的时候,objective function 就是 maximize 或 minimize 的对象, 因为我们现在是 maximize likelihood 所以其实是 maximize, 你要 maximize 的对象,如下式所示: $$ -\begin{aligned} -J_{P P O 2}^{\theta^{k}}(\theta) \approx \sum_{\left(s_{t}, a_{t}\right)} \min &\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)} A^{\theta^{k}}\left(s_{t}, a_{t}\right),\right.\\ -&\left.\operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right) A^{\theta^{k}}\left(s_{t}, a_{t}\right)\right) -\end{aligned} -$$ -这个式子看起来有点复杂,但实际 implement 就很简单。我们来实际看一下说这个式子到底是什么意思。 -min 这个 operator 做的事情是第一项跟第二项里面选比较小的那个。第二项前面有个clip function,clip 这个function 的意思是说,在括号里面有3 项,如果第一项小于第二项的话,那就output $1-\varepsilon$ 。第一项如果大于第三项的话,那就output $1+\varepsilon$。 $\varepsilon$ 是一个 hyper parameter,你要tune 的,你可以设成 0.1 或 设 0.2 。 -假设这边设0.2 的话,如下式所示 -$$ -\operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 0.8, 1.2\right) +\frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}} \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right) $$ -如果$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$算出来小于0.8,那就当作0.8。如果算出来大于1.2,那就当作1.2。 +像这种 loss function。你可在 TensorFlow 里 call 现成的 function,它就会自动帮你算。 +然后你就可以把 gradient 计算出来,这是一般的分类问题。RL 唯一不同的地方是 loss 前面乘上一个 weight,这个是整场游戏的时候得到的 total reward R, 它并不是在 state s 采取 action a 的时候得到的 reward。 你要把你的每一笔 training data,都 weighted by 这个 R。然后你用 TensorFlow 或 PyTorch 去帮你算 gradient 就结束了,跟一般 classification 差不多。 -我们先看一下下面这项这个算出来到底是什么的东西。 -$$ -\operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right) -$$ +## Tips +这边有一些在实现的时候,你也许用得上的 tip。 +### Tip 1: Add a Baseline ![](img/4.11.png) -上图的横轴是 $\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$,纵轴是 clip function 实际的输出。 - -* 如果 $\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$ 大于$1+\varepsilon$,输出就是$1+\varepsilon$。 -* 如果小于 $1-\varepsilon$, 它输出就是 $1-\varepsilon$。 -* 如果介于 $1+\varepsilon$ 跟 $1-\varepsilon$ 之间, 就是输入等于输出。 +第一个 tip 是 add 一个 baseline。add baseline 是什么意思呢?如果 given state s 采取 action a 会给你整场游戏正面的 reward,就要增加它的概率。如果 state s 执行 action a,整场游戏得到负的 reward,就要减少这一项的概率。 +但在很多游戏里面, reward 总是正的,就是说最低都是 0。比如说打乒乓球游戏, 你的分数就是介于 0 到 21 分之间,所以这个 R 总是正的。假设你直接套用这个式子, 在 training 的时候,告诉 model 说,不管是什么 action 你都应该要把它的概率提升。 在理想上,这么做并不一定会有问题。因为虽然说 R 总是正的,但它正的量总是有大有小,你在玩乒乓球那个游戏里面,得到的 reward 总是正的,但它是介于 0~21分之间,有时候你采取某些 action 可能是得到 0 分,采取某些 action 可能是得到 20 分。 ![](img/4.12.png) - $\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$ 是绿色的线,$\operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right)$ 是蓝色的线。在绿色的线跟蓝色的线中间,我们要取一个最小的。假设前面乘上的这个 term A,它是大于0 的话,取最小的结果,就是红色的这一条线。 - -![](img/4.13.png) - -如果 A 小于0 的话,取最小的以后,就得到红色的这一条线。 -这一个式子虽然看起来有点复杂,implement 起来是蛮简单的,因为这个式子想要做的事情就是希望 $p_{\theta}(a_{t} | s_{t})$ 跟$p_{\theta^k}(a_{t} | s_{t})$,也就是你拿来做 demonstration 的那个model, 跟你实际上 learn 的 model,在optimize 以后不要差距太大。那你要怎么让它做到不要差距太大呢? - -如果 A 大于 0,也就是某一个 state-action 的pair 是好的。那我们希望增加这个state-action pair 的概率。也就是说,我们想要让 $p_{\theta}(a_{t} | s_{t})$ 越大越好,但它跟 $p_{\theta^k}(a_{t} | s_{t})$ 的比值不可以超过 $1+\varepsilon$。如果超过$1+\varepsilon$ 的话,就没有benefit 了。红色的线就是我们的objective function,我们希望objective 越大越好,我们希望 $p_{\theta}(a_{t} | s_{t})$ 越大越好。但是$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$只要大过 $1+\varepsilon$,就没有benefit 了。 - -所以今天在train 的时候,当$p_{\theta}(a_{t} | s_{t})$ 被 train 到$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$大于 $1+\varepsilon$ 时,它就会停止。 - -假设 $p_{\theta}(a_{t} | s_{t})$ 比 $p_{\theta^k}(a_{t} | s_{t})$ 还要小,那我们的目标是要让 $p_{\theta}(a_{t} | s_{t})$ 越大越好。 - -* 假设这个 advantage 是正的,我们希望$p_{\theta}(a_{t} | s_{t})$ 越大越好。假设这个 action 是好的,我们当然希望这个 action 被采取的概率越大越好。所以假设 $p_{\theta}(a_{t} | s_{t})$ 还比 $p_{\theta^k}(a_{t} | s_{t})$ 小,那就尽量把它挪大,但只要大到$1+\varepsilon$ 就好。 -* 负的时候也是一样,如果某一个state-action pair 是不好的,我们希望把 $p_{\theta}(a_{t} | s_{t})$ 减小。如果 $p_{\theta}(a_{t} | s_{t})$ 比$p_{\theta^k}(a_{t} | s_{t})$ 还大,那你就尽量把它压小,压到$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$是$1-\epsilon$ 的时候就停了,就不要再压得更小。 - -这样的好处就是, 你不会让 $p_{\theta}(a_{t} | s_{t})$ 跟 $p_{\theta^k}(a_{t} | s_{t})$ 差距太大。要 implement 这个东西,很简单。 +假设你有 3 个 action a/b/c 可以执行,在某一个 state 有 3 个 action a/b/c可以执行。根据这个式子,你要把这 3 项的概率, log probability 都拉高。 但是它们前面 weight 的这个 R 是不一样的。 R 是有大有小的,weight 小的,它上升的就少,weight 多的,它上升的就大一点。 因为这个 log probability,它是一个概率,所以action a、b、c 的和要是 0。 所以上升少的,在做完 normalize 以后, 它其实就是下降的,上升的多的,才会上升。 -![](img/4.14.png) -上图是 PPO 跟其它方法的比较。Actor-Critic 和 A2C+Trust Region 方法是actor-critic based 的方法。PPO 是紫色线的方法,这边每张图就是某一个RL 的任务,你会发现说在多数的cases 里面,PPO 都是不错的,不是最好的,就是第二好的。 + ![1](img/4.13.png) + + +这个是一个理想上的状况,但是实际上,我们是在做 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 不要总是正的。 + +![1.](img/4.14.png) + +为了解决 reward 总是正的这个问题,你可以把 reward 减掉一项叫做 b,这项 b 叫做 baseline。你减掉这项 b 以后,就可以让 $R(\tau^n)-b$ 这一项, 有正有负。 所以如果得到的 total reward $R(\tau^n)$ 大于 b 的话,就让它的概率上升。如果这个 total reward 小于 b,就算它是正的,正的很小也是不好的,你就要让这一项的概率下降。 如果$R(\tau^n) 注:李宏毅深度强化学习课程提到的 Q-learning,其实是 DQN。 -> -> DQN 是指基于深度学习的 Q-learning 算法,主要结合了`价值函数近似(Value Function Approximation)`与神经网络技术,并采用了目标网络和经历回放的方法进行网络的训练。 -> -> 在 Q-learning 中,我们使用表格来存储每个状态 s 下采取动作 a 获得的奖励,即状态-动作值函数 $Q(s,a)$。然而,这种方法在状态量巨大甚至是连续的任务中,会遇到维度灾难问题,往往是不可行的。因此,DQN 采用了价值函数近似的表示方法。 - -举例来说,有一种 critic 叫做 `state value function`。State value function 的意思就是说,假设 actor 叫做 $\pi$,拿 $\pi$ 跟环境去做互动。假设 $\pi$ 看到了某一个state s,如果在玩 Atari 游戏的话,state s 是某一个画面,看到某一个画面的时候,接下来一直玩到游戏结束,累积的 reward 的期望值有多大。所以 $V^{\pi}$ 是一个function,这个 function input 一个 state,然后它会 output 一个 scalar。这个 scalar 代表说,$\pi$ 这个 actor 看到 state s 的时候,接下来预期到游戏结束的时候,它可以得到多大的 value。 - -举个例子,假设你是玩 space invader 的话, - -* 左边这个 state s,这一个游戏画面,你的 $V^{\pi}(s)$ 也许会很大,因为还有很多的怪可以杀, 所以你会得到很大的分数。一直到游戏结束的时候,你仍然有很多的分数可以吃。 -* 右边那个case,也许你得到的 $V^{\pi}(s)$ 就很小,因为剩下的怪也不多了,并且红色的防护罩已经消失了,所以可能很快就会死掉。所以接下来得到预期的 reward,就不会太大。 - -这边需要强调的一个点是说,当你在讲这一个 critic 的时候,critic 都是绑一个 actor 的,critic 没有办法去凭空去 evaluate 一个 state 的好坏,它所 evaluate 的东西是在给定某一个 state 的时候, 假设接下来互动的 actor 是 $\pi$,那我会得到多少 reward。因为就算是给同样的 state,你接下来的 $\pi$ 不一样,你得到的 reward 也是不一样的。举例来说,在左边那个case,虽然假设是一个正常的 $\pi$,它可以杀很多怪,那假设他是一个很弱的 $\pi$,它就站在原地不动,然后马上就被射死了,那你得到的 V 还是很小。所以 critic output 值有多大,其实是取决于两件事:state 和 actor。所以你的 critic 其实都要绑一个 actor,它是在衡量某一个 actor 的好坏,而不是 generally 衡量一个 state 的好坏。这边要强调一下,critic output 是跟 actor 有关的,state value 其实是 depend on 你的 actor。当你的 actor 变的时候,state value function 的output 其实也是会跟着改变的。 - -### State-value Function Bellman Equation - -记策略 $\pi $ 的状态值函数为 $V^{\pi}(s_t)$ ,它表示在状态 $s_t$ 下带来的累积奖励 $G_t$ 的期望,具体公式为: $$ -\begin{aligned} V ^ { \pi } \left( s _ { t } \right) & = \mathbb { E } \left[ G _ { t } \mid s _ { t } \right] \\ & = \mathbb { E } \left[ r _ { t } + \gamma r _ { t + 1 } + \gamma ^ { 2 } r _ { t + 2 } + \cdots \mid s _ { t } \right] \\ & = \mathbb { E } \left[ r _ { t } + \gamma \left( r _ { t + 1 } + \gamma r _ { t + 2 } + \cdots \right) \mid s _ { t } \right] \\ -&= \mathbb{E}[r_t|s_t]+ \gamma\mathbb{E}[r_{t+1}+\gamma r_{t+2}+\cdots|s_t] \\ -& =\mathbb{E}[r_t|s_t]+ \gamma\mathbb{E}[G_{t+1}|s_t] -\\& = \mathbb { E } \left[ r _ { t } + \gamma V ^ { \pi } \left( s _ { t + 1 } \right) \mid s _ { t} \right] \end{aligned} +\nabla \bar{R}_{\theta}=E_{\tau \sim p_{\theta}(\tau)}\left[R(\tau) \nabla \log p_{\theta}(\tau)\right] $$ -上式是 State-value Function 的 Bellman Equation。 - -### State Value Function Estimation - +问题是上面这个 update 的式子中的 $E_{\tau \sim p_{\theta}(\tau)}$ 应该是你现在的 policy $\theta$ 所 sample 出来的 trajectory $\tau$ 做 expectation。一旦 update 了参数,从 $\theta$ 变成 $\theta'$ ,$p_\theta(\tau)$这个概率就不对了,之前sample 出来的 data 就变的不能用了。所以 policy gradient 是一个会花很多时间来 sample data 的 algorithm,你会发现大多数时间都在 sample data,agent 去跟环境做互动以后,接下来就要 update 参数。你只能 update 参数一次。接下来你就要重新再去 collect data, 然后才能再次update 参数,这显然是非常花时间的。所以我们想要从 on-policy 变成 off-policy。 这样做就可以用另外一个policy, 另外一个actor $\theta'$ 去跟环境做互动。用 $\theta'$ collect 到的data 去训练 $\theta$。假设我们可以用 $\theta'$ collect 到的data 去训练 $\theta$,意味着说我们可以把$\theta'$ collect 到的data 用非常多次。我们可以执行 gradient ascent 好几次,我们可以 update 参数好几次, 都只要用同一笔data 就好了。因为假设 $\theta$ 有能力学习另外一个actor $\theta'$ 所 sample 出来的 data 的话, 那$\theta'$ 就只要sample 一次,也许sample 多一点的data, 让$\theta$ 去update 很多次,这样就会比较有效率。 ![](img/5.2.png) -怎么衡量这个 state value function $V^{\pi}(s)$ 呢?有两种不同的做法。一个是用` Monte-Carlo(MC) based` 的方法。MC based 的方法就是让 actor 去跟环境做互动,你要看 actor 好不好, 你就让 actor 去跟环境做互动,给 critic 看。然后,critic 就统计说,actor 如果看到 state $s_a$,接下来 accumulated reward 会有多大。如果它看到 state $s_b$,接下来accumulated reward 会有多大。但是实际上,你不可能把所有的state 通通都扫过。如果你是玩 Atari 游戏的话,你的 state 是 image ,你没有办法把所有的state 通通扫过。所以实际上我们的 $V^{\pi}(s)$ 是一个 network。对一个 network 来说,就算是 input state 是从来都没有看过的,它也可以想办法估测一个 value 的值。 +具体怎么做呢?这边就需要介绍 `important sampling` 的概念。假设你有一个function $f(x)$,你要计算从 p 这个 distribution sample x,再把 x 带到 f 里面,得到$f(x)$。你要该怎么计算这个 $f(x)$ 的期望值?假设你不能对 p 这个distribution 做积分的话,那你可以从 p 这个 distribution 去 sample 一些data $x^i$。把 $x^i$ 代到 $f(x)$ 里面,然后取它的平均值,就可以近似 $f(x)$ 的期望值。 -怎么训练这个 network 呢?因为如果在state $s_a$,接下来的 accumulated reward 就是 $G_a$。也就是说,对这个 value function 来说,如果 input 是 state $s_a$,正确的 output 应该是$G_a$。如果 input state $s_b$,正确的output 应该是value $G_b$。所以在 training 的时候, 它就是一个 `regression problem`。Network 的 output 就是一个 value,你希望在 input $s_a$ 的时候,output value 跟 $G_a$ 越近越好,input $s_b$ 的时候,output value 跟 $G_b$ 越近越好。接下来把 network train 下去,就结束了。这是第一个方法,MC based 的方法。 +现在有另外一个问题,我们没有办法从 p 这个 distribution 里面 sample data。假设我们不能从 p sample data,只能从另外一个 distribution q 去 sample data,q 可以是任何 distribution。我们不能够从 p 去sample data,但可以从 q 去 sample $x$。我们从 q 去 sample $x^i$ 的话就不能直接套下面的式子。 +$$ +E_{x \sim p}[f(x)] \approx \frac{1}{N} \sum_{i=1}^N f(x^i) +$$ +因为上式是假设你的 $x$ 都是从 p sample 出来的。所以做一个修正,修正是这样子的。期望值$E_{x \sim p}[f(x)]$其实就是$\int f(x) p(x) dx$,我们对其做如下的变换: +$$ +\int f(x) p(x) d x=\int f(x) \frac{p(x)}{q(x)} q(x) d x=E_{x \sim q}[f(x){\frac{p(x)}{q(x)}}] +$$ +我们就可以写成对 q 里面所 sample 出来的 x 取期望值。我们从q 里面 sample x,然后再去计算$f(x) \frac{p(x)}{q(x)}$,再去取期望值。所以就算我们不能从 p 里面去 sample data,只要能够从 q 里面去sample data,然后代入上式,你就可以计算从 p 这个distribution sample x 代入 f 以后所算出来的期望值。 + +这边是从 q 做 sample,所以从 q 里 sample 出来的每一笔data,你需要乘上一个 weight 来修正这两个 distribution 的差异,weight 就是$\frac{p(x)}{q(x)}$。$q(x)$ 可以是任何 distribution,唯一的限制就是 $q(x)$ 的概率是 0 的时候,$p(x)$ 的概率不为 0,不然这样会没有定义。假设 $q(x)$ 的概率是 0 的时候,$p(x)$ 的概率也都是 0 的话,那这样 $p(x)$ 除以 $q(x)$是有定义的。所以这个时候你就可以 apply important sampling 这个技巧。你就可以从 p 做 sample 换成从 q 做 sample。 ![](img/5.3.png) -第二个方法是`Temporal-difference(时序差分)` 的方法, `即 TD based ` 的方法。在 MC based 的方法中,每次我们都要算 accumulated reward,也就是从某一个 state $s_a$ 一直玩到游戏结束的时候,得到的所有 reward 的总和。所以你要 apply MC based 的 approach,你必须至少把这个游戏玩到结束。但有些游戏非常的长,你要玩到游戏结束才能够 update network,花的时间太长了。因此我们会采用 TD based 的方法。TD based 的方法不需要把游戏玩到底,只要在游戏的某一个情况,某一个 state $s_t$ 的时候,采取 action $a_t$ 得到 reward $r_t$ ,跳到 state $s_{t+1}$,就可以 apply TD 的方法。 +Important sampling 有一些 issue。虽然理论上你可以把 p 换成任何的 q。但是在实现上, p 和 q 不能够差太多。差太多的话,会有一些问题。什么样的问题呢? -怎么 apply TD 的方法呢?这边是基于以下这个式子: $$ -V^{\pi}\left(s_{t}\right)=V^{\pi}\left(s_{t+1}\right)+r_{t} +E_{x \sim p}[f(x)]=E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] +$$ +虽然上式成立。但上式左边是$f(x)$ 的期望值,它的distribution 是 p,上式右边是$f(x) \frac{p(x)}{q(x)}$ 的期望值,它的distribution 是 q。如果不是算期望值,而是算 variance 的话。这两个variance 是不一样的。两个 random variable 的 mean 一样,并不代表它的 variance 一样。 + +我们可以代一下方差的公式 +$$ +\operatorname{Var}_{x \sim p}[f(x)]=E_{x \sim p}\left[f(x)^{2}\right]-\left(E_{x \sim p}[f(x)]\right)^{2} $$ -假设我们现在用的是某一个 policy $\pi$,在 state $s_t$,它会采取 action $a_t$,给我们 reward $r_t$ ,接下来进入$s_{t+1}$ 。state $s_{t+1}$ 的 value 跟 state $s_t$ 的 value,它们的中间差了一项 $r_t$。因为你把 $s_{t+1}$ 得到的 value 加上得到的 reward $r_t$ 就会等于 $s_t$ 得到的 value。有了这个式子以后,你在 training 的时候,你并不是直接去估测 V,而是希望你得到的结果 V 可以满足这个式子。也就是说你会是这样 train 的,你把 $s_t$ 丢到 network 里面,因为 $s_t$ 丢到 network 里面会得到 $V^{\pi}(s_t)$,把 $s_{t+1}$ 丢到你的 value network 里面会得到$V^{\pi}(s_{t+1})$,这个式子告诉我们,$V^{\pi}(s_t)$ 减 $V^{\pi}(s_{t+1})$ 的值应该是 $r_t$。然后希望它们两个相减的 loss 跟 $r_t$ 越接近,train 下去,update V 的参数,你就可以把 V function learn 出来。 +$$ +\begin{aligned} +\operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right] &=E_{x \sim q}\left[\left(f(x) \frac{p(x)}{q(x)}\right)^{2}\right]-\left(E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]\right)^{2} \\ +&=E_{x \sim p}\left[f(x)^{2} \frac{p(x)}{q(x)}\right]-\left(E_{x \sim p}[f(x)]\right)^{2} +\end{aligned} +$$ + +$\operatorname{Var}_{x \sim p}[f(x)]$ 和 $\operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$ 的差别在第一项是不同的, $\operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$ 的第一项多乘了$\frac{p(x)}{q(x)}$,如果$\frac{p(x)}{q(x)}$ 差距很大的话, $\operatorname{Var}_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$的 variance 就会很大。所以虽然理论上它们的expectation 一样,也就是说,你只要对 p 这个distribution sample 够多次,q 这个distribution sample 够多,你得到的结果会是一样的。但是假设你sample 的次数不够多,因为它们的variance 差距是很大的,所以你就有可能得到非常大的差别。 ![](img/5.4.png) -MC 跟 TD 有什么样的差别呢?**MC 最大的问题就是 variance 很大**。因为我们在玩游戏的时候,它本身是有随机性的。所以你可以把 $G_a$ 看成一个 random 的 variable。因为你每次同样走到 $s_a$ 的时候,最后你得到的 $G_a$ 其实是不一样的。你看到同样的state $s_a$,最后玩到游戏结束的时候,因为游戏本身是有随机性的,玩游戏的 model 搞不好也有随机性,所以你每次得到的 $G_a$ 是不一样的,每一次得到$G_a$ 的差别其实会很大。为什么它会很大呢?因为 $G_a$ 其实是很多个不同的 step 的 reward 的和。假设你每一个step 都会得到一个reward,$G_a$ 是从 state $s_a$ 开始,一直玩到游戏结束,每一个timestamp reward 的和。 +举个例子,当 $p(x)$ 和 $q(x)$ 差距很大的时候,会发生什么样的问题。假设蓝线是 $p(x)$ 的distribution,绿线是 $q(x)$ 的 distribution,红线是 $f(x)$。如果我们要计算$f(x)$的期望值,从 $p(x)$ 这个distribution 做 sample 的话,那显然 $E_{x \sim p}[f(x)]$ 是负的,因为左边那块区域 $p(x)$ 的概率很高,所以要 sample 的话,都会 sample 到这个地方,而 $f(x)$ 在这个区域是负的, 所以理论上这一项算出来会是负。 -举例来说,我在右上角就列一个式子是说, - -$$ -\operatorname{Var}[k X]=k^{2} \operatorname{Var}[X] -$$ -Var 就是指 variance。 -通过这个式子,我们知道 $G_a$ 的 variance 相较于某一个 state 的 reward,它会是比较大的,$G_a$ 的variance 是比较大的。 - -如果用 TD 的话,你是要去 minimize 这样的一个式子: +接下来我们改成从 $q(x)$ 这边做 sample,因为 $q(x)$ 在右边这边的概率比较高,所以如果你sample 的点不够的话,那你可能都只sample 到右侧。如果你都只 sample 到右侧的话,你会发现说,算 $E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$这一项,搞不好还应该是正的。你这边sample 到这些点,然后你去计算它们的$f(x) \frac{p(x)}{q(x)}$都是正的,所以你sample 到这些点都是正的。 你取期望值以后,也都是正的。为什么会这样,因为你 sample 的次数不够多,因为假设你sample 次数很少,你只能sample 到右边这边。左边这边虽然概率很低,但也不是没有可能被 sample 到。假设你今天好不容易 sample 到左边的点,因为左边的点,$p(x)$ 和 $q(x)$ 是差很多的, 这边 $p(x)$ 很小,$q(x)$ 很大。今天 $f(x)$ 好不容易终于 sample 到一个负的,这个负的就会被乘上一个非常大的 weight ,这样就可以平衡掉刚才那边一直 sample 到 positive 的 value 的情况。最终你算出这一项的期望值,终究还是负的。但前提是你要sample 够多次,这件事情才会发生。但有可能sample 不够,$E_{x \sim p}[f(x)]$跟$E_{x \sim q}\left[f(x) \frac{p(x)}{q(x)}\right]$就有可能有很大的差距。这就是 importance sampling 的问题。 ![](img/5.5.png) -在这中间会有随机性的是 r。因为计算你在 $s_t$ 采取同一个 action,你得到的 reward 也不一定是一样的,所以 r 是一个 random variable。但这个 random variable 的 variance 会比 $G_a$ 还要小,因为 $G_a$ 是很多 r 合起来,这边只是某一个 r 而已。$G_a$ 的 variance 会比较大,r 的 variance 会比较小。但是这边你会遇到的**一个问题是你这个 V 不一定估得准**。假设你的这个 V 估得是不准的,那你 apply 这个式子 learn 出来的结果,其实也会是不准的。所以 MC 跟 TD各有优劣。**今天其实 TD 的方法是比较常见的,MC 的方法其实是比较少用的。** +现在要做的事情就是把 importance sampling 用在 off-policy 的 case。把 on-policy training 的algorithm 改成 off-policy training 的 algorithm。怎么改呢,之前我们是拿 $\theta$ 这个policy 去跟环境做互动,sample 出trajectory $\tau$,然后计算$R(\tau) \nabla \log p_{\theta}(\tau)$。 + +现在我们不用$\theta$ 去跟环境做互动,假设有另外一个 policy $\theta'$,它就是另外一个actor。它的工作是他要去做demonstration,$\theta'$ 的工作是要去示范给$\theta$ 看。它去跟环境做互动,告诉 $\theta$ 说,它跟环境做互动会发生什么事。然后,借此来训练$\theta$。我们要训练的是$\theta$ ,$\theta'$ 只是负责做 demo,负责跟环境做互动。 + +我们现在的$\tau$ 是从 $\theta'$ sample 出来的,是拿 $\theta'$ 去跟环境做互动。所以sample 出来的 $\tau$ 是从 $\theta'$ sample 出来的,这两个distribution 不一样。但没有关系,假设你本来是从 p 做sample,但你发现你不能够从 p 做sample,所以我们不拿$\theta$ 去跟环境做互动。你可以把 p 换 q,然后在后面这边补上一个 importance weight。现在的状况就是一样,把 $\theta$ 换成 $\theta'$ 后,要补上一个importance weight $\frac{p_{\theta}(\tau)}{p_{\theta^{\prime}}(\tau)}$。这个 importance weight 就是某一个 trajectory $\tau$ 用 $\theta$ 算出来的概率除以这个 trajectory $\tau$,用$\theta'$ 算出来的概率。这一项是很重要的,因为今天你要learn 的是actor $\theta$ 和 $\theta'$ 是不太一样的。$\theta'$ 会见到的情形跟 $\theta$ 见到的情形不见得是一样的,所以中间要做一个修正的项。 + +现在的data 不是从$\theta$ sample 出来,是从 $\theta'$ sample 出来的。从$\theta$ 换成$\theta'$ 有什么好处呢?因为现在跟环境做互动是$\theta'$ 而不是$\theta$。所以 sample 出来的东西跟 $\theta$ 本身是没有关系的。所以你就可以让 $\theta'$ 做互动 sample 一大堆的data,$\theta$ 可以update 参数很多次。然后一直到 $\theta$ train 到一定的程度,update 很多次以后,$\theta'$ 再重新去做sample,这就是on-policy 换成off-policy 的妙用。 ![](img/5.6.png) -上图是讲 TD 跟 MC 的差异。假设有某一个 critic,它去观察某一个 policy $\pi$ 跟环境互动的 8 个 episode 的结果。有一个actor $\pi$ 跟环境互动了8 次,得到了8 次玩游戏的结果。接下来这个 critic 去估测 state 的 value。 -* 我们看看 $s_b$ 的 value 是多少。$s_b$ 这个state 在 8 场游戏里面都有经历过,其中有6 场得到 reward 1,有两场得到 reward 0,所以如果你是要算期望值的话,就看到 state $s_b$ 以后得到的 reward,一直到游戏结束的时候得到的 accumulated reward 期望值是 3/4。 -* 但 $s_a$ 期望的 reward 到底应该是多少呢?这边其实有两个可能的答案:一个是 0,一个是 3/4。为什么有两个可能的答案呢?这取决于你用MC 还是TD。用 MC 跟用 TD 算出来的结果是不一样的。 - -假如你用 MC 的话,你会发现这个$s_a$ 就出现一次,看到$s_a$ 这个state,接下来 accumulated reward 就是 0。所以今天 $s_a$ expected reward 就是 0。 - -但 TD 在计算的时候,它要update 下面这个式子。 +实际在做 policy gradient 的时候,我们并不是给整个 trajectory $\tau$ 都一样的分数,而是每一个state-action 的pair 会分开来计算。实际上 update gradient 的时候,我们的式子是长这样子的。 $$ -V^{\pi}\left(s_{a}\right)=V^{\pi}\left(s_{b}\right)+r +=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta}}\left[A^{\theta}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] $$ -因为我们在 state $s_a$ 得到 reward r=0 以后,跳到 state $s_b$。所以 state $s_b$ 的 reward 会等于 state $s_b$ 的 reward 加上在state $s_a$ 跳到 state $s_b$ 的时候可能得到的 reward r。而这个得到的 reward r 的值是 0,$s_b$ expected reward 是3/4,那$s_a$ 的reward 应该是3/4。 +我们用 $\theta$ 这个actor 去sample 出$s_t$ 跟$a_t$,sample 出state 跟action 的pair,我们会计算这个state 跟action pair 它的advantage, 就是它有多好。$A^{\theta}\left(s_{t}, a_{t}\right)$就是 accumulated 的 reward 减掉 bias,这一项就是估测出来的。它要估测的是,在state $s_t$ 采取action $a_t$ 是好的,还是不好的。那接下来后面会乘上$\nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)$,也就是说如果$A^{\theta}\left(s_{t}, a_{t}\right)$是正的,就要增加概率, 如果是负的,就要减少概率。 -用 MC 跟 TD 估出来的结果,其实很有可能是不一样的。就算 critic 观察到一样的 training data,它最后估出来的结果。也不见得会是一样。那为什么会这样呢?你可能问说,那一个比较对呢?其实就都对。 +那现在用了 importance sampling 的技术把 on-policy 变成 off-policy,就从 $\theta$ 变成 $\theta'$。所以现在$s_t$、$a_t$ 是$\theta'$ ,另外一个actor 跟环境互动以后所 sample 到的data。 但是拿来训练要调整参数是 model $\theta$。因为 $\theta'$ 跟 $\theta$ 是不同的model,所以你要做一个修正的项。这项修正的项,就是用 importance sampling 的技术,把$s_t$、$a_t$ 用 $\theta$ sample 出来的概率除掉$s_t$、$a_t$ 用 $\theta'$ sample 出来的概率。 -因为在第一个 trajectory, $s_a$ 得到 reward 0 以后,再跳到 $s_b$ 也得到 reward 0。这边有两个可能。 +$$ +=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{P_{\theta}\left(s_{t}, a_{t}\right)}{P_{\theta^{\prime}}\left(s_{t}, a_{t}\right)} A^{\theta}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] +$$ -* 一个可能是$s_a$,它就是一个带 sign 的 state,所以只要看到 $s_a$ 以后,$s_b$ 就会拿不到reward,有可能$s_a$ 其实影响了$s_b$。如果是用 MC 的算法的话,它会把 $s_a$ 影响 $s_b$ 这件事考虑进去。所以看到 $s_a$ 以后,接下来 $s_b$ 就得不到 reward,所以看到$s_a$ 以后,期望的reward 是 0。 +这边 $A^{\theta}(s_t,a_t)$ 有一个上标 $\theta$,$\theta$ 代表说这个是 actor $\theta$ 跟环境互动的时候所计算出来的 A。但是实际上从 $\theta$ 换到 $\theta'$ 的时候,$A^{\theta}(s_t,a_t)$ 应该改成 $A^{\theta'}(s_t,a_t)$,为什么?A 这一项是想要估测说现在在某一个 state 采取某一个 action,接下来会得到 accumulated reward 的值减掉base line 。你怎么估 A 这一项,你就会看在 state $s_t$,采取 action $a_t$,接下来会得到的reward 的总和,再减掉baseline。之前是 $\theta$ 在跟环境做互动,所以你观察到的是 $\theta$ 可以得到的reward。但现在是 $\theta'$ 在跟环境做互动,所以你得到的这个advantage, 其实是根据 $\theta'$ 所estimate 出来的advantage。但我们现在先不要管那么多, 我们就假设这两项可能是差不多的。 -* 另一个可能是,看到$s_a$ 以后, $s_b$ 的 reward 是0 这件事只是一个巧合,就并不是 $s_a$ 所造成,而是因为说 $s_b$ 有时候就是会得到 reward 0,这只是单纯运气的问题。其实平常 $s_b$ 会得到 reward 期望值是 3/4,跟 $s_a$ 是完全没有关系的。所以假设 $s_a$ 之后会跳到 $s_b$,那其实得到的 reward 按照 TD 来算应该是 3/4。 +那接下来,我们可以拆解 $p_{\theta}\left(s_{t}, a_{t}\right)$ 和 $p_{\theta'}\left(s_{t}, a_{t}\right)$,即 +$$ +\begin{aligned} +p_{\theta}\left(s_{t}, a_{t}\right)&=p_{\theta}\left(a_{t}|s_{t}\right) p_{\theta}(s_t) \\ +p_{\theta'}\left(s_{t}, a_{t}\right)&=p_{\theta'}\left(a_{t}|s_{t}\right) p_{\theta'}(s_t) +\end{aligned} +$$ +于是我们得到下式: +$$ +=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} \frac{p_{\theta}\left(s_{t}\right)}{p_{\theta^{\prime}}\left(s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] +$$ -所以不同的方法考虑了不同的假设,运算结果不同。 -## State-action Value Function +然后这边需要做一件事情是,假设 model 是 $\theta$ 的时候,你看到$s_t$ 的概率,跟 model 是$\theta'$ 的时候,你看到$s_t$ 的概率是差不多的,即$p_{\theta}(s_t)=p_{\theta'}(s_t)$。因为它们是一样的,所以你可以把它删掉,即 +$$ +=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right) \nabla \log p_{\theta}\left(a_{t}^{n} | s_{t}^{n}\right)\right] \quad(1) +$$ + +为什么可以假设它是差不多的。举例来说,会看到什么state 往往跟你会采取什么样的action 是没有太大的关系的。比如说你玩不同的 Atari 的游戏,其实你看到的游戏画面都是差不多的,所以也许不同的 $\theta$ 对 $s_t$ 是没有影响的。但是有一个更直觉的理由就是这一项到时候真的要你算,你会算吗?因为想想看这项要怎么算,这一项你还要说我有一个参数$\theta$,然后拿$\theta$ 去跟环境做互动,算$s_t$ 出现的概率,这个你根本很难算。尤其是你如果 input 是image 的话, 同样的 $s_t$ 根本就不会出现第二次。你根本没有办法估这一项, 所以干脆就无视这个问题。 + +但是 $p_{\theta}(a_t|s_t)$很好算。你手上有$\theta$ 这个参数,它就是个network。你就把$s_t$ 带进去,$s_t$ 就是游戏画面,你把游戏画面带进去,它就会告诉你某一个state 的 $a_t$ 概率是多少。我们其实有个 policy 的network,把 $s_t$ 带进去,它会告诉我们每一个 $a_t$ 的概率是多少。所以 +$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)}$ 这一项,你只要知道$\theta$ 和 $\theta'$ 的参数就可以算。 + +现在我们得到一个新的objective function。 + +$$ +J^{\theta^{\prime}}(\theta)=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)\right] +$$ + + +式(1)是 gradient,其实我们可以从 gradient 去反推原来的 objective function。这边有一个公式 + +$$ +\nabla f(x)=f(x) \nabla \log f(x) +$$ + +我们可以用这个公式来反推objective function,要注意一点,对 $\theta$ 求梯度时,$p_{\theta^{\prime}}(a_{t} | s_{t})$ 和 $A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)$ 都是常数。 + + +所以实际上,当我们apply importance sampling 的时候,要去optimize 的那一个objective function 就长这样子,我们把它写作$J^{\theta^{\prime}}(\theta)$。为什么写成$J^{\theta^{\prime}}(\theta)$ 呢,这个括号里面那个$\theta$ 代表我们要去optimize 的那个参数。$\theta'$ 是说我们拿 $\theta'$ 去做demonstration,就是现在真正在跟环境互动的是$\theta'$。因为 $\theta$ 不跟环境做互动,是 $\theta'$ 在跟环境互动。 + +然后你用$\theta'$ 去跟环境做互动,sample 出$s_t$、$a_t$ 以后,你要去计算$s_t$ 跟$a_t$ 的advantage,然后你再去把它乘上$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)}$。$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)}$是好算的,$A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)$ 可以从这个 sample 的结果里面去估测出来的,所以 $J^{\theta^{\prime}}(\theta)$ 是可以算的。实际上在 update 参数的时候,就是按照式(1) 来 update 参数。 + + + +## PPO ![](img/5.7.png) -还有另外一种critic,这种critic 叫做 `Q-function`。它又叫做`state-action value function`。 +我们可以把 on-policy 换成 off-policy,但 importance sampling 有一个 issue,如果 $p_{\theta}\left(a_{t} | s_{t}\right)$ 跟 $p_{\theta'}\left(a_{t} | s_{t}\right)$ 差太多的话,这两个 distribution 差太多的话,importance sampling 的结果就会不好。怎么避免它差太多呢?这个就是 `Proximal Policy Optimization (PPO) ` 在做的事情。它实际上做的事情就是这样,在 off-policy 的方法里要optimize 的是 $J^{\theta^{\prime}}(\theta)$。但是这个 objective function 又牵涉到 importance sampling。在做 importance sampling 的时候,$p_{\theta}\left(a_{t} | s_{t}\right)$ 不能跟 $p_{\theta'}\left(a_{t} | s_{t}\right)$差太多。你做 demonstration 的 model 不能够跟真正的 model 差太多,差太多的话 importance sampling 的结果就会不好。我们在 training 的时候,多加一个 constrain。这个constrain 是 $\theta$ 跟 $\theta'$ output 的 action 的 KL divergence,简单来说,这一项的意思就是要衡量说 $\theta$ 跟 $\theta'$ 有多像。 -* state value function 的 input 是一个 state,它是根据 state 去计算出,看到这个state 以后的 expected accumulated reward 是多少。 -* state-action value function 的 input 是一个 state 跟 action 的 pair,它的意思是说,在某一个 state 采取某一个action,假设我们都使用 actor $\pi$ ,得到的 accumulated reward 的期望值有多大。 +然后我们希望在 training 的过程中,learn 出来的 $\theta$ 跟 $\theta'$ 越像越好。因为如果 $\theta$ 跟 $\theta'$ 不像的话,最后的结果就会不好。所以在 PPO 里面有两个式子,一方面是 optimize 本来要 optimize 的东西,但再加一个 constrain。这个 constrain 就好像那个 regularization 的 term 一样,在做 machine learning 的时候不是有 L1/L2 的regularization。这一项也很像 regularization,这样 regularization 做的事情就是希望最后 learn 出来的 $\theta$ 不要跟 $\theta'$ 太不一样。 -Q-function 有一个需要注意的问题是,这个 actor $\pi$,在看到 state s 的时候,它采取的 action 不一定是 a。Q-function 假设在 state s 强制采取 action a。不管你现在考虑的这个 actor $\pi$, 它会不会采取 action a,这不重要。在state s 强制采取 action a。接下来都用 actor $\pi$ 继续玩下去,就只有在 state s,我们才强制一定要采取 action a,接下来就进入自动模式,让actor $\pi$ 继续玩下去,得到的 expected reward 才是$Q^{\pi}(s,a)$ 。 +PPO 有一个前身叫做TRPO,TRPO 的式子如下式所示。 +$$ +\begin{aligned} +J_{T R P O}^{\theta^{\prime}}(\theta)=E_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} | s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)\right] \\ \\ +\mathrm{KL}\left(\theta, \theta^{\prime}\right)<\delta +\end{aligned} +$$ -Q-function 有两种写法: +它与PPO不一样的地方 是 constrain 摆的位置不一样,PPO是直接把 constrain 放到你要 optimize 的那个式子里面,然后你就可以用 gradient ascent 的方法去 maximize 这个式子。但 TRPO 是把 KL divergence 当作constrain,它希望 $\theta$ 跟 $\theta'$ 的 KL divergence 小于一个$\delta$。如果你是用 gradient based optimization 时,有 constrain 是很难处理的。 -* input 是 state 跟action,output 就是一个 scalar; -* input 是一个 state s,output 就是好几个 value。 +PPO是很难处理的,因为它是把 KL divergence constrain 当做一个额外的 constrain,没有放 objective 里面,所以它很难算。所以不想搬石头砸自己的脚的话, 你就用PPO 不要用TRPO。看文献上的结果是,PPO 跟TRPO 可能 performance 差不多,但 PPO 在实现上比 TRPO 容易的多。 -假设 action 是 discrete 的,action 就只有3 个可能,往左往右或是开火。那这个 Q-function output 的3 个 values 就分别代表 a 是向左的时候的 Q value,a 是向右的时候的Q value,还有 a 是开火的时候的 Q value。 +KL divergence 到底指的是什么?这边我是直接把 KL divergence 当做一个 function,input 是 $\theta$ 跟 $\theta'$,但我的意思并不是说把 $\theta$ 或 $\theta'$ 当做一个distribution,算这两个distribution 之间的距离,我不是这个意思。所谓的 $\theta$ 跟 $\theta'$ 的距离并不是参数上的距离,而是 behavior 上的距离。 -那你要注意的事情是,上图右边的 function 只有discrete action 才能够使用。如果 action 是无法穷举的,你只能够用上图左边这个式子,不能够用右边这个式子。 +假设你有一个model,有一个actor 它是$\theta$,你有另外一个actor 的参数是$\theta'$ ,所谓参数上的距离就是你算这两组参数有多像。我今天所讲的不是参数上的距离, 而是它们行为上的距离。就是你先带进去一个state s,它会对这个 action 的 space output 一个 distribution。假设你有 3 个actions,3 个可能的 actions 就 output 3 个值。那今天所指的 distance 是behavior distance。也就是说,给同样的 state 的时候,输出 action 之间的差距。这两个 actions 的 distribution 都是一个概率分布。所以就可以计算这两个概率分布的 KL divergence。把不同的 state output 的这两个 distribution 的KL divergence 平均起来才是我这边所指的两个 actor 间的 KL divergence。你可能说怎么不直接算这个 $\theta$ 或 $\theta'$ 之间的距离,甚至不要用KL divergence 算,L1 跟 L2 的 norm 也可以保证 $\theta$ 跟 $\theta'$ 很接近啊。在做reinforcement learning 的时候,之所以我们考虑的不是参数上的距离,而是 action 上的距离,是因为很有可能对 actor 来说,参数的变化跟 action 的变化不一定是完全一致的。有时候你参数小小变了一下,它可能 output 的行为就差很多。或是参数变很多,但 output 的行为可能没什么改变。**所以我们真正在意的是这个actor 它的行为上的差距,而不是它们参数上的差距。**所以在做PPO 的时候,所谓的 KL divergence 并不是参数的距离,而是action 的距离。 ![](img/5.8.png) -上图是文献上的结果,你去 estimate Q-function 的话,看到的结果可能会像是这个样子。这是什么意思呢?它说假设我们有 3 个 actions,3 个 actions 就是原地不动、向上、向下。 +我们来看一下PPO1 的algorithm。它先initial 一个policy 的参数$\theta^0$。然后在每一个iteration 里面呢,你要用参数$\theta^k$,$\theta^k$ 就是你在前一个training 的iteration得到的actor 的参数,你用$\theta^k$ 去跟环境做互动,sample 到一大堆 state-action 的pair。 -* 假设是在第一个state,不管是采取哪个action,最后到游戏结束的时候,得到的 expected reward 其实都差不多。因为球在这个地方,就算是你向下,接下来你其实应该还来的急救,所以今天不管是采取哪一个action,就差不了太多。 - -* 假设在第二个state,这个乒乓球它已经反弹到很接近边缘的地方,这个时候你采取向上,你才能得到positive 的reward,才接的到球。如果你是站在原地不动或向下的话,接下来你都会miss 掉这个球。你得到的reward 就会是负的。 - -* 假设在第三个state,球很近了,所以就要向上。 - -* 假设在第四个state,球被反弹回去,这时候采取那个action就都没有差了。 - -这个是 state-action value 的一个例子。 +然后你根据$\theta^k$ 互动的结果,估测一下$A^{\theta^{k}}\left(s_{t}, a_{t}\right)$。然后你就 apply PPO 的 optimization 的 formulation。但跟原来的policy gradient 不一样,原来的 policy gradient 只能 update 一次参数,update 完以后,你就要重新 sample data。但是现在不用,你拿 $\theta^k$ 去跟环境做互动,sample 到这组 data 以后,你可以让 $\theta$ update 很多次,想办法去 maximize objective function。这边 $\theta$ update 很多次没有关系,因为我们已经有做 importance sampling,所以这些experience,这些 state-action 的 pair 是从 $\theta^k$ sample 出来的没有关系。$\theta$ 可以 update 很多次,它跟 $\theta^k$ 变得不太一样也没有关系,你还是可以照样训练 $\theta$。 ![](img/5.9.png) -虽然表面上我们 learn 一个 Q-function,它只能拿来评估某一个 actor $\pi$ 的好坏,但只要有了这个 Q-function,我们就可以做 reinforcement learning。有了这个 Q-function,我们就可以决定要采取哪一个 action,我们就可以进行`策略改进(Policy Improvement)`。 - -它的大原则是这样,假设你有一个初始的 actor,也许一开始很烂, 随机的也没有关系。初始的 actor 叫做 $\pi$,这个 $\pi$ 跟环境互动,会 collect data。接下来你 learn 一个 $\pi$ 这个 actor 的 Q value,你去衡量一下 $\pi$ 这个actor 在某一个 state 强制采取某一个 action,接下来用 $\pi$ 这个 policy 会得到的 expected reward,那用 TD 或 MC 也是可以的。你 learn 出一个 Q-function 以后,就保证你可以找到一个新的 policy $\pi'$ ,policy $\pi'$ 一定会比原来的 policy $\pi$ 还要好。那等一下会定义说,什么叫做好。所以这边神奇的地方是,假设你有一个 Q-function 和 某一个policy $\pi$,你根据 policy $\pi$ learn 出 policy $\pi$ 的 Q-function,接下来保证你可以找到一个新的 policy $\pi'$ ,它一定会比 $\pi$ 还要好,然后你用 $\pi'$ 取代 $\pi$,再去找它的 Q-function,得到新的以后,再去找一个更好的 policy。 然后这个循环一直下去,你的 policy 就会越来越好。 +在PPO 的paper 里面还有一个 `adaptive KL divergence`,这边会遇到一个问题就是 $\beta$ 要设多少,它就跟那个regularization 一样。regularization 前面也要乘一个weight,所以这个 KL divergence 前面也要乘一个 weight,但 $\beta$ 要设多少呢?所以有个动态调整 $\beta$ 的方法。在这个方法里面呢,你先设一个 KL divergence,你可以接受的最大值。然后假设你发现说你 optimize 完这个式子以后,KL divergence 的项太大,那就代表说后面这个 penalize 的 term 没有发挥作用,那就把 $\beta$ 调大。那另外你定一个 KL divergence 的最小值。如果发现 optimize 完上面这个式子以后,KL divergence 比最小值还要小,那代表后面这一项的效果太强了,你怕他只弄后面这一项,那 $\theta$ 跟 $\theta^k$ 都一样,这不是你要的,所以你这个时候你叫要减少 $\beta$。所以 $\beta$ 是可以动态调整的。这个叫做 adaptive KL penalty。 ![](img/5.10.png) -上图就是讲我们刚才讲的到底是什么。 - -* 首先要定义的是什么叫做比较好?我们说 $\pi'$ 一定会比 $\pi$ 还要好,什么叫做好呢?这边所谓好的意思是说,对所有可能的 state s 而言,对同一个 state s 而言,$\pi$ 的 value function 一定会小于 $\pi'$ 的 value function。也就是说我们走到同一个 state s 的时候,如果拿 $\pi$ 继续跟环境互动下去,我们得到的 reward 一定会小于用 $\pi'$ 跟环境互动下去得到的reward。所以不管在哪一个state,你用 $\pi'$ 去做 interaction,得到的 expected reward 一定会比较大。所以 $\pi'$ 是比 $\pi$ 还要好的一个policy。 - -* 有了这个 Q-function 以后,怎么找这个 $\pi'$ 呢?事实上这个 $\pi'$ 是什么?这个$\pi'$ 就是, 如果你根据以下的这个式子去决定你的action, +如果你觉得算 KL divergence 很复杂。有一个PPO2。PPO2 要去 maximize 的 objective function 如下式所示,它的式子里面就没有 KL divergence 。 $$ -\pi^{\prime}(s)=\arg \max _{a} Q^{\pi}(s, a) +\begin{aligned} +J_{P P O 2}^{\theta^{k}}(\theta) \approx \sum_{\left(s_{t}, a_{t}\right)} \min &\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)} A^{\theta^{k}}\left(s_{t}, a_{t}\right),\right.\\ +&\left.\operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right) A^{\theta^{k}}\left(s_{t}, a_{t}\right)\right) +\end{aligned} +$$ +这个式子看起来有点复杂,但实际 implement 就很简单。我们来实际看一下说这个式子到底是什么意思。 +min 这个 operator 做的事情是第一项跟第二项里面选比较小的那个。第二项前面有个clip function,clip 这个function 的意思是说,在括号里面有3 项,如果第一项小于第二项的话,那就output $1-\varepsilon$ 。第一项如果大于第三项的话,那就output $1+\varepsilon$。 $\varepsilon$ 是一个 hyper parameter,你要tune 的,你可以设成 0.1 或 设 0.2 。 +假设这边设0.2 的话,如下式所示 +$$ +\operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 0.8, 1.2\right) $$ -根据上式去决定你的action 的步骤叫做 $\pi'$ 的话,那这个 $\pi'$ 一定会比$\pi$ 还要好。这个意思是说,假设你已经 learn 出 $\pi$ 的Q-function,今天在某一个 state s,你把所有可能的 action a 都一一带入这个 Q-function,看看说那一个 a 可以让 Q-function 的 value 最大,那这一个 action,就是 $\pi'$ 会采取的 action。这边要注意一下,给定这个 state s,你的 policy $\pi$ 并不一定会采取 action a。我们是 给定某一个 state s 强制采取 action a,用 $\pi$ 继续互动下去得到的 expected reward,这个才是 Q-function 的定义。所以在 state s 里面不一定会采取 action a。假设用这一个 $\pi'$ 在 state s 采取action a 跟 $\pi$ 所谓采取 action 是不一定会一样的。然后 $\pi'$ 所采取的 action 会让他得到比较大的 reward。 +如果$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$算出来小于0.8,那就当作0.8。如果算出来大于1.2,那就当作1.2。 -* 所以根本就没有一个 policy 叫做 $\pi'$,这个$\pi'$ 是用 Q-function 推出来的。所以没有另外一个 network 决定 $\pi'$ 怎么interaction,有 Q-function 就可以找出$\pi'$。 -* 但是这边有另外一个问题就是,在这边要解一个 arg max 的 problem。所以 a 如果是continuous 的就会有问题,如果是discrete 的,a 只有3 个选项,一个一个带进去, 看谁的 Q 最大,没有问题。但如果是 continuous 要解 arg max problem,你就会有问题,但这个是之后才会解决的。 +我们先看一下下面这项这个算出来到底是什么的东西。 +$$ +\operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right) +$$ ![](img/5.11.png) -上图想要跟大家讲的是说,为什么用 $Q^{\pi}(s,a)$ 这个 Q-function 所决定出来的 $\pi'$,一定会比 $\pi$ 还要好。 +上图的横轴是 $\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$,纵轴是 clip function 实际的输出。 -假设有一个policy 叫做 $\pi'$,它是由 $Q^{\pi}$ 决定的。我们要证对所有的 state s 而言,$V^{\pi^{\prime}}(s) \geq V^{\pi}(s)$。怎么证呢?我们先把$V^{\pi^{\prime}}(s)$写出来: -$$ -V^{\pi}(s)=Q^{\pi}(s, \pi(s)) -$$ -假设在 state s 这个地方,你 follow $\pi$ 这个actor,它会采取的action,也就是$\pi(s)$,那你算出来的$Q^{\pi}(s, \pi(s))$ 会等于$V^{\pi}(s)$。In general 而言,$Q^{\pi}(s, \pi(s))$ 不见得等于$V^{\pi}(s)$ ,因为 action 不见得是$\pi(s)$。但如果这个 action 是 $\pi(s)$ 的话,$Q^{\pi}(s, \pi(s))$ 是等于$V^{\pi}(s)$的。 - - -$Q^{\pi}(s, \pi(s))$ 还满足如下的关系: -$$ -Q^{\pi}(s, \pi(s)) \le \max _{a} Q^{\pi}(s, a) -$$ - -因为这边是所有action 里面可以让 Q 最大的那个action,所以今天这一项一定会比它大。那我们知道说这一项是什么,这一项就是$Q^{\pi}(s, a)$,$a$ 就是 $\pi'(s)$。因为$\pi'(s)$ output 的 a, 就是可以让 $Q^\pi(s,a)$ 最大的那一个。所以我们得到了下面的式子: -$$ -\max _{a} Q^{\pi}(s, a)=Q^{\pi}\left(s, \pi^{\prime}(s)\right) -$$ - -于是: -$$ -V^{\pi}(s) \leq Q^{\pi}\left(s, \pi^{\prime}(s)\right) -$$ -也就是说某一个 state,如果你按照policy $\pi$,一直做下去,你得到的 reward 一定会小于等于,在这个 state s。你故意不按照 $\pi$ 所给你指示的方向,而是按照 $\pi'$ 的方向走一步,但之后只有第一步是按照 $\pi'$ 的方向走,只有在state s 这个地方,你才按照 $\pi'$ 的指示走,但接下来你就按照 $\pi$ 的指示走。虽然只有一步之差, 但是我从上面这个式子知道说,只有一步之差,你得到的 reward 一定会比完全 follow $\pi$ 得到的 reward 还要大。 - -那接下来你想要证的东西就是: -$$ -Q^{\pi}\left(s, \pi^{\prime}(s) \right) \le V^{\pi'}(s) -$$ - -也就是说,只有一步之差,你会得到比较大的reward。但假设每步都是不一样的, 每步都是 follow $\pi'$ 而不是$\pi$ 的话,那你得到的reward 一定会更大。如果你要用数学式把它写出来的话,你可以这样写 $Q^{\pi}\left(s, \pi^{\prime}(s)\right)$ 这个式子,它的意思就是说,我们在state $s_t$ 采取 action $a_t$,得到 reward $r_{t+1}$,然后跳到state $s_{t+1}$,即如下式所示: - -$$ -Q^{\pi}\left(s, \pi^{\prime}(s)\right)=E\left[r_{t+1}+V^{\pi}\left(s_{t+1}\right) \mid s_{t}=s, a_{t}=\pi^{\prime}\left(s_{t}\right)\right] -$$ -这边有一个地方写得不太好,这边应该写成$r_t$ 跟之前的notation 比较一致,但这边写成了$r_{t+1}$,其实这都是可以的。在文献上有时候有人会说 在state $s_t$ 采取action $a_t$ 得到reward $r_{t+1}$, 有人会写成$r_t$,但意思其实都是一样的。在state s,按照$\pi'$ 采取某一个action $a_t$ ,得到 reward $r_{t+1}$,然后跳到state $s_{t+1}$,$V^{\pi}\left(s_{t+1}\right)$是state $s_{t+1}$,根据$\pi$ 这个actor 所估出来的value。这边要取一个期望值,因为在同样的state 采取同样的action,你得到的reward,还有会跳到的 state 不一定是一样, 所以这边需要取一个期望值。 - -接下来我们会得到如下的式子: -$$ -\begin{array}{l} -E\left[r_{t+1}+V^{\pi}\left(s_{t+1}\right) | s_{t}=s, a_{t}=\pi^{\prime}\left(s_{t}\right)\right] \\ -\leq E\left[r_{t+1}+Q^{\pi}\left(s_{t+1}, \pi^{\prime}\left(s_{t+1}\right)\right) | s_{t}=s, a_{t}=\pi^{\prime}\left(s_{t}\right)\right] -\end{array} -$$ -上式为什么成立呢?因为 -$$ -V^{\pi}(s) \leq Q^{\pi}\left(s, \pi^{\prime}(s)\right) -$$ -也就是 -$$ -V^{\pi}(s_{t+1}) \leq Q^{\pi}\left(s_{t+1}, \pi^{\prime}(s_{t+1})\right) -$$ - -也就是说,现在你一直follow $\pi$,跟某一步follow $\pi'$,接下来都follow $\pi$ 比起来,某一步follow $\pi'$ 得到的reward 是比较大的。 - -接着我们得到下式: -$$ -\begin{array}{l} -E\left[r_{t+1}+Q^{\pi}\left(s_{t+1}, \pi^{\prime}\left(s_{t+1}\right)\right) | s_{t}=s, a_{t}=\pi^{\prime}\left(s_{t}\right)\right] \\ -=E\left[r_{t+1}+r_{t+2}+V^{\pi}\left(s_{t+2}\right) | \ldots\right] -\end{array} -$$ - -因为 -$$ -Q^{\pi}\left(s_{t+1}, \pi^{\prime}\left(s_{t+1}\right)\right) = r_{t+2}+V^{\pi}\left(s_{t+2}\right) -$$ - -然后你再代入 - -$$ -V^{\pi}(s) \leq Q^{\pi}\left(s, \pi^{\prime}(s)\right) -$$ - -一直算到底,算到episode 结束。那你就知道说 -$$ -V^{\pi}(s)\le V^{\pi'}(s) -$$ - -**从这边我们可以知道,你可以 estimate 某一个 policy 的 Q-function,接下来你就可以找到另外一个 policy $\pi'$ 比原来的 policy 还要更好。** - -## Target Network +* 如果 $\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$ 大于$1+\varepsilon$,输出就是$1+\varepsilon$。 +* 如果小于 $1-\varepsilon$, 它输出就是 $1-\varepsilon$。 +* 如果介于 $1+\varepsilon$ 跟 $1-\varepsilon$ 之间, 就是输入等于输出。 ![](img/5.12.png) -接下来讲一下在 DQN 里你一定会用到的 tip。第一个是 `target network`,什么意思呢?我们在 learn Q-function 的时候,也会用到 TD 的概念。那怎么用 TD?你现在收集到一个 data, 是说在state $s_t$,你采取action $a_t$ 以后,你得到reward $r_t$ ,然后跳到state $s_{t+1}$。然后根据这个Q-function,你会知道说 -$$ -\mathrm{Q}^{\pi}\left(s_{t}, a_{t}\right) -=r_{t}+\mathrm{Q}^{\pi}\left(s_{t+1}, \pi\left(s_{t+1}\right)\right) -$$ - -所以你在 learn 的时候,你会说我们有 Q-function,input $s_t$, $a_t$ 得到的 value,跟 input $s_{t+1}$, $\pi (s_{t+1})$ 得到的 value 中间,我们希望它差了一个$r_t$, 这跟刚才讲的 TD 的概念是一样的。 - -但是实际上在 learn 的时候,你会发现这样的一个function 并不好 learn,因为假设这是一个 regression problem,$\mathrm{Q}^{\pi}\left(s_{t}, a_{t}\right) $ 是 network 的 output,$r_{t}+\mathrm{Q}^{\pi}\left(s_{t+1}, \pi\left(s_{t+1}\right)\right)$是 target,你会发现 target 是会动的。当然你要 implement 这样的 training,其实也没有问题,就是你在做 backpropagation 的时候, $Q^{\pi}$ 的参数会被 update,你会把两个 update 的结果加在一起。因为它们是同一个 model $Q^{\pi}$, 所以两个 update 的结果会加在一起。但这样会导致 training 变得不太稳定。因为假设你把 $\mathrm{Q}^{\pi}\left(s_{t}, a_{t}\right) $ 当作你model 的output, $r_{t}+\mathrm{Q}^{\pi}\left(s_{t+1}, \pi\left(s_{t+1}\right)\right)$ 当作 target 的话。你要去 fit 的 target 是一直在变的,这种一直在变的 target 的 training 是不太好 train 的。所以你会把其中一个 Q-network,通常是你会把右边这个 Q-network 固定住。也就是说你在 training 的时候,你只 update 左边这个 Q-network 的参数,而右边这个 Q-network 的参数会被固定住。因为右边的 Q-network 负责产生 target,所以叫做 `target network`。因为 target network 是固定的,所以你现在得到的 target $r_{t}+\mathrm{Q}^{\pi}\left(s_{t+1}, \pi\left(s_{t+1}\right)\right)$ 的值也是固定的。因为 target network 是固定的,我们只调左边 network 的参数,它就变成是一个 regression problem。我们希望 model 的 output 的值跟目标越接近越好,你会 minimize 它的 mean square error。 - -在实现的时候,你会把左边的 Q-network update 好几次以后,再去用 update 过的 Q-network 替换这个 target network 。但它们两个不要一起动,它们两个一起动的话, 结果会很容易坏掉。一开始这两个 network 是一样的,然后在 train 的时候,你会把右边的 Q-network fix 住。你在做 gradient decent 的时候,只调左边这个 network 的参数,那你可能update 100 次以后才把这个参数复制到右边的 network 去,把它盖过去。把它盖过去以后,你这个 target value 就变了。就好像说你本来在做一个 regression problem,那你 train 后把这个 regression problem 的 loss 压下去以后,接下来你把这边的参数把它 copy 过去以后,你的 target 就变掉了,接下来就要重新再 train。 - - - -### Intuition + $\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$ 是绿色的线,$\operatorname{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right)$ 是蓝色的线。在绿色的线跟蓝色的线中间,我们要取一个最小的。假设前面乘上的这个 term A,它是大于0 的话,取最小的结果,就是红色的这一条线。 ![](img/5.13.png) -下面我们通过猫追老鼠的例子来直观地理解为什么要 fix target network。猫是 `Q estimation`,老鼠是 `Q target`。一开始的话,猫离老鼠很远,所以我们想让这个猫追上老鼠。 +如果 A 小于0 的话,取最小的以后,就得到红色的这一条线。 +这一个式子虽然看起来有点复杂,implement 起来是蛮简单的,因为这个式子想要做的事情就是希望 $p_{\theta}(a_{t} | s_{t})$ 跟$p_{\theta^k}(a_{t} | s_{t})$,也就是你拿来做 demonstration 的那个model, 跟你实际上 learn 的 model,在optimize 以后不要差距太大。那你要怎么让它做到不要差距太大呢? + +如果 A 大于 0,也就是某一个 state-action 的pair 是好的。那我们希望增加这个state-action pair 的概率。也就是说,我们想要让 $p_{\theta}(a_{t} | s_{t})$ 越大越好,但它跟 $p_{\theta^k}(a_{t} | s_{t})$ 的比值不可以超过 $1+\varepsilon$。如果超过$1+\varepsilon$ 的话,就没有benefit 了。红色的线就是我们的objective function,我们希望objective 越大越好,我们希望 $p_{\theta}(a_{t} | s_{t})$ 越大越好。但是$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$只要大过 $1+\varepsilon$,就没有benefit 了。 + +所以今天在train 的时候,当$p_{\theta}(a_{t} | s_{t})$ 被 train 到$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$大于 $1+\varepsilon$ 时,它就会停止。 + +假设 $p_{\theta}(a_{t} | s_{t})$ 比 $p_{\theta^k}(a_{t} | s_{t})$ 还要小,那我们的目标是要让 $p_{\theta}(a_{t} | s_{t})$ 越大越好。 + +* 假设这个 advantage 是正的,我们希望$p_{\theta}(a_{t} | s_{t})$ 越大越好。假设这个 action 是好的,我们当然希望这个 action 被采取的概率越大越好。所以假设 $p_{\theta}(a_{t} | s_{t})$ 还比 $p_{\theta^k}(a_{t} | s_{t})$ 小,那就尽量把它挪大,但只要大到$1+\varepsilon$ 就好。 +* 负的时候也是一样,如果某一个state-action pair 是不好的,我们希望把 $p_{\theta}(a_{t} | s_{t})$ 减小。如果 $p_{\theta}(a_{t} | s_{t})$ 比$p_{\theta^k}(a_{t} | s_{t})$ 还大,那你就尽量把它压小,压到$\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta^{k}}\left(a_{t} | s_{t}\right)}$是$1-\epsilon$ 的时候就停了,就不要再压得更小。 + +这样的好处就是, 你不会让 $p_{\theta}(a_{t} | s_{t})$ 跟 $p_{\theta^k}(a_{t} | s_{t})$ 差距太大。要 implement 这个东西,很简单。 + ![](img/5.14.png) - -因为 Q target 也是跟模型参数相关的,所以每次优化后,Q target 也会动。这就导致一个问题,猫和老鼠都在动。 - -![](img/5.15.png) -然后它们就会在优化空间里面到处乱动,就会产生非常奇怪的优化轨迹,这就使得训练过程十分不稳定。所以我们可以固定 Q target,让老鼠动得不是那么频繁,可能让它每 5 步动一次,猫则是每一步都在动。如果老鼠每 5 次动一步的话,猫就有足够的时间来接近老鼠。然后它们之间的距离会随着优化过程越来越小,最后它们就可以拟合,拟合过后就可以得到一个最好的 Q-network。 - - -## Exploration - -![](img/5.16.png)第二个 tip 是`Exploration`。当我们使用 Q-function 的时候,policy 完全 depend on Q-function。给定某一个 state,你就穷举所有的 a, 看哪个 a 可以让 Q value 最大,它就是采取的action。那其实这个跟 policy gradient 不一样,在做 policy gradient 的时候,output 其实是 stochastic 的。我们 output 一个action 的distribution,根据这个action 的distribution 去做sample, 所以在policy gradient 里面,你每次采取的action 是不一样的,是有随机性的。那像这种 Q-function, 如果你采取的action 总是固定的,会有什么问题呢?你会遇到的问题就是这不是一个好的收集 data 的方式。因为假设我们今天真的要估某一个state,你可以采取 action $a_{1}$, $a_{2}$, $a_{3}$。你要估测在某一个state 采取某一个action 会得到的Q value,你一定要在那一个 state 采取过那一个action,才估得出它的value。如果你没有在那个state 采取过那个action,你其实估不出那个value 的。当然如果是用 deep 的network,就你的 Q-function 其实是一个 network,这种情形可能会没有那么严重。但是 in general 而言,假设 Q-function 是一个 table,没有看过的 state-action pair,它就是估不出值来。Network 也是会有一样的问题就是, 只是没有那么严重。所以今天假设你在某一个state,action $a_{1}$, $a_{2}$, $a_{3}$ 你都没有采取过,那你估出来的 $Q(s,a_{1})$, $Q(s,a_{2})$, $Q(s,a_{3})$ 的 value 可能都是一样的,就都是一个初始值,比如说 0,即 - -$$ -\begin{array}{l} -Q(s, a_1)=0 \\ -Q(s, a_2)=0 \\ -Q(s, a_3)=0 -\end{array} -$$ - -但是假设你在state s,你 sample 过某一个action $a_{2}$ ,它得到的值是 positive 的 reward。那 $Q(s, a_2)$ 就会比其他的action 都要好。在采取action 的时候, 就看说谁的Q value 最大就采取谁,所以之后你永远都只会 sample 到 $a_{2}$,其他的action 就再也不会被做了,所以就会有问题。就好像说你进去一个餐厅吃饭,其实你都很难选。你今天点了某一个东西以后,假说点了某一样东西, 比如说椒麻鸡,你觉得还可以。接下来你每次去就都会点椒麻鸡,再也不会点别的东西了,那你就不知道说别的东西是不是会比椒麻鸡好吃,这个是一样的问题。 - -如果你没有好的 exploration 的话, 你在training 的时候就会遇到这种问题。举一个实际的例子, 假设你今天是用 DQN 来玩比如说`slither.io`。在玩`slither.io` 你会有一个蛇,然后它在环境里面就走来走去, 然后就吃到星星,它就加分。假设这个游戏一开始,它采取往上走,然后就吃到那个星星,它就得到分数,它就知道说往上走是positive。接下来它就再也不会采取往上走以外的action 了,所以接下来就会变成每次游戏一开始,它就往上冲,然后就死掉,再也做不了别的事。所以今天需要有exploration 的机制,需要让 machine 知道说,虽然根据之前sample 的结果,$a_2$ 好像是不错的,但你至少偶尔也试一下$a_{1}$ 跟$a_{3}$,搞不好他们更好也说不定。 - -这个问题其实就是`探索-利用窘境(Exploration-Exploitation dilemma)`问题。 - -有两个方法解这个问题,一个是`Epsilon Greedy`。Epsilon Greedy 的意思是说,我们有$1-\varepsilon$ 的机率,通常$\varepsilon$ 就设一个很小的值, $1-\varepsilon$ 可能是90%,也就是90% 的机率,完全按照Q-function 来决定action。但是你有10% 的机率是随机的。通常在实现上 $\varepsilon$ 会随着时间递减。也就是在最开始的时候。因为还不知道那个action 是比较好的,所以你会花比较大的力气在做 exploration。接下来随着training 的次数越来越多。已经比较确定说哪一个Q 是比较好的。你就会减少你的exploration,你会把 $\varepsilon$ 的值变小,主要根据Q-function 来决定你的action,比较少做random,这是Epsilon Greedy。 - -还有一个方法叫做 `Boltzmann Exploration`,这个方法就比较像是 policy gradient。在 policy gradient 里面我们说network 的output 是一个 expected action space 上面的一个的 probability distribution。再根据 probability distribution 去做 sample。那其实你也可以根据 Q value 去定一个 probability distribution,假设某一个 action 的 Q value 越大,代表它越好,我们采取这个 action 的机率就越高。但是某一个 action 的 Q value 小,不代表我们不能try。所以我们有时候也要 try 那些 Q value 比较差的 action,怎么做呢? - -因为 Q value 是有正有负的,所以可以它弄成一个概率,你先取 exponential,再做 normalize。然后把 $\exp(Q(s,a))$ 做 normalize 的这个概率当作是你在决定 action 的时候 sample 的概率。在实现上,Q 是一个 network,所以你有点难知道, 在一开始的时候 network 的 output 到底会长怎么样子。假设你一开始没有任何的 training data,你的参数是随机的,那给定某一个 state s,不同的 a output 的值,可能就是差不多的,所以一开始 $Q(s,a)$ 应该会倾向于是 uniform。也就是在一开始的时候,你这 个 probability distribution 算出来,它可能是比较 uniform 的。 - -## Experience Replay - -![](img/5.17.png) - -第三个tip是`Experience Replay(经验回放)`。 Experience Replay 会构建一个 `Replay Buffer`,Replay Buffer 又被称为 `Replay Memory`。Replay Buffer 是说现在会有某一个 policy $\pi$ 去跟环境做互动,然后它会去收集 data。我们会把所有的 data 放到一个buffer 里面,buffer 里面就存了很多data。比如说 buffer 是 5 万,这样它里面可以存 5 万笔资料,每一笔资料就是记得说,我们之前在某一个 state $s_t$,采取某一个action $a_t$,得到了 reward $r_t$。然后跳到 state $s_{t+1}$。那你用 $\pi$ 去跟环境互动很多次,把收集到的资料都放到这个 replay buffer 里面。 - -这边要注意是 replay buffer 里面的 experience 可能是来自于不同的 policy,你每次拿 $\pi$ 去跟环境互动的时候,你可能只互动 10000 次,然后接下来你就更新你的 $\pi$ 了。但是这个 buffer 里面可以放 5 万笔资料,所以 5 万笔资料可能是来自于不同的 policy。Buffer 只有在它装满的时候,才会把旧的资料丢掉。所以这个 buffer 里面它其实装了很多不同的 policy 的 experiences。 - -![](img/5.18.png) - -有了这个 buffer 以后,你是怎么 train 这个 Q 的 model 呢,怎么估 Q-function?你的做法是这样:你会 iterative 去 train 这个 Q-function,在每一个 iteration 里面,你从这个 buffer 里面,随机挑一个 batch 出来,就跟一般的 network training 一样,你从那个 training data set 里面,去挑一个 batch 出来。你去 sample 一个 batch 出来,里面有一把的 experiences,根据这把 experiences 去 update 你的 Q-function。就跟 TD learning 要有一个 target network 是一样的。你去 sample 一堆 batch,sample 一个 batch 的 data,sample 一堆 experiences,然后再去 update 你的 Q-function。 - -当我们这么做的时候, 它变成了一个 `off-policy` 的做法。因为本来我们的 Q 是要观察 $\pi$ 的 experience,但实际上存在你的 replay buffer 里面的这些 experiences 不是通通来自于 $\pi$,有些是过去其他的 $\pi$ 所遗留下来的 experience。因为你不会拿某一个 $\pi$ 就把整个 buffer 装满,然后拿去测 Q-function,这个 $\pi$ 只是 sample 一些 data 塞到那个 buffer 里面去,然后接下来就让 Q 去 train。所以 Q 在 sample 的时候, 它会 sample 到过去的一些资料。 - -这么做有两个好处。 - -* 第一个好处,其实在做 reinforcement learning 的时候, 往往最花时间的 step 是在跟环境做互动,train network 反而是比较快的。因为你用 GPU train 其实很快, 真正花时间的往往是在跟环境做互动。用 replay buffer 可以减少跟环境做互动的次数,因为在做 training 的时候,你的 experience 不需要通通来自于某一个policy。一些过去的 policy 所得到的 experience 可以放在 buffer 里面被使用很多次,被反复的再利用,这样让你的 sample 到 experience 的利用是比较 efficient。 - -* 第二个好处,在 train network 的时候,其实我们希望一个 batch 里面的 data 越 diverse 越好。如果你的 batch 里面的 data 都是同样性质的,你 train 下去是容易坏掉的。如果 batch 里面都是一样的 data,你 train 的时候,performance 会比较差。我们希望 batch data 越 diverse 越好。那如果 buffer 里面的那些 experience 通通来自于不同的 policy ,那你 sample 到的一个 batch 里面的 data 会是比较 diverse 。 - -Q:我们明明是要观察 $\pi$ 的 value,里面混杂了一些不是 $\pi$ 的 experience ,这有没有关系? - -A:没关系。这并不是因为过去的 $\pi$ 跟现在的 $\pi$ 很像, 就算过去的$\pi$ 没有很像,其实也是没有关系的。主要的原因是因为, 我们并不是去sample 一个trajectory,我们只sample 了一笔experience,所以跟是不是 off-policy 这件事是没有关系的。就算是off-policy,就算是这些 experience 不是来自于 $\pi$,我们其实还是可以拿这些 experience 来估测 $Q^{\pi}(s,a)$。这件事有点难解释,不过你就记得说 Experience Replay 在理论上也是没有问题的。 - -## DQN - -![](img/5.19.png) - - -上图就是一般的 `Deep Q-network(DQN)` 的算法。 - -这个算法是这样的。Initialize 的时候,你 initialize 2 个network,一个是 Q,一个是 $\hat{Q}$,其实 $\hat{Q}$ 就等于 Q。一开始这个 target Q-network,跟你原来的 Q-network 是一样的。在每一个 episode,你拿你的 actor 去跟环境做互动,在每一次互动的过程中,你都会得到一个 state $s_t$,那你会采取某一个action $a_t$。怎么知道采取哪一个action $a_t$ 呢?你就根据你现在的 Q-function。但是你要有 exploration 的机制。比如说你用 Boltzmann exploration 或是 Epsilon Greedy 的 exploration。那接下来你得到 reward $r_t$,然后跳到 state $s_{t+1}$。所以现在 collect 到一笔 data,这笔 data 是 ($s_t$, $a_t$ ,$r_t$, $s_{t+1}$)。这笔 data 就塞到你的 buffer 里面去。如果 buffer 满的话, 你就再把一些旧的资料丢掉。接下来你就从你的buffer 里面去 sample data,那你 sample 到的是 $(s_{i}, a_{i}, r_{i}, s_{i+1})$。这笔data 跟你刚放进去的不一定是同一笔,你可能抽到一个旧的。要注意的是,其实你 sample 出来不是一笔 data,你 sample 出来的是一个 batch 的 data,你 sample 一个batch 出来,sample 一把 experiences 出来。接下来就是计算你的 target。假设你 sample 出这么一笔 data。根据这笔 data 去算你的 target。你的 target 是什么呢?target 记得要用 target network $\hat{Q}$ 来算。Target 是: - -$$ -y=r_{i}+\max _{a} \hat{Q}\left(s_{i+1}, a\right) -$$ -其中 a 就是让 $\hat{Q}$ 的值最大的 a。因为我们在 state $s_{i+1}$会采取的action a,其实就是那个可以让 Q value 的值最大的那一个 a。接下来我们要update Q 的值,那就把它当作一个 regression problem。希望$Q(s_i,a_i)$ 跟你的target 越接近越好。然后假设已经 update 了某一个数量的次,比如说 C 次,设 C = 100, 那你就把 $\hat{Q}$ 设成 Q,这就是 DQN。我们给出 [DQN 的 PyTorch 实现](https://github.com/qfettes/DeepRL-Tutorials/blob/master/01.DQN.ipynb) 。 - -Q: DQN 和 Q-learning 有什么不同? - -A: 整体来说,DQN 与 Q-learning 的目标价值以及价值的更新方式都非常相似,主要的不同点在于: - -* DQN 将 Q-learning 与深度学习结合,用深度网络来近似动作价值函数,而 Q-learning 则是采用表格存储; -* DQN 采用了经验回放的训练方法,从历史数据中随机采样,而 Q-learning 直接采用下一个状态的数据进行学习。 - -## References - -* [Intro to Reinforcement Learning (强化学习纲要)](https://github.com/zhoubolei/introRL) +上图是 PPO 跟其它方法的比较。Actor-Critic 和 A2C+Trust Region 方法是actor-critic based 的方法。PPO 是紫色线的方法,这边每张图就是某一个RL 的任务,你会发现说在多数的cases 里面,PPO 都是不错的,不是最好的,就是第二好的。 diff --git a/docs/chapter5/img/5.1.png b/docs/chapter5/img/5.1.png index 9d55f34..341489a 100644 Binary files a/docs/chapter5/img/5.1.png and b/docs/chapter5/img/5.1.png differ diff --git a/docs/chapter5/img/5.10.png b/docs/chapter5/img/5.10.png index 5280698..b34d9aa 100644 Binary files a/docs/chapter5/img/5.10.png and b/docs/chapter5/img/5.10.png differ diff --git a/docs/chapter5/img/5.11.png b/docs/chapter5/img/5.11.png index 5a29a67..13c06d7 100644 Binary files a/docs/chapter5/img/5.11.png and b/docs/chapter5/img/5.11.png differ diff --git a/docs/chapter5/img/5.12.png b/docs/chapter5/img/5.12.png index 33baec0..bd502df 100644 Binary files a/docs/chapter5/img/5.12.png and b/docs/chapter5/img/5.12.png differ diff --git a/docs/chapter5/img/5.13.png b/docs/chapter5/img/5.13.png index 5add0a3..4f32003 100644 Binary files a/docs/chapter5/img/5.13.png and b/docs/chapter5/img/5.13.png differ diff --git a/docs/chapter5/img/5.14.png b/docs/chapter5/img/5.14.png index fbf1ba8..a11a36e 100644 Binary files a/docs/chapter5/img/5.14.png and b/docs/chapter5/img/5.14.png differ diff --git a/docs/chapter5/img/5.2.png b/docs/chapter5/img/5.2.png index 8cb76ab..0bfcffa 100644 Binary files a/docs/chapter5/img/5.2.png and b/docs/chapter5/img/5.2.png differ diff --git a/docs/chapter5/img/5.3.png b/docs/chapter5/img/5.3.png index cdd679e..8ada283 100644 Binary files a/docs/chapter5/img/5.3.png and b/docs/chapter5/img/5.3.png differ diff --git a/docs/chapter5/img/5.4.png b/docs/chapter5/img/5.4.png index 9fb4134..ae8562d 100644 Binary files a/docs/chapter5/img/5.4.png and b/docs/chapter5/img/5.4.png differ diff --git a/docs/chapter5/img/5.5.png b/docs/chapter5/img/5.5.png index fed7cc6..90e3a1c 100644 Binary files a/docs/chapter5/img/5.5.png and b/docs/chapter5/img/5.5.png differ diff --git a/docs/chapter5/img/5.6.png b/docs/chapter5/img/5.6.png index 4bb8720..8158e0f 100644 Binary files a/docs/chapter5/img/5.6.png and b/docs/chapter5/img/5.6.png differ diff --git a/docs/chapter5/img/5.7.png b/docs/chapter5/img/5.7.png index 1388c7a..6eef590 100644 Binary files a/docs/chapter5/img/5.7.png and b/docs/chapter5/img/5.7.png differ diff --git a/docs/chapter5/img/5.8.png b/docs/chapter5/img/5.8.png index 09c9e14..6f85510 100644 Binary files a/docs/chapter5/img/5.8.png and b/docs/chapter5/img/5.8.png differ diff --git a/docs/chapter5/img/5.9.png b/docs/chapter5/img/5.9.png index c15191c..97e02b4 100644 Binary files a/docs/chapter5/img/5.9.png and b/docs/chapter5/img/5.9.png differ diff --git a/docs/chapter6/chapter6.md b/docs/chapter6/chapter6.md index 39df6c8..f0cb189 100644 --- a/docs/chapter6/chapter6.md +++ b/docs/chapter6/chapter6.md @@ -1,111 +1,341 @@ -# Tips of Q-learning -## Double DQN +# Q-learning + +## State Value Function + ![](img/6.1.png) -接下来要讲的是 train Q-learning 的一些 tip。第一个 tip 是做 `Double DQN`。那为什么要有 Double DQN 呢?因为在实现上,你会发现 Q value 往往是被高估的。上图来自于 Double DQN 的原始 paper,它想要显示的结果就是 Q value 往往是被高估的。这边有 4 个不同的小游戏,横轴是 training 的时间,红色锯齿状一直在变的线就是 Q-function 对不同的 state estimate 出来的平均 Q value,有很多不同的 state,每个 state 你都 sample 一下,然后算它们的 Q value,把它们平均起来。红色这一条线,它在training 的过程中会改变,但它是不断上升的,为什么它不断上升,因为 Q-function 是 depend on 你的 policy 的。learn 的过程中你的 policy 越来越强,所以你得到 Q value 会越来越大。在同一个state, 你得到 expected reward 会越来越大,所以 general 而言,这个值都是上升的,但这是 Q-network 估测出来的值。 +Q-learning 是 `value-based` 的方法。在 value based 的方法里面,我们 learn 的不是 policy,我们要 learn 的是一个 `critic`。Critic 并不直接采取行为,它想要做的事情是评价现在的行为有多好或是有多不好。假设有一个 actor $\pi$ ,critic 的工作就是来评价这个 actor 的 policy $\pi$ 好还是不好,即 `Policy Evaluation(策略评估)`。 -接下来你真地去算它,那怎么真地去算?你有那个policy,然后真的去玩那个游戏。就玩很多次,玩个一百万次。然后就去真地估说,在某一个 state, 你会得到的 Q value 到底有多少。你会得到说在某一个 state,采取某一个 action。你接下来会得到 accumulated reward 是多少。你会发现估测出来的值是远比实际的值大。在每一个游戏都是这样,都大很多。所以今天要 propose Double DQN 的方法,它可以让估测的值跟实际的值是比较接近的。我们先看它的结果,蓝色的锯齿状的线是Double DQN 的 Q-network 所估测出来的Q value,蓝色的无锯齿状的线是真正的Q value,你会发现它们是比较接近的。 用 network 估测出来的就不用管它,比较没有参考价值。用 Double DQN 得出来真正的 accumulated reward,在这 3 个case 都是比原来的DQN 高的,代表 Double DQN learn 出来那个 policy 比较强。所以它实际上得到的reward 是比较大的。虽然一般的 DQN 的 Q-network 高估了自己会得到的reward,但实际上它得到的 reward 是比较低的。 +> 注:李宏毅深度强化学习课程提到的 Q-learning,其实是 DQN。 +> +> DQN 是指基于深度学习的 Q-learning 算法,主要结合了`价值函数近似(Value Function Approximation)`与神经网络技术,并采用了目标网络和经历回放的方法进行网络的训练。 +> +> 在 Q-learning 中,我们使用表格来存储每个状态 s 下采取动作 a 获得的奖励,即状态-动作值函数 $Q(s,a)$。然而,这种方法在状态量巨大甚至是连续的任务中,会遇到维度灾难问题,往往是不可行的。因此,DQN 采用了价值函数近似的表示方法。 + +举例来说,有一种 critic 叫做 `state value function`。State value function 的意思就是说,假设 actor 叫做 $\pi$,拿 $\pi$ 跟环境去做互动。假设 $\pi$ 看到了某一个state s,如果在玩 Atari 游戏的话,state s 是某一个画面,看到某一个画面的时候,接下来一直玩到游戏结束,累积的 reward 的期望值有多大。所以 $V^{\pi}$ 是一个function,这个 function input 一个 state,然后它会 output 一个 scalar。这个 scalar 代表说,$\pi$ 这个 actor 看到 state s 的时候,接下来预期到游戏结束的时候,它可以得到多大的 value。 + +举个例子,假设你是玩 space invader 的话, + +* 左边这个 state s,这一个游戏画面,你的 $V^{\pi}(s)$ 也许会很大,因为还有很多的怪可以杀, 所以你会得到很大的分数。一直到游戏结束的时候,你仍然有很多的分数可以吃。 +* 右边那个case,也许你得到的 $V^{\pi}(s)$ 就很小,因为剩下的怪也不多了,并且红色的防护罩已经消失了,所以可能很快就会死掉。所以接下来得到预期的 reward,就不会太大。 + +这边需要强调的一个点是说,当你在讲这一个 critic 的时候,critic 都是绑一个 actor 的,critic 没有办法去凭空去 evaluate 一个 state 的好坏,它所 evaluate 的东西是在给定某一个 state 的时候, 假设接下来互动的 actor 是 $\pi$,那我会得到多少 reward。因为就算是给同样的 state,你接下来的 $\pi$ 不一样,你得到的 reward 也是不一样的。举例来说,在左边那个case,虽然假设是一个正常的 $\pi$,它可以杀很多怪,那假设他是一个很弱的 $\pi$,它就站在原地不动,然后马上就被射死了,那你得到的 V 还是很小。所以 critic output 值有多大,其实是取决于两件事:state 和 actor。所以你的 critic 其实都要绑一个 actor,它是在衡量某一个 actor 的好坏,而不是 generally 衡量一个 state 的好坏。这边要强调一下,critic output 是跟 actor 有关的,state value 其实是 depend on 你的 actor。当你的 actor 变的时候,state value function 的output 其实也是会跟着改变的。 + +### State-value Function Bellman Equation + +记策略 $\pi $ 的状态值函数为 $V^{\pi}(s_t)$ ,它表示在状态 $s_t$ 下带来的累积奖励 $G_t$ 的期望,具体公式为: +$$ +\begin{aligned} V ^ { \pi } \left( s _ { t } \right) & = \mathbb { E } \left[ G _ { t } \mid s _ { t } \right] \\ & = \mathbb { E } \left[ r _ { t } + \gamma r _ { t + 1 } + \gamma ^ { 2 } r _ { t + 2 } + \cdots \mid s _ { t } \right] \\ & = \mathbb { E } \left[ r _ { t } + \gamma \left( r _ { t + 1 } + \gamma r _ { t + 2 } + \cdots \right) \mid s _ { t } \right] \\ +&= \mathbb{E}[r_t|s_t]+ \gamma\mathbb{E}[r_{t+1}+\gamma r_{t+2}+\cdots|s_t] \\ +& =\mathbb{E}[r_t|s_t]+ \gamma\mathbb{E}[G_{t+1}|s_t] +\\& = \mathbb { E } \left[ r _ { t } + \gamma V ^ { \pi } \left( s _ { t + 1 } \right) \mid s _ { t} \right] \end{aligned} +$$ + +上式是 State-value Function 的 Bellman Equation。 + +### State Value Function Estimation ![](img/6.2.png) -Q: 为什么 Q value 总是被高估了呢? +怎么衡量这个 state value function $V^{\pi}(s)$ 呢?有两种不同的做法。一个是用` Monte-Carlo(MC) based` 的方法。MC based 的方法就是让 actor 去跟环境做互动,你要看 actor 好不好, 你就让 actor 去跟环境做互动,给 critic 看。然后,critic 就统计说,actor 如果看到 state $s_a$,接下来 accumulated reward 会有多大。如果它看到 state $s_b$,接下来accumulated reward 会有多大。但是实际上,你不可能把所有的state 通通都扫过。如果你是玩 Atari 游戏的话,你的 state 是 image ,你没有办法把所有的state 通通扫过。所以实际上我们的 $V^{\pi}(s)$ 是一个 network。对一个 network 来说,就算是 input state 是从来都没有看过的,它也可以想办法估测一个 value 的值。 -A: 因为实际上在做的时候,是要让左边这个式子跟右边这个 target 越接近越好。那你会发现说,target 的值很容易一不小心就被设得太高。因为在算这个 target 的时候,我们实际上在做的事情是看哪一个a 可以得到最大的Q value,就把它加上去,就变成我们的target。所以假设有某一个 action 得到的值是被高估的。 - -举例来说, 现在有 4 个 actions,本来其实它们得到的值都是差不多的,它们得到的reward 都是差不多的。但是在estimate 的时候,那毕竟是个network。所以estimate 的时候是有误差的。所以假设今天是第一个action它被高估了,假设绿色的东西代表是被高估的量,它被高估了,那这个target 就会选这个action。然后就会选这个高估的Q value来加上$r_t$,来当作你的target。如果第4 个action 被高估了,那就会选第4 个action 来加上$r_t$ 来当作你的target value。所以你总是会选那个Q value 被高估的,你总是会选那个reward 被高估的action 当作这个max 的结果去加上$r_t$ 当作你的target。所以你的target 总是太大。 +怎么训练这个 network 呢?因为如果在state $s_a$,接下来的 accumulated reward 就是 $G_a$。也就是说,对这个 value function 来说,如果 input 是 state $s_a$,正确的 output 应该是$G_a$。如果 input state $s_b$,正确的output 应该是value $G_b$。所以在 training 的时候, 它就是一个 `regression problem`。Network 的 output 就是一个 value,你希望在 input $s_a$ 的时候,output value 跟 $G_a$ 越近越好,input $s_b$ 的时候,output value 跟 $G_b$ 越近越好。接下来把 network train 下去,就结束了。这是第一个方法,MC based 的方法。 ![](img/6.3.png) -Q: 怎么解决这target 总是太大的问题呢? -A: 在 Double DQN 里面,选 action 的 Q-function 跟算 value 的 Q-function,不是同一个。在原来的DQN 里面,你穷举所有的 a,把每一个a 都带进去, 看哪一个 a 可以给你的 Q value 最高,那你就把那个 Q value 加上$r_t$。但是在 Double DQN 里面,你有两个 Q-network,第一个 Q-network,决定哪一个 action 的 Q value 最大,你用第一个 Q-network 去带入所有的 a,去看看哪一个Q value 最大。然后你决定你的action 以后,你的 Q value 是用 $Q'$ 算出来的,这样子有什么好处呢?为什么这样就可以避免 over estimate 的问题呢?因为今天假设我们有两个 Q-function,假设第一个Q-function 它高估了它现在选出来的action a,那没关系,只要第二个Q-function $Q'$ 没有高估这个action a 的值,那你算出来的,就还是正常的值。假设反过来是 $Q'$ 高估了某一个action 的值,那也没差, 因为反正只要前面这个Q 不要选那个action 出来就没事了。这个就是 Double DQN 神奇的地方。 +第二个方法是`Temporal-difference(时序差分)` 的方法, `即 TD based ` 的方法。在 MC based 的方法中,每次我们都要算 accumulated reward,也就是从某一个 state $s_a$ 一直玩到游戏结束的时候,得到的所有 reward 的总和。所以你要 apply MC based 的 approach,你必须至少把这个游戏玩到结束。但有些游戏非常的长,你要玩到游戏结束才能够 update network,花的时间太长了。因此我们会采用 TD based 的方法。TD based 的方法不需要把游戏玩到底,只要在游戏的某一个情况,某一个 state $s_t$ 的时候,采取 action $a_t$ 得到 reward $r_t$ ,跳到 state $s_{t+1}$,就可以 apply TD 的方法。 -Q: 哪来 Q 跟 $Q'$ 呢?哪来两个 network 呢? +怎么 apply TD 的方法呢?这边是基于以下这个式子: +$$ +V^{\pi}\left(s_{t}\right)=V^{\pi}\left(s_{t+1}\right)+r_{t} +$$ -A: 在实现上,你有两个 Q-network, 一个是 target 的 Q-network,一个是真正你会 update 的 Q-network。所以在 Double DQN 里面,你的实现方法会是拿你会 update 参数的那个 Q-network 去选action,然后你拿target 的network,那个固定住不动的network 去算value。而 Double DQN 相较于原来的 DQN 的更改是最少的,它几乎没有增加任何的运算量,连新的network 都不用,因为你原来就有两个network 了。你唯一要做的事情只有,本来你在找最大的a 的时候,你在决定这个a 要放哪一个的时候,你是用$Q'$ 来算,你是用target network 来算,现在改成用另外一个会 update 的 Q-network 来算。 +假设我们现在用的是某一个 policy $\pi$,在 state $s_t$,它会采取 action $a_t$,给我们 reward $r_t$ ,接下来进入$s_{t+1}$ 。state $s_{t+1}$ 的 value 跟 state $s_t$ 的 value,它们的中间差了一项 $r_t$。因为你把 $s_{t+1}$ 得到的 value 加上得到的 reward $r_t$ 就会等于 $s_t$ 得到的 value。有了这个式子以后,你在 training 的时候,你并不是直接去估测 V,而是希望你得到的结果 V 可以满足这个式子。也就是说你会是这样 train 的,你把 $s_t$ 丢到 network 里面,因为 $s_t$ 丢到 network 里面会得到 $V^{\pi}(s_t)$,把 $s_{t+1}$ 丢到你的 value network 里面会得到$V^{\pi}(s_{t+1})$,这个式子告诉我们,$V^{\pi}(s_t)$ 减 $V^{\pi}(s_{t+1})$ 的值应该是 $r_t$。然后希望它们两个相减的 loss 跟 $r_t$ 越接近,train 下去,update V 的参数,你就可以把 V function learn 出来。 -假如你今天只选一个tip 的话,正常人都是 implement Double DQN,因为很容易实现。 - -## Dueling DQN ![](img/6.4.png) -第二个 tip 是 `Dueling DQN`。其实 Dueling DQN 也蛮好做的,相较于原来的DQN。它唯一的差别是改了network 的架构,Dueling DQN 唯一做的事情是改network 的架构。Q-network 就是input state,output 就是每一个action 的Q value。dueling DQN 唯一做的事情,是改了network 的架构,其它的算法,你都不要去动它。 -Q: Dueling DQN 是怎么改了network 的架构呢? +MC 跟 TD 有什么样的差别呢?**MC 最大的问题就是 variance 很大**。因为我们在玩游戏的时候,它本身是有随机性的。所以你可以把 $G_a$ 看成一个 random 的 variable。因为你每次同样走到 $s_a$ 的时候,最后你得到的 $G_a$ 其实是不一样的。你看到同样的state $s_a$,最后玩到游戏结束的时候,因为游戏本身是有随机性的,玩游戏的 model 搞不好也有随机性,所以你每次得到的 $G_a$ 是不一样的,每一次得到$G_a$ 的差别其实会很大。为什么它会很大呢?因为 $G_a$ 其实是很多个不同的 step 的 reward 的和。假设你每一个step 都会得到一个reward,$G_a$ 是从 state $s_a$ 开始,一直玩到游戏结束,每一个timestamp reward 的和。 -A: 本来的DQN 就是直接output Q value 的值。现在这个dueling 的DQN,就是下面这个network 的架构。它不直接output Q value 的值,它分成两条path 去运算,第一个path,它算出一个scalar,这个scalar 我们叫做$V(s)$。因为它跟input s 是有关系,所以叫做$V(s)$,$V(s)$ 是一个scalar。下面这个会output 一个vector,这个vector 叫做$A(s,a)$。下面这个vector,它是每一个action 都有一个value。然后你再把这两个东西加起来,就得到你的Q value。 +举例来说,我在右上角就列一个式子是说, + +$$ +\operatorname{Var}[k X]=k^{2} \operatorname{Var}[X] +$$ +Var 就是指 variance。 +通过这个式子,我们知道 $G_a$ 的 variance 相较于某一个 state 的 reward,它会是比较大的,$G_a$ 的variance 是比较大的。 + +如果用 TD 的话,你是要去 minimize 这样的一个式子: ![](img/6.5.png) -Q: 这么改有什么好处? - -A : 那我们假设说,原来的$Q(s,a)$ 就是一个table。我们假设 state 是discrete 的,实际上state 不是discrete 的。那为了说明方便,我们假设就是只有4 个不同的state,只有3 个不同的action,所以$Q(s,a)$ 你可以看作是一个table。 - -我们知道: -$$ -Q(s,a) = V(s) + A(s,a) -$$ - -其中 - -* $V(s)$ 是对不同的state 它都有一个值。 -* $A(s,a)$ 它是对不同的state,不同的action都有一个值。 - -你把这个 V 的值加到 A 的每一个 column 就会得到Q 的值。把 2+1,2+(-1),2+0,就得到 3,1,2,以此类推。 - -如上图所示,假设说你在train network 的时候,target 是希望这一个值变成 4,这一个值变成 0。但是你实际上能更改的并不是Q 的值,你的network 更改的是V 跟A 的值。根据network 的参数,V 跟A 的值output 以后,就直接把它们加起来,所以其实不是更动Q 的值。然后在learn network 的时候,假设你希望这边的值,这个3 增加1 变成 4,这个-1 增加1 变成 0。最后你在train network 的时候,network 可能会说,我们就不要动这个 A 的值,就动 V 的值,把 V 的值从0 变成 1。把0 变成1 有什么好处呢?你会发现说,本来你只想动这两个东西的值,那你会发现说,这个第三个值也动了,-2 变成 -1。所以有可能说你在某一个state,你明明只sample 到这2 个action,你没sample 到第三个action,但是你其实也可以更改第三个action 的Q value。这样的好处就是你不需要把所有的 state-action pair 都sample 过,你可以用比较efficient 的方式去 estimate Q value 出来。因为有时候你update 的时候,不一定是update 下面这个table。而是只update 了$V(s)$,但update $V(s)$ 的时候,只要一改所有的值就会跟着改。这是一个比较有效率的方法,去使用你的data,这个是Dueling DQN 可以带给我们的好处。 - -那可是接下来有人就会问说会不会最后learn 出来的结果是说,反正machine 就学到 V 永远都是 0,然后反正A 就等于 Q,那你就没有得到任何 Dueling DQN 可以带给你的好处, 就变成跟原来的DQN 一模一样。为了避免这个问题,实际上你要给 A 一些constrain,让update A 其实比较麻烦,让network 倾向于会想要去用V 来解问题。 - -举例来说,你可以看原始的文献,它有不同的constrain 。那一个最直觉的constrain 是你必须要让这个A 的每一个column 的和都是 0,所以看我这边举的例子,我的column 的和都是 0。那如果这边column 的和都是 0,这边这个V 的值,你就可以想成是上面 Q 的每一个column 的平均值。这个平均值,加上这些值才会变成是Q 的value。所以今天假设你发现说你在update 参数的时候,你是要让整个row 一起被update。你就不会想要update 这边,因为你不会想要update A这个matrix。因为 A 这个matrix 的每一个column 的和都要是 0,所以你没有办法说,让这边的值,通通都+1,这件事是做不到的。因为它的constrain 就是你的和永远都是要 0。所以不可以都+1,这时候就会强迫network 去update V 的值,然后让你可以用比较有效率的方法,去使用你的data。 +在这中间会有随机性的是 r。因为计算你在 $s_t$ 采取同一个 action,你得到的 reward 也不一定是一样的,所以 r 是一个 random variable。但这个 random variable 的 variance 会比 $G_a$ 还要小,因为 $G_a$ 是很多 r 合起来,这边只是某一个 r 而已。$G_a$ 的 variance 会比较大,r 的 variance 会比较小。但是这边你会遇到的**一个问题是你这个 V 不一定估得准**。假设你的这个 V 估得是不准的,那你 apply 这个式子 learn 出来的结果,其实也会是不准的。所以 MC 跟 TD各有优劣。**今天其实 TD 的方法是比较常见的,MC 的方法其实是比较少用的。** ![](img/6.6.png) +上图是讲 TD 跟 MC 的差异。假设有某一个 critic,它去观察某一个 policy $\pi$ 跟环境互动的 8 个 episode 的结果。有一个actor $\pi$ 跟环境互动了8 次,得到了8 次玩游戏的结果。接下来这个 critic 去估测 state 的 value。 -实现时,你要给这个 A 一个 constrain。举个例子,假设你有 3 个actions,然后在这边 output 的 vector 是7 3 2,你在把这个 A 跟这个 V 加起来之前,先加一个normalization,就好像做那个layer normalization 一样。加一个normalization,这个normalization 做的事情就是把 7+3+2 加起来等于 12,12/3 = 4。然后把这边通通减掉 4,变成 3, -1, 2。再把 3, -1, 2 加上 1.0,得到最后的Q value。这个normalization 的 step 就是 network 的其中一部分,在train 的时候,你从这边也是一路 back propagate 回来的,只是 normalization 是没有参数的,它只是一个normalization 的operation。把它可以放到network 里面,跟network 的其他部分 jointly trained,这样 A 就会有比较大的 constrain。这样network 就会给它一些benefit, 倾向于去update V 的值,这个是Dueling DQN。 +* 我们看看 $s_b$ 的 value 是多少。$s_b$ 这个state 在 8 场游戏里面都有经历过,其中有6 场得到 reward 1,有两场得到 reward 0,所以如果你是要算期望值的话,就看到 state $s_b$ 以后得到的 reward,一直到游戏结束的时候得到的 accumulated reward 期望值是 3/4。 +* 但 $s_a$ 期望的 reward 到底应该是多少呢?这边其实有两个可能的答案:一个是 0,一个是 3/4。为什么有两个可能的答案呢?这取决于你用MC 还是TD。用 MC 跟用 TD 算出来的结果是不一样的。 +假如你用 MC 的话,你会发现这个$s_a$ 就出现一次,看到$s_a$ 这个state,接下来 accumulated reward 就是 0。所以今天 $s_a$ expected reward 就是 0。 -## Prioritized Experience Replay +但 TD 在计算的时候,它要update 下面这个式子。 +$$ +V^{\pi}\left(s_{a}\right)=V^{\pi}\left(s_{b}\right)+r +$$ + +因为我们在 state $s_a$ 得到 reward r=0 以后,跳到 state $s_b$。所以 state $s_b$ 的 reward 会等于 state $s_b$ 的 reward 加上在state $s_a$ 跳到 state $s_b$ 的时候可能得到的 reward r。而这个得到的 reward r 的值是 0,$s_b$ expected reward 是3/4,那$s_a$ 的reward 应该是3/4。 + +用 MC 跟 TD 估出来的结果,其实很有可能是不一样的。就算 critic 观察到一样的 training data,它最后估出来的结果。也不见得会是一样。那为什么会这样呢?你可能问说,那一个比较对呢?其实就都对。 + +因为在第一个 trajectory, $s_a$ 得到 reward 0 以后,再跳到 $s_b$ 也得到 reward 0。这边有两个可能。 + +* 一个可能是$s_a$,它就是一个带 sign 的 state,所以只要看到 $s_a$ 以后,$s_b$ 就会拿不到reward,有可能$s_a$ 其实影响了$s_b$。如果是用 MC 的算法的话,它会把 $s_a$ 影响 $s_b$ 这件事考虑进去。所以看到 $s_a$ 以后,接下来 $s_b$ 就得不到 reward,所以看到$s_a$ 以后,期望的reward 是 0。 + +* 另一个可能是,看到$s_a$ 以后, $s_b$ 的 reward 是0 这件事只是一个巧合,就并不是 $s_a$ 所造成,而是因为说 $s_b$ 有时候就是会得到 reward 0,这只是单纯运气的问题。其实平常 $s_b$ 会得到 reward 期望值是 3/4,跟 $s_a$ 是完全没有关系的。所以假设 $s_a$ 之后会跳到 $s_b$,那其实得到的 reward 按照 TD 来算应该是 3/4。 + +所以不同的方法考虑了不同的假设,运算结果不同。 + +## State-action Value Function ![](img/6.7.png) -有一个技巧叫做 `Prioritized Experience Replay`。Prioritized Experience Replay 是什么意思呢? -我们原来在 sample data 去 train 你的 Q-network 的时候,你是 uniformly 从 experience buffer 里面去 sample data。那这样不见得是最好的, 因为也许有一些 data 比较重要。假设有一些 data,你之前有 sample 过。你发现这些 data 的 TD error 特别大(TD error 就是 network 的 output 跟 target 之间的差距),那这些 data 代表说你在 train network 的时候, 你是比较 train 不好的。那既然比较 train 不好, 那你就应该给它比较大的概率被 sample 到,即给它 `priority`。这样在 training 的时候才会多考虑那些 train 不好的 training data。实际上在做 prioritized experience replay 的时候,你不仅会更改 sampling 的 process,你还会因为更改了 sampling 的 process,更改 update 参数的方法。所以 prioritized experience replay 不仅改变了 sample data 的 distribution,还改变了 training process。 -## Balance between MC and TD +还有另外一种critic,这种critic 叫做 `Q-function`。它又叫做`state-action value function`。 + +* state value function 的 input 是一个 state,它是根据 state 去计算出,看到这个state 以后的 expected accumulated reward 是多少。 +* state-action value function 的 input 是一个 state 跟 action 的 pair,它的意思是说,在某一个 state 采取某一个action,假设我们都使用 actor $\pi$ ,得到的 accumulated reward 的期望值有多大。 + +Q-function 有一个需要注意的问题是,这个 actor $\pi$,在看到 state s 的时候,它采取的 action 不一定是 a。Q-function 假设在 state s 强制采取 action a。不管你现在考虑的这个 actor $\pi$, 它会不会采取 action a,这不重要。在state s 强制采取 action a。接下来都用 actor $\pi$ 继续玩下去,就只有在 state s,我们才强制一定要采取 action a,接下来就进入自动模式,让actor $\pi$ 继续玩下去,得到的 expected reward 才是$Q^{\pi}(s,a)$ 。 + +Q-function 有两种写法: + +* input 是 state 跟action,output 就是一个 scalar; +* input 是一个 state s,output 就是好几个 value。 + +假设 action 是 discrete 的,action 就只有3 个可能,往左往右或是开火。那这个 Q-function output 的3 个 values 就分别代表 a 是向左的时候的 Q value,a 是向右的时候的Q value,还有 a 是开火的时候的 Q value。 + +那你要注意的事情是,上图右边的 function 只有discrete action 才能够使用。如果 action 是无法穷举的,你只能够用上图左边这个式子,不能够用右边这个式子。 ![](img/6.8.png) -另外一个可以做的方法是,你可以balance MC 跟TD。MC 跟 TD 的方法各自有各自的优劣。我们怎么在MC 跟TD 里面取得一个平衡呢?我们的做法是这样,在TD 里面,在某一个state $s_t$采取某一个action $a_t$ 得到 reward $r_t$,接下来跳到那一个state $s_{t+1}$。但是我们可以不要只存一个step 的data,我们存 N 个step 的data。 -我们记录在$s_t$ 采取$a_t$,得到$r_t$,会跳到什么样$s_t$。一直纪录到在第N 个step 以后,在$s_{t+N}$采取$a_{t+N}$得到 reward $r_{t+N}$,跳到$s_{t+N+1}$的这个经验,通通把它存下来。实际上你今天在做update 的时候, 在做你 Q-network learning 的时候,你的learning 的方法会是这样,你learning 的时候,要让 $Q(s_t,a_t)$ 跟你的target value 越接近越好。$\hat{Q}$ 所计算的不是$s_{t+1}$,而是$s_{t+N+1}$的。你会把 N 个step 以后的state 丢进来,去计算 N 个step 以后,你会得到的reward。要算 target value 的话,要再加上multi-step 的reward $\sum_{t^{\prime}=t}^{t+N} r_{t^{\prime}}$ ,multi-step 的 reward 是从时间 t 一直到 t+N 的 N 个reward 的和。然后希望你的 $Q(s_t,a_t)$ 和 target value 越接近越好。 +上图是文献上的结果,你去 estimate Q-function 的话,看到的结果可能会像是这个样子。这是什么意思呢?它说假设我们有 3 个 actions,3 个 actions 就是原地不动、向上、向下。 -你会发现说这个方法就是 MC 跟 TD 的结合。因此它就有 MC 的好处跟坏处,也有 TD 的好处跟坏处。如果看它的这个好处的话,因为我们现在 sample 了比较多的step,之前是只sample 了一个step, 所以某一个step 得到的data 是real 的,接下来都是Q value 估测出来的。现在sample 比较多step,sample N 个step 才估测value,所以估测的部分所造成的影响就会比小。当然它的坏处就跟MC 的坏处一样,因为你的 r 比较多项,你把 N 项的 r 加起来,你的variance 就会比较大。但是你可以去调这个N 的值,去在variance 跟不精确的 Q 之间取得一个平衡。N 就是一个hyper parameter,你要调这个N 到底是多少,你是要多 sample 三步,还是多 sample 五步。 +* 假设是在第一个state,不管是采取哪个action,最后到游戏结束的时候,得到的 expected reward 其实都差不多。因为球在这个地方,就算是你向下,接下来你其实应该还来的急救,所以今天不管是采取哪一个action,就差不了太多。 + +* 假设在第二个state,这个乒乓球它已经反弹到很接近边缘的地方,这个时候你采取向上,你才能得到positive 的reward,才接的到球。如果你是站在原地不动或向下的话,接下来你都会miss 掉这个球。你得到的reward 就会是负的。 + +* 假设在第三个state,球很近了,所以就要向上。 + +* 假设在第四个state,球被反弹回去,这时候采取那个action就都没有差了。 + +这个是 state-action value 的一个例子。 -## Noisy Net ![](img/6.9.png) -有一个技术是要improve 这个exploration 这件事,我们之前讲的Epsilon Greedy 这样的 exploration 是在action 的space 上面加noise,但是有另外一个更好的方法叫做`Noisy Net`,它是在参数的space 上面加noise。Noisy Net 的意思是说,每一次在一个episode 开始的时候,在你要跟环境互动的时候,你就把你的Q-function 拿出来,Q-function 里面其实就是一个network ,就变成你把那个network 拿出来,在network 的每一个参数上面加上一个Gaussian noise。那你就把原来的Q-function 变成$\tilde{Q}$ 。因为$\hat{Q}$ 已经用过,$\hat{Q}$ 是那个target network,我们用 $\tilde{Q}$ 来代表一个`Noisy Q-function`。我们把每一个参数都可能都加上一个Gaussian noise,就得到一个新的network 叫做$\tilde{Q}$。这边要注意在每个episode 开始的时候,开始跟环境互动之前,我们就 sample network。接下来你就会用这个固定住的 noisy network 去玩这个游戏,直到游戏结束,你才重新再去sample 新的noise。OpenAI 跟 Deep mind 又在同时间 propose 一模一样的方法,通通都publish 在ICLR 2018,两篇paper 的方法就是一样的。不一样的地方是,他们用不同的方法,去加noise。OpenAI 加的方法好像比较简单,他就直接加一个 Gaussian noise 就结束了,就你把每一个参数,每一个weight都加一个Gaussian noise 就结束了。Deep mind 做比较复杂,他们的noise 是由一组参数控制的,也就是说 network 可以自己决定说它那个noise 要加多大,但是概念就是一样的。总之就是把你的Q-function的里面的那个network 加上一些noise,把它变得有点不一样,跟原来的Q-function 不一样,然后拿去跟环境做互动。两篇paper 里面都有强调说,你这个参数虽然会加noise,但在同一个episode 里面你的参数就是固定的,你是在换episode, 玩第二场新的游戏的时候,你才会重新sample noise,在同一场游戏里面就是同一个noisy Q-network 在玩那一场游戏,这件事非常重要。为什么这件事非常重要呢?因为这是导致了Noisy Net 跟原来的Epsilon Greedy 或其它在action 做sample 方法的本质上的差异。 + +虽然表面上我们 learn 一个 Q-function,它只能拿来评估某一个 actor $\pi$ 的好坏,但只要有了这个 Q-function,我们就可以做 reinforcement learning。有了这个 Q-function,我们就可以决定要采取哪一个 action,我们就可以进行`策略改进(Policy Improvement)`。 + +它的大原则是这样,假设你有一个初始的 actor,也许一开始很烂, 随机的也没有关系。初始的 actor 叫做 $\pi$,这个 $\pi$ 跟环境互动,会 collect data。接下来你 learn 一个 $\pi$ 这个 actor 的 Q value,你去衡量一下 $\pi$ 这个actor 在某一个 state 强制采取某一个 action,接下来用 $\pi$ 这个 policy 会得到的 expected reward,那用 TD 或 MC 也是可以的。你 learn 出一个 Q-function 以后,就保证你可以找到一个新的 policy $\pi'$ ,policy $\pi'$ 一定会比原来的 policy $\pi$ 还要好。那等一下会定义说,什么叫做好。所以这边神奇的地方是,假设你有一个 Q-function 和 某一个policy $\pi$,你根据 policy $\pi$ learn 出 policy $\pi$ 的 Q-function,接下来保证你可以找到一个新的 policy $\pi'$ ,它一定会比 $\pi$ 还要好,然后你用 $\pi'$ 取代 $\pi$,再去找它的 Q-function,得到新的以后,再去找一个更好的 policy。 然后这个循环一直下去,你的 policy 就会越来越好。 ![](img/6.10.png) +上图就是讲我们刚才讲的到底是什么。 -有什么样本质上的差异呢?在原来sample 的方法,比如说Epsilon Greedy 里面,就算是给同样的state,你的agent 采取的action 也不一定是一样的。因为你是用sample 决定的,given 同一个state,要根据 Q-function 的network,你会得到一个action,你 sample 到random,你会采取另外一个action。所以 given 同样的state,如果你今天是用Epsilon Greedy 的方法,它得到的 action 是不一样的。但实际上你的policy 并不是这样运作的啊。在一个真实世界的policy,给同样的state,他应该会有同样的回应。而不是给同样的state,它其实有时候吃 Q-function,然后有时候又是随机的,所以这是一个不正常的action,是在真实的情况下不会出现的action。但是如果你是在Q-function 上面去加noise 的话, 就不会有这个情形。因为如果你今天在Q-function 上加 noise,在Q-function 的network 的参数上加noise,那在整个互动的过程中,在同一个episode 里面,它的network 的参数总是固定的,所以看到同样的state,或是相似的state,就会采取同样的action,那这个是比较正常的。在paper 里面有说,这个叫做 `state-dependent exploration`,也就是说你虽然会做 explore 这件事, 但是你的explore 是跟state 有关系的,看到同样的state, 你就会采取同样的exploration 的方式,而 noisy 的 action 只是随机乱试。但如果你是在参数下加noise,那在同一个episode 里面,里面你的参数是固定的。那你就是有系统地在尝试,每次会试说,在某一个state,我都向左试试看。然后再下一次在玩这个同样游戏的时候,看到同样的state,你就说我再向右试试看,你是有系统地在explore 这个环境。 +* 首先要定义的是什么叫做比较好?我们说 $\pi'$ 一定会比 $\pi$ 还要好,什么叫做好呢?这边所谓好的意思是说,对所有可能的 state s 而言,对同一个 state s 而言,$\pi$ 的 value function 一定会小于 $\pi'$ 的 value function。也就是说我们走到同一个 state s 的时候,如果拿 $\pi$ 继续跟环境互动下去,我们得到的 reward 一定会小于用 $\pi'$ 跟环境互动下去得到的reward。所以不管在哪一个state,你用 $\pi'$ 去做 interaction,得到的 expected reward 一定会比较大。所以 $\pi'$ 是比 $\pi$ 还要好的一个policy。 + +* 有了这个 Q-function 以后,怎么找这个 $\pi'$ 呢?事实上这个 $\pi'$ 是什么?这个$\pi'$ 就是, 如果你根据以下的这个式子去决定你的action, + +$$ +\pi^{\prime}(s)=\arg \max _{a} Q^{\pi}(s, a) +$$ + +根据上式去决定你的action 的步骤叫做 $\pi'$ 的话,那这个 $\pi'$ 一定会比$\pi$ 还要好。这个意思是说,假设你已经 learn 出 $\pi$ 的Q-function,今天在某一个 state s,你把所有可能的 action a 都一一带入这个 Q-function,看看说那一个 a 可以让 Q-function 的 value 最大,那这一个 action,就是 $\pi'$ 会采取的 action。这边要注意一下,给定这个 state s,你的 policy $\pi$ 并不一定会采取 action a。我们是 给定某一个 state s 强制采取 action a,用 $\pi$ 继续互动下去得到的 expected reward,这个才是 Q-function 的定义。所以在 state s 里面不一定会采取 action a。假设用这一个 $\pi'$ 在 state s 采取action a 跟 $\pi$ 所谓采取 action 是不一定会一样的。然后 $\pi'$ 所采取的 action 会让他得到比较大的 reward。 + +* 所以根本就没有一个 policy 叫做 $\pi'$,这个$\pi'$ 是用 Q-function 推出来的。所以没有另外一个 network 决定 $\pi'$ 怎么interaction,有 Q-function 就可以找出$\pi'$。 +* 但是这边有另外一个问题就是,在这边要解一个 arg max 的 problem。所以 a 如果是continuous 的就会有问题,如果是discrete 的,a 只有3 个选项,一个一个带进去, 看谁的 Q 最大,没有问题。但如果是 continuous 要解 arg max problem,你就会有问题,但这个是之后才会解决的。 -## Distributional Q-function ![](img/6.11.png) -还有一个技巧叫做 Distributional Q-function。我们不讲它的细节,只告诉你大致的概念。Distributional Q-function 还蛮有道理的, 但是它没有红起来。你就发现说没有太多人真的在实现的时候用这个技术,可能一个原因就是它不好实现。它的意思是什么?Q-function 到底是什么意思啊,Q-function 是 accumulated reward 的期望值,所以我们算出来的这个Q value 其实是一个期望值。因为环境是有随机性的,在某一个state 采取某一个action 的时候,我们把所有的reward 玩到游戏结束的时候所有的 reward 进行一个统计,你其实得到的是一个distribution。也许在reward 得到0 的机率很高,在-10 的概率比较低,在+10 的概率比较低,但是它是一个distribution。我们对这一个distribution 算它的mean才是这个Q value,我们算出来是 expected accumulated reward。所以这accumulated reward 是一个distribution,对它取expectation,对它取mean,你得到了Q value。但不同的distribution,它们其实可以有同样的mean。也许真正的distribution 是右边的distribution,它算出来的 mean 跟左边的 distribution 算出来的mean 其实是一样的,但它们背后所代表的distribution 其实是不一样的。假设我们只用一个 expected 的 Q value 来代表整个reward 的话,其实可能会丢失一些 information,你没有办法 model reward 的distribution。 +上图想要跟大家讲的是说,为什么用 $Q^{\pi}(s,a)$ 这个 Q-function 所决定出来的 $\pi'$,一定会比 $\pi$ 还要好。 + +假设有一个policy 叫做 $\pi'$,它是由 $Q^{\pi}$ 决定的。我们要证对所有的 state s 而言,$V^{\pi^{\prime}}(s) \geq V^{\pi}(s)$。怎么证呢?我们先把$V^{\pi^{\prime}}(s)$写出来: +$$ +V^{\pi}(s)=Q^{\pi}(s, \pi(s)) +$$ +假设在 state s 这个地方,你 follow $\pi$ 这个actor,它会采取的action,也就是$\pi(s)$,那你算出来的$Q^{\pi}(s, \pi(s))$ 会等于$V^{\pi}(s)$。In general 而言,$Q^{\pi}(s, \pi(s))$ 不见得等于$V^{\pi}(s)$ ,因为 action 不见得是$\pi(s)$。但如果这个 action 是 $\pi(s)$ 的话,$Q^{\pi}(s, \pi(s))$ 是等于$V^{\pi}(s)$的。 + + +$Q^{\pi}(s, \pi(s))$ 还满足如下的关系: +$$ +Q^{\pi}(s, \pi(s)) \le \max _{a} Q^{\pi}(s, a) +$$ + +因为这边是所有action 里面可以让 Q 最大的那个action,所以今天这一项一定会比它大。那我们知道说这一项是什么,这一项就是$Q^{\pi}(s, a)$,$a$ 就是 $\pi'(s)$。因为$\pi'(s)$ output 的 a, 就是可以让 $Q^\pi(s,a)$ 最大的那一个。所以我们得到了下面的式子: +$$ +\max _{a} Q^{\pi}(s, a)=Q^{\pi}\left(s, \pi^{\prime}(s)\right) +$$ + +于是: +$$ +V^{\pi}(s) \leq Q^{\pi}\left(s, \pi^{\prime}(s)\right) +$$ +也就是说某一个 state,如果你按照policy $\pi$,一直做下去,你得到的 reward 一定会小于等于,在这个 state s。你故意不按照 $\pi$ 所给你指示的方向,而是按照 $\pi'$ 的方向走一步,但之后只有第一步是按照 $\pi'$ 的方向走,只有在state s 这个地方,你才按照 $\pi'$ 的指示走,但接下来你就按照 $\pi$ 的指示走。虽然只有一步之差, 但是我从上面这个式子知道说,只有一步之差,你得到的 reward 一定会比完全 follow $\pi$ 得到的 reward 还要大。 + +那接下来你想要证的东西就是: +$$ +Q^{\pi}\left(s, \pi^{\prime}(s) \right) \le V^{\pi'}(s) +$$ + +也就是说,只有一步之差,你会得到比较大的reward。但假设每步都是不一样的, 每步都是 follow $\pi'$ 而不是$\pi$ 的话,那你得到的reward 一定会更大。如果你要用数学式把它写出来的话,你可以这样写 $Q^{\pi}\left(s, \pi^{\prime}(s)\right)$ 这个式子,它的意思就是说,我们在state $s_t$ 采取 action $a_t$,得到 reward $r_{t+1}$,然后跳到state $s_{t+1}$,即如下式所示: + +$$ +Q^{\pi}\left(s, \pi^{\prime}(s)\right)=E\left[r_{t+1}+V^{\pi}\left(s_{t+1}\right) \mid s_{t}=s, a_{t}=\pi^{\prime}\left(s_{t}\right)\right] +$$ +这边有一个地方写得不太好,这边应该写成$r_t$ 跟之前的notation 比较一致,但这边写成了$r_{t+1}$,其实这都是可以的。在文献上有时候有人会说 在state $s_t$ 采取action $a_t$ 得到reward $r_{t+1}$, 有人会写成$r_t$,但意思其实都是一样的。在state s,按照$\pi'$ 采取某一个action $a_t$ ,得到 reward $r_{t+1}$,然后跳到state $s_{t+1}$,$V^{\pi}\left(s_{t+1}\right)$是state $s_{t+1}$,根据$\pi$ 这个actor 所估出来的value。这边要取一个期望值,因为在同样的state 采取同样的action,你得到的reward,还有会跳到的 state 不一定是一样, 所以这边需要取一个期望值。 + +接下来我们会得到如下的式子: +$$ +\begin{array}{l} +E\left[r_{t+1}+V^{\pi}\left(s_{t+1}\right) | s_{t}=s, a_{t}=\pi^{\prime}\left(s_{t}\right)\right] \\ +\leq E\left[r_{t+1}+Q^{\pi}\left(s_{t+1}, \pi^{\prime}\left(s_{t+1}\right)\right) | s_{t}=s, a_{t}=\pi^{\prime}\left(s_{t}\right)\right] +\end{array} +$$ +上式为什么成立呢?因为 +$$ +V^{\pi}(s) \leq Q^{\pi}\left(s, \pi^{\prime}(s)\right) +$$ +也就是 +$$ +V^{\pi}(s_{t+1}) \leq Q^{\pi}\left(s_{t+1}, \pi^{\prime}(s_{t+1})\right) +$$ + +也就是说,现在你一直follow $\pi$,跟某一步follow $\pi'$,接下来都follow $\pi$ 比起来,某一步follow $\pi'$ 得到的reward 是比较大的。 + +接着我们得到下式: +$$ +\begin{array}{l} +E\left[r_{t+1}+Q^{\pi}\left(s_{t+1}, \pi^{\prime}\left(s_{t+1}\right)\right) | s_{t}=s, a_{t}=\pi^{\prime}\left(s_{t}\right)\right] \\ +=E\left[r_{t+1}+r_{t+2}+V^{\pi}\left(s_{t+2}\right) | \ldots\right] +\end{array} +$$ + +因为 +$$ +Q^{\pi}\left(s_{t+1}, \pi^{\prime}\left(s_{t+1}\right)\right) = r_{t+2}+V^{\pi}\left(s_{t+2}\right) +$$ + +然后你再代入 + +$$ +V^{\pi}(s) \leq Q^{\pi}\left(s, \pi^{\prime}(s)\right) +$$ + +一直算到底,算到episode 结束。那你就知道说 +$$ +V^{\pi}(s)\le V^{\pi'}(s) +$$ + +**从这边我们可以知道,你可以 estimate 某一个 policy 的 Q-function,接下来你就可以找到另外一个 policy $\pi'$ 比原来的 policy 还要更好。** + +## Target Network ![](img/6.12.png) -Distributional Q-function 它想要做的事情是model distribution,怎么做呢?在原来的 Q-function 里面,假设你只能够采取 $a_1$, $a_2$, $a_3$, 3 个actions,那你就是input 一个state,output 3 个values。3 个values 分别代表3 个actions 的Q value,但是这个 Q value 是一个distribution 的期望值。所以 Distributional Q-function 的想法就是何不直接output 那个 distribution。但是要直接output 一个distribution 也不知道怎么做嘛。实际上的做法是说, 假设 distribution 的值就分布在某一个 range 里面,比如说-10 到10,那把-10 到10 中间拆成一个一个的bin,拆成一个一个的长条图。举例来说,在这个例子里面,每一个action 的 reward 的space 就拆成 5 个bin。假设reward 可以拆成5 个bin 的话,今天你的Q-function 的output 是要预测说,你在某一个 state,采取某一个action,你得到的reward,落在某一个bin 里面的概率。所以其实这边的概率的和,这些绿色的bar 的和应该是 1,它的高度代表说,在某一个state,采取某一个action 的时候,它落在某一个bin 的机率。这边绿色的代表action 1,红色的代表action 2,蓝色的代表action 3。所以今天你就可以真的用Q-function 去 estimate $a_1$ 的distribution,$a_2$ 的distribution,$a_3$ 的distribution。那实际上在做testing 的时候, 我们还是要选某一个action去执行嘛,那选哪一个action 呢?实际上在做的时候,还是选这个mean 最大的那个action 去执行。但假设我们今天可以 model distribution 的话,除了选mean 最大的以外,也许在未来你可以有更多其他的运用。举例来说,你可以考虑它的distribution 长什么样子。若distribution variance 很大,代表说采取这个action 虽然mean 可能平均而言很不错,但也许风险很高,你可以train一个network 它是可以规避风险的。就在 2 个action mean 都差不多的情况下,也许可以选一个风险比较小的 action 来执行,这是 Distributional Q-function 的好处。关于怎么train 这样的 Q-network 的细节,我们就不讲,你只要记得说 Q-network 有办法output 一个distribution 就对了。我们可以不只是估测得到的期望reward mean 的值。我们其实是可以估测一个distribution 的。 +接下来讲一下在 DQN 里你一定会用到的 tip。第一个是 `target network`,什么意思呢?我们在 learn Q-function 的时候,也会用到 TD 的概念。那怎么用 TD?你现在收集到一个 data, 是说在state $s_t$,你采取action $a_t$ 以后,你得到reward $r_t$ ,然后跳到state $s_{t+1}$。然后根据这个Q-function,你会知道说 +$$ +\mathrm{Q}^{\pi}\left(s_{t}, a_{t}\right) +=r_{t}+\mathrm{Q}^{\pi}\left(s_{t+1}, \pi\left(s_{t+1}\right)\right) +$$ -## Rainbow +所以你在 learn 的时候,你会说我们有 Q-function,input $s_t$, $a_t$ 得到的 value,跟 input $s_{t+1}$, $\pi (s_{t+1})$ 得到的 value 中间,我们希望它差了一个$r_t$, 这跟刚才讲的 TD 的概念是一样的。 + +但是实际上在 learn 的时候,你会发现这样的一个function 并不好 learn,因为假设这是一个 regression problem,$\mathrm{Q}^{\pi}\left(s_{t}, a_{t}\right) $ 是 network 的 output,$r_{t}+\mathrm{Q}^{\pi}\left(s_{t+1}, \pi\left(s_{t+1}\right)\right)$是 target,你会发现 target 是会动的。当然你要 implement 这样的 training,其实也没有问题,就是你在做 backpropagation 的时候, $Q^{\pi}$ 的参数会被 update,你会把两个 update 的结果加在一起。因为它们是同一个 model $Q^{\pi}$, 所以两个 update 的结果会加在一起。但这样会导致 training 变得不太稳定。因为假设你把 $\mathrm{Q}^{\pi}\left(s_{t}, a_{t}\right) $ 当作你model 的output, $r_{t}+\mathrm{Q}^{\pi}\left(s_{t+1}, \pi\left(s_{t+1}\right)\right)$ 当作 target 的话。你要去 fit 的 target 是一直在变的,这种一直在变的 target 的 training 是不太好 train 的。所以你会把其中一个 Q-network,通常是你会把右边这个 Q-network 固定住。也就是说你在 training 的时候,你只 update 左边这个 Q-network 的参数,而右边这个 Q-network 的参数会被固定住。因为右边的 Q-network 负责产生 target,所以叫做 `target network`。因为 target network 是固定的,所以你现在得到的 target $r_{t}+\mathrm{Q}^{\pi}\left(s_{t+1}, \pi\left(s_{t+1}\right)\right)$ 的值也是固定的。因为 target network 是固定的,我们只调左边 network 的参数,它就变成是一个 regression problem。我们希望 model 的 output 的值跟目标越接近越好,你会 minimize 它的 mean square error。 + +在实现的时候,你会把左边的 Q-network update 好几次以后,再去用 update 过的 Q-network 替换这个 target network 。但它们两个不要一起动,它们两个一起动的话, 结果会很容易坏掉。一开始这两个 network 是一样的,然后在 train 的时候,你会把右边的 Q-network fix 住。你在做 gradient decent 的时候,只调左边这个 network 的参数,那你可能update 100 次以后才把这个参数复制到右边的 network 去,把它盖过去。把它盖过去以后,你这个 target value 就变了。就好像说你本来在做一个 regression problem,那你 train 后把这个 regression problem 的 loss 压下去以后,接下来你把这边的参数把它 copy 过去以后,你的 target 就变掉了,接下来就要重新再 train。 + + + +### Intuition ![](img/6.13.png) -最后一个技巧叫做 rainbow 。Rainbow 就是把刚才所有的方法都综合起来就变成 rainbow 。因为刚才每一个方法,就是有一种自己的颜色,把所有的颜色通通都合起来,就变成rainbow,它把原来的DQN 也算是一种方法,故有 7 色。 - -那我们来看看这些不同的方法。横轴是 training process,纵轴是玩了10 几个 Atari 小游戏的平均的分数的和,但它取的是median 的分数,为什么是取 median 不是直接取平均呢?因为它说每一个小游戏的分数,其实差很多。如果你取平均的话,到时候某几个游戏就dominate 你的结果,所以它取median 的值。 - -如果你是一般的DQN,就灰色这一条线,就没有很强。那如果是你换noisy DQN,就强很多。如果这边每一个单一颜色的线是代表说只用某一个方法,那紫色这一条线是DDQN(Double DQN),DDQN 还蛮有效的。然后 Prioritized DDQN、Dueling DDQN 和 Distributional DQN 都蛮强的,它们都差不多很强的。A3C 其实是 Actor-Critic 的方法。单纯的 A3C 看起来是比DQN 强的。这边怎么没有 multi-step 的方法,multi-step 的方法就是 balance TD 跟MC,我猜是因为 A3C 本身内部就有做 multi-step 的方法,所以他可能觉得说有 implement A3C 就算是有 implement multi-step 的方法。所以可以把这个 A3C 的结果想成是 multi-step 方法的结果。其实这些方法他们本身之间是没有冲突的,所以全部都用上去就变成七彩的一个方法,就叫做rainbow,然后它很高。 +下面我们通过猫追老鼠的例子来直观地理解为什么要 fix target network。猫是 `Q estimation`,老鼠是 `Q target`。一开始的话,猫离老鼠很远,所以我们想让这个猫追上老鼠。 ![](img/6.14.png) -上图是说,在rainbow 这个方法里面, 如果我们每次拿掉其中一个技术,到底差多少。因为现在是把所有的方法都加在一起,发现说进步很多,但会不会有些方法其实是没用的。所以看看说, 每一个方法哪些方法特别有用,哪些方法特别没用。这边的虚线就是拿掉某一种方法以后的结果,你会发现说,黄色的虚线,拿掉 multi-step 掉很多。Rainbow 是彩色这一条,拿掉 multi-step 会掉下来。拿掉 Prioritized Experience Replay 后也马上就掉下来。拿掉这个distribution,它也掉下来。 +因为 Q target 也是跟模型参数相关的,所以每次优化后,Q target 也会动。这就导致一个问题,猫和老鼠都在动。 + +![](img/6.15.png) +然后它们就会在优化空间里面到处乱动,就会产生非常奇怪的优化轨迹,这就使得训练过程十分不稳定。所以我们可以固定 Q target,让老鼠动得不是那么频繁,可能让它每 5 步动一次,猫则是每一步都在动。如果老鼠每 5 次动一步的话,猫就有足够的时间来接近老鼠。然后它们之间的距离会随着优化过程越来越小,最后它们就可以拟合,拟合过后就可以得到一个最好的 Q-network。 + + +## Exploration + +![](img/6.16.png)第二个 tip 是`Exploration`。当我们使用 Q-function 的时候,policy 完全 depend on Q-function。给定某一个 state,你就穷举所有的 a, 看哪个 a 可以让 Q value 最大,它就是采取的action。那其实这个跟 policy gradient 不一样,在做 policy gradient 的时候,output 其实是 stochastic 的。我们 output 一个action 的distribution,根据这个action 的distribution 去做sample, 所以在policy gradient 里面,你每次采取的action 是不一样的,是有随机性的。那像这种 Q-function, 如果你采取的action 总是固定的,会有什么问题呢?你会遇到的问题就是这不是一个好的收集 data 的方式。因为假设我们今天真的要估某一个state,你可以采取 action $a_{1}$, $a_{2}$, $a_{3}$。你要估测在某一个state 采取某一个action 会得到的Q value,你一定要在那一个 state 采取过那一个action,才估得出它的value。如果你没有在那个state 采取过那个action,你其实估不出那个value 的。当然如果是用 deep 的network,就你的 Q-function 其实是一个 network,这种情形可能会没有那么严重。但是 in general 而言,假设 Q-function 是一个 table,没有看过的 state-action pair,它就是估不出值来。Network 也是会有一样的问题就是, 只是没有那么严重。所以今天假设你在某一个state,action $a_{1}$, $a_{2}$, $a_{3}$ 你都没有采取过,那你估出来的 $Q(s,a_{1})$, $Q(s,a_{2})$, $Q(s,a_{3})$ 的 value 可能都是一样的,就都是一个初始值,比如说 0,即 + +$$ +\begin{array}{l} +Q(s, a_1)=0 \\ +Q(s, a_2)=0 \\ +Q(s, a_3)=0 +\end{array} +$$ + +但是假设你在state s,你 sample 过某一个action $a_{2}$ ,它得到的值是 positive 的 reward。那 $Q(s, a_2)$ 就会比其他的action 都要好。在采取action 的时候, 就看说谁的Q value 最大就采取谁,所以之后你永远都只会 sample 到 $a_{2}$,其他的action 就再也不会被做了,所以就会有问题。就好像说你进去一个餐厅吃饭,其实你都很难选。你今天点了某一个东西以后,假说点了某一样东西, 比如说椒麻鸡,你觉得还可以。接下来你每次去就都会点椒麻鸡,再也不会点别的东西了,那你就不知道说别的东西是不是会比椒麻鸡好吃,这个是一样的问题。 + +如果你没有好的 exploration 的话, 你在training 的时候就会遇到这种问题。举一个实际的例子, 假设你今天是用 DQN 来玩比如说`slither.io`。在玩`slither.io` 你会有一个蛇,然后它在环境里面就走来走去, 然后就吃到星星,它就加分。假设这个游戏一开始,它采取往上走,然后就吃到那个星星,它就得到分数,它就知道说往上走是positive。接下来它就再也不会采取往上走以外的action 了,所以接下来就会变成每次游戏一开始,它就往上冲,然后就死掉,再也做不了别的事。所以今天需要有exploration 的机制,需要让 machine 知道说,虽然根据之前sample 的结果,$a_2$ 好像是不错的,但你至少偶尔也试一下$a_{1}$ 跟$a_{3}$,搞不好他们更好也说不定。 + +这个问题其实就是`探索-利用窘境(Exploration-Exploitation dilemma)`问题。 + +有两个方法解这个问题,一个是`Epsilon Greedy`。Epsilon Greedy 的意思是说,我们有$1-\varepsilon$ 的机率,通常$\varepsilon$ 就设一个很小的值, $1-\varepsilon$ 可能是90%,也就是90% 的机率,完全按照Q-function 来决定action。但是你有10% 的机率是随机的。通常在实现上 $\varepsilon$ 会随着时间递减。也就是在最开始的时候。因为还不知道那个action 是比较好的,所以你会花比较大的力气在做 exploration。接下来随着training 的次数越来越多。已经比较确定说哪一个Q 是比较好的。你就会减少你的exploration,你会把 $\varepsilon$ 的值变小,主要根据Q-function 来决定你的action,比较少做random,这是Epsilon Greedy。 + +还有一个方法叫做 `Boltzmann Exploration`,这个方法就比较像是 policy gradient。在 policy gradient 里面我们说network 的output 是一个 expected action space 上面的一个的 probability distribution。再根据 probability distribution 去做 sample。那其实你也可以根据 Q value 去定一个 probability distribution,假设某一个 action 的 Q value 越大,代表它越好,我们采取这个 action 的机率就越高。但是某一个 action 的 Q value 小,不代表我们不能try。所以我们有时候也要 try 那些 Q value 比较差的 action,怎么做呢? + +因为 Q value 是有正有负的,所以可以它弄成一个概率,你先取 exponential,再做 normalize。然后把 $\exp(Q(s,a))$ 做 normalize 的这个概率当作是你在决定 action 的时候 sample 的概率。在实现上,Q 是一个 network,所以你有点难知道, 在一开始的时候 network 的 output 到底会长怎么样子。假设你一开始没有任何的 training data,你的参数是随机的,那给定某一个 state s,不同的 a output 的值,可能就是差不多的,所以一开始 $Q(s,a)$ 应该会倾向于是 uniform。也就是在一开始的时候,你这 个 probability distribution 算出来,它可能是比较 uniform 的。 + +## Experience Replay + +![](img/6.17.png) + +第三个tip是`Experience Replay(经验回放)`。 Experience Replay 会构建一个 `Replay Buffer`,Replay Buffer 又被称为 `Replay Memory`。Replay Buffer 是说现在会有某一个 policy $\pi$ 去跟环境做互动,然后它会去收集 data。我们会把所有的 data 放到一个buffer 里面,buffer 里面就存了很多data。比如说 buffer 是 5 万,这样它里面可以存 5 万笔资料,每一笔资料就是记得说,我们之前在某一个 state $s_t$,采取某一个action $a_t$,得到了 reward $r_t$。然后跳到 state $s_{t+1}$。那你用 $\pi$ 去跟环境互动很多次,把收集到的资料都放到这个 replay buffer 里面。 + +这边要注意是 replay buffer 里面的 experience 可能是来自于不同的 policy,你每次拿 $\pi$ 去跟环境互动的时候,你可能只互动 10000 次,然后接下来你就更新你的 $\pi$ 了。但是这个 buffer 里面可以放 5 万笔资料,所以 5 万笔资料可能是来自于不同的 policy。Buffer 只有在它装满的时候,才会把旧的资料丢掉。所以这个 buffer 里面它其实装了很多不同的 policy 的 experiences。 + +![](img/6.18.png) + +有了这个 buffer 以后,你是怎么 train 这个 Q 的 model 呢,怎么估 Q-function?你的做法是这样:你会 iterative 去 train 这个 Q-function,在每一个 iteration 里面,你从这个 buffer 里面,随机挑一个 batch 出来,就跟一般的 network training 一样,你从那个 training data set 里面,去挑一个 batch 出来。你去 sample 一个 batch 出来,里面有一把的 experiences,根据这把 experiences 去 update 你的 Q-function。就跟 TD learning 要有一个 target network 是一样的。你去 sample 一堆 batch,sample 一个 batch 的 data,sample 一堆 experiences,然后再去 update 你的 Q-function。 + +当我们这么做的时候, 它变成了一个 `off-policy` 的做法。因为本来我们的 Q 是要观察 $\pi$ 的 experience,但实际上存在你的 replay buffer 里面的这些 experiences 不是通通来自于 $\pi$,有些是过去其他的 $\pi$ 所遗留下来的 experience。因为你不会拿某一个 $\pi$ 就把整个 buffer 装满,然后拿去测 Q-function,这个 $\pi$ 只是 sample 一些 data 塞到那个 buffer 里面去,然后接下来就让 Q 去 train。所以 Q 在 sample 的时候, 它会 sample 到过去的一些资料。 + +这么做有两个好处。 + +* 第一个好处,其实在做 reinforcement learning 的时候, 往往最花时间的 step 是在跟环境做互动,train network 反而是比较快的。因为你用 GPU train 其实很快, 真正花时间的往往是在跟环境做互动。用 replay buffer 可以减少跟环境做互动的次数,因为在做 training 的时候,你的 experience 不需要通通来自于某一个policy。一些过去的 policy 所得到的 experience 可以放在 buffer 里面被使用很多次,被反复的再利用,这样让你的 sample 到 experience 的利用是比较 efficient。 + +* 第二个好处,在 train network 的时候,其实我们希望一个 batch 里面的 data 越 diverse 越好。如果你的 batch 里面的 data 都是同样性质的,你 train 下去是容易坏掉的。如果 batch 里面都是一样的 data,你 train 的时候,performance 会比较差。我们希望 batch data 越 diverse 越好。那如果 buffer 里面的那些 experience 通通来自于不同的 policy ,那你 sample 到的一个 batch 里面的 data 会是比较 diverse 。 + +Q:我们明明是要观察 $\pi$ 的 value,里面混杂了一些不是 $\pi$ 的 experience ,这有没有关系? + +A:没关系。这并不是因为过去的 $\pi$ 跟现在的 $\pi$ 很像, 就算过去的$\pi$ 没有很像,其实也是没有关系的。主要的原因是因为, 我们并不是去sample 一个trajectory,我们只sample 了一笔experience,所以跟是不是 off-policy 这件事是没有关系的。就算是off-policy,就算是这些 experience 不是来自于 $\pi$,我们其实还是可以拿这些 experience 来估测 $Q^{\pi}(s,a)$。这件事有点难解释,不过你就记得说 Experience Replay 在理论上也是没有问题的。 + +## DQN + +![](img/6.19.png) + + +上图就是一般的 `Deep Q-network(DQN)` 的算法。 + +这个算法是这样的。Initialize 的时候,你 initialize 2 个network,一个是 Q,一个是 $\hat{Q}$,其实 $\hat{Q}$ 就等于 Q。一开始这个 target Q-network,跟你原来的 Q-network 是一样的。在每一个 episode,你拿你的 actor 去跟环境做互动,在每一次互动的过程中,你都会得到一个 state $s_t$,那你会采取某一个action $a_t$。怎么知道采取哪一个action $a_t$ 呢?你就根据你现在的 Q-function。但是你要有 exploration 的机制。比如说你用 Boltzmann exploration 或是 Epsilon Greedy 的 exploration。那接下来你得到 reward $r_t$,然后跳到 state $s_{t+1}$。所以现在 collect 到一笔 data,这笔 data 是 ($s_t$, $a_t$ ,$r_t$, $s_{t+1}$)。这笔 data 就塞到你的 buffer 里面去。如果 buffer 满的话, 你就再把一些旧的资料丢掉。接下来你就从你的buffer 里面去 sample data,那你 sample 到的是 $(s_{i}, a_{i}, r_{i}, s_{i+1})$。这笔data 跟你刚放进去的不一定是同一笔,你可能抽到一个旧的。要注意的是,其实你 sample 出来不是一笔 data,你 sample 出来的是一个 batch 的 data,你 sample 一个batch 出来,sample 一把 experiences 出来。接下来就是计算你的 target。假设你 sample 出这么一笔 data。根据这笔 data 去算你的 target。你的 target 是什么呢?target 记得要用 target network $\hat{Q}$ 来算。Target 是: + +$$ +y=r_{i}+\max _{a} \hat{Q}\left(s_{i+1}, a\right) +$$ +其中 a 就是让 $\hat{Q}$ 的值最大的 a。因为我们在 state $s_{i+1}$会采取的action a,其实就是那个可以让 Q value 的值最大的那一个 a。接下来我们要update Q 的值,那就把它当作一个 regression problem。希望$Q(s_i,a_i)$ 跟你的target 越接近越好。然后假设已经 update 了某一个数量的次,比如说 C 次,设 C = 100, 那你就把 $\hat{Q}$ 设成 Q,这就是 DQN。我们给出 [DQN 的 PyTorch 实现](https://github.com/qfettes/DeepRL-Tutorials/blob/master/01.DQN.ipynb) 。 + +Q: DQN 和 Q-learning 有什么不同? + +A: 整体来说,DQN 与 Q-learning 的目标价值以及价值的更新方式都非常相似,主要的不同点在于: + +* DQN 将 Q-learning 与深度学习结合,用深度网络来近似动作价值函数,而 Q-learning 则是采用表格存储; +* DQN 采用了经验回放的训练方法,从历史数据中随机采样,而 Q-learning 直接采用下一个状态的数据进行学习。 + +## References + +* [Intro to Reinforcement Learning (强化学习纲要)](https://github.com/zhoubolei/introRL) -这边有一个有趣的地方是说,在开始的时候,distribution 训练的方法跟其他方法速度差不多。但是如果你拿掉distribution 的时候,你的训练不会变慢,但是 performance 最后会收敛在比较差的地方。拿掉 Noisy Net 后performance 也是差一点。拿掉Dueling 也是差一点。拿掉 Double 没什么差,所以看来全部合在一起的时候,Double 是比较没有影响的。其实在paper 里面有给一个make sense 的解释,其实当你有用 Distributional DQN的 时候,本质上就不会over estimate 你的reward。我们是为了避免over estimate reward 才加了Double DQN。那在paper 里面有讲说,如果有做 Distributional DQN,就比较不会有over estimate 的结果。 事实上他有真的算了一下发现说,其实多数的状况是 under estimate reward 的,所以会变成Double DQN 没有用。那为什么做 Distributional DQN,不会over estimate reward,反而会under estimate reward 呢?因为这个 distributional DQN 的 output 的是一个distribution 的range,output 的 range 不可能是无限宽的,你一定是设一个range, 比如说我最大output range 就是从-10 到10。假设今天得到的reward 超过10 怎么办?是100 怎么办,就当作没看到这件事。所以 reward 很极端的值,很大的值其实是会被丢掉的, 所以用 Distributional DQN 的时候,你不会有over estimate 的现象,反而会 under estimate。 \ No newline at end of file diff --git a/docs/chapter6/img/6.1.png b/docs/chapter6/img/6.1.png index f2e4c77..9d55f34 100644 Binary files a/docs/chapter6/img/6.1.png and b/docs/chapter6/img/6.1.png differ diff --git a/docs/chapter6/img/6.10.png b/docs/chapter6/img/6.10.png index bbe4247..5280698 100644 Binary files a/docs/chapter6/img/6.10.png and b/docs/chapter6/img/6.10.png differ diff --git a/docs/chapter6/img/6.11.png b/docs/chapter6/img/6.11.png index da79108..5a29a67 100644 Binary files a/docs/chapter6/img/6.11.png and b/docs/chapter6/img/6.11.png differ diff --git a/docs/chapter6/img/6.12.png b/docs/chapter6/img/6.12.png index b2ac0a0..33baec0 100644 Binary files a/docs/chapter6/img/6.12.png and b/docs/chapter6/img/6.12.png differ diff --git a/docs/chapter6/img/6.13.png b/docs/chapter6/img/6.13.png index 8957ca5..5add0a3 100644 Binary files a/docs/chapter6/img/6.13.png and b/docs/chapter6/img/6.13.png differ diff --git a/docs/chapter6/img/6.14.png b/docs/chapter6/img/6.14.png index 8ecd196..fbf1ba8 100644 Binary files a/docs/chapter6/img/6.14.png and b/docs/chapter6/img/6.14.png differ diff --git a/docs/chapter5/img/5.15.png b/docs/chapter6/img/6.15.png similarity index 100% rename from docs/chapter5/img/5.15.png rename to docs/chapter6/img/6.15.png diff --git a/docs/chapter5/img/5.16.png b/docs/chapter6/img/6.16.png similarity index 100% rename from docs/chapter5/img/5.16.png rename to docs/chapter6/img/6.16.png diff --git a/docs/chapter5/img/5.17.png b/docs/chapter6/img/6.17.png similarity index 100% rename from docs/chapter5/img/5.17.png rename to docs/chapter6/img/6.17.png diff --git a/docs/chapter5/img/5.18.png b/docs/chapter6/img/6.18.png similarity index 100% rename from docs/chapter5/img/5.18.png rename to docs/chapter6/img/6.18.png diff --git a/docs/chapter5/img/5.19.png b/docs/chapter6/img/6.19.png similarity index 100% rename from docs/chapter5/img/5.19.png rename to docs/chapter6/img/6.19.png diff --git a/docs/chapter6/img/6.2.png b/docs/chapter6/img/6.2.png index 02c9d86..8cb76ab 100644 Binary files a/docs/chapter6/img/6.2.png and b/docs/chapter6/img/6.2.png differ diff --git a/docs/chapter6/img/6.3.png b/docs/chapter6/img/6.3.png index 0cdff9d..cdd679e 100644 Binary files a/docs/chapter6/img/6.3.png and b/docs/chapter6/img/6.3.png differ diff --git a/docs/chapter6/img/6.4.png b/docs/chapter6/img/6.4.png index a312b48..9fb4134 100644 Binary files a/docs/chapter6/img/6.4.png and b/docs/chapter6/img/6.4.png differ diff --git a/docs/chapter6/img/6.5.png b/docs/chapter6/img/6.5.png index 68a78e0..fed7cc6 100644 Binary files a/docs/chapter6/img/6.5.png and b/docs/chapter6/img/6.5.png differ diff --git a/docs/chapter6/img/6.6.png b/docs/chapter6/img/6.6.png index 7197cf6..4bb8720 100644 Binary files a/docs/chapter6/img/6.6.png and b/docs/chapter6/img/6.6.png differ diff --git a/docs/chapter6/img/6.7.png b/docs/chapter6/img/6.7.png index aa3cf84..1388c7a 100644 Binary files a/docs/chapter6/img/6.7.png and b/docs/chapter6/img/6.7.png differ diff --git a/docs/chapter6/img/6.8.png b/docs/chapter6/img/6.8.png index d776fb0..09c9e14 100644 Binary files a/docs/chapter6/img/6.8.png and b/docs/chapter6/img/6.8.png differ diff --git a/docs/chapter6/img/6.9.png b/docs/chapter6/img/6.9.png index 49f17b7..c15191c 100644 Binary files a/docs/chapter6/img/6.9.png and b/docs/chapter6/img/6.9.png differ diff --git a/docs/chapter7/chapter7.md b/docs/chapter7/chapter7.md index beab930..b16209c 100644 --- a/docs/chapter7/chapter7.md +++ b/docs/chapter7/chapter7.md @@ -1,34 +1,111 @@ -# Q-learning for Continuous Actions - +# Tips of Q-learning +## Double DQN ![](img/7.1.png) -继续讲一下 Q-learning,其实跟 policy gradient based 方法比起来,Q-learning 其实是比较稳的。policy gradient 其实是没有太多游戏是玩得起来的。policy gradient 其实比较不稳,尤其在没有 PPO 之前,你很难用 policy gradient 做什么事情。Q-learning 相对而言是比较稳的。最早 deepmind 的 paper 拿 deep reinforcement learning 来玩 Atari 的游戏,用的就是 Q-learning。那我觉得 Q-learning 比较容易 train 的一个理由是:在 Q-learning 里面,你只要能够 estimate 出Q-function,就保证你一定可以找到一个比较好的 policy。也就是你只要能够 estimate 出 Q-function,就保证你可以 improve 你的 policy。而 estimate Q-function 这件事情,是比较容易的,为什么?因为它就是一个 regression 的 problem。在这个 regression 的 problem 里面, 你可以轻易地知道说,你现在的 model learn 的是不是越来越好,你只要看那个 regression 的 loss 有没有下降,你就知道说你的 model learn 的好不好。所以 estimate Q-function 相较于 learn 一个 policy 是比较容易的。你只要 estimate Q-function,就可以保证说现在一定会得到比较好的 policy。 +接下来要讲的是 train Q-learning 的一些 tip。第一个 tip 是做 `Double DQN`。那为什么要有 Double DQN 呢?因为在实现上,你会发现 Q value 往往是被高估的。上图来自于 Double DQN 的原始 paper,它想要显示的结果就是 Q value 往往是被高估的。这边有 4 个不同的小游戏,横轴是 training 的时间,红色锯齿状一直在变的线就是 Q-function 对不同的 state estimate 出来的平均 Q value,有很多不同的 state,每个 state 你都 sample 一下,然后算它们的 Q value,把它们平均起来。红色这一条线,它在training 的过程中会改变,但它是不断上升的,为什么它不断上升,因为 Q-function 是 depend on 你的 policy 的。learn 的过程中你的 policy 越来越强,所以你得到 Q value 会越来越大。在同一个state, 你得到 expected reward 会越来越大,所以 general 而言,这个值都是上升的,但这是 Q-network 估测出来的值。 -所以一般而言 Q-learning 是比较容易操作。那 Q-learning 有什么问题呢?最大的问题是它不太容易处理 continuous action,很多时候你的 action 是 continuous 的。什么时候你的 action 会是 continuous 的呢?我们玩 Atari 的游戏,你的 agent 只需要决定比如说上下左右,这种 action 是 discrete 的。那很多时候你的 action 是 continuous 的。举例来说假设你的 agent 要做的事情是开自驾车,它要决定说它方向盘要左转几度, 右转几度,这是 continuous 的。假设你的 agent 是一个机器人,假设它身上有 50 个 关节,它的每一个 action 就对应到它身上的这 50 个关节的角度。而那些角度也是 continuous 的。所以很多时候你的 action,并不是一个 discrete 的东西,它是一个 vector,这个 vector 里面,它的每一个 dimension 都有一个对应的 value,都是 real number,它是 continuous 的。 - -假设你的 action 是 continuous 的时候,做 Q-learning 就会有困难。因为在做 Q-learning 里面一个很重要的一步是你要能够解这个 optimization 的 problem。你 estimate 出Q-function $Q(s,a)$ 以后,必须要找到一个 a,它可以让 $Q(s,a)$ 最大。假设 a 是 discrete 的,那 a 的可能性都是有限的。举例来说,Atari 的小游戏里面,a 就是上下左右跟开火,它是有限的,你可以把每一个可能的 action 都带到 Q 里面算它的 Q value。但假如 a 是 continuous 的,你无法穷举所有可能 continuous action,试试看哪一个 continuous action 可以让 Q 的 value 最大。所以怎么办呢?在概念上,我们就是要能够解这个问题。怎么解这个问题呢?就有各种不同的 solution。 - -第一个 solution 是假设你不知道怎么解这个问题,因为 a 是很多的,a 是没有办法穷举的。怎么办?用 sample 的。Sample 出 N 个 可能的 a,一个一个带到 Q-function 里面,看谁最快?这个方法其实也不会太不 efficient, 因为你真的在运算的时候,你会用 GPU,所以你一次会把 N 个 continuous action都丢到 Q-function 里面,一次得到 N 个 Q value,然后看谁最大。当然这个不是一个 非常精确的做法,因为你真的没有办法做太多的 sample, 所以你 estimate 出来的 Q value,你最后决定的 action 可能不是非常的精确, 这是第一个 solution。 - -第二个 solution 是什么呢?今天既然我们要解的是一个 optimization 的 problem。我们其实是要 maximize 我们的 objective function,我们是要 maximize 一个东西, 就可以用 gradient ascent。你就把 a 当作是你的 parameter,然后你要找一组 a 去 maximize 你的 Q-function,你就用 gradient ascent 去 update a 的 value,最后看看你能不能找到一个 a 去 maximize 你的 Q-function,也就是你的 objective function。当然这样子你会遇到的问题,就是 global maximum 的问题, 就不见得能够真的找到 optimal 的结果,而且这个运算量显然很大, 因为你要 iterative 的去 update 你的 a。我们 train 一个 network 就很花时间了。如果你用 gradient ascent 的方法来处理 continuous 的 problem, 等于是你每次要决定要 take 哪一个 action 的时候,你都还要做一次 train network 的 process,显然运算量是很大的。这是第二个 solution。 +接下来你真地去算它,那怎么真地去算?你有那个policy,然后真的去玩那个游戏。就玩很多次,玩个一百万次。然后就去真地估说,在某一个 state, 你会得到的 Q value 到底有多少。你会得到说在某一个 state,采取某一个 action。你接下来会得到 accumulated reward 是多少。你会发现估测出来的值是远比实际的值大。在每一个游戏都是这样,都大很多。所以今天要 propose Double DQN 的方法,它可以让估测的值跟实际的值是比较接近的。我们先看它的结果,蓝色的锯齿状的线是Double DQN 的 Q-network 所估测出来的Q value,蓝色的无锯齿状的线是真正的Q value,你会发现它们是比较接近的。 用 network 估测出来的就不用管它,比较没有参考价值。用 Double DQN 得出来真正的 accumulated reward,在这 3 个case 都是比原来的DQN 高的,代表 Double DQN learn 出来那个 policy 比较强。所以它实际上得到的reward 是比较大的。虽然一般的 DQN 的 Q-network 高估了自己会得到的reward,但实际上它得到的 reward 是比较低的。 ![](img/7.2.png) -第三个 solution 是特别 design 一个network 的架构,特别 design 你的 Q-function,使得解那个 arg max 的 problem 变得非常容易。也就是这边的 Q-function 不是一个 general 的 Q-function,特别设计一下它的样子,让你要找让这个 Q-function 最大的 a 的时候非常容易。这边是一个例子,这边有我们的 Q-function,然后这个 Q-function 它的做法是这样。 +Q: 为什么 Q value 总是被高估了呢? -* Input 你的 state s,通常它就是一个 image, 它可以用一个向量或一个 matrix 来表示。 -* Input 这个 s,这个 Q-function 会 output 3 个东西。它会 output $\mu(s)$,这是一个 vector。它会 output $\Sigma(s)$ ,这是一个 matrix。它会 output $V(s)$,是一个 scalar。 -* output 这 3 个东西以后, 我们知道 Q-function 其实是吃一个 s 跟 a,然后决定一个 value。Q-function 意思是说在某一个 state,take 某一个 action 的时候,你 expected 的 reward 有多大。到目前为止这个 Q-function 只吃 s,它还没有吃 a 进来,a 在那里呢,当这个 Q-function 吐出 $\mu$、 $\Sigma$ 跟 $V$ 的时候,我们才把 s 引入,用 a 跟 $\mu(s)、\Sigma(s)、V$ 互相作用一下,你才算出最终的 Q value。 +A: 因为实际上在做的时候,是要让左边这个式子跟右边这个 target 越接近越好。那你会发现说,target 的值很容易一不小心就被设得太高。因为在算这个 target 的时候,我们实际上在做的事情是看哪一个a 可以得到最大的Q value,就把它加上去,就变成我们的target。所以假设有某一个 action 得到的值是被高估的。 -* a 怎么和这 3 个东西互相作用呢?实际上 $Q(s,a)$,你的 Q-function 的运作方式是先 input s,让你得到 $\mu,\Sigma$ 跟 V。然后再 input a,然后接下来把 a 跟 $\mu$ 相减。注意一下 a 现在是 continuous 的 action,所以它也是一个 vector,假设你现在是要操作机器人的话,这个 vector 的每一个 dimension,可能就对应到机器人的某一个关节,它的数值就是那关节的角度,所以 a 是一个 vector。把 a 的这个 vector减掉 $\mu$ 的这个 vector,取 transpose,所以它是一个横的 vector。$\Sigma$ 是一个 matrix。然后 a 减掉 $\mu(s)$ ,a 和 $\mu(s)$ 都是 vector,减掉以后还是一个竖的 vector。所以 $-(a-\mu(s))^{T} \Sigma(s)(a-\mu(s))+V(s)$ 是一个 scalar,这一个数值就是你的 Q value $Q(s,a)$,。 - -* 假设我们的 $Q(s,a)$ 定义成这个样子,我们要怎么找到一个 a去 maximize 这个 Q value 呢?其实这个 solution 非常简单,什么样的 a, 可以让这一个 Q-function 最终的值最大呢?。因为 $(a-\mu(s))^{T} \Sigma(s)(a-\mu(s))$ 一定是正的,它前面乘上一个负号,所以第一项就假设我们不要看这个负号的话,第一项这个值越小,你最终的这个 Q value 就越大。因为我们是把 V(s) 减掉第一项,所以第一项的值越小,最后的 Q value 就越大。怎么让第一项的值最小呢?你直接把 a 带 $\mu$,让它变成 0,就会让第一项的值最小。 - -* $\Sigma$ 一定是正定的。因为你知道这个东西就像是那个 Gaussian distribution,所以 $\mu$ 就是 Gaussian 的 mean,$\Sigma$ 就是 Gaussian 的 variance。但 variance 是一个 positive definite 的 matrix,怎么样让这个 $\Sigma$ 一定是 positive definite 的 matrix 呢?其实在 $Q^{\pi}$ 里面,它不是直接 output $\Sigma$,如果直接 output 一个 $\Sigma$, 它不一定是 positive definite 的 matrix。它其实是 output 一个 matrix,然后再把那个 matrix 跟另外一个 matrix 做 transpose 相乘, 然后可以确保 $\Sigma $ 是 positive definite 的。这边要强调的点就是说,实际上它不是直接output 一个 matrix,你再去那个 paper 里面 check 一下它的 trick,它可以保证说 $\Sigma$ 是 positive definite 的。 -* 你把 a 带 $\mu(s)$ 以后呢,你可以让 Q 的值最大。所以今天假设要你 arg max 这个东西,虽然 in general 而言,若 Q 是一个 general function, 你很难算,但是我们这边 design 了 Q 这个 function,a 只要设 $\mu(s)$,我们就得到 maximum 的 value。你在解这个 arg max 的 problem 的时候就变得非常容易。所以 Q-learning 也可以用在 continuous 的 case,只是就是有一些局限,就是你的 function 就是不能够随便乱设,它必须有一些限制。 +举例来说, 现在有 4 个 actions,本来其实它们得到的值都是差不多的,它们得到的reward 都是差不多的。但是在estimate 的时候,那毕竟是个network。所以estimate 的时候是有误差的。所以假设今天是第一个action它被高估了,假设绿色的东西代表是被高估的量,它被高估了,那这个target 就会选这个action。然后就会选这个高估的Q value来加上$r_t$,来当作你的target。如果第4 个action 被高估了,那就会选第4 个action 来加上$r_t$ 来当作你的target value。所以你总是会选那个Q value 被高估的,你总是会选那个reward 被高估的action 当作这个max 的结果去加上$r_t$ 当作你的target。所以你的target 总是太大。 ![](img/7.3.png) +Q: 怎么解决这target 总是太大的问题呢? -第 4 招就是不要用 Q-learning。用 Q-learning 处理 continuous 的 action 还是比较麻烦。 +A: 在 Double DQN 里面,选 action 的 Q-function 跟算 value 的 Q-function,不是同一个。在原来的DQN 里面,你穷举所有的 a,把每一个a 都带进去, 看哪一个 a 可以给你的 Q value 最高,那你就把那个 Q value 加上$r_t$。但是在 Double DQN 里面,你有两个 Q-network,第一个 Q-network,决定哪一个 action 的 Q value 最大,你用第一个 Q-network 去带入所有的 a,去看看哪一个Q value 最大。然后你决定你的action 以后,你的 Q value 是用 $Q'$ 算出来的,这样子有什么好处呢?为什么这样就可以避免 over estimate 的问题呢?因为今天假设我们有两个 Q-function,假设第一个Q-function 它高估了它现在选出来的action a,那没关系,只要第二个Q-function $Q'$ 没有高估这个action a 的值,那你算出来的,就还是正常的值。假设反过来是 $Q'$ 高估了某一个action 的值,那也没差, 因为反正只要前面这个Q 不要选那个action 出来就没事了。这个就是 Double DQN 神奇的地方。 -我们讲了 policy based 的方法 PPO ,讲了 value based 的方法 Q-learning。这两者其实是可以结合在一起的, 也就是 Actor-Critic 的方法。 \ No newline at end of file +Q: 哪来 Q 跟 $Q'$ 呢?哪来两个 network 呢? + +A: 在实现上,你有两个 Q-network, 一个是 target 的 Q-network,一个是真正你会 update 的 Q-network。所以在 Double DQN 里面,你的实现方法会是拿你会 update 参数的那个 Q-network 去选action,然后你拿target 的network,那个固定住不动的network 去算value。而 Double DQN 相较于原来的 DQN 的更改是最少的,它几乎没有增加任何的运算量,连新的network 都不用,因为你原来就有两个network 了。你唯一要做的事情只有,本来你在找最大的a 的时候,你在决定这个a 要放哪一个的时候,你是用$Q'$ 来算,你是用target network 来算,现在改成用另外一个会 update 的 Q-network 来算。 + +假如你今天只选一个tip 的话,正常人都是 implement Double DQN,因为很容易实现。 + +## Dueling DQN +![](img/7.4.png) +第二个 tip 是 `Dueling DQN`。其实 Dueling DQN 也蛮好做的,相较于原来的DQN。它唯一的差别是改了network 的架构,Dueling DQN 唯一做的事情是改network 的架构。Q-network 就是input state,output 就是每一个action 的Q value。dueling DQN 唯一做的事情,是改了network 的架构,其它的算法,你都不要去动它。 + +Q: Dueling DQN 是怎么改了network 的架构呢? + +A: 本来的DQN 就是直接output Q value 的值。现在这个dueling 的DQN,就是下面这个network 的架构。它不直接output Q value 的值,它分成两条path 去运算,第一个path,它算出一个scalar,这个scalar 我们叫做$V(s)$。因为它跟input s 是有关系,所以叫做$V(s)$,$V(s)$ 是一个scalar。下面这个会output 一个vector,这个vector 叫做$A(s,a)$。下面这个vector,它是每一个action 都有一个value。然后你再把这两个东西加起来,就得到你的Q value。 + +![](img/7.5.png) + +Q: 这么改有什么好处? + +A : 那我们假设说,原来的$Q(s,a)$ 就是一个table。我们假设 state 是discrete 的,实际上state 不是discrete 的。那为了说明方便,我们假设就是只有4 个不同的state,只有3 个不同的action,所以$Q(s,a)$ 你可以看作是一个table。 + +我们知道: +$$ +Q(s,a) = V(s) + A(s,a) +$$ + +其中 + +* $V(s)$ 是对不同的state 它都有一个值。 +* $A(s,a)$ 它是对不同的state,不同的action都有一个值。 + +你把这个 V 的值加到 A 的每一个 column 就会得到Q 的值。把 2+1,2+(-1),2+0,就得到 3,1,2,以此类推。 + +如上图所示,假设说你在train network 的时候,target 是希望这一个值变成 4,这一个值变成 0。但是你实际上能更改的并不是Q 的值,你的network 更改的是V 跟A 的值。根据network 的参数,V 跟A 的值output 以后,就直接把它们加起来,所以其实不是更动Q 的值。然后在learn network 的时候,假设你希望这边的值,这个3 增加1 变成 4,这个-1 增加1 变成 0。最后你在train network 的时候,network 可能会说,我们就不要动这个 A 的值,就动 V 的值,把 V 的值从0 变成 1。把0 变成1 有什么好处呢?你会发现说,本来你只想动这两个东西的值,那你会发现说,这个第三个值也动了,-2 变成 -1。所以有可能说你在某一个state,你明明只sample 到这2 个action,你没sample 到第三个action,但是你其实也可以更改第三个action 的Q value。这样的好处就是你不需要把所有的 state-action pair 都sample 过,你可以用比较efficient 的方式去 estimate Q value 出来。因为有时候你update 的时候,不一定是update 下面这个table。而是只update 了$V(s)$,但update $V(s)$ 的时候,只要一改所有的值就会跟着改。这是一个比较有效率的方法,去使用你的data,这个是Dueling DQN 可以带给我们的好处。 + +那可是接下来有人就会问说会不会最后learn 出来的结果是说,反正machine 就学到 V 永远都是 0,然后反正A 就等于 Q,那你就没有得到任何 Dueling DQN 可以带给你的好处, 就变成跟原来的DQN 一模一样。为了避免这个问题,实际上你要给 A 一些constrain,让update A 其实比较麻烦,让network 倾向于会想要去用V 来解问题。 + +举例来说,你可以看原始的文献,它有不同的constrain 。那一个最直觉的constrain 是你必须要让这个A 的每一个column 的和都是 0,所以看我这边举的例子,我的column 的和都是 0。那如果这边column 的和都是 0,这边这个V 的值,你就可以想成是上面 Q 的每一个column 的平均值。这个平均值,加上这些值才会变成是Q 的value。所以今天假设你发现说你在update 参数的时候,你是要让整个row 一起被update。你就不会想要update 这边,因为你不会想要update A这个matrix。因为 A 这个matrix 的每一个column 的和都要是 0,所以你没有办法说,让这边的值,通通都+1,这件事是做不到的。因为它的constrain 就是你的和永远都是要 0。所以不可以都+1,这时候就会强迫network 去update V 的值,然后让你可以用比较有效率的方法,去使用你的data。 + +![](img/7.6.png) + +实现时,你要给这个 A 一个 constrain。举个例子,假设你有 3 个actions,然后在这边 output 的 vector 是7 3 2,你在把这个 A 跟这个 V 加起来之前,先加一个normalization,就好像做那个layer normalization 一样。加一个normalization,这个normalization 做的事情就是把 7+3+2 加起来等于 12,12/3 = 4。然后把这边通通减掉 4,变成 3, -1, 2。再把 3, -1, 2 加上 1.0,得到最后的Q value。这个normalization 的 step 就是 network 的其中一部分,在train 的时候,你从这边也是一路 back propagate 回来的,只是 normalization 是没有参数的,它只是一个normalization 的operation。把它可以放到network 里面,跟network 的其他部分 jointly trained,这样 A 就会有比较大的 constrain。这样network 就会给它一些benefit, 倾向于去update V 的值,这个是Dueling DQN。 + + +## Prioritized Experience Replay + +![](img/7.7.png) +有一个技巧叫做 `Prioritized Experience Replay`。Prioritized Experience Replay 是什么意思呢? + +我们原来在 sample data 去 train 你的 Q-network 的时候,你是 uniformly 从 experience buffer 里面去 sample data。那这样不见得是最好的, 因为也许有一些 data 比较重要。假设有一些 data,你之前有 sample 过。你发现这些 data 的 TD error 特别大(TD error 就是 network 的 output 跟 target 之间的差距),那这些 data 代表说你在 train network 的时候, 你是比较 train 不好的。那既然比较 train 不好, 那你就应该给它比较大的概率被 sample 到,即给它 `priority`。这样在 training 的时候才会多考虑那些 train 不好的 training data。实际上在做 prioritized experience replay 的时候,你不仅会更改 sampling 的 process,你还会因为更改了 sampling 的 process,更改 update 参数的方法。所以 prioritized experience replay 不仅改变了 sample data 的 distribution,还改变了 training process。 +## Balance between MC and TD + +![](img/7.8.png) +另外一个可以做的方法是,你可以balance MC 跟TD。MC 跟 TD 的方法各自有各自的优劣。我们怎么在MC 跟TD 里面取得一个平衡呢?我们的做法是这样,在TD 里面,在某一个state $s_t$采取某一个action $a_t$ 得到 reward $r_t$,接下来跳到那一个state $s_{t+1}$。但是我们可以不要只存一个step 的data,我们存 N 个step 的data。 + +我们记录在$s_t$ 采取$a_t$,得到$r_t$,会跳到什么样$s_t$。一直纪录到在第N 个step 以后,在$s_{t+N}$采取$a_{t+N}$得到 reward $r_{t+N}$,跳到$s_{t+N+1}$的这个经验,通通把它存下来。实际上你今天在做update 的时候, 在做你 Q-network learning 的时候,你的learning 的方法会是这样,你learning 的时候,要让 $Q(s_t,a_t)$ 跟你的target value 越接近越好。$\hat{Q}$ 所计算的不是$s_{t+1}$,而是$s_{t+N+1}$的。你会把 N 个step 以后的state 丢进来,去计算 N 个step 以后,你会得到的reward。要算 target value 的话,要再加上multi-step 的reward $\sum_{t^{\prime}=t}^{t+N} r_{t^{\prime}}$ ,multi-step 的 reward 是从时间 t 一直到 t+N 的 N 个reward 的和。然后希望你的 $Q(s_t,a_t)$ 和 target value 越接近越好。 + +你会发现说这个方法就是 MC 跟 TD 的结合。因此它就有 MC 的好处跟坏处,也有 TD 的好处跟坏处。如果看它的这个好处的话,因为我们现在 sample 了比较多的step,之前是只sample 了一个step, 所以某一个step 得到的data 是real 的,接下来都是Q value 估测出来的。现在sample 比较多step,sample N 个step 才估测value,所以估测的部分所造成的影响就会比小。当然它的坏处就跟MC 的坏处一样,因为你的 r 比较多项,你把 N 项的 r 加起来,你的variance 就会比较大。但是你可以去调这个N 的值,去在variance 跟不精确的 Q 之间取得一个平衡。N 就是一个hyper parameter,你要调这个N 到底是多少,你是要多 sample 三步,还是多 sample 五步。 + +## Noisy Net +![](img/7.9.png) +有一个技术是要improve 这个exploration 这件事,我们之前讲的Epsilon Greedy 这样的 exploration 是在action 的space 上面加noise,但是有另外一个更好的方法叫做`Noisy Net`,它是在参数的space 上面加noise。Noisy Net 的意思是说,每一次在一个episode 开始的时候,在你要跟环境互动的时候,你就把你的Q-function 拿出来,Q-function 里面其实就是一个network ,就变成你把那个network 拿出来,在network 的每一个参数上面加上一个Gaussian noise。那你就把原来的Q-function 变成$\tilde{Q}$ 。因为$\hat{Q}$ 已经用过,$\hat{Q}$ 是那个target network,我们用 $\tilde{Q}$ 来代表一个`Noisy Q-function`。我们把每一个参数都可能都加上一个Gaussian noise,就得到一个新的network 叫做$\tilde{Q}$。这边要注意在每个episode 开始的时候,开始跟环境互动之前,我们就 sample network。接下来你就会用这个固定住的 noisy network 去玩这个游戏,直到游戏结束,你才重新再去sample 新的noise。OpenAI 跟 Deep mind 又在同时间 propose 一模一样的方法,通通都publish 在ICLR 2018,两篇paper 的方法就是一样的。不一样的地方是,他们用不同的方法,去加noise。OpenAI 加的方法好像比较简单,他就直接加一个 Gaussian noise 就结束了,就你把每一个参数,每一个weight都加一个Gaussian noise 就结束了。Deep mind 做比较复杂,他们的noise 是由一组参数控制的,也就是说 network 可以自己决定说它那个noise 要加多大,但是概念就是一样的。总之就是把你的Q-function的里面的那个network 加上一些noise,把它变得有点不一样,跟原来的Q-function 不一样,然后拿去跟环境做互动。两篇paper 里面都有强调说,你这个参数虽然会加noise,但在同一个episode 里面你的参数就是固定的,你是在换episode, 玩第二场新的游戏的时候,你才会重新sample noise,在同一场游戏里面就是同一个noisy Q-network 在玩那一场游戏,这件事非常重要。为什么这件事非常重要呢?因为这是导致了Noisy Net 跟原来的Epsilon Greedy 或其它在action 做sample 方法的本质上的差异。 + +![](img/7.10.png) + +有什么样本质上的差异呢?在原来sample 的方法,比如说Epsilon Greedy 里面,就算是给同样的state,你的agent 采取的action 也不一定是一样的。因为你是用sample 决定的,given 同一个state,要根据 Q-function 的network,你会得到一个action,你 sample 到random,你会采取另外一个action。所以 given 同样的state,如果你今天是用Epsilon Greedy 的方法,它得到的 action 是不一样的。但实际上你的policy 并不是这样运作的啊。在一个真实世界的policy,给同样的state,他应该会有同样的回应。而不是给同样的state,它其实有时候吃 Q-function,然后有时候又是随机的,所以这是一个不正常的action,是在真实的情况下不会出现的action。但是如果你是在Q-function 上面去加noise 的话, 就不会有这个情形。因为如果你今天在Q-function 上加 noise,在Q-function 的network 的参数上加noise,那在整个互动的过程中,在同一个episode 里面,它的network 的参数总是固定的,所以看到同样的state,或是相似的state,就会采取同样的action,那这个是比较正常的。在paper 里面有说,这个叫做 `state-dependent exploration`,也就是说你虽然会做 explore 这件事, 但是你的explore 是跟state 有关系的,看到同样的state, 你就会采取同样的exploration 的方式,而 noisy 的 action 只是随机乱试。但如果你是在参数下加noise,那在同一个episode 里面,里面你的参数是固定的。那你就是有系统地在尝试,每次会试说,在某一个state,我都向左试试看。然后再下一次在玩这个同样游戏的时候,看到同样的state,你就说我再向右试试看,你是有系统地在explore 这个环境。 + +## Distributional Q-function +![](img/7.11.png) + +还有一个技巧叫做 Distributional Q-function。我们不讲它的细节,只告诉你大致的概念。Distributional Q-function 还蛮有道理的, 但是它没有红起来。你就发现说没有太多人真的在实现的时候用这个技术,可能一个原因就是它不好实现。它的意思是什么?Q-function 到底是什么意思啊,Q-function 是 accumulated reward 的期望值,所以我们算出来的这个Q value 其实是一个期望值。因为环境是有随机性的,在某一个state 采取某一个action 的时候,我们把所有的reward 玩到游戏结束的时候所有的 reward 进行一个统计,你其实得到的是一个distribution。也许在reward 得到0 的机率很高,在-10 的概率比较低,在+10 的概率比较低,但是它是一个distribution。我们对这一个distribution 算它的mean才是这个Q value,我们算出来是 expected accumulated reward。所以这accumulated reward 是一个distribution,对它取expectation,对它取mean,你得到了Q value。但不同的distribution,它们其实可以有同样的mean。也许真正的distribution 是右边的distribution,它算出来的 mean 跟左边的 distribution 算出来的mean 其实是一样的,但它们背后所代表的distribution 其实是不一样的。假设我们只用一个 expected 的 Q value 来代表整个reward 的话,其实可能会丢失一些 information,你没有办法 model reward 的distribution。 + +![](img/7.12.png) + +Distributional Q-function 它想要做的事情是model distribution,怎么做呢?在原来的 Q-function 里面,假设你只能够采取 $a_1$, $a_2$, $a_3$, 3 个actions,那你就是input 一个state,output 3 个values。3 个values 分别代表3 个actions 的Q value,但是这个 Q value 是一个distribution 的期望值。所以 Distributional Q-function 的想法就是何不直接output 那个 distribution。但是要直接output 一个distribution 也不知道怎么做嘛。实际上的做法是说, 假设 distribution 的值就分布在某一个 range 里面,比如说-10 到10,那把-10 到10 中间拆成一个一个的bin,拆成一个一个的长条图。举例来说,在这个例子里面,每一个action 的 reward 的space 就拆成 5 个bin。假设reward 可以拆成5 个bin 的话,今天你的Q-function 的output 是要预测说,你在某一个 state,采取某一个action,你得到的reward,落在某一个bin 里面的概率。所以其实这边的概率的和,这些绿色的bar 的和应该是 1,它的高度代表说,在某一个state,采取某一个action 的时候,它落在某一个bin 的机率。这边绿色的代表action 1,红色的代表action 2,蓝色的代表action 3。所以今天你就可以真的用Q-function 去 estimate $a_1$ 的distribution,$a_2$ 的distribution,$a_3$ 的distribution。那实际上在做testing 的时候, 我们还是要选某一个action去执行嘛,那选哪一个action 呢?实际上在做的时候,还是选这个mean 最大的那个action 去执行。但假设我们今天可以 model distribution 的话,除了选mean 最大的以外,也许在未来你可以有更多其他的运用。举例来说,你可以考虑它的distribution 长什么样子。若distribution variance 很大,代表说采取这个action 虽然mean 可能平均而言很不错,但也许风险很高,你可以train一个network 它是可以规避风险的。就在 2 个action mean 都差不多的情况下,也许可以选一个风险比较小的 action 来执行,这是 Distributional Q-function 的好处。关于怎么train 这样的 Q-network 的细节,我们就不讲,你只要记得说 Q-network 有办法output 一个distribution 就对了。我们可以不只是估测得到的期望reward mean 的值。我们其实是可以估测一个distribution 的。 + +## Rainbow + +![](img/7.13.png) + +最后一个技巧叫做 rainbow 。Rainbow 就是把刚才所有的方法都综合起来就变成 rainbow 。因为刚才每一个方法,就是有一种自己的颜色,把所有的颜色通通都合起来,就变成rainbow,它把原来的DQN 也算是一种方法,故有 7 色。 + +那我们来看看这些不同的方法。横轴是 training process,纵轴是玩了10 几个 Atari 小游戏的平均的分数的和,但它取的是median 的分数,为什么是取 median 不是直接取平均呢?因为它说每一个小游戏的分数,其实差很多。如果你取平均的话,到时候某几个游戏就dominate 你的结果,所以它取median 的值。 + +如果你是一般的DQN,就灰色这一条线,就没有很强。那如果是你换noisy DQN,就强很多。如果这边每一个单一颜色的线是代表说只用某一个方法,那紫色这一条线是DDQN(Double DQN),DDQN 还蛮有效的。然后 Prioritized DDQN、Dueling DDQN 和 Distributional DQN 都蛮强的,它们都差不多很强的。A3C 其实是 Actor-Critic 的方法。单纯的 A3C 看起来是比DQN 强的。这边怎么没有 multi-step 的方法,multi-step 的方法就是 balance TD 跟MC,我猜是因为 A3C 本身内部就有做 multi-step 的方法,所以他可能觉得说有 implement A3C 就算是有 implement multi-step 的方法。所以可以把这个 A3C 的结果想成是 multi-step 方法的结果。其实这些方法他们本身之间是没有冲突的,所以全部都用上去就变成七彩的一个方法,就叫做rainbow,然后它很高。 + +![](img/7.14.png) + +上图是说,在rainbow 这个方法里面, 如果我们每次拿掉其中一个技术,到底差多少。因为现在是把所有的方法都加在一起,发现说进步很多,但会不会有些方法其实是没用的。所以看看说, 每一个方法哪些方法特别有用,哪些方法特别没用。这边的虚线就是拿掉某一种方法以后的结果,你会发现说,黄色的虚线,拿掉 multi-step 掉很多。Rainbow 是彩色这一条,拿掉 multi-step 会掉下来。拿掉 Prioritized Experience Replay 后也马上就掉下来。拿掉这个distribution,它也掉下来。 + +这边有一个有趣的地方是说,在开始的时候,distribution 训练的方法跟其他方法速度差不多。但是如果你拿掉distribution 的时候,你的训练不会变慢,但是 performance 最后会收敛在比较差的地方。拿掉 Noisy Net 后performance 也是差一点。拿掉Dueling 也是差一点。拿掉 Double 没什么差,所以看来全部合在一起的时候,Double 是比较没有影响的。其实在paper 里面有给一个make sense 的解释,其实当你有用 Distributional DQN的 时候,本质上就不会over estimate 你的reward。我们是为了避免over estimate reward 才加了Double DQN。那在paper 里面有讲说,如果有做 Distributional DQN,就比较不会有over estimate 的结果。 事实上他有真的算了一下发现说,其实多数的状况是 under estimate reward 的,所以会变成Double DQN 没有用。那为什么做 Distributional DQN,不会over estimate reward,反而会under estimate reward 呢?因为这个 distributional DQN 的 output 的是一个distribution 的range,output 的 range 不可能是无限宽的,你一定是设一个range, 比如说我最大output range 就是从-10 到10。假设今天得到的reward 超过10 怎么办?是100 怎么办,就当作没看到这件事。所以 reward 很极端的值,很大的值其实是会被丢掉的, 所以用 Distributional DQN 的时候,你不会有over estimate 的现象,反而会 under estimate。 \ No newline at end of file diff --git a/docs/chapter7/img/7.1.png b/docs/chapter7/img/7.1.png index cedda5a..f2e4c77 100644 Binary files a/docs/chapter7/img/7.1.png and b/docs/chapter7/img/7.1.png differ diff --git a/docs/chapter7/img/7.10.png b/docs/chapter7/img/7.10.png new file mode 100644 index 0000000..bbe4247 Binary files /dev/null and b/docs/chapter7/img/7.10.png differ diff --git a/docs/chapter7/img/7.11.png b/docs/chapter7/img/7.11.png new file mode 100644 index 0000000..da79108 Binary files /dev/null and b/docs/chapter7/img/7.11.png differ diff --git a/docs/chapter7/img/7.12.png b/docs/chapter7/img/7.12.png new file mode 100644 index 0000000..b2ac0a0 Binary files /dev/null and b/docs/chapter7/img/7.12.png differ diff --git a/docs/chapter7/img/7.13.png b/docs/chapter7/img/7.13.png new file mode 100644 index 0000000..8957ca5 Binary files /dev/null and b/docs/chapter7/img/7.13.png differ diff --git a/docs/chapter7/img/7.14.png b/docs/chapter7/img/7.14.png new file mode 100644 index 0000000..8ecd196 Binary files /dev/null and b/docs/chapter7/img/7.14.png differ diff --git a/docs/chapter7/img/7.2.png b/docs/chapter7/img/7.2.png index b4bdc3b..02c9d86 100644 Binary files a/docs/chapter7/img/7.2.png and b/docs/chapter7/img/7.2.png differ diff --git a/docs/chapter7/img/7.3.png b/docs/chapter7/img/7.3.png index cc9c314..0cdff9d 100644 Binary files a/docs/chapter7/img/7.3.png and b/docs/chapter7/img/7.3.png differ diff --git a/docs/chapter7/img/7.4.png b/docs/chapter7/img/7.4.png new file mode 100644 index 0000000..a312b48 Binary files /dev/null and b/docs/chapter7/img/7.4.png differ diff --git a/docs/chapter7/img/7.5.png b/docs/chapter7/img/7.5.png new file mode 100644 index 0000000..68a78e0 Binary files /dev/null and b/docs/chapter7/img/7.5.png differ diff --git a/docs/chapter7/img/7.6.png b/docs/chapter7/img/7.6.png new file mode 100644 index 0000000..7197cf6 Binary files /dev/null and b/docs/chapter7/img/7.6.png differ diff --git a/docs/chapter7/img/7.7.png b/docs/chapter7/img/7.7.png new file mode 100644 index 0000000..aa3cf84 Binary files /dev/null and b/docs/chapter7/img/7.7.png differ diff --git a/docs/chapter7/img/7.8.png b/docs/chapter7/img/7.8.png new file mode 100644 index 0000000..d776fb0 Binary files /dev/null and b/docs/chapter7/img/7.8.png differ diff --git a/docs/chapter7/img/7.9.png b/docs/chapter7/img/7.9.png new file mode 100644 index 0000000..49f17b7 Binary files /dev/null and b/docs/chapter7/img/7.9.png differ diff --git a/docs/chapter8/chapter8.md b/docs/chapter8/chapter8.md index b96f8a1..5e7decb 100644 --- a/docs/chapter8/chapter8.md +++ b/docs/chapter8/chapter8.md @@ -1,117 +1,34 @@ -# Actor-Critic - -## Actor-Critic +# Q-learning for Continuous Actions ![](img/8.1.png) -在 `Actor-Critic` 里面,最知名的方法就是 `A3C(Asynchronous Advantage Actor-Critic)`。如果去掉前面这个 Asynchronous,只有 `Advantage Actor-Critic`,就叫做 `A2C`。如果前面加了 Asynchronous,变成 Asynchronous Advantage Actor-Critic,就变成 A3C。 -那我们复习一下 policy gradient,在 policy gradient,我们在 update policy 的参数 $\theta$ 的时候,我们是用了下面这个式子来算出我们的 gradient。 -$$ -\nabla \bar{R}_{\theta} \approx \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}}\left(\sum_{t^{\prime}=t}^{T_{n}} \gamma^{t^{\prime}-t} r_{t^{\prime}}^{n}-b\right) \nabla \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right) -$$ -这个式子是在说,我们先让 agent 去跟环境互动一下,那我们可以计算出在某一个 state s,采取了某一个 action a 的概率 $p_{\theta}(a_t|s_t)$。接下来,我们去计算在某一个 state s 采取了某一个 action a 之后,到游戏结束为止,accumulated reward 有多大。我们把这些 reward 从时间 t 到时间 T 的 reward 通通加起来,并且会在前面乘一个 discount factor,可能设 0.9 或 0.99。我们会减掉一个 baseline b,减掉这个值 b 的目的,是希望括号这里面这一项是有正有负的。如果括号里面这一项是正的,我们就要增加在这个 state 采取这个 action 的机率;如果括号里面是负的,我们就要减少在这个 state 采取这个 action 的机率。 +继续讲一下 Q-learning,其实跟 policy gradient based 方法比起来,Q-learning 其实是比较稳的。policy gradient 其实是没有太多游戏是玩得起来的。policy gradient 其实比较不稳,尤其在没有 PPO 之前,你很难用 policy gradient 做什么事情。Q-learning 相对而言是比较稳的。最早 deepmind 的 paper 拿 deep reinforcement learning 来玩 Atari 的游戏,用的就是 Q-learning。那我觉得 Q-learning 比较容易 train 的一个理由是:在 Q-learning 里面,你只要能够 estimate 出Q-function,就保证你一定可以找到一个比较好的 policy。也就是你只要能够 estimate 出 Q-function,就保证你可以 improve 你的 policy。而 estimate Q-function 这件事情,是比较容易的,为什么?因为它就是一个 regression 的 problem。在这个 regression 的 problem 里面, 你可以轻易地知道说,你现在的 model learn 的是不是越来越好,你只要看那个 regression 的 loss 有没有下降,你就知道说你的 model learn 的好不好。所以 estimate Q-function 相较于 learn 一个 policy 是比较容易的。你只要 estimate Q-function,就可以保证说现在一定会得到比较好的 policy。 -我们把用 G 来表示 accumulated reward。但 G 这个值,其实是非常的 unstable 的。因为互动的 process 本身是有随机性的,所以在某一个 state s 采取某一个 action a,然后计算 accumulated reward,每次算出来的结果都是不一样的,所以 G 其实是一个 random variable。给同样的 state s,给同样的 action a,G 可能有一个固定的 distribution。但我们是采取 sample 的方式,我们在某一个 state s 采取某一个 action a,然后玩到底,我们看看得到多少的 reward,我们就把这个东西当作 G。把 G 想成是一个 random variable 的话,我们实际上是对这个 G 做一些 sample,然后拿这些 sample 的结果,去 update 我们的参数。但实际上在某一个 state s 采取某一个 action a,接下来会发生什么事,它本身是有随机性的。虽然说有个固定的 distribution,但它本身是有随机性的,而这个 random variable 的 variance 可能会非常大。你在同一个 state 采取同一个 action,你最后得到的结果可能会是天差地远的。假设我们可以 sample 足够的次数,在每次 update 参数之前,我们都可以 sample 足够的次数,那其实没有什么问题。但问题就是我们每次做 policy gradient,每次 update 参数之前都要做一些 sample,这个 sample 的次数其实是不可能太多的,我们只能够做非常少量的 sample。如果你正好 sample 到差的结果,比如说你 sample 到 G = 100,sample 到 G = -10,那显然你的结果会是很差的。 +所以一般而言 Q-learning 是比较容易操作。那 Q-learning 有什么问题呢?最大的问题是它不太容易处理 continuous action,很多时候你的 action 是 continuous 的。什么时候你的 action 会是 continuous 的呢?我们玩 Atari 的游戏,你的 agent 只需要决定比如说上下左右,这种 action 是 discrete 的。那很多时候你的 action 是 continuous 的。举例来说假设你的 agent 要做的事情是开自驾车,它要决定说它方向盘要左转几度, 右转几度,这是 continuous 的。假设你的 agent 是一个机器人,假设它身上有 50 个 关节,它的每一个 action 就对应到它身上的这 50 个关节的角度。而那些角度也是 continuous 的。所以很多时候你的 action,并不是一个 discrete 的东西,它是一个 vector,这个 vector 里面,它的每一个 dimension 都有一个对应的 value,都是 real number,它是 continuous 的。 + +假设你的 action 是 continuous 的时候,做 Q-learning 就会有困难。因为在做 Q-learning 里面一个很重要的一步是你要能够解这个 optimization 的 problem。你 estimate 出Q-function $Q(s,a)$ 以后,必须要找到一个 a,它可以让 $Q(s,a)$ 最大。假设 a 是 discrete 的,那 a 的可能性都是有限的。举例来说,Atari 的小游戏里面,a 就是上下左右跟开火,它是有限的,你可以把每一个可能的 action 都带到 Q 里面算它的 Q value。但假如 a 是 continuous 的,你无法穷举所有可能 continuous action,试试看哪一个 continuous action 可以让 Q 的 value 最大。所以怎么办呢?在概念上,我们就是要能够解这个问题。怎么解这个问题呢?就有各种不同的 solution。 + +第一个 solution 是假设你不知道怎么解这个问题,因为 a 是很多的,a 是没有办法穷举的。怎么办?用 sample 的。Sample 出 N 个 可能的 a,一个一个带到 Q-function 里面,看谁最快?这个方法其实也不会太不 efficient, 因为你真的在运算的时候,你会用 GPU,所以你一次会把 N 个 continuous action都丢到 Q-function 里面,一次得到 N 个 Q value,然后看谁最大。当然这个不是一个 非常精确的做法,因为你真的没有办法做太多的 sample, 所以你 estimate 出来的 Q value,你最后决定的 action 可能不是非常的精确, 这是第一个 solution。 + +第二个 solution 是什么呢?今天既然我们要解的是一个 optimization 的 problem。我们其实是要 maximize 我们的 objective function,我们是要 maximize 一个东西, 就可以用 gradient ascent。你就把 a 当作是你的 parameter,然后你要找一组 a 去 maximize 你的 Q-function,你就用 gradient ascent 去 update a 的 value,最后看看你能不能找到一个 a 去 maximize 你的 Q-function,也就是你的 objective function。当然这样子你会遇到的问题,就是 global maximum 的问题, 就不见得能够真的找到 optimal 的结果,而且这个运算量显然很大, 因为你要 iterative 的去 update 你的 a。我们 train 一个 network 就很花时间了。如果你用 gradient ascent 的方法来处理 continuous 的 problem, 等于是你每次要决定要 take 哪一个 action 的时候,你都还要做一次 train network 的 process,显然运算量是很大的。这是第二个 solution。 ![](img/8.2.png) -能不能让这整个 training process 变得比较 stable 一点,能不能够直接估测 G 这个 random variable 的期望值?我们在 state s 采取 action a 的时候,直接用一个 network 去估测在 state s 采取 action a 的时候,G 的期望值。如果这件事情是可行的,那之后 training 的时候,就用期望值来代替 sample 的值,这样会让 training 变得比较 stable。 +第三个 solution 是特别 design 一个network 的架构,特别 design 你的 Q-function,使得解那个 arg max 的 problem 变得非常容易。也就是这边的 Q-function 不是一个 general 的 Q-function,特别设计一下它的样子,让你要找让这个 Q-function 最大的 a 的时候非常容易。这边是一个例子,这边有我们的 Q-function,然后这个 Q-function 它的做法是这样。 -怎么拿期望值代替 sample 的值呢?这边就需要引入 value based 的方法。value based 的方法就是 Q-learning。Q-learning 有两种 functions,有两种 critics。第一种 critic 我们写作 $V^{\pi}(s)$,它的意思是说,假设 actor 是 $\pi$,拿 $\pi$ 去跟环境做互动,当今天我们看到 state s 的时候,接下来 accumulated reward 的期望值有多少。还有一个 critic 叫做 $Q^{\pi}(s,a)$。$Q^{\pi}(s,a)$ 把 s 跟 a 当作 input,它的意思是说,在 state s 采取 action a,接下来都用 actor $\pi$ 来跟环境进行互动,accumulated reward 的期望值是多少。 +* Input 你的 state s,通常它就是一个 image, 它可以用一个向量或一个 matrix 来表示。 +* Input 这个 s,这个 Q-function 会 output 3 个东西。它会 output $\mu(s)$,这是一个 vector。它会 output $\Sigma(s)$ ,这是一个 matrix。它会 output $V(s)$,是一个 scalar。 +* output 这 3 个东西以后, 我们知道 Q-function 其实是吃一个 s 跟 a,然后决定一个 value。Q-function 意思是说在某一个 state,take 某一个 action 的时候,你 expected 的 reward 有多大。到目前为止这个 Q-function 只吃 s,它还没有吃 a 进来,a 在那里呢,当这个 Q-function 吐出 $\mu$、 $\Sigma$ 跟 $V$ 的时候,我们才把 s 引入,用 a 跟 $\mu(s)、\Sigma(s)、V$ 互相作用一下,你才算出最终的 Q value。 -$V^{\pi}$ input s,output 一个 scalar。$Q^{\pi}$ input s,然后它会给每一个 a 都 assign 一个 Q value。这个 estimate 的时候,你可以用 TD 也可以用 MC。用TD 比较稳,用 MC 比较精确。 +* a 怎么和这 3 个东西互相作用呢?实际上 $Q(s,a)$,你的 Q-function 的运作方式是先 input s,让你得到 $\mu,\Sigma$ 跟 V。然后再 input a,然后接下来把 a 跟 $\mu$ 相减。注意一下 a 现在是 continuous 的 action,所以它也是一个 vector,假设你现在是要操作机器人的话,这个 vector 的每一个 dimension,可能就对应到机器人的某一个关节,它的数值就是那关节的角度,所以 a 是一个 vector。把 a 的这个 vector减掉 $\mu$ 的这个 vector,取 transpose,所以它是一个横的 vector。$\Sigma$ 是一个 matrix。然后 a 减掉 $\mu(s)$ ,a 和 $\mu(s)$ 都是 vector,减掉以后还是一个竖的 vector。所以 $-(a-\mu(s))^{T} \Sigma(s)(a-\mu(s))+V(s)$ 是一个 scalar,这一个数值就是你的 Q value $Q(s,a)$,。 + +* 假设我们的 $Q(s,a)$ 定义成这个样子,我们要怎么找到一个 a去 maximize 这个 Q value 呢?其实这个 solution 非常简单,什么样的 a, 可以让这一个 Q-function 最终的值最大呢?。因为 $(a-\mu(s))^{T} \Sigma(s)(a-\mu(s))$ 一定是正的,它前面乘上一个负号,所以第一项就假设我们不要看这个负号的话,第一项这个值越小,你最终的这个 Q value 就越大。因为我们是把 V(s) 减掉第一项,所以第一项的值越小,最后的 Q value 就越大。怎么让第一项的值最小呢?你直接把 a 带 $\mu$,让它变成 0,就会让第一项的值最小。 + +* $\Sigma$ 一定是正定的。因为你知道这个东西就像是那个 Gaussian distribution,所以 $\mu$ 就是 Gaussian 的 mean,$\Sigma$ 就是 Gaussian 的 variance。但 variance 是一个 positive definite 的 matrix,怎么样让这个 $\Sigma$ 一定是 positive definite 的 matrix 呢?其实在 $Q^{\pi}$ 里面,它不是直接 output $\Sigma$,如果直接 output 一个 $\Sigma$, 它不一定是 positive definite 的 matrix。它其实是 output 一个 matrix,然后再把那个 matrix 跟另外一个 matrix 做 transpose 相乘, 然后可以确保 $\Sigma $ 是 positive definite 的。这边要强调的点就是说,实际上它不是直接output 一个 matrix,你再去那个 paper 里面 check 一下它的 trick,它可以保证说 $\Sigma$ 是 positive definite 的。 +* 你把 a 带 $\mu(s)$ 以后呢,你可以让 Q 的值最大。所以今天假设要你 arg max 这个东西,虽然 in general 而言,若 Q 是一个 general function, 你很难算,但是我们这边 design 了 Q 这个 function,a 只要设 $\mu(s)$,我们就得到 maximum 的 value。你在解这个 arg max 的 problem 的时候就变得非常容易。所以 Q-learning 也可以用在 continuous 的 case,只是就是有一些局限,就是你的 function 就是不能够随便乱设,它必须有一些限制。 ![](img/8.3.png) -G 的 random variable 的期望值正好就是 Q ,即 -$$ -E\left[G_{t}^{n}\right]=Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)} -$$ +第 4 招就是不要用 Q-learning。用 Q-learning 处理 continuous 的 action 还是比较麻烦。 -因为这个就是 Q 的定义。Q 的定义就是在某一个 state s,采取某一个 action a,假设 policy 就是 $\pi$ 的情况下会得到的 accumulated reward 的期望值有多大,而这个东西就是 G 的期望值。为什么会这样,因为这个就是 Q 的定义,Q-function 的定义。Accumulated reward 的期望值就是 G 的期望值。所以假设用期望值来代表 $\sum_{t^{\prime}=t}^{T_{n}} \gamma^{t^{\prime}-t} r_{t^{\prime}}^{n}$ 这一项的话,把 Q-function 套在这里就结束了。那我们就可以 Actor 跟 Critic 这两个方法结合起来。 - -有不同的方法来表示 baseline,但一个常见的做法是,你用 value function $V^{\pi_{\theta}}\left(s_{t}^{n}\right)$ 来表示 baseline。Value function 的意思是说,假设 policy 是 $\pi$,在某一个 state s 一直 interact 到游戏结束。那你 expected 的 reward 有多大。 $V^{\pi_{\theta}}\left(s_{t}^{n}\right)$ 没有 involve action,然后 $ Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)}$ 有 involve action。其实 $V^{\pi_{\theta}}\left(s_{t}^{n}\right)$ 会是 $Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)}$ 的期望值,所以$Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)}-V^{\pi_{\theta}}\left(s_{t}^{n}\right)$ 会有正有负,所以 $\sum_{t^{\prime}=t}^{T_{n}} \gamma^{t^{\prime}-t} r_{t^{\prime}}^{n}-b$ 这一项就会是有正有负的。 - -所以我们就把 policy gradient 里面 $\sum_{t^{\prime}=t}^{T_{n}} \gamma^{t^{\prime}-t} r_{t^{\prime}}^{n}-b$ 这一项换成了 $Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)}-V^{\pi_{\theta}}\left(s_{t}^{n}\right)$。 - -![](img/8.4.png) - -如果你这么实现的话,有一个缺点是,你要 estimate 2 个 networks,而不是一个 network。你要 estimate Q-network,你也要 estimate V-network,你 estimate 估测不准的风险就变成两倍。所以我们何不只估测一个 network 就好了呢?事实上在这个 Actor-Critic 方法里面。你可以只估测 V 这个 network,你可以用 V 的值来表示 Q 的值,什么意思呢?$Q^{\pi}\left(s_{t}^{n}, a_{t}^{n}\right)$可以写成$r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)$的期望值,即 - -$$ -Q^{\pi}\left(s_{t}^{n}, a_{t}^{n}\right)=E\left[r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)\right] -$$ - -你在 state s 采取 action a,接下来你会得到 reward r,然后跳到 state, $s_{t+1}$,但是你会得到什么样的 reward r,跳到什么样的 state $s_{t+1}$,它本身是有随机性的。所以要把右边这个式子,取期望值它才会等于 Q-function。但我们现在把期望值这件事情去掉,即 -$$ -Q^{\pi}\left(s_{t}^{n}, a_{t}^{n}\right)=r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right) -$$ - -我们就可以把 Q-function 用 r + V 取代掉,然后得到下式 -$$ -r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)-V^{\pi}\left(s_{t}^{n}\right) -$$ -把这个期望值去掉的好处就是你不需要再 estimate Q 了,你只需要 estimate V 就够了。你只要 estimate 一个 network 就够了,你不需要 estimate 2 个 network,你只需要 estimate 一个 network 就够了。但这样你就引入了一个随机的东西 r ,它是有随机性的,它是一个 random variable。但是这个 random variable,相较于刚才的 accumulated reward G 可能还好,因为它是某一个 step 会得到的 reward。而 G 是所有未来会得到的 reward 的总和。G variance 比较大,r 虽然也有一些 variance,但它的 variance 会比 G 要小。所以把原来 variance 比较大的 G 换成 variance 比较小的 r 也是合理的。如果你觉得把期望值拿掉不靠谱的话,那我就告诉你原始的 A3C paper 试了各式各样的方法,最后做出来就是这个最好这样。当然你可能说,搞不好 estimate Q 跟 V 也都 estimate 很好,那我告诉你就是做实验的时候,最后结果就是这个最好。所以后来大家都用这个。 - -![](img/8.5.png) - -因为 $r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)-V^{\pi}\left(s_{t}^{n}\right)$ 叫做 `Advantage function`。所以这整个方法就叫 `Advantage Actor-Critic`。 - -整个流程是这样子的。我们有一个 $\pi$,有个初始的 actor 去跟环境做互动,先收集资料。在 policy gradient 方法里面收集资料以后,你就要拿去 update policy。但是在 actor-critic 方法里面,你不是直接拿那些资料去 update policy。你先拿这些资料去 estimate value function,你可以用 TD 或 MC 来 estimate value function 。接下来,你再 based on value function,套用下面这个式子去 update $\pi$。 -$$ -\nabla \bar{R}_{\theta} \approx \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}}\left(r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)-V^{\pi}\left(s_{t}^{n}\right)\right) \nabla \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right) -$$ -然后你有了新的 $\pi$ 以后,再去跟环境互动,再收集新的资料,去 estimate value function。然后再用新的 value function 去 update policy,去 update actor。整个 actor-critic 的 algorithm 就是这么运作的。 - -![](img/8.6.png) - -实现 Actor-Critic 的时候,有两个一定会用的 tip。 - -* 第一个 tip 是说,我们需要 estimate 两个 network,estimate V function,另外一个需要 estimate 的 network 是 policy 的 network,也就是你的 actor。 V-network input 一个 state,output 一个 scalar。然后 actor 这个 network,它是 input 一个 state,output 就是一个 action 的 distribution,假设你的 action 是 discrete,不是 continuous 的话,如果是 continuous 的话,它也是一样。如果是 continuous 的话,就只是 output 一个 continuous 的 vector。上图是举的是 discrete 的例子,但 continuous 的 case 其实也是一样的,input 一个 state,然后他决定你现在要 take 那一个 action。**这两个 network,actor 和 critic 的 input 都是 s,所以它们前面几个 layer,其实是可以 share 的。**尤其是假设你今天是玩 Atari 游戏,input 都是 image。那 input 那个 image 都非常复杂,image 很大,通常你前面都会用一些 CNN 来处理,把那些 image 抽象成 high level 的 information。把 pixel level 到 high level information 这件事情,其实对 actor 跟 critic 来说是可以共用的。所以通常你会让 actor 跟 critic 的前面几个 layer 是 shared,你会让 actor 跟 critic 的前面几个 layer 共用同一组参数。那这一组参数可能是 CNN。先把 input 的 pixel 变成比较 high level 的信息,然后再给 actor 去决定说它要采取什么样的行为,给这个 critic,给 value function 去计算 expected reward。 - -* 第二个 tip 是我们一样需要 exploration 的机制。在做 Actor-Critic 的时候,有一个常见的 exploration 的方法是你会对你的 $\pi$ 的 output 的 distribution 下一个 constrain。这个 constrain 是希望这个 distribution 的 entropy 不要太小,希望这个 distribution 的 entropy 可以大一点,也就是希望不同的 action 它的被采用的机率,平均一点。这样在 testing 的时候,它才会多尝试各种不同的 action,才会把这个环境探索的比较好,才会得到比较好的结果。这个就是 Advantage Actor-Critic。 - -## A3C -![](img/8.7.png) - -什么是 A3C 呢?Reinforcement learning 有一个问题就是它很慢。那怎么增加训练的速度呢?这个可以讲到火影忍者就是有一次鸣人说,他想要在一周之内打败晓,所以要加快修行的速度,他老师就教他一个方法,这个方法是说你只要用影分身进行同样修行。那两个一起修行的话呢?经验值累积的速度就会变成2倍,所以,鸣人就开了 1000 个影分身,开始修行了。这个其实就是 Asynchronous(异步的) Advantage Actor-Critic,也就是 A3C 这个方法的精神。 - -![](img/8.8.png) - -A3C 这个方法就是同时开很多个 worker,那每一个 worker 其实就是一个影分身。那最后这些影分身会把所有的经验,通通集合在一起。首先你如果没有很多个 CPU,可能也是不好实现的,你可以 implement A2C 就好。 - -这个 A3C 是怎么运作的呢?A3C 是这样子,一开始有一个 global network。那我们刚才有讲过说,其实 policy network 跟 value network 是 tie 在一起的,它们的前几个 layer 会被 tie 一起。我们有一个 global network,它们有包含 policy 的部分和 value 的部分。假设它的参数就是 $\theta_1$,你会开很多个 worker。每一个 worker 就用一张 CPU 去跑,比如你就开 8 个 worker ,那你至少 8 张 CPU。第一个 worker 就把 global network 的参数 copy 过来,每一个 worker 工作前都会global network 的参数 copy 过来。接下来你就去跟环境做互动,每一个 actor 去跟环境做互动的时候,为了要 collect 到比较 diverse 的 data,所以举例来说如果是走迷宫的话,可能每一个 actor 起始的位置都会不一样,这样它们才能够收集到比较多样性的 data。每一个 actor 就自己跟环境做互动,互动完之后,你就会计算出 gradient。那计算出 gradient 以后,你要拿 gradient 去 update 你的参数。你就计算一下你的 gradient,然后用你的 gradient 去 update global network 的参数。就是这个 worker 算出 gradient 以后,就把 gradient 传回给中央的控制中心。然后中央的控制中心,就会拿这个 gradient 去 update 原来的参数。但是要注意一下,所有的 actor 都是平行跑的,就每一个 actor 就是各做各的,互相之间就不要管彼此。所以每个人都是去要了一个参数以后,做完就把参数传回去。所以当第一个 worker 做完想要把参数传回去的时候,本来它要的参数是 $\theta_1$,等它要把 gradient 传回去的时候。可能别人已经把原来的参数覆盖掉,变成 $\theta_2$了。但是没有关系,它一样会把这个 gradient 就覆盖过去就是了。Asynchronous actor-critic 就是这么做的,这个就是 A3C。 - - ## Pathwise Derivative Policy Gradient -![](img/8.9.png) - -讲完 A3C 之后,我们要讲另外一个方法叫做 `Pathwise Derivative Policy Gradient`,这个方法很神奇,它可以想成是 Q-learning 解 continuous action 的一种特别的方法。那它也可以想成是一种特别的 Actor-Critic 的方法。 - 用棋灵王来比喻的话,阿光是一个 actor,佐为是一个 critic。阿光落某一子以后呢,如果佐为是一般的 Actor-Critic,他会告诉他说这时候不应该下小马步飞,他会告诉你,你现在采取的这一步算出来的 value 到底是好还是不好,但这样就结束了,他只告诉你说好还是不好。因为一般的这个 Actor-Critic 里面那个 critic 就是 input state 或 input state 跟 action 的 pair,然后给你一个 value 就结束了。所以对 actor 来说,它只知道它做的这个行为到底是好还是不好。但如果是在pathwise derivative policy gradient 里面,这个 critic 会直接告诉 actor 说采取什么样的 action 才是好的。所以今天佐为不只是告诉阿光说,这个时候不要下小马步飞,同时还告诉阿光说这个时候应该要下大马步飞,所以这个就是Pathwise Derivative Policy Gradient 中的 critic。critic 会直接告诉 actor 做什么样的 action 才可以得到比较大的 value。 - -从 Q-learning 的观点来看,Q-learning 的一个问题是你没有办法在用 Q-learning 的时候,考虑 continuous vector。其实也不是完全没办法,就是比较麻烦,比较没有 general solution,我们怎么解这个 optimization problem 呢?我们用一个 actor 来解这个 optimization 的 problem。本来在 Q-learning 里面,如果是一个 continuous action,我们要解这个 optimization problem。但是现在这个 optimization problem 由 actor 来解,我们假设 actor 就是一个 solver,这个 solver 的工作就是给你 state, s,然后它就去解解告诉我们说,哪一个 action 可以给我们最大的 Q value,这是从另外一个观点来看 pathwise derivative policy gradient 这件事情。这个说法,你有没有觉得非常的熟悉呢?我们在讲 GAN 的时候,不是也讲过一个说法。我们 learn 一个 discriminator,它是要 evaluate 东西好不好,discriminator 要自己生成东西,非常的困难,那怎么办?因为要解一个 arg max 的 problem 非常的困难,所以用 generator 来生,所以今天的概念其实是一样的。Q 就是那个 discriminator,要根据这个 discriminator 决定 action 非常困难,怎么办?另外 learn 一个 network 来解这个 optimization problem,这个东西就是 actor。所以,两个不同的观点是同一件事,从两个不同的观点来看,一个观点是说,我们可以对原来的 Q-learning 加以改进,怎么改进呢?我们 learn 一个 actor 来决定 action 以解决 arg max 不好解的问题。或是另外一个观点是,原来的 actor-critic 的问题是 critic 并没有给 actor 足够的信息,它只告诉它好或不好,没有告诉它说什么样叫好,那现在有新的方法可以直接告诉 actor 说,什么样叫做好。 - -![](img/8.10.png) - -那我们讲一下它的 algorithm。假设我们 learn 了一个 Q-function,Q-function 就是 input s 跟 a,output 就是 $Q^{\pi}(s,a)$。那接下来,我们要 learn 一个 actor,这个 actor 的工作就是解这个 arg max 的 problem。这个 actor 的工作就是 input 一个 state s,希望可以 output 一个 action a。这个 action a 被丢到 Q-function 以后,它可以让 $Q^{\pi}(s,a)$ 的值越大越好。那实际上在 train 的时候,你其实就是把 Q 跟 actor 接起来变成一个比较大的 network。Q 是一个 network,input s 跟 a,output 一个 value。Actor 在 training 的时候,它要做的事情就是 input s,output a。把 a 丢到 Q 里面,希望 output 的值越大越好。在 train 的时候会把 Q 跟 actor 接起来,当作是一个大的 network。然后你会 fix 住 Q 的参数,只去调 actor 的参数,就用 gradient ascent 的方法去 maximize Q 的 output。这就是一个 GAN,这就是 conditional GAN。Q 就是 discriminator,但在 reinforcement learning 就是 critic,actor 在 GAN 里面就是 generator,其实它们就是同一件事情。 - -![](img/8.11.png) - -我们来看一下这个 pathwise derivative policy gradient 的算法。一开始你会有一个 actor $\pi$,它去跟环境互动,然后,你可能会要它去 estimate Q value。estimate 完 Q value 以后,你就把 Q value 固定,只去 learn 一个 actor。假设这个 Q 估得是很准的,它知道在某一个 state 采取什么样的 action,会真的得到很大的 value。接下来就 learn 这个 actor,actor 在 given s 的时候,它采取了 a,可以让最后 Q-function 算出来的 value 越大越好。你用这个 criteria 去 update 你的 actor $\pi$。然后有新的 $\pi$ 再去跟环境做互动,再 estimate Q,再得到新的 $\pi$ 去 maximize Q 的 output。本来在 Q-learning 里面,你用得上的技巧,在这边也几乎都用得上,比如说 replay buffer、exploration 等等。 - -![](img/8.12.png) - -上图是原来 Q-learning 的 algorithm。你有一个 Q-function Q,你有另外一个 target 的 Q-function 叫做 $\hat{Q}$。然后在每一次 training,在每一个 episode 的每一个 timestamp 里面,你会看到一个 state $s_t$,你会 take 某一个 action $a_{t}$。至于 take 哪一个 action 是由 Q-function 所决定的,因为解一个 arg max 的 problem。如果是 discrete 的话没有问题,你就看说哪一个 a 可以让 Q 的 value 最大,就 take 哪一个 action。那你需要加一些 exploration,这样 performance 才会好。你会得到 reward $r_t$,跳到新的 state $s_{t+1}$。你会把 $s_t$, $a_{t}$, $r_t$, $s_{t+1}$ 塞到你的 buffer 里面去。你会从你的 buffer 里面 sample 一个 batch 的 data,这个 batch data 里面,可能某一笔是 $s_i, a_i, r_i, s_{i+1}$。接下来你会算一个 target,这个 target 叫做$y$ ,$y=r_{i}+\max _{a} \hat{Q}\left(s_{i+1}, a\right)$。然后怎么 learn 你的 Q 呢?你希望 $Q(s_i,a_i)$ 跟 y 越接近越好,这是一个 regression 的 problem,最后每 C 个 step,你要把用 Q 替代 $\hat{Q}$ 。 - -![](img/8.13.png) - - 接下来我们把它改成 Pathwise Derivative Policy Gradient,这边就是只要做四个改变就好。 - -* 第一个改变是,你要把 Q 换成 $\pi$,本来是用 Q 来决定在 state $s_t$ 产生那一个 action, $a_{t}$ 现在是直接用 $\pi$ 。我们不用再解 arg max 的 problem 了,我们直接 learn 了一个 actor。这个 actor input $s_t$ 就会告诉我们应该采取哪一个 $a_{t}$。所以本来 input $s_t$,采取哪一个 $a_t$,是 Q 决定的。在 Pathwise Derivative Policy Gradient 里面,我们会直接用 $\pi$ 来决定,这是第一个改变。 -* 第二个改变是,本来这个地方是要计算在 $s_{i+1}$,根据你的 policy 采取某一个 action a 会得到多少的 Q value。那你会采取让 $\hat{Q}$ 最大的那个 action a。那现在因为我们其实不好解这个 arg max 的 problem,所以 arg max problem,其实现在就是由 policy $\pi$ 来解了,所以我们就直接把 $s_{i+1}$ 代到 policy $\pi$ 里面,你就会知道说 given $s_{i+1}$ ,哪一个 action 会给我们最大的 Q value,那你在这边就会 take 那一个 action。在 Q-function 里面,有两个 Q network,一个是真正的 Q network,另外一个是 target Q network。那实际上你在 implement 这个 algorithm 的时候,你也会有两个 actor,你会有一个真正要 learn 的 actor $\pi$,你会有一个 target actor $\hat{\pi}$ 。这个原理就跟为什么要有 target Q network 一样,我们在算 target value 的时候,我们并不希望它一直的变动,所以我们会有一个 target 的 actor 和一个 target 的 Q-function,它们平常的参数就是固定住的,这样可以让你的这个 target 的 value 不会一直地变化。所以本来到底是要用哪一个 action a,你会看说哪一个 action a 可以让 $\hat{Q}$ 最大。但现在因为哪一个 action a 可以让 $\hat{Q}$ 最大这件事情已经被用那个 policy 取代掉了,所以我们要知道哪一个 action a 可以让 $\hat{Q}$ 最大,就直接把那个 state 带到 $\hat{\pi}$ 里面,看它得到哪一个 a,就用那一个 a,那一个 a 就是会让 $\hat{Q}(s,a)$ 的值最大的那个 a 。其实跟原来的这个 Q-learning 也是没什么不同,只是原来你要解 arg max 的地方,通通都用 policy 取代掉了,那这个是第二个不同。 -* 第三个不同就是之前只要 learn Q,现在你多 learn 一个 $\pi$,那 learn $\pi$ 的时候的方向是什么呢?learn $\pi$ 的目的,就是为了 maximize Q-function,希望你得到的这个 actor,它可以让你的 Q-function output 越大越好,这个跟 learn GAN 里面的 generator 的概念。其实是一样的。 -* 第四个 step,就跟原来的 Q-function 一样。你要把 target 的 Q network 取代掉,你现在也要把 target policy 取代掉。 - -## Connection with GAN -![](img/8.14.png) - -其实 GAN 跟 Actor-Critic 的方法是非常类似的。这边就不细讲,你可以去找到一篇 paper 叫做 `Connecting Generative Adversarial Network and Actor-Critic Methods`。知道 GAN 跟 Actor-Critic 非常像有什么帮助呢?一个很大的帮助就是 GAN 跟 Actor-Critic 都是以难 train 而闻名的。所以在文献上就会收集各式各样的方法,告诉你说怎么样可以把 GAN train 起来。怎么样可以把 Actor-Critic train 起来。但是因为做 GAN 跟 Actor-Critic 的人是两群人,所以这篇 paper 里面就列出说在 GAN 上面有哪些技术是有人做过的,在 Actor-Critic 上面,有哪些技术是有人做过的。也许在 GAN 上面有试过的技术,你可以试着 apply 在 Actor-Critic 上,在 Actor-Critic 上面做过的技术,你可以试着 apply 在 GAN 上面,看看是否 work。 \ No newline at end of file +我们讲了 policy based 的方法 PPO ,讲了 value based 的方法 Q-learning。这两者其实是可以结合在一起的, 也就是 Actor-Critic 的方法。 \ No newline at end of file diff --git a/docs/chapter8/img/8.1.png b/docs/chapter8/img/8.1.png index 7bbc0ee..cedda5a 100644 Binary files a/docs/chapter8/img/8.1.png and b/docs/chapter8/img/8.1.png differ diff --git a/docs/chapter8/img/8.10.png b/docs/chapter8/img/8.10.png deleted file mode 100644 index a10f9ae..0000000 Binary files a/docs/chapter8/img/8.10.png and /dev/null differ diff --git a/docs/chapter8/img/8.2.png b/docs/chapter8/img/8.2.png index 395629f..b4bdc3b 100644 Binary files a/docs/chapter8/img/8.2.png and b/docs/chapter8/img/8.2.png differ diff --git a/docs/chapter8/img/8.3.png b/docs/chapter8/img/8.3.png index 964d4ff..cc9c314 100644 Binary files a/docs/chapter8/img/8.3.png and b/docs/chapter8/img/8.3.png differ diff --git a/docs/chapter8/img/8.4.png b/docs/chapter8/img/8.4.png deleted file mode 100644 index ab3b876..0000000 Binary files a/docs/chapter8/img/8.4.png and /dev/null differ diff --git a/docs/chapter8/img/8.5.png b/docs/chapter8/img/8.5.png deleted file mode 100644 index c147a2f..0000000 Binary files a/docs/chapter8/img/8.5.png and /dev/null differ diff --git a/docs/chapter8/img/8.6.png b/docs/chapter8/img/8.6.png deleted file mode 100644 index d2e4f2a..0000000 Binary files a/docs/chapter8/img/8.6.png and /dev/null differ diff --git a/docs/chapter8/img/8.7.png b/docs/chapter8/img/8.7.png deleted file mode 100644 index c3ca4e5..0000000 Binary files a/docs/chapter8/img/8.7.png and /dev/null differ diff --git a/docs/chapter8/img/8.8.png b/docs/chapter8/img/8.8.png deleted file mode 100644 index 9ac19fe..0000000 Binary files a/docs/chapter8/img/8.8.png and /dev/null differ diff --git a/docs/chapter8/img/8.9.png b/docs/chapter8/img/8.9.png deleted file mode 100644 index 4c2ad93..0000000 Binary files a/docs/chapter8/img/8.9.png and /dev/null differ diff --git a/docs/chapter9/chapter9.md b/docs/chapter9/chapter9.md index 2f43a8b..5f6f49d 100644 --- a/docs/chapter9/chapter9.md +++ b/docs/chapter9/chapter9.md @@ -1,81 +1,117 @@ -# Sparse Reward -实际上用 reinforcement learning learn agent 的时候,多数的时候 agent 都是没有办法得到 reward 的。那在没有办法得到 reward 的情况下,对 agent 来说它的训练是非常困难的。举例来说,假设你今天要训练一个机器手臂,然后桌上有一个螺丝钉跟螺丝起子,那你要训练它用螺丝起子把螺丝钉栓进去,那这个很难,为什么?因为你知道一开始你的 agent 是什么都不知道的,它唯一能够做不同的 action 的原因是 exploration。举例来说,你在做 Q-learning 的时候,会有一些随机性,让它去采取一些过去没有采取过的 action,那你要随机到说它把螺丝起子捡起来,再把螺丝栓进去,然后就会得到 reward 1,这件事情是永远不可能发生的。所以,不管你的 actor 做了什么事情,它得到 reward 永远都是 0,对它来说不管采取什么样的 action 都是一样糟或者是一样得好。所以,它最后什么都不会学到。如果环境中的 reward 非常的 sparse,reinforcement learning 的问题就会变得非常的困难。但是人类可以在非常 sparse 的 reward 上面去学习,我们的人生通常多数的时候,我们就只是活在那里,都没有得到什么 reward 或是 penalty。但是,人还是可以采取各种各式各样的行为。所以,一个真正厉害的 AI 应该能够在 sparse reward 的情况下也学到要怎么跟这个环境互动。 +# Actor-Critic + +## Actor-Critic -怎么解决 sparse reward 的这件事情呢?我们等一下会讲三个方向。 -## Reward Shaping ![](img/9.1.png) +在 `Actor-Critic` 里面,最知名的方法就是 `A3C(Asynchronous Advantage Actor-Critic)`。如果去掉前面这个 Asynchronous,只有 `Advantage Actor-Critic`,就叫做 `A2C`。如果前面加了 Asynchronous,变成 Asynchronous Advantage Actor-Critic,就变成 A3C。 -第一个方向叫做 `reward shaping`,reward shaping 的意思是说环境有一个固定的 reward,它是真正的 reward,但是我们为了让 agent 学出来的结果是我们要的样子,我们刻意地设计了一些 reward 来引导我们的 agent。举例来说,如果是把小孩当成一个 agent 的话。那一个小孩,他可 以take 两个 actions,一个action 是他可以出去玩,那他出去玩的话,在下一秒钟它会得到 reward 1。但是他在月考的时候,成绩可能会很差。所以在100 个小时之后呢,他会得到 reward -100。然后,他也可以决定要念书,然后在下一个时间,因为他没有出去玩,所以他觉得很不爽,所以他得到 reward -1。但是在 100 个小时后,他可以得到 reward 100。但对一个小孩来说,他可能就会想要 take play 而不是 take study。我们计算的是 accumulated reward,但也许对小孩来说,他的 discount factor 会很大,所以他就不太在意未来的reward。而且因为他是一个小孩,他还没有很多 experience,所以他的 Q-function estimate 是非常不精准的。所以要他去 estimate 很远以后会得到的 accumulated reward,他其实是预测不出来的。所以这时候大人就要引导他,怎么引导呢?就骗他说,如果你坐下来念书我就给你吃一个棒棒糖。所以,对他来说,下一个时间点会得到的 reward 就变成是positive 的。所以他就觉得说,也许 take 这个 study 是比 play 好的。虽然这并不是真正的 reward,而是其他人骗他的reward,告诉他说你采取这个 action 是好的。Reward shaping 的概念是一样的,简单来说,就是你自己想办法 design 一些 reward,它不是环境真正的 reward。在玩 Atari 游戏里面,真的 reward 是游戏主机给你的 reward,但你自己去设计一些 reward 好引导你的 machine,做你想要它做的事情。 +那我们复习一下 policy gradient,在 policy gradient,我们在 update policy 的参数 $\theta$ 的时候,我们是用了下面这个式子来算出我们的 gradient。 +$$ +\nabla \bar{R}_{\theta} \approx \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}}\left(\sum_{t^{\prime}=t}^{T_{n}} \gamma^{t^{\prime}-t} r_{t^{\prime}}^{n}-b\right) \nabla \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right) +$$ +这个式子是在说,我们先让 agent 去跟环境互动一下,那我们可以计算出在某一个 state s,采取了某一个 action a 的概率 $p_{\theta}(a_t|s_t)$。接下来,我们去计算在某一个 state s 采取了某一个 action a 之后,到游戏结束为止,accumulated reward 有多大。我们把这些 reward 从时间 t 到时间 T 的 reward 通通加起来,并且会在前面乘一个 discount factor,可能设 0.9 或 0.99。我们会减掉一个 baseline b,减掉这个值 b 的目的,是希望括号这里面这一项是有正有负的。如果括号里面这一项是正的,我们就要增加在这个 state 采取这个 action 的机率;如果括号里面是负的,我们就要减少在这个 state 采取这个 action 的机率。 + +我们把用 G 来表示 accumulated reward。但 G 这个值,其实是非常的 unstable 的。因为互动的 process 本身是有随机性的,所以在某一个 state s 采取某一个 action a,然后计算 accumulated reward,每次算出来的结果都是不一样的,所以 G 其实是一个 random variable。给同样的 state s,给同样的 action a,G 可能有一个固定的 distribution。但我们是采取 sample 的方式,我们在某一个 state s 采取某一个 action a,然后玩到底,我们看看得到多少的 reward,我们就把这个东西当作 G。把 G 想成是一个 random variable 的话,我们实际上是对这个 G 做一些 sample,然后拿这些 sample 的结果,去 update 我们的参数。但实际上在某一个 state s 采取某一个 action a,接下来会发生什么事,它本身是有随机性的。虽然说有个固定的 distribution,但它本身是有随机性的,而这个 random variable 的 variance 可能会非常大。你在同一个 state 采取同一个 action,你最后得到的结果可能会是天差地远的。假设我们可以 sample 足够的次数,在每次 update 参数之前,我们都可以 sample 足够的次数,那其实没有什么问题。但问题就是我们每次做 policy gradient,每次 update 参数之前都要做一些 sample,这个 sample 的次数其实是不可能太多的,我们只能够做非常少量的 sample。如果你正好 sample 到差的结果,比如说你 sample 到 G = 100,sample 到 G = -10,那显然你的结果会是很差的。 ![](img/9.2.png) -举例来说,这个例子是 Facebook 玩 VizDoom 的 agent。VizDoom 是一个第一人射击游戏,在这个射击游戏中,杀了敌人就得到 positive reward,被杀就得到 negative reward。他们设计了一些新的 reward,用新的 reward 来引导 agent 让他们做得更好,这不是游戏中真正的 reward。 +能不能让这整个 training process 变得比较 stable 一点,能不能够直接估测 G 这个 random variable 的期望值?我们在 state s 采取 action a 的时候,直接用一个 network 去估测在 state s 采取 action a 的时候,G 的期望值。如果这件事情是可行的,那之后 training 的时候,就用期望值来代替 sample 的值,这样会让 training 变得比较 stable。 -比如说掉血就扣 0.05 的分数,弹药减少就扣分,捡到补给包就加分,呆在原地就扣分,移动就加分。 活着会扣一个很小的分数,因为不这样做的话,machine 会只想活着,一直躲避敌人,这样会让 machine 好战一点。表格中的参数都是调出来的。 +怎么拿期望值代替 sample 的值呢?这边就需要引入 value based 的方法。value based 的方法就是 Q-learning。Q-learning 有两种 functions,有两种 critics。第一种 critic 我们写作 $V^{\pi}(s)$,它的意思是说,假设 actor 是 $\pi$,拿 $\pi$ 去跟环境做互动,当今天我们看到 state s 的时候,接下来 accumulated reward 的期望值有多少。还有一个 critic 叫做 $Q^{\pi}(s,a)$。$Q^{\pi}(s,a)$ 把 s 跟 a 当作 input,它的意思是说,在 state s 采取 action a,接下来都用 actor $\pi$ 来跟环境进行互动,accumulated reward 的期望值是多少。 -Reward shaping是有问题的,因为我们需要 domain knowledge,举例来说,机器人想要学会的事情是把蓝色的板子从这个柱子穿过去。机器人很难学会,我们可以做 Reward Shaping。一个貌似合理的说法是,蓝色的板子离柱子越近,reward 越大。但是 machine 靠近的方式会有问题,它会用蓝色的板子打柱子。而我们要把蓝色板子放在柱子上面去,才能把蓝色板子穿过柱子。 这种 reward shaping的方式是没有帮助的,那至于什么 reward shaping 有帮助,什么 reward shaping 没帮助,会变成一个 domain knowledge,你要去调的。 +$V^{\pi}$ input s,output 一个 scalar。$Q^{\pi}$ input s,然后它会给每一个 a 都 assign 一个 Q value。这个 estimate 的时候,你可以用 TD 也可以用 MC。用TD 比较稳,用 MC 比较精确。 -## Curiosity ![](img/9.3.png) -接下来就是介绍各种你可以自己加进去,in general 看起来是有用的 reward。举例来说,一个技术是给 machine 加上 curiosity,所以叫 `curiosity driven reward`。上图是我们之前讲 Actor-Critic 的时候看过的图。我们有一个 reward function,它给你某一个s tate,给你某一个 action,它就会评断说在这个 state 采取 这个action 得到多少的 reward。那我们当然希望 total reward 越大越好。在 curiosity driven 的这种技术里面,你会加上一个新的 reward function。这个新的 reward function 叫做 `ICM(intrinsic curiosity module)`,它就是要给机器加上好奇心。ICM 会吃 3 个东西,它会吃 state $s_1$、action $a_1$ 和 state $s_2$。根据$s_1$ 、$a_1$、 $a_2$,它会 output 另外一个 reward,我们这边叫做 $r_1^i$。对 machine 来说,total reward 并不是只有 r 而已,还有 $r^i$。它不是只有把所有的 r 都加起来,它还把所有 $r^i$ 加起来当作total reward。所以,它在跟环境互动的时候,它不是只希望 r 越大越好,它还同时希望 $r^i$ 越大越好,它希望从 ICM 的 module 里面得到的 reward 越大越好。ICM 就代表了一种curiosity。 +G 的 random variable 的期望值正好就是 Q ,即 +$$ +E\left[G_{t}^{n}\right]=Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)} +$$ +因为这个就是 Q 的定义。Q 的定义就是在某一个 state s,采取某一个 action a,假设 policy 就是 $\pi$ 的情况下会得到的 accumulated reward 的期望值有多大,而这个东西就是 G 的期望值。为什么会这样,因为这个就是 Q 的定义,Q-function 的定义。Accumulated reward 的期望值就是 G 的期望值。所以假设用期望值来代表 $\sum_{t^{\prime}=t}^{T_{n}} \gamma^{t^{\prime}-t} r_{t^{\prime}}^{n}$ 这一项的话,把 Q-function 套在这里就结束了。那我们就可以 Actor 跟 Critic 这两个方法结合起来。 + +有不同的方法来表示 baseline,但一个常见的做法是,你用 value function $V^{\pi_{\theta}}\left(s_{t}^{n}\right)$ 来表示 baseline。Value function 的意思是说,假设 policy 是 $\pi$,在某一个 state s 一直 interact 到游戏结束。那你 expected 的 reward 有多大。 $V^{\pi_{\theta}}\left(s_{t}^{n}\right)$ 没有 involve action,然后 $ Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)}$ 有 involve action。其实 $V^{\pi_{\theta}}\left(s_{t}^{n}\right)$ 会是 $Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)}$ 的期望值,所以$Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)}-V^{\pi_{\theta}}\left(s_{t}^{n}\right)$ 会有正有负,所以 $\sum_{t^{\prime}=t}^{T_{n}} \gamma^{t^{\prime}-t} r_{t^{\prime}}^{n}-b$ 这一项就会是有正有负的。 + +所以我们就把 policy gradient 里面 $\sum_{t^{\prime}=t}^{T_{n}} \gamma^{t^{\prime}-t} r_{t^{\prime}}^{n}-b$ 这一项换成了 $Q^{\pi_{\theta}\left(s_{t}^{n}, a_{t}^{n}\right)}-V^{\pi_{\theta}}\left(s_{t}^{n}\right)$。 ![](img/9.4.png) -怎么设计这个 ICM ?这个是最原始的设计。这个设计是这样。curiosity module 就是 input 3 个东西,input 现在的 state,input 在这个 state 采取的 action,然后接 input 下一个 state $s_{t+1}$。接下来会 output 一个 reward $r^i_t$。那这个 $r^i_t$ 是怎么算出来的呢?在 ICM 里面,你有一个 network,这个 network 会 take $a_t$ 跟$s_t$,然后去 output $\hat{s}_{t+1}$,也就是这个 network 根据 $a_t$ 和 $s_t$ 去 predict $\hat{s}_{t+1}$ 。接下来再看说,这个 network 的预测 $\hat{s}_{t+1}$ 跟真实的情况 $s_{t+1}$ 像不像,越不像那得到的 reward 就越大。所以这个 reward $r_t^i$ 的意思是说,如果未来的 state 越难被预测的话,那得到的 reward 就越大。这就是鼓励 machine 去冒险,现在采取这个 action,未来会发生什么事越没有办法预测的话,这个 action 的 reward 就大。所以如果有这样子的 ICM,machine 就会倾向于采取一些风险比较大的 action,它想要去探索未知的世界,它想要去看看说,假设某一个 state 是它没有办法预测,它会特别去想要采取那个 state,这可以增加 machine exploration 的能力。 +如果你这么实现的话,有一个缺点是,你要 estimate 2 个 networks,而不是一个 network。你要 estimate Q-network,你也要 estimate V-network,你 estimate 估测不准的风险就变成两倍。所以我们何不只估测一个 network 就好了呢?事实上在这个 Actor-Critic 方法里面。你可以只估测 V 这个 network,你可以用 V 的值来表示 Q 的值,什么意思呢?$Q^{\pi}\left(s_{t}^{n}, a_{t}^{n}\right)$可以写成$r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)$的期望值,即 -这个 network 1 其实是另外 train 出来的。Training 的时候,这个network 1,你会给它 $a_t$、 $s_t$、 $s_{t+1}$,然后让这个network 1 去学说 given $a_t, s_t$,怎么 predict $\hat{s}_{t+1}$。Apply 到 agent 互动的时候,其实要把 ICM module fix 住。其实,这一整个想法里面是有一个问题的。这个问题是某一些 state它很难被预测并不代表它就是好的,它就应该要去被尝试的。举例来说,俄罗斯轮盘的结果也是没有办法预测的,并不代表说,人应该每天去玩俄罗斯轮盘这样子。所以只是鼓励 machine 去冒险是不够的,因为如果光是只有这个 network 的架构,machine 只知道说什么东西它无法预测。如果在某一个 state 采取某一个 action,它无法预测接下来结果,它就会采取那个action,但并不代表这样的结果一定是好的。举例来说,可能在某个游戏里面,背景会有风吹草动,会有树叶飘动。那也许树叶飘动这件事情,是很难被预测的,对 machine 来说它在某一个 state 什么都不做,看着树叶飘动,然后,发现这个树叶飘动是没有办法预测的,接下来它就会一直站在那边,看树叶飘动。所以说,光是有好奇心是不够的,还要让它知道说,什么事情是真正重要的。 +$$ +Q^{\pi}\left(s_{t}^{n}, a_{t}^{n}\right)=E\left[r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)\right] +$$ + +你在 state s 采取 action a,接下来你会得到 reward r,然后跳到 state, $s_{t+1}$,但是你会得到什么样的 reward r,跳到什么样的 state $s_{t+1}$,它本身是有随机性的。所以要把右边这个式子,取期望值它才会等于 Q-function。但我们现在把期望值这件事情去掉,即 +$$ +Q^{\pi}\left(s_{t}^{n}, a_{t}^{n}\right)=r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right) +$$ + +我们就可以把 Q-function 用 r + V 取代掉,然后得到下式 +$$ +r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)-V^{\pi}\left(s_{t}^{n}\right) +$$ +把这个期望值去掉的好处就是你不需要再 estimate Q 了,你只需要 estimate V 就够了。你只要 estimate 一个 network 就够了,你不需要 estimate 2 个 network,你只需要 estimate 一个 network 就够了。但这样你就引入了一个随机的东西 r ,它是有随机性的,它是一个 random variable。但是这个 random variable,相较于刚才的 accumulated reward G 可能还好,因为它是某一个 step 会得到的 reward。而 G 是所有未来会得到的 reward 的总和。G variance 比较大,r 虽然也有一些 variance,但它的 variance 会比 G 要小。所以把原来 variance 比较大的 G 换成 variance 比较小的 r 也是合理的。如果你觉得把期望值拿掉不靠谱的话,那我就告诉你原始的 A3C paper 试了各式各样的方法,最后做出来就是这个最好这样。当然你可能说,搞不好 estimate Q 跟 V 也都 estimate 很好,那我告诉你就是做实验的时候,最后结果就是这个最好。所以后来大家都用这个。 ![](img/9.5.png) -怎么让 machine 知道说什么事情是真正重要的?你要加上另外一个 module,我们要 learn 一个`feature extractor`,黄色的格子代表 feature extractor,它是 input 一个 state,然后 output 一个feature vector 来代表这个state,那我们期待这个 feature extractor 可以把那种没有意义的画面,state 里面没有意义的东西把它过滤掉,比如说风吹草动、白云的飘动、树叶的飘动这种没有意义的东西直接把它过滤掉, +因为 $r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)-V^{\pi}\left(s_{t}^{n}\right)$ 叫做 `Advantage function`。所以这整个方法就叫 `Advantage Actor-Critic`。 -假设这个 feature extractor 真的可以把无关紧要的东西过滤掉以后,network 1 实际上做的事情是,给它一个 actor,给它一个state $s_t$ 的feature representation,让它预测 state $s_{t+1}$ 的feature representation。接下来我们再看说,这个预测的结果跟真正的 state $s_{t+1}$ 的 feature representation 像不像,越不像,reward 就越大。怎么 learn 这个 feature extractor 呢?让这个feature extractor 可以把无关紧要的事情滤掉呢?这边的 learn 法就是 learn 另外一个network 2。这个 network 2 是吃 $\phi(s_t)$、$\phi(s_{t+1})$ 这两个 vector 当做 input,然后接下来它要predict action a 是什么,然后它希望呢这个 action a 跟真正的 action a 越接近越好。这个network 2 会 output 一个 action,它output 说,从 state $s_t$ 跳到 state $s_{t+1}$,要采取哪一个 action 才能够做到,那希望这个 action 跟真正的 action 越接近越好。加上这个 network 2 的好处就是因为要用 $\phi(s_t)$、$\phi(s_{t+1})$ 预测action。所以,今天我们抽出来的 feature 跟预测action 这件事情是有关的。所以风吹草动等与 machine 要采取的 action 无关的东西就会被滤掉,就不会被放在抽出来的 vector representation 里面。 - - - -## Curriculum Learning +整个流程是这样子的。我们有一个 $\pi$,有个初始的 actor 去跟环境做互动,先收集资料。在 policy gradient 方法里面收集资料以后,你就要拿去 update policy。但是在 actor-critic 方法里面,你不是直接拿那些资料去 update policy。你先拿这些资料去 estimate value function,你可以用 TD 或 MC 来 estimate value function 。接下来,你再 based on value function,套用下面这个式子去 update $\pi$。 +$$ +\nabla \bar{R}_{\theta} \approx \frac{1}{N} \sum_{n=1}^{N} \sum_{t=1}^{T_{n}}\left(r_{t}^{n}+V^{\pi}\left(s_{t+1}^{n}\right)-V^{\pi}\left(s_{t}^{n}\right)\right) \nabla \log p_{\theta}\left(a_{t}^{n} \mid s_{t}^{n}\right) +$$ +然后你有了新的 $\pi$ 以后,再去跟环境互动,再收集新的资料,去 estimate value function。然后再用新的 value function 去 update policy,去 update actor。整个 actor-critic 的 algorithm 就是这么运作的。 ![](img/9.6.png) -接下来讲 `curriculum learning` ,curriculum learning 不是 reinforcement learning 所独有的概念。其实在 machine learning,尤其是 deep learning 里面,你都会用到 curriculum learning 的概念。举例来说,curriculum learning 的意思是说,你为机器的学习做规划,你给他喂 training data 的时候,是有顺序的,通常都是由简单到难。就好比说,假设你今天要交一个小朋友作微积分,他做错就打他一巴掌,这样他永远都不会做对,太难了。你要先教他九九乘法,然后才教他微积分。所以curriculum learning 的意思就是在教机器的时候,从简单的题目教到难的题目。就算不是 reinforcement learning,一般在 train deep network 的时候,你有时候也会这么做。举例来说,在 train RNN 的时候,已经有很多的文献都 report 说,你给机器先看短的 sequence,再慢慢给它长的 sequence,通常可以学得比较好。那用在reinforcement learning 里面,你就是要帮机器规划一下它的课程,从最简单的到最难的。 举例来说,在 Facebook 玩 VizDoom 的 agent 里面,Facebook 玩 VizDoom 的 agent 蛮强的。他们在参加这个 VizDoom 的比赛,机器的 VizDoom 比赛是得第一名的,他们是有为机器规划课程的。先从课程 0 一直上到课程 7。在这个课程里面,怪物的速度跟血量是不一样的。所以,在越进阶的课程里面,怪物的速度越快,然后他的血量越多。在 paper 里面也有讲说,如果直接上课程 7,machine 是学不起来的。你就是要从课程 0 一路玩上去,这样 machine 才学得起来。 -再举个例子,把蓝色的板子穿过柱子,怎么让机器一直从简单学到难呢? +实现 Actor-Critic 的时候,有两个一定会用的 tip。 -如第一张图所示,也许一开始机器初始的时候,它的板子就已经在柱子上了。这个时候,机器要做的事情只有把蓝色的板子压下去,就结束了。这比较简单,它应该很快就学的会。它只有往上跟往下这两个选择嘛,往下就得到 reward,就结束了,他也不知道学的是什么。 +* 第一个 tip 是说,我们需要 estimate 两个 network,estimate V function,另外一个需要 estimate 的 network 是 policy 的 network,也就是你的 actor。 V-network input 一个 state,output 一个 scalar。然后 actor 这个 network,它是 input 一个 state,output 就是一个 action 的 distribution,假设你的 action 是 discrete,不是 continuous 的话,如果是 continuous 的话,它也是一样。如果是 continuous 的话,就只是 output 一个 continuous 的 vector。上图是举的是 discrete 的例子,但 continuous 的 case 其实也是一样的,input 一个 state,然后他决定你现在要 take 那一个 action。**这两个 network,actor 和 critic 的 input 都是 s,所以它们前面几个 layer,其实是可以 share 的。**尤其是假设你今天是玩 Atari 游戏,input 都是 image。那 input 那个 image 都非常复杂,image 很大,通常你前面都会用一些 CNN 来处理,把那些 image 抽象成 high level 的 information。把 pixel level 到 high level information 这件事情,其实对 actor 跟 critic 来说是可以共用的。所以通常你会让 actor 跟 critic 的前面几个 layer 是 shared,你会让 actor 跟 critic 的前面几个 layer 共用同一组参数。那这一组参数可能是 CNN。先把 input 的 pixel 变成比较 high level 的信息,然后再给 actor 去决定说它要采取什么样的行为,给这个 critic,给 value function 去计算 expected reward。 -如第二张图所示,这边就是把板子挪高一点,挪高一点,所以它有时候会很笨的往上拉,然后把板子拿出来了。如果它压板子学得会的话,拿板子也比较有机会学得会。假设它现在学的到说,只要板子接近柱子,它就可以把这个板子压下去的话。接下来,你再让它学更 general 的 case。 - -如第三张图所示,一开始,让板子离柱子远一点。然后,板子放到柱子上面的时候,它就会知道把板子压下去,这个就是Curriculum Learning 的概念。当然 curriculum learning 有点 ad hoc(特别),就是需要人去为机器设计它的课程。 +* 第二个 tip 是我们一样需要 exploration 的机制。在做 Actor-Critic 的时候,有一个常见的 exploration 的方法是你会对你的 $\pi$ 的 output 的 distribution 下一个 constrain。这个 constrain 是希望这个 distribution 的 entropy 不要太小,希望这个 distribution 的 entropy 可以大一点,也就是希望不同的 action 它的被采用的机率,平均一点。这样在 testing 的时候,它才会多尝试各种不同的 action,才会把这个环境探索的比较好,才会得到比较好的结果。这个就是 Advantage Actor-Critic。 +## A3C ![](img/9.7.png) -有一个比较 general 的方法叫做 `Reverse Curriculum Generation`。你可以用一个比较通用的方法来帮机器设计课程,这个比较通用的方法是怎么样呢?假设你现在一开始有一个state $s_g$,这是你的gold state,也就是最后最理想的结果。如果拿刚才那个板子和柱子的实验作为例子的话,就把板子放到柱子里面,这样子叫做 gold state。你就已经完成了,或者你让机器去抓东西,你训练一个机器手臂抓东西,抓到东西以后叫做 gold state。接下来你根据你的 gold state 去找其他的 state,这些其他的 state 跟 gold state 是比较接近的。举例来说,如果是让机器抓东西的例子里面,你的机器手臂可能还没有抓到东西。假设这些跟 gold state 很近的 state 叫做 $s_1$。你的机械手臂还没有抓到东西,但它离 gold state 很近,那这个叫做$s_1$。至于什么叫做近,这是 case dependent,你要根据你的 task 来 design 说怎么从 $s_g$ sample 出 $s_1$。如果是机械手臂的例子,可能就比较好想。其他例子可能就比较难想。接下来呢,你再从这些 $s_1$ 开始做互动,看它能不能够达到gold state $s_g$,那每一个state,你跟环境做互动的时候,你都会得到一个reward R。 +什么是 A3C 呢?Reinforcement learning 有一个问题就是它很慢。那怎么增加训练的速度呢?这个可以讲到火影忍者就是有一次鸣人说,他想要在一周之内打败晓,所以要加快修行的速度,他老师就教他一个方法,这个方法是说你只要用影分身进行同样修行。那两个一起修行的话呢?经验值累积的速度就会变成2倍,所以,鸣人就开了 1000 个影分身,开始修行了。这个其实就是 Asynchronous(异步的) Advantage Actor-Critic,也就是 A3C 这个方法的精神。 ![](img/9.8.png) -接下来,我们把 reward 特别极端的 case 去掉,reward 特别极端的 case 的意思就是说那些 case 太简单或是太难了。如果 reward 很大,代表说这个 case 太简单了,就不用学了,因为机器已经会了,它可以得到很大的 reward。如果 reward 太小,代表这个 case 太难了,依照机器现在的能力这个课程太难了,它学不会,所以就不要学这个,所以只找一些 reward 适中的 case。那当然什么叫做适中,这个就是你要调的参数,找一些 reward 适中的 case。接下来,再根据这些 reward 适中的 case 去 sample 出更多的 state。就假设你一开始,你机械手臂在这边,可以抓的到以后。接下来,就再离远一点,看看能不能够抓得到,又抓的到以后,再离远一点,看看能不能抓得到。这是一个有用的方法,它叫做`Reverse Curriculum learning`。刚才讲的是 Curriculum learning,就是你要为机器规划它学习的顺序。而 reverse curriculum learning 是从 gold state 去反推,就是说你原来的目标是长这个样子,我们从我们的目标去反推,所以这个叫做 reverse。 +A3C 这个方法就是同时开很多个 worker,那每一个 worker 其实就是一个影分身。那最后这些影分身会把所有的经验,通通集合在一起。首先你如果没有很多个 CPU,可能也是不好实现的,你可以 implement A2C 就好。 -## Hierarchical RL +这个 A3C 是怎么运作的呢?A3C 是这样子,一开始有一个 global network。那我们刚才有讲过说,其实 policy network 跟 value network 是 tie 在一起的,它们的前几个 layer 会被 tie 一起。我们有一个 global network,它们有包含 policy 的部分和 value 的部分。假设它的参数就是 $\theta_1$,你会开很多个 worker。每一个 worker 就用一张 CPU 去跑,比如你就开 8 个 worker ,那你至少 8 张 CPU。第一个 worker 就把 global network 的参数 copy 过来,每一个 worker 工作前都会global network 的参数 copy 过来。接下来你就去跟环境做互动,每一个 actor 去跟环境做互动的时候,为了要 collect 到比较 diverse 的 data,所以举例来说如果是走迷宫的话,可能每一个 actor 起始的位置都会不一样,这样它们才能够收集到比较多样性的 data。每一个 actor 就自己跟环境做互动,互动完之后,你就会计算出 gradient。那计算出 gradient 以后,你要拿 gradient 去 update 你的参数。你就计算一下你的 gradient,然后用你的 gradient 去 update global network 的参数。就是这个 worker 算出 gradient 以后,就把 gradient 传回给中央的控制中心。然后中央的控制中心,就会拿这个 gradient 去 update 原来的参数。但是要注意一下,所有的 actor 都是平行跑的,就每一个 actor 就是各做各的,互相之间就不要管彼此。所以每个人都是去要了一个参数以后,做完就把参数传回去。所以当第一个 worker 做完想要把参数传回去的时候,本来它要的参数是 $\theta_1$,等它要把 gradient 传回去的时候。可能别人已经把原来的参数覆盖掉,变成 $\theta_2$了。但是没有关系,它一样会把这个 gradient 就覆盖过去就是了。Asynchronous actor-critic 就是这么做的,这个就是 A3C。 + ## Pathwise Derivative Policy Gradient ![](img/9.9.png) -那最后一个 tip 叫做 `Hierarchical Reinforcement learning`,分层的 reinforcement learning。 -所谓分层的Reinforcement learning 是说,我们有好几个 agent。然后,有一些agent 负责比较high level 的东西,它负责订目标,然后它订完目标以后,再分配给其他的 agent,去把它执行完成。这样的想法其实也是很合理的。因为我们知道说,我们人在一生之中,并不是时时刻刻都在做决定。举例来说,假设你想要写一篇paper,你会说就我先想个梗这样子,然后想完梗以后,你还要跑个实验。跑完实验以后,你还要写。写完以后呢,你还要这个去发表。每一个动作下面又还会再细分,比如说怎么跑实验呢?你要先 collect data,collect 完data 以后,你要再 label,你要弄一个network,然后又 train 不起来,要 train 很多次。然后重新 design network 架构好几次,最后才把network train 起来。 +讲完 A3C 之后,我们要讲另外一个方法叫做 `Pathwise Derivative Policy Gradient`,这个方法很神奇,它可以想成是 Q-learning 解 continuous action 的一种特别的方法。那它也可以想成是一种特别的 Actor-Critic 的方法。 + 用棋灵王来比喻的话,阿光是一个 actor,佐为是一个 critic。阿光落某一子以后呢,如果佐为是一般的 Actor-Critic,他会告诉他说这时候不应该下小马步飞,他会告诉你,你现在采取的这一步算出来的 value 到底是好还是不好,但这样就结束了,他只告诉你说好还是不好。因为一般的这个 Actor-Critic 里面那个 critic 就是 input state 或 input state 跟 action 的 pair,然后给你一个 value 就结束了。所以对 actor 来说,它只知道它做的这个行为到底是好还是不好。但如果是在pathwise derivative policy gradient 里面,这个 critic 会直接告诉 actor 说采取什么样的 action 才是好的。所以今天佐为不只是告诉阿光说,这个时候不要下小马步飞,同时还告诉阿光说这个时候应该要下大马步飞,所以这个就是Pathwise Derivative Policy Gradient 中的 critic。critic 会直接告诉 actor 做什么样的 action 才可以得到比较大的 value。 -所以,我们要完成一个很大的 task 的时候,我们并不是从非常底层的那些 action 开始想起,我们其实是有个 plan。我们先想说,如果要完成这个最大的任务,那接下来要拆解成哪些小任务。每一个小任务要再怎么拆解成小小的任务。举例来说,叫你直接写一本书可能很困难,但叫你先把一本书拆成好几个章节,每个章节拆成好几段,每一段又拆成好几个句子,每一个句子又拆成好几个词汇,这样你可能就比较写得出来,这个就是分层的 Reinforcement learning 的概念。 - -这边是举一个例子,就是假设校长、教授和研究生通通都是 agent。那今天假设我们的reward 就是只要进入百大就可以得到 reward。假设进入百大的话,校长就要提出愿景告诉其他的agent 说,现在你要达到什么样的目标。那校长的愿景可能就是说教授每年都要发三篇期刊。然后接下来这些agent 都是有分层的,所以上面的 agent,他的动作就是提出愿景这样。那他把他的愿景传给下一层的agent,下一层的 agent 就把这个愿景吃下去。如果他下面还有其他人的话,它就会提出新的愿景。比如说,校长要教授发期刊,但其实教授自己也是不做实验的。所以,教授也只能够叫下面的研究生做实验。所以教授就提出愿景,就做出实验的规划,然后研究生才是真的去执行这个实验的人。然后,真的把实验做出来,最后大家就可以得到reward。那现在是这样子的,在 learn 的时候,其实每一个 agent 都会 learn。那他们的整体的目标就是要达到最后的reward。那前面的这些 agent,他提出来的 actions 就是愿景这样。你如果是玩游戏的话,他提出来的就是,我现在想要产生这样的游戏画面。但是,假设他提出来的愿景是下面的 agent 达不到的,那就会被讨厌。举例来说,教授对研究生都一直逼迫研究生做一些很困难的实验,研究生都做不出来的话,研究生就会跑掉,所以他就会得到一个penalty。所以如果今天下层的 agent 没有办法达到上层 agent 所提出来的 goal 的话,上层的 agent 就会被讨厌,它就会得到一个 negative reward。所以他要避免提出那些愿景是底下的agent 所做不到的。那每一个agent 都是把上层的 agent 所提出来的愿景当作输入,然后决定他自己要产生什么输出。 - -但是你知道说,就算你看到上面的的愿景说,叫你做这一件事情。你最后也不一定能做成这一件事情。假设本来教授目标是要写期刊,但是不知道怎么回事,他就要变成一个YouTuber。这个paper 里面的 solution,我觉得非常有趣。给大家做一个参考,这其实本来的目标是要写期刊,但却变成 YouTuber,那怎么办呢? 把原来的愿景改成变成 YouTuber 就行了,在paper 里面就是这么做的,为什么这么做呢? 因为虽然本来的愿景是要写期刊,但是后来变成YouTuber,难道这些动作都浪费了吗? 不是,这些动作是没有被浪费的。我们就假设说,本来的愿景其实就是要成为YouTuber,那你就知道成为 YouTuber 要怎做了。这个是分层 RL,是可以做得起来的 tip。 +从 Q-learning 的观点来看,Q-learning 的一个问题是你没有办法在用 Q-learning 的时候,考虑 continuous vector。其实也不是完全没办法,就是比较麻烦,比较没有 general solution,我们怎么解这个 optimization problem 呢?我们用一个 actor 来解这个 optimization 的 problem。本来在 Q-learning 里面,如果是一个 continuous action,我们要解这个 optimization problem。但是现在这个 optimization problem 由 actor 来解,我们假设 actor 就是一个 solver,这个 solver 的工作就是给你 state, s,然后它就去解解告诉我们说,哪一个 action 可以给我们最大的 Q value,这是从另外一个观点来看 pathwise derivative policy gradient 这件事情。这个说法,你有没有觉得非常的熟悉呢?我们在讲 GAN 的时候,不是也讲过一个说法。我们 learn 一个 discriminator,它是要 evaluate 东西好不好,discriminator 要自己生成东西,非常的困难,那怎么办?因为要解一个 arg max 的 problem 非常的困难,所以用 generator 来生,所以今天的概念其实是一样的。Q 就是那个 discriminator,要根据这个 discriminator 决定 action 非常困难,怎么办?另外 learn 一个 network 来解这个 optimization problem,这个东西就是 actor。所以,两个不同的观点是同一件事,从两个不同的观点来看,一个观点是说,我们可以对原来的 Q-learning 加以改进,怎么改进呢?我们 learn 一个 actor 来决定 action 以解决 arg max 不好解的问题。或是另外一个观点是,原来的 actor-critic 的问题是 critic 并没有给 actor 足够的信息,它只告诉它好或不好,没有告诉它说什么样叫好,那现在有新的方法可以直接告诉 actor 说,什么样叫做好。 ![](img/9.10.png) +那我们讲一下它的 algorithm。假设我们 learn 了一个 Q-function,Q-function 就是 input s 跟 a,output 就是 $Q^{\pi}(s,a)$。那接下来,我们要 learn 一个 actor,这个 actor 的工作就是解这个 arg max 的 problem。这个 actor 的工作就是 input 一个 state s,希望可以 output 一个 action a。这个 action a 被丢到 Q-function 以后,它可以让 $Q^{\pi}(s,a)$ 的值越大越好。那实际上在 train 的时候,你其实就是把 Q 跟 actor 接起来变成一个比较大的 network。Q 是一个 network,input s 跟 a,output 一个 value。Actor 在 training 的时候,它要做的事情就是 input s,output a。把 a 丢到 Q 里面,希望 output 的值越大越好。在 train 的时候会把 Q 跟 actor 接起来,当作是一个大的 network。然后你会 fix 住 Q 的参数,只去调 actor 的参数,就用 gradient ascent 的方法去 maximize Q 的 output。这就是一个 GAN,这就是 conditional GAN。Q 就是 discriminator,但在 reinforcement learning 就是 critic,actor 在 GAN 里面就是 generator,其实它们就是同一件事情。 -上图是真实的例子。实际上呢,这里面就做了一些比较简单的游戏,这个是走迷宫,蓝色是 agent,蓝色的 agent 要走到黄色的目标。这边也是,这个单摆要碰到黄色的球。那愿景是什么呢? +![](img/9.11.png) -在这个 task 里面,它只有两个 agent ,下层的一个 agent 负责决定说要怎么走,上层的 agent 就负责提出愿景。虽然,实际上你可以用很多层,但 paper 就用了两层。 +我们来看一下这个 pathwise derivative policy gradient 的算法。一开始你会有一个 actor $\pi$,它去跟环境互动,然后,你可能会要它去 estimate Q value。estimate 完 Q value 以后,你就把 Q value 固定,只去 learn 一个 actor。假设这个 Q 估得是很准的,它知道在某一个 state 采取什么样的 action,会真的得到很大的 value。接下来就 learn 这个 actor,actor 在 given s 的时候,它采取了 a,可以让最后 Q-function 算出来的 value 越大越好。你用这个 criteria 去 update 你的 actor $\pi$。然后有新的 $\pi$ 再去跟环境做互动,再 estimate Q,再得到新的 $\pi$ 去 maximize Q 的 output。本来在 Q-learning 里面,你用得上的技巧,在这边也几乎都用得上,比如说 replay buffer、exploration 等等。 -走迷宫的例子是说粉红色的这个点代表的就是愿景。上层这个 agent,它告诉蓝色的这个 agent 说,你现在的第一个目标是先走到这个地方,蓝色的 agent 走到以后,再说你的新的目标是走到这里。蓝色的 agent 再走到以后,新的目标在这里。接下来又跑到这边,最后希望蓝色的 agent 就可以走到黄色的这个位置。 +![](img/9.12.png) -单摆的例子也一样,就是粉红色的这个点代表的是上层的 agent 所提出来的愿景,所以这个agent 先摆到这边,接下来,新的愿景又跑到这边,所以它又摆到这里。然后,新的愿景又跑到上面。然后又摆到上面,最后就走到黄色的位置了。这个就是 hierarchical 的 Reinforcement Learning。 +上图是原来 Q-learning 的 algorithm。你有一个 Q-function Q,你有另外一个 target 的 Q-function 叫做 $\hat{Q}$。然后在每一次 training,在每一个 episode 的每一个 timestamp 里面,你会看到一个 state $s_t$,你会 take 某一个 action $a_{t}$。至于 take 哪一个 action 是由 Q-function 所决定的,因为解一个 arg max 的 problem。如果是 discrete 的话没有问题,你就看说哪一个 a 可以让 Q 的 value 最大,就 take 哪一个 action。那你需要加一些 exploration,这样 performance 才会好。你会得到 reward $r_t$,跳到新的 state $s_{t+1}$。你会把 $s_t$, $a_{t}$, $r_t$, $s_{t+1}$ 塞到你的 buffer 里面去。你会从你的 buffer 里面 sample 一个 batch 的 data,这个 batch data 里面,可能某一笔是 $s_i, a_i, r_i, s_{i+1}$。接下来你会算一个 target,这个 target 叫做$y$ ,$y=r_{i}+\max _{a} \hat{Q}\left(s_{i+1}, a\right)$。然后怎么 learn 你的 Q 呢?你希望 $Q(s_i,a_i)$ 跟 y 越接近越好,这是一个 regression 的 problem,最后每 C 个 step,你要把用 Q 替代 $\hat{Q}$ 。 + +![](img/9.13.png) + + 接下来我们把它改成 Pathwise Derivative Policy Gradient,这边就是只要做四个改变就好。 + +* 第一个改变是,你要把 Q 换成 $\pi$,本来是用 Q 来决定在 state $s_t$ 产生那一个 action, $a_{t}$ 现在是直接用 $\pi$ 。我们不用再解 arg max 的 problem 了,我们直接 learn 了一个 actor。这个 actor input $s_t$ 就会告诉我们应该采取哪一个 $a_{t}$。所以本来 input $s_t$,采取哪一个 $a_t$,是 Q 决定的。在 Pathwise Derivative Policy Gradient 里面,我们会直接用 $\pi$ 来决定,这是第一个改变。 +* 第二个改变是,本来这个地方是要计算在 $s_{i+1}$,根据你的 policy 采取某一个 action a 会得到多少的 Q value。那你会采取让 $\hat{Q}$ 最大的那个 action a。那现在因为我们其实不好解这个 arg max 的 problem,所以 arg max problem,其实现在就是由 policy $\pi$ 来解了,所以我们就直接把 $s_{i+1}$ 代到 policy $\pi$ 里面,你就会知道说 given $s_{i+1}$ ,哪一个 action 会给我们最大的 Q value,那你在这边就会 take 那一个 action。在 Q-function 里面,有两个 Q network,一个是真正的 Q network,另外一个是 target Q network。那实际上你在 implement 这个 algorithm 的时候,你也会有两个 actor,你会有一个真正要 learn 的 actor $\pi$,你会有一个 target actor $\hat{\pi}$ 。这个原理就跟为什么要有 target Q network 一样,我们在算 target value 的时候,我们并不希望它一直的变动,所以我们会有一个 target 的 actor 和一个 target 的 Q-function,它们平常的参数就是固定住的,这样可以让你的这个 target 的 value 不会一直地变化。所以本来到底是要用哪一个 action a,你会看说哪一个 action a 可以让 $\hat{Q}$ 最大。但现在因为哪一个 action a 可以让 $\hat{Q}$ 最大这件事情已经被用那个 policy 取代掉了,所以我们要知道哪一个 action a 可以让 $\hat{Q}$ 最大,就直接把那个 state 带到 $\hat{\pi}$ 里面,看它得到哪一个 a,就用那一个 a,那一个 a 就是会让 $\hat{Q}(s,a)$ 的值最大的那个 a 。其实跟原来的这个 Q-learning 也是没什么不同,只是原来你要解 arg max 的地方,通通都用 policy 取代掉了,那这个是第二个不同。 +* 第三个不同就是之前只要 learn Q,现在你多 learn 一个 $\pi$,那 learn $\pi$ 的时候的方向是什么呢?learn $\pi$ 的目的,就是为了 maximize Q-function,希望你得到的这个 actor,它可以让你的 Q-function output 越大越好,这个跟 learn GAN 里面的 generator 的概念。其实是一样的。 +* 第四个 step,就跟原来的 Q-function 一样。你要把 target 的 Q network 取代掉,你现在也要把 target policy 取代掉。 + +## Connection with GAN +![](img/9.14.png) + +其实 GAN 跟 Actor-Critic 的方法是非常类似的。这边就不细讲,你可以去找到一篇 paper 叫做 `Connecting Generative Adversarial Network and Actor-Critic Methods`。知道 GAN 跟 Actor-Critic 非常像有什么帮助呢?一个很大的帮助就是 GAN 跟 Actor-Critic 都是以难 train 而闻名的。所以在文献上就会收集各式各样的方法,告诉你说怎么样可以把 GAN train 起来。怎么样可以把 Actor-Critic train 起来。但是因为做 GAN 跟 Actor-Critic 的人是两群人,所以这篇 paper 里面就列出说在 GAN 上面有哪些技术是有人做过的,在 Actor-Critic 上面,有哪些技术是有人做过的。也许在 GAN 上面有试过的技术,你可以试着 apply 在 Actor-Critic 上,在 Actor-Critic 上面做过的技术,你可以试着 apply 在 GAN 上面,看看是否 work。 \ No newline at end of file diff --git a/docs/chapter9/img/9.1.png b/docs/chapter9/img/9.1.png index f394ac0..7bbc0ee 100644 Binary files a/docs/chapter9/img/9.1.png and b/docs/chapter9/img/9.1.png differ diff --git a/docs/chapter9/img/9.10.png b/docs/chapter9/img/9.10.png index 8a4edbc..a10f9ae 100644 Binary files a/docs/chapter9/img/9.10.png and b/docs/chapter9/img/9.10.png differ diff --git a/docs/chapter8/img/8.11.png b/docs/chapter9/img/9.11.png similarity index 100% rename from docs/chapter8/img/8.11.png rename to docs/chapter9/img/9.11.png diff --git a/docs/chapter8/img/8.12.png b/docs/chapter9/img/9.12.png similarity index 100% rename from docs/chapter8/img/8.12.png rename to docs/chapter9/img/9.12.png diff --git a/docs/chapter8/img/8.13.png b/docs/chapter9/img/9.13.png similarity index 100% rename from docs/chapter8/img/8.13.png rename to docs/chapter9/img/9.13.png diff --git a/docs/chapter8/img/8.14.png b/docs/chapter9/img/9.14.png similarity index 100% rename from docs/chapter8/img/8.14.png rename to docs/chapter9/img/9.14.png diff --git a/docs/chapter9/img/9.2.png b/docs/chapter9/img/9.2.png index e1dda19..395629f 100644 Binary files a/docs/chapter9/img/9.2.png and b/docs/chapter9/img/9.2.png differ diff --git a/docs/chapter9/img/9.3.png b/docs/chapter9/img/9.3.png index 1d4b264..964d4ff 100644 Binary files a/docs/chapter9/img/9.3.png and b/docs/chapter9/img/9.3.png differ diff --git a/docs/chapter9/img/9.4.png b/docs/chapter9/img/9.4.png index 5e1d209..ab3b876 100644 Binary files a/docs/chapter9/img/9.4.png and b/docs/chapter9/img/9.4.png differ diff --git a/docs/chapter9/img/9.5.png b/docs/chapter9/img/9.5.png index 487f858..c147a2f 100644 Binary files a/docs/chapter9/img/9.5.png and b/docs/chapter9/img/9.5.png differ diff --git a/docs/chapter9/img/9.6.png b/docs/chapter9/img/9.6.png index 50599e9..d2e4f2a 100644 Binary files a/docs/chapter9/img/9.6.png and b/docs/chapter9/img/9.6.png differ diff --git a/docs/chapter9/img/9.7.png b/docs/chapter9/img/9.7.png index 1c08fad..c3ca4e5 100644 Binary files a/docs/chapter9/img/9.7.png and b/docs/chapter9/img/9.7.png differ diff --git a/docs/chapter9/img/9.8.png b/docs/chapter9/img/9.8.png index e9a38f5..9ac19fe 100644 Binary files a/docs/chapter9/img/9.8.png and b/docs/chapter9/img/9.8.png differ diff --git a/docs/chapter9/img/9.9.png b/docs/chapter9/img/9.9.png index 813ebfb..4c2ad93 100644 Binary files a/docs/chapter9/img/9.9.png and b/docs/chapter9/img/9.9.png differ