Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
johnjim0816 committed Sep 10, 2023
1 parent a0c80ef commit afde03c
Show file tree
Hide file tree
Showing 24 changed files with 204 additions and 127 deletions.
12 changes: 9 additions & 3 deletions docs/ch1/main.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# 第 1 章 绪论

$\qquad$ 在正式介绍具体的强化学习算法之前,本章将宏观地讨论一下强化学习( $\text{reinforcement learning,RL}$ )的相关概念以及应用等,帮助读者更好地 “观其大略” 。尤其是对于想用强化学习做一些交叉研究的读者来说,更应该首先通过本章了解强化学习是什么,大概能做什么,能做到什么样的效果等等,而不是直接从一个个的算法开始。强化学习发展至今,尽管算法已经有成百上千种样式,但实际上从大类来看要掌握的核心并不多,大多数算法都只是做了一些较小的改进。举个例子,如图 $\text{1-1}$ 所示,我们知道用水加上咖啡豆通过一定的方法就能调制成咖啡,加上糖块就能变成糖水,虽然看起来形式不同,但本质上都是水,只是为了符合不同的口味而已。
$\qquad$ 在正式介绍具体的强化学习算法之前,本章将宏观地讨论一下强化学习( $\text{reinforcement learning,RL}$ )的相关概念以及应用等,帮助读者更好地 “观其大略” 。尤其是对于想用强化学习做一些交叉研究的读者来说,更应该首先通过本章了解强化学习是什么,大概能做什么,能做到什么样的效果等等,而不是直接从一个个的算法开始。

$\qquad$ 强化学习发展至今,尽管算法已经有成百上千种样式,但实际上从大类来看要掌握的核心并不多,大多数算法都只是做了一些较小的改进。举个例子,如图 $\text{1-1}$ 所示,我们知道用水加上咖啡豆通过一定的方法就能调制成咖啡,加上糖块就能变成糖水,虽然看起来形式不同,但本质上都是水,只是为了符合不同的口味而已。

<div align=center>
<img width="400" src="../figs/ch1/water_examp.png"/>
Expand All @@ -9,7 +11,9 @@ $\qquad$ 在正式介绍具体的强化学习算法之前,本章将宏观地

## 1.1 为什么选择强化学习?

$\qquad$ 首先,我们先讨论一下为什么要学习强化学习,强化学习对于我们的意义是什么。可能大部分读者都是通过先了解到人工智能和机器学习才了解到强化学习的,但实际上早在我们认知人工智能之前就已经不知不觉地接触到了强化学习。笔者想起了初中生物课本中关于蚯蚓的一个实验,其内容大致是这样的:如图 $\text{1-2}$ 所示,将蚯蚓放在一个盒子中,盒子中间有一条分叉路口,路口尽头分别放有食物和电极,让蚯蚓自己爬行到其中一个路口的尽头,在食物的一端蚯蚓会品尝到美味,而在电极的一头则会受到轻微的电击。
$\qquad$ 首先,我们先讨论一下为什么要学习强化学习,强化学习对于我们的意义是什么。可能大部分读者都是通过先了解到人工智能和机器学习才了解到强化学习的,但实际上早在我们认知人工智能之前就已经不知不觉地接触到了强化学习。

$\qquad$ 笔者想起了初中生物课本中关于蚯蚓的一个实验,其内容大致是这样的:如图 $\text{1-2}$ 所示,将蚯蚓放在一个盒子中,盒子中间有一条分叉路口,路口尽头分别放有食物和电极,让蚯蚓自己爬行到其中一个路口的尽头,在食物的一端蚯蚓会品尝到美味,而在电极的一头则会受到轻微的电击。

<div align=center>
<img width="200" src="../figs/ch1/qiuyin.png"/>
Expand Down Expand Up @@ -69,10 +73,12 @@ $\qquad$ 强化学习不光应用十分广泛,从技术角度来讲子方向
* 多任务强化学习( $\text{multi-task reinforcement learning}$ )。这个问题在深度学习中也较为常见,在实际应用中,智能体往往需要同时解决多个任务,例如机器人需要同时完成抓取、搬运、放置等任务,而不是单一的抓取任务。在这种情况下,如何在多个任务之间做出权衡是一个难题。目前比较常用的方法有联合训练( $\text{joint training}$ )和分层强化学习( $\text{hierarchical reinforcement learning}$ )等等。联合训练的思路是将多个任务的奖励进行加权求和,然后通过强化学习来学习一个策略。分层强化学习的思路是将多个任务分为两个层次,一个是高层策略,另一个是低层策略。高层策略的作用是决策当前的任务,而低层策略的作用是决策当前任务的动作。这样就可以通过强化学习来学习高层策略和低层策略,从而解决多任务强化学习的问题。但分层强化学习也存在着一定的问题,例如高层策略的决策可能会导致低层策略的决策出错,因此如何提高高层策略的决策精度也是一个难题。


## 学习本书之前的一些准备
## 1.4 学习本书之前的一些准备

$\qquad$ 我们先介绍一下关于本书的初衷。其实日前强化学习相关的书籍在市面上已经琳琅满目了,但是这些普遍偏向理论,缺少一些实际的经验性总结,比如大佬们可能会通过数学推导来告诉你某某算法是可行的,可是一些实验细节和不同算法的对比很难在这些书籍中体现出来,理论与实践之间、公式与代码之间其实存在着一定的鸿沟。另一方面,由于信息时代知识的高速迭代,面对如海洋一般的信息,我们需要从中梳理出重点并快速学习,以便于尽快看到实际应用的效果,而这中间就不得不需要一个经验丰富的老师傅来带路了,这也是本书的初衷之一。笔者会基于大量的强化学习实践经验,对于理论部分删繁就简,并与实践紧密结合,以更通俗易懂的方式帮助读者们快速实践。

$\qquad$ 其次,在具体的学习之前,先给读者做一些基础的知识铺垫。第一,强化学习是机器学习的一个分支,因此读者需要具备一定的机器学习基础,例如基本的线性代数、概率论、数理统计等等。当然只需要读者们修过相关的大学课程即可,不必先去刻意回顾一些知识,原理部分跟随本书的推导即可。第二,在学习强化学习初期是不涉及深度神经网络相关的东西的,这一部分通常称为传统强化学习部分。尽管这部分的算法在今天已经不常用,但是其中蕴含的一些思想和技巧是非常重要的,因此读者们需要对这部分内容有所了解。在过渡到结合神经网络的深度强化学习部分之前,本书会花一章的时间帮助读者整理需要的深度学习知识。

$\qquad$ 深度学习在强化学习中扮演的角色主要是提供了一个强大的函数拟合能力,使得智能体能够处理复杂、高维度和非线性的环境。深度学习与强化学习之间的关系相当于眼睛和大脑的关键,眼睛是帮助大脑决策更好地观测世界的工具,对于一些没有眼睛的动物例如蚯蚓也可以通过其他的感官来观测并解析状态。再比如,同样大脑水平下,即相同的强化学习算法条件下,正常人要比双目失明的人日常的决策要更方便。但是,即使深度学习部分是相同的,例如正常大人和小孩都能通过眼睛观测世界,然由于大脑决策水平的差异也会让两者表现有所差异。总而言之,深度与强化在更复杂的环境下缺一不可。最后,尽管强化学习算法很多,但基本上就分为两类,即基于价值的和基于策略梯度的算法,这两种算法各有优势,请读者们再学习之后根据实际需要谨慎选择即可。


17 changes: 13 additions & 4 deletions docs/ch10/main.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ tag{10.1}
\end{aligned}
$$

$\qquad$ 在 $\text{Actor-Critic}$ 算法中,我们使用蒙特卡洛估计来表示当前状态-动作对 $(s_t,a_t)$ 的价值。而这里其实可以类比于 $Q$ 函数,用 $Q^\pi(s_t, a_t)$ 来估计当前的价值,注意这里的输入是状态和动作,而不单单是状态,输出的是单个值,也可以用 $Q_{\phi}(s_t, a_t)$ 表示,其中 $\phi$ 表示 $\text{Critic}$ 网络的参数。这样我们就可以将目标函数写成如式 $\text(10.2)$ 所示的形式。
$\qquad$ 在 $\text{REINFORCE}$ 算法中,我们使用蒙特卡洛估计来表示当前状态-动作对 $(s_t,a_t)$ 的价值。而这里其实可以类比于 $Q$ 函数,用 $Q^\pi(s_t, a_t)$ 来估计当前的价值,注意这里的输入是状态和动作,而不单单是状态,输出的是单个值,也可以用 $Q_{\phi}(s_t, a_t)$ 表示,其中 $\phi$ 表示 $\text{Critic}$ 网络的参数。这样我们就可以将目标函数写成如式 $\text(10.2)$ 所示的形式。

$$
tag{10.2}
Expand Down Expand Up @@ -211,7 +211,7 @@ $\qquad$ 注意这里直接利用了 `PyTorch` 中的 `Categorical` 分布函数

### 10.5.3 策略更新

我们首先需要计算出优势函数,一般先计算出回报,然后减去网络输出的值即可,如代码清单 $\text{10-4}$ 所示。
$\qquad$ 我们首先需要计算出优势函数,一般先计算出回报,然后减去网络输出的值即可,如代码清单 $\text{10-4}$ 所示。

<div style="text-align: center;">
<figcaption> 代码清单 $\text{10-4}$ 计算优势函数 </figcaption>
Expand Down Expand Up @@ -266,10 +266,19 @@ class Agent:
return actor_loss, critic_loss
```

到这里,我们就实现了 $\text{A2C}$ 算法的所有核心代码,完整代码请读者参考本书的代码仓库。最后展示一下训练的效果,如图 $\text{10-3}$ 所示。
$\qquad$ 到这里,我们就实现了 $\text{A2C}$ 算法的所有核心代码,完整代码请读者参考本书的代码仓库。最后展示一下训练的效果,如图 $\text{10-3}$ 所示。


<div align=center>
<img width="400" src="../figs/ch10/a2c_CartPole_training.png"/>
</div>
<div align=center>图 $\text{10-3}$ $\text{CartPole}$ 环境 $\text{A2C}$ 算法训练曲线</div>
<div align=center>图 $\text{10-3}$ $\text{CartPole}$ 环境 $\text{A2C}$ 算法训练曲线</div>

## 10.5 本章小结

$\qquad$ 本章主要介绍了 $\text{A2C}$ 与 $\text{A3C}$ 算法,相比于前一章讲的 $\text{REINFORCE}$ 算法,主要优化了 $\text{Critic}$ 部分的估计,提高了算法的收敛速度。并且通过引入异步训练的方式来进一步提高这类算法的收敛速度,实践中我们会用 $\text{multiprocessing}$ 等多进程模块来实现。

## 10.6 练习题

1. 相比于 $\text{REINFORCE}$ 算法, $\text{A2C}$ 主要的改进点在哪里,为什么能提高速度?
2. $\text{A2C}$ 算法是 $\text{on-policy}$ 的吗?为什么?
10 changes: 5 additions & 5 deletions docs/ch11/main.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ $\qquad$ 本章先讲 $\text{DDPG}$ 算法和 $\text{TD3}$ 算法,其中后者

$\qquad$ 深度确定性策略梯度算法( $\text{deep deterministic policy gradient,DDPG}$),是一种确定性的策略梯度算法。为了让读者更好地理解 $\text{DDPG}$ 算法,我们先把 “深度” 二字去掉,即先介绍一下 $\text{DPG}$ 算法,也是 $\text{DDPG}$ 算法的核心所在。

$\qquad$ 有了前面 $\text{Actor-Critic}$ 算法的铺垫之后,从策略梯度的角度来理解 $\text{DPG}$ 算法是比较容易的。首先我们知道 $\text{DQN}$ 算法的一个主要缺点就是不能用于连续动作空间,这是因为在 $\text{DQN}$ 算法中动作是通过贪心策略或者说 $\text{argmax}$ 的方式来从 $Q$ 函数间接得到,这里 $Q$ 函数就相当于 $\text{DDPG}$ 算法 中的 $\text{Critic}$。
$\qquad$ 有了前面 $\text{Actor-Critic}$ 算法的铺垫之后,从策略梯度的角度来理解 $\text{DPG}$ 算法是比较容易的。首先我们知道 $\text{DQN}$ 算法的一个主要缺点就是不能用于连续动作空间,这是因为在 $\text{DQN}$ 算法中动作是通过贪心策略或者说 $\text{argmax}$ 的方式来从 $Q$ 函数间接得到,这里 $Q$ 函数就相当于 $\text{DDPG}$ 算法中的 $\text{Critic}$。

$\qquad$ 而要想适配连续动作空间,我们干脆就将选择动作的过程变成一个直接从状态映射到具体动作的函数 $\mu_\theta (s)$,其中 $\theta$ 表示模型的参数,这样一来就把求解 $Q$ 函数、贪心选择动作这两个过程合并成了一个函数,也就是我们常说的 $\text{Actor}$ 。注意,这里的 $\mu_\theta (s)$ 输出的是一个动作值,而不是像 $\text{Actor-Critic}$ 章节中提到的概率分布 $\pi_{\theta}(a|s)$。

$\qquad$ 我们知道 $Q(s,a)$ 函数实际上是有两个变量的,相当于一个曲线平面,如图 $\text{11-1}$ 所示。当我们输入某个状态到 $\text{Actor}$ 时,即固定 $s=s_t$ 时,则相当于把曲线平面截断成一条曲线。而 $\text{Actor}$ 的任务就是寻找这条曲线的最高点,并返回对应的横坐标,即 最大 $Q$ 值对应的动作。
$\qquad$ 我们知道 $Q(s,a)$ 函数实际上是有两个变量的,相当于一个曲线平面,如图 $\text{11-1}$ 所示。当我们输入某个状态到 $\text{Actor}$ 时,即固定 $s=s_t$ 时,则相当于把曲线平面截断成一条曲线。而 $\text{Actor}$ 的任务就是寻找这条曲线的最高点,并返回对应的横坐标,即最大 $Q$ 值对应的动作。

<div align=center>
<img width="500" src="../figs/ch11/ddpg_actor.png"/>
Expand Down Expand Up @@ -142,11 +142,11 @@ $$

$\qquad$ 其中 $N(0, \sigma)$ 表示均值为 $\text{0}$,方差为 $\sigma$ 的高斯噪声,$\epsilon$ 表示噪声,$\operatorname{clip}$ 表示裁剪函数,即将噪声裁剪到 $[-c, c]$ 的范围内,$c$ 是一个超参数,用于控制噪声的大小。可以看到,这里噪声更像是一种正则化的方式,使得值函数更新更加平滑,因此笔者称之为噪声正则。

## 10.5 实战:DDPG 算法
## 11.5 实战:DDPG 算法

$\qquad$ 同之前章节一样,本书在实战中将演示一些核心的代码,完整的代码请参考 $\text{JoyRL}$ 代码仓库。

### 10.5.1 DDPG 伪代码
### 11.5.1 DDPG 伪代码

$\qquad$ 如图 $\text{11-3}$ 所示,$\text{DDPG}$ 算法的训练方式其实更像 $\text{DQN}$ 算法。注意在第 $15$ 步中 $\text{DDPG}$ 算法将当前网络参数复制到目标网络的方式是软更新,即每次一点点地将参数复制到目标网络中,与之对应的是 $\text{DQN}$ 算法中的硬更新。软更新的好处是更加平滑缓慢,可以避免因权重更新过于迅速而导致的震荡,同时降低训练发散的风险。

Expand All @@ -155,7 +155,7 @@ $\qquad$ 如图 $\text{11-3}$ 所示,$\text{DDPG}$ 算法的训练方式其实
</div>
<div align=center>图 $\text{11-3}$ $\text{DDPG}$ 算法伪代码</div>

### 10.5.2 定义模型
### 11.5.2 定义模型

$\qquad$ 如代码清单 $\text{11-1}$ 所示,$\text{DDPG}$ 算法的模型结构跟 $\text{Actor-Critic}$ 算法几乎是一样的,只是由于$\text{DDPG}$ 算法的 $\text{Critic}$ 是 $Q$ 函数,因此也需要将动作作为输入。除了模型之外,目标网络和经验回放的定义方式跟 $\text{DQN}$ 算法一样,这里不做展开。

Expand Down
Loading

0 comments on commit afde03c

Please sign in to comment.