Skip to content

Commit

Permalink
update actor critic
Browse files Browse the repository at this point in the history
  • Loading branch information
johnjim0816 committed Jul 29, 2023
1 parent ab5b369 commit b964464
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 6 deletions.
42 changes: 42 additions & 0 deletions docs/ch10/main.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,51 @@
# Actor-Critic 算法

在策略梯度的章节中,实际上我们已经开了一部分 Actor-Critic 算法的头了,这一章我们将继续深入探讨 Actor-Critic 算法。

## 策略梯度算法的缺点

这里策略梯度算法特指蒙特卡洛策略梯度算法,相比于 DQN 之类的基于价值的算法,策略梯度算法有以下优点:

* **适配连续动作空间**。在将策略函数设计的时候我们已经展开过,这里不再赘述。
* **适配随机策略**。由于策略梯度算法是基于策略函数的,因此可以适配随机策略,而基于价值的算法则需要一个确定的策略。此外其计算出来的策略梯度是无偏的,而基于价值的算法则是有偏的。

但同样的,策略梯度算法也有其缺点:

* **采样效率低**。由于使用的是蒙特卡洛估计,与基于价值算法的时序差分估计相比其采样速度必然是要慢很多的,这个问题在前面相关章节中也提到过。
* **高方差**。虽然跟基于价值的算法一样都会导致高方差,但是策略梯度算法通常是在估计梯度时蒙特卡洛采样引起的高方差,这样的方差甚至比基于价值的算法还要高。
* **收敛性差**。容易陷入局部最优,策略梯度方法并不保证全局最优解,因为它们可能会陷入局部最优点。策略空间可能非常复杂,存在多个局部最优点,因此算法可能会在局部最优点附近停滞。
* **难以处理高维离散动作空间**:对于离散动作空间,采样的效率可能会受到限制,因为对每个动作的采样都需要计算一次策略。当动作空间非常大时,这可能会导致计算成本的急剧增加。

而结合了策略梯度和值函数的 Actor-Critic 算法则能同时兼顾两者的优点,并且甚至能缓解两种方法都很难解决的高方差问题。可能读者会奇怪为什么各自都有高方差的问题,结合了之后反而缓解了这个问题呢?我们再仔细分析一下两者高方差的根本来源,策略梯度算法是因为直接对策略参数化,相当于既要利用策略去与环境交互采样,又要利用采样去估计策略梯度,而基于价值的算法也是需要与环境交互采样来估计值函数的,因此也会有高方差的问题。而结合之后呢,Actor 部分还是负责估计策略梯度和采样,但 Critic 即原来的值函数部分就不需要采样而只负责估计值函数了,并且由于它估计的值函数指的是策略函数的值,相当于带来了一个更稳定的估计,来指导 Actor 的更新,反而能够缓解策略梯度估计带来的方差。当然尽管 Actor-Critic 算法能够缓解方差问题,但并不能彻底解决问题,在接下来的章节中我们也会展开介绍一些改进的方法。


## Q Actor-Critic 算法

在策略梯度章节中,我们其实已经对 Actor-Critic 算法的目标函数进行过推导了,这里就不详细展开,只是简单回顾一下目标函数,如下:

$$
\begin{aligned}
\nabla_\theta J(\theta) \propto \mathbb{E}_{\pi_{\theta}}\left[Q^\pi(s, a) \nabla_\theta \log \pi_\theta(a \mid s)\right]
\end{aligned}
$$

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

$$
\begin{aligned}
\nabla_\theta J(\theta) \propto \mathbb{E}_{\pi_{\theta}}\left[Q_{\phi}(s_t, a_t) \nabla_\theta \log \pi_\theta(a_t \mid s_t)\right]
\end{aligned}
$$

这样的算法通常称之为 Q Actor-Critic 算法,这也是最简单的 Actor-Critic 算法,现在我们一般都不用这个算法了,但是这个算法的思想是很重要的,因为后面的算法都是在这个算法的基础上进行改进的。


<div align=center>
<img width="500" src="../figs/ch10/actor_critic_architecture.png"/>
</div>
<div align=center>图 10.1 actor-critic 算法架构</div>

如图所示,我们通常将 Actor 和 Critic 分别用两个模块来表示,即图中的 策略函数(Policy)和价值函数(Value Function)。Actor 与环境交互采样,然后将采样的轨迹输入 Critic 网络,Critic 网络估计出当前状态-动作对的价值,然后再将这个价值作为 Actor 网络的梯度更新的依据,这也是所有 Actor-Critic 算法的基本通用架构。
## A2C 算法

## A3C 算法
Expand Down
13 changes: 7 additions & 6 deletions docs/ch9/main.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# 策略梯度


本章开始介绍基于策略梯度(policy based)的算法,与前面介绍的基于价值(value based)的算法(包括 DQN 等算法)不同,这类算法直接对策略本身进行近似优化。在这种情况下,我们可以将策略描述成一个带有参数$\theta$的连续函数,该函数将某个状态作为输入,输出的不再是某个确定性(deterministic)的离散动作,而是对应的动作概率分布,通常用$\pi_{\theta}(a|s)$表示,称作随机性(stochastic)策略。

## 基于价值算法的缺点
Expand Down Expand Up @@ -206,11 +205,11 @@ $$
\begin{aligned}
\nabla_\theta J(\theta) & \propto \sum_{s \in \mathcal{S}} d^\pi(s) \sum_{a \in \mathcal{A}} Q^\pi(s, a) \nabla_\theta \pi_\theta(a \mid s) \\
&=\sum_{s \in \mathcal{S}} d^\pi(s) \sum_{a \in \mathcal{A}} \pi_\theta(a \mid s) Q^\pi(s, a) \frac{\nabla_\theta \pi_\theta(a \mid s)}{\pi_\theta(a \mid s)} \\
&=\mathbb{E}_\pi\left[Q^\pi(s, a) \nabla_\theta \log \pi_\theta(a \mid s)\right]
&=\mathbb{E}_{\pi_{\theta}}\left[Q^\pi(s, a) \nabla_\theta \log \pi_\theta(a \mid s)\right]
\end{aligned}
$$

到这里我们会发现,REINFORCE 算法只是利用蒙特卡洛的方式将公式中的 $Q^\pi(s, a)$ 替换成了 $G(\tau)$。实际上读者们在学习了结合深度学习的 DQN 算法之后,$Q^\pi(s, a)$ 也是可以用神经网络模型来近似的,只是略有不同的是这里的 $Q^\pi(s, a)$ 相比于 DQN 算法中的 Q 函数多了一个策略函数 $\pi$ 作为输入,因此更多的像是在评判策略的价值而不是状态的价值,而用来近似 $Q^\pi(s, a)$ 的模型我们一般称作 Critic。相应地,另外只包含策略梯度的一部分 $\nabla_\theta \log \pi_\theta(a \mid s)$ 的模型我们一般称作 Actor。这样一来已经不是单纯的策略梯度算法了,而是同时结合了基于价值和策略梯度的算法,我们一般把这类算法称之为 Actor-Critic 算法,具体会在后面的章节中展开。
到这里我们会发现,REINFORCE 算法只是利用蒙特卡洛的方式将公式中的 $Q^\pi(s, a)$ 替换成了 $G(\tau)$。实际上读者们在学习了结合深度学习的 DQN 算法之后,$Q^\pi(s, a)$ 也是可以用神经网络模型来近似的,只是略有不同的是这里的 $Q^\pi(s, a)$ 相比于 DQN 算法中的 Q 函数多了一个策略 $\pi$ 作为输入,并且输出的不再是所有动作对应的 Q 值,而是针对当前状态和动作 $(s_t,a_t)$ 的单个值,因此更多的像是在评判策略的价值而不是状态的价值,而用来近似 $Q^\pi(s, a)$ 的模型我们一般称作 Critic。相应地,另外只包含策略梯度的一部分 $\nabla_\theta \log \pi_\theta(a \mid s)$ 的模型我们一般称作 Actor。这样一来已经不是单纯的策略梯度算法了,而是同时结合了基于价值和策略梯度的算法,我们一般把这类算法称之为 Actor-Critic 算法,具体会在后面的章节中展开。

## 策略函数的设计

Expand All @@ -219,7 +218,6 @@ $$
我们先回顾一下在 DQN 算法中是如何设计网络模型来近似 Q 函数的,通常是包含一个输入层、一个隐藏层和一个输出层,其中输入层一般是维度等于状态数的线性层,输出层则是维度等于动作数的线性层,对于更复杂的情况读者可以根据实际需要自行设计,比如中间多增加几层隐藏层或者改成 CNN 网络,只需要保证模型能够接收状态作为输入,并且能够输出等于每个动作的 Q 值即可。对于策略函数来说,我们也可以采用类似的设计,只不过我们输出的不是 Q 值,而是各个动作的概率分布。其实动作概率分布在实现上跟 Q 值的唯一区别就是必须都大于 0 且和为 1,最简单的做法是在 Q 网络模型的最后一层增加处理层,一般称作为动作层 (action layer)。由于原来 Q 网络模型输出的值是有正有负的,怎么把它们转换成动作概率分布呢?读者可能想到一个最简单的方式就是用最大值减去最小值得到一个范围值,然后原来的最小值变成0,其他原来的值则各自减去原来的最小值然后除以范围值,例如对于 $[-0.5,0,0.5]$,用最大值减去最小值得到 1,然后原来的最小值变成 0,其他原来的值则各自减去原来的最小值然后除以 1,最后得到的就是 $[0,0.5,0.5]$,这样一来就满足了概率分布的要求了,这就是最原始的 min-max 归一化思路。但是这种方法会有一些缺点,感兴趣的读者可自行查阅相关资料,这里就不详细展开了。我们通常采取目前比较流行的方式,即用 Softmax 函数来处理,定义如下:

$$
\label{eq:softmax_act}
\pi_\theta(s, a)=\frac{e^{\phi(s, a)^T} \theta}{\sum_b e^{\phi(s, b)^T}}
$$

Expand All @@ -242,7 +240,7 @@ $$
\nabla_\theta \log \pi_\theta(s \mid a)= \log p_\theta(s, a)
$$

在很多代码和论文中,一般都把它写作 `logits_p`,对应的 $p_\theta(s, a)$ 叫做 `probs`, 这个在后面实战中我们会看到。
在很多代码实践中,一般都把它写作 `logits_p`,对应的 $p_\theta(s, a)$ 叫做 `probs`, 这个在后面实战中我们会看到。

### 连续动作的策略函数

Expand All @@ -252,4 +250,7 @@ $$
\nabla_\theta \log \pi_\theta(s, a)==\frac{\left(a-\phi(s)^T \theta\right) \phi(s)}{\sigma^2}
$$

这个公式虽然看起来很复杂,但实现起来其实很简单,只需要在模型最后一层输出两个值,一个是均值,一个是方差,然后再用这两个值来构建一个高斯分布,然后采样即可,具体同样在实战中展开。
这个公式虽然看起来很复杂,但实现起来其实很简单,只需要在模型最后一层输出两个值,一个是均值,一个是方差,然后再用这两个值来构建一个高斯分布,然后采样即可,具体同样在实战中展开。


## 实战:REINFORCE 算法
Binary file added docs/figs/ch10/actor_critic_architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b964464

Please sign in to comment.