【深度强化学习】Actor-Critic 算法

本书之前的章节讲解了基于值函数的方法(DQN)和基于策略的方法(REINFORCE),其中基于值函数的方法只学习一个价值函数,而基于策略的方法只学习一个策略函数。那么,一个很自然的问题是,有没有什么方法既学习价值函数,又学习策略函数呢? 答案就是 Actor-Critic。Actor-Critic 是囊括一系列算法的整体架构,目前很多高效的前沿算法都属于 Actor-Critic 算法,本章接下来将会介绍一种最简单的 Actor-Critic 算法。需要明确的是,Actor-Critic 算法本质上是基于策略的算法,因为这一系列算法的目标都是优化一个带参数的策略,只是会额外学习价值函数,从而帮助策略函数更好地学习。

回顾策略梯度

回顾一下,在 REINFORCE 算法中,目标函数的梯度中有一项轨迹回报,用于指导策略的更新。REINFOCE 算法用蒙特卡洛方法来估计 Q ( s , a ) Q(s,a) Q(s,a),能不能考虑拟合一个值函数来指导策略进行学习呢?这正是 Actor-Critic 算法所做的。在策略梯度中,可以把梯度写成下面这个更加一般的形式: g = E [ ∑ t = 0 T ψ t ∇ θ log ⁡ π θ ( a t ∣ s t ) ] g=\mathbb{E}\left[\sum_{t=0}^T\psi_t\nabla_\theta\log\pi_\theta(a_t|s_t)\right] g=E[t=0Tψtθlogπθ(atst)]其中, ψ t \psi_t ψt可以有很多种形式: 1. ∑ t ′ = 0 T γ t ′ r t ′ : 轨迹的总回报; 2. ∑ t ′ = t T γ t ′ − t r t ′ : 动作 a t 之后的回报; 3. ∑ t ′ = t T γ t ′ − t r t ′ − b ( s t ) : 基准线版本的改进; 4. Q π θ ( s t , a t ) : 动作价值函数; 5. A π θ ( s t , a t ) : 优势函数; 6. r t + γ V π θ ( s t + 1 ) − V π θ ( s t ) : 时序差分残差。 \begin{aligned} & 1.\sum_{t^{\prime}=0}^T\gamma^{t^{\prime}}r_{t^{\prime}}:\text{轨迹的总回报;} \\ & 2.\sum_{t^{\prime}=t}^T\gamma^{t^{\prime}-t}r_{t^{\prime}}:\text{动作}a_t\text{之后的回报;} \\ & 3.\sum_{t^{\prime}=t}^T\gamma^{t^{\prime}-t}r_{t^{\prime}}-b(s_t):\text{基准线版本的改进;} \\ & 4.Q^{\pi_\theta}(s_t,a_t):\text{动作价值函数;} \\ & 5.\mathrm{~A}^{\pi_\theta}(s_t,a_t):\text{优势函数;} \\ & 6.r_t+\gamma V^{\pi_\theta}(s_{t+1})-V^{\pi_\theta}(s_t):\text{时序差分残差。} \end{aligned} 1.t=0Tγtrt:轨迹的总回报;2.t=tTγttrt:动作at之后的回报;3.t=tTγttrtb(st):基准线版本的改进;4.Qπθ(st,at):动作价值函数;5. Aπθ(st,at):优势函数;6.rt+γVπθ(st+1)Vπθ(st):时序差分残差。

REINFORCE 通过蒙特卡洛采样的方法对策略梯度的估计是无偏的,但是方差非常大。我们可以用形式(3)引入基线函数(baseline function) b ( s t ) b(s_t) b(st)来减小方差。此外,我们也可以采用 Actor-Critic 算法估计一个动作价值函数 Q Q Q,代替蒙特卡洛采样得到的回报,这便是形式(4)。这个时候,我们可以把状态价值函数 V V V作为基线,从 Q Q Q函数减去这个 V V V函数则得到了 A A A函数,我们称之为优势函数(advantage function),这便是形式(5)。更进一步,我们可以利用等式 Q = r + γ V Q=r+\gamma V Q=r+γV得到形式(6)。

本文将着重介绍形式(6),即通过时序差分残差 ψ t = r t + γ V π ( s t + 1 ) − V π ( s t ) \psi_t=r_t+\gamma V^{\pi}(s_{t+1})-V^{\pi}(s_t) ψt=rt+γVπ(st+1)Vπ(st)来指导策略梯度进行学习。事实上,用值或者值本质上也是用奖励来进行指导,但是用神经网络进行估计的方法可以减小方差、提高鲁棒性。除此之外,REINFORCE 算法基于蒙特卡洛采样,只能在序列结束后进行更新,这同时也要求任务具有有限的步数,而 Actor-Critic 算法则可以在每一步之后都进行更新,并且不对任务的步数做限制。

学到这里兴许你会产生一些疑问,至少下面是我当时产生的疑问:

Q1: 为什么减去基线函数为什么能够减小方差?

在强化学习等相关领域中, ∑ t ′ = t T γ t ′ − t r t ′ − b ( s t ) \sum_{t' = t}^{T} \gamma^{t' - t} r_{t'} - b(s_t) t=tTγttrtb(st) 这种形式常见于策略梯度方法中引入基线(baseline)的情形,以下从几个方面解释减去基线函数能够减小方差的原因:

1. 策略梯度的基本形式

策略梯度算法用于优化策略网络的参数,目标是最大化累计奖励的期望。策略梯度的一般形式为 ∇ θ J ( θ ) ≈ E τ ∼ π θ [ ( ∑ t = 0 T r ( s t , a t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] \nabla_{\theta} J(\theta) \approx \mathbb{E}_{\tau \sim \pi_{\theta}} \left[ \left(\sum_{t = 0}^{T} r(s_t, a_t) \right) \nabla_{\theta} \log \pi_{\theta}(a_t | s_t) \right] θJ(θ)Eτπθ[(t=0Tr(st,at))θlogπθ(atst)] ,其中 τ \tau τ 是一个轨迹, r ( s t , a t ) r(s_t, a_t) r(st,at) 是在状态 s t s_t st 采取动作 a t a_t at 获得的奖励, π θ ( a t ∣ s t ) \pi_{\theta}(a_t | s_t) πθ(atst) 是策略网络在状态 s t s_t st 采取动作 a t a_t at 的概率。

2. 引入基线函数的策略梯度

为了减小策略梯度估计的方差,引入基线函数 b ( s t ) b(s_t) b(st) ,改进后的策略梯度变为 ∇ θ J ( θ ) ≈ E τ ∼ π θ [ ( ∑ t = 0 T r ( s t , a t ) − b ( s t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] \nabla_{\theta} J(\theta) \approx \mathbb{E}_{\tau \sim \pi_{\theta}} \left[ \left(\sum_{t = 0}^{T} r(s_t, a_t) - b(s_t) \right) \nabla_{\theta} \log \pi_{\theta}(a_t | s_t) \right] θJ(θ)Eτπθ[(t=0Tr(st,at)b(st))θlogπθ(atst)]

3. 减小方差的原理
  • 期望不变性:只要基线函数 b ( s t ) b(s_t) b(st) 仅依赖于状态 s t s_t st (而不依赖于动作 a t a_t at ),那么 E a t ∼ π θ ( a t ∣ s t ) [ b ( s t ) ] = b ( s t ) \mathbb{E}_{a_t \sim \pi_{\theta}(a_t | s_t)} [b(s_t)] = b(s_t) Eatπθ(atst)[b(st)]=b(st) 。这意味着 E τ ∼ π θ [ ( ∑ t = 0 T r ( s t , a t ) − b ( s t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] = E τ ∼ π θ [ ( ∑ t = 0 T r ( s t , a t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] \mathbb{E}_{\tau \sim \pi_{\theta}} \left[ \left(\sum_{t = 0}^{T} r(s_t, a_t) - b(s_t) \right) \nabla_{\theta} \log \pi_{\theta}(a_t | s_t) \right] = \mathbb{E}_{\tau \sim \pi_{\theta}} \left[ \left(\sum_{t = 0}^{T} r(s_t, a_t) \right) \nabla_{\theta} \log \pi_{\theta}(a_t | s_t) \right] Eτπθ[(t=0Tr(st,at)b(st))θlogπθ(atst)]=Eτπθ[(t=0Tr(st,at))θlogπθ(atst)] ,即引入基线函数不会改变策略梯度的期望,保证了算法的正确性。
  • 方差减小:通过选择合适的基线函数(例如状态价值函数 V π ( s t ) V^{\pi}(s_t) Vπ(st) 的估计),可以使得 ∑ t = 0 T r ( s t , a t ) − b ( s t ) \sum_{t = 0}^{T} r(s_t, a_t) - b(s_t) t=0Tr(st,at)b(st) 的方差小于 ∑ t = 0 T r ( s t , a t ) \sum_{t = 0}^{T} r(s_t, a_t) t=0Tr(st,at) 的方差。直观地说,基线函数起到了一个参考点的作用,它去除了一些与动作选择无关的背景噪声。例如,如果某个状态本身就倾向于产生高奖励,减去一个基于状态的基线函数可以抵消这种状态本身的奖励倾向,使得不同动作的优劣更加凸显,从而减小了策略梯度估计的方差。

总之,减去基线函数在不改变策略梯度期望的前提下,通过去除状态相关的奖励偏差,有效地减小了策略梯度估计的方差,提高了强化学习算法的稳定性和收敛速度。

Q2: 为什么引入基线函数不会改变策略梯度的期望

在强化学习策略梯度相关内容中,引入基线函数不改变策略梯度期望,原因如下:

前提条件

策略梯度的目标是最大化累计奖励的期望,策略梯度原始形式为 ∇ θ J ( θ ) ≈ E τ ∼ π θ [ ( ∑ t = 0 T r ( s t , a t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] \nabla_{\theta}J(\theta) \approx \mathbb{E}_{\tau \sim \pi_{\theta}}\left[\left(\sum_{t = 0}^{T}r(s_t, a_t)\right)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] θJ(θ)Eτπθ[(t=0Tr(st,at))θlogπθ(atst)] ,其中 τ \tau τ 是轨迹, r ( s t , a t ) r(s_t, a_t) r(st,at) 是在状态 s t s_t st 采取动作 a t a_t at 获得的奖励, π θ ( a t ∣ s t ) \pi_{\theta}(a_t|s_t) πθ(atst) 是策略网络在状态 s t s_t st 采取动作 a t a_t at 的概率。

引入基线函数 b ( s t ) b(s_t) b(st) 后,策略梯度变为 ∇ θ J ( θ ) ≈ E τ ∼ π θ [ ( ∑ t = 0 T r ( s t , a t ) − b ( s t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] \nabla_{\theta}J(\theta) \approx \mathbb{E}_{\tau \sim \pi_{\theta}}\left[\left(\sum_{t = 0}^{T}r(s_t, a_t) - b(s_t)\right)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] θJ(θ)Eτπθ[(t=0Tr(st,at)b(st))θlogπθ(atst)]

期望推导

根据期望的性质,对于随机变量 X X X Y Y Y ,有 E [ X − Y ] = E [ X ] − E [ Y ] \mathbb{E}[X - Y] = \mathbb{E}[X] - \mathbb{E}[Y] E[XY]=E[X]E[Y] 。这里令 X = ( ∑ t = 0 T r ( s t , a t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) X = \left(\sum_{t = 0}^{T}r(s_t, a_t)\right)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t) X=(t=0Tr(st,at))θlogπθ(atst) Y = b ( s t ) ∇ θ log ⁡ π θ ( a t ∣ s t ) Y = b(s_t)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t) Y=b(st)θlogπθ(atst)

由于基线函数 b ( s t ) b(s_t) b(st) 只依赖于状态 s t s_t st ,不依赖于动作 a t a_t at ,那么对于给定状态 s t s_t st ,在动作 a t a_t at 上的期望 E a t ∼ π θ ( a t ∣ s t ) [ b ( s t ) ] = b ( s t ) \mathbb{E}_{a_t \sim \pi_{\theta}(a_t|s_t)}[b(s_t)] = b(s_t) Eatπθ(atst)[b(st)]=b(st)

所以 E τ ∼ π θ [ b ( s t ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] = E τ ∼ π θ [ E a t ∼ π θ ( a t ∣ s t ) [ b ( s t ) ] ∇ θ log ⁡ π θ ( a t ∣ s t ) ] = E τ ∼ π θ [ b ( s t ) E a t ∼ π θ ( a t ∣ s t ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] \mathbb{E}_{\tau \sim \pi_{\theta}}\left[b(s_t)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] = \mathbb{E}_{\tau \sim \pi_{\theta}}\left[\mathbb{E}_{a_t \sim \pi_{\theta}(a_t|s_t)}[b(s_t)]\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] = \mathbb{E}_{\tau \sim \pi_{\theta}}\left[b(s_t)\mathbb{E}_{a_t \sim \pi_{\theta}(a_t|s_t)}\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] Eτπθ[b(st)θlogπθ(atst)]=Eτπθ[Eatπθ(atst)[b(st)]θlogπθ(atst)]=Eτπθ[b(st)Eatπθ(atst)θlogπθ(atst)]

又因为 E a t ∼ π θ ( a t ∣ s t ) ∇ θ log ⁡ π θ ( a t ∣ s t ) = 0 \mathbb{E}_{a_t \sim \pi_{\theta}(a_t|s_t)}\nabla_{\theta}\log\pi_{\theta}(a_t|s_t) = 0 Eatπθ(atst)θlogπθ(atst)=0 (这是概率分布的一个性质,对概率分布的对数求期望关于参数的梯度为 0 ),所以 E τ ∼ π θ [ b ( s t ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] = 0 \mathbb{E}_{\tau \sim \pi_{\theta}}\left[b(s_t)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] = 0 Eτπθ[b(st)θlogπθ(atst)]=0

E τ ∼ π θ [ ( ∑ t = 0 T r ( s t , a t ) − b ( s t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] = E τ ∼ π θ [ ( ∑ t = 0 T r ( s t , a t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] − E τ ∼ π θ [ b ( s t ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] = E τ ∼ π θ [ ( ∑ t = 0 T r ( s t , a t ) ) ∇ θ log ⁡ π θ ( a t ∣ s t ) ] \mathbb{E}_{\tau \sim \pi_{\theta}}\left[\left(\sum_{t = 0}^{T}r(s_t, a_t) - b(s_t)\right)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] = \mathbb{E}_{\tau \sim \pi_{\theta}}\left[\left(\sum_{t = 0}^{T}r(s_t, a_t)\right)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] - \mathbb{E}_{\tau \sim \pi_{\theta}}\left[b(s_t)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] = \mathbb{E}_{\tau \sim \pi_{\theta}}\left[\left(\sum_{t = 0}^{T}r(s_t, a_t)\right)\nabla_{\theta}\log\pi_{\theta}(a_t|s_t)\right] Eτπθ[(t=0Tr(st,at)b(st))θlogπθ(atst)]=Eτπθ[(t=0Tr(st,at))θlogπθ(atst)]Eτπθ[b(st)θlogπθ(atst)]=Eτπθ[(t=0Tr(st,at))θlogπθ(atst)]

综上,引入仅依赖于状态的基线函数不会改变策略梯度的期望。

Q3: 为什么对概率分布的对数求期望关于参数的梯度为 0?

设策略 π θ ( a ∣ s ) \pi_{\theta}(a|s) πθ(as) 是关于参数 θ \theta θ 的概率分布,表示在状态 s s s 下采取动作 a a a 的概率。我们要证明 E a ∼ π θ ( a ∣ s ) [ ∇ θ log ⁡ π θ ( a ∣ s ) ] = 0 \mathbb{E}_{a\sim\pi_{\theta}(a|s)}\left[\nabla_{\theta}\log\pi_{\theta}(a|s)\right]=0 Eaπθ(as)[θlogπθ(as)]=0 ,推导过程如下:

1. 根据期望的定义展开

期望的定义为 E a ∼ π θ ( a ∣ s ) [ f ( a ) ] = ∑ a π θ ( a ∣ s ) f ( a ) \mathbb{E}_{a\sim\pi_{\theta}(a|s)}[f(a)]=\sum_{a}\pi_{\theta}(a|s)f(a) Eaπθ(as)[f(a)]=aπθ(as)f(a) (对于离散动作空间,若为连续动作空间则是积分形式 ∫ π θ ( a ∣ s ) f ( a ) d a \int\pi_{\theta}(a|s)f(a)da πθ(as)f(a)da ,这里以离散为例说明,连续情况类似),那么 E a ∼ π θ ( a ∣ s ) [ ∇ θ log ⁡ π θ ( a ∣ s ) ] = ∑ a π θ ( a ∣ s ) ∇ θ log ⁡ π θ ( a ∣ s ) \mathbb{E}_{a\sim\pi_{\theta}(a|s)}\left[\nabla_{\theta}\log\pi_{\theta}(a|s)\right]=\sum_{a}\pi_{\theta}(a|s)\nabla_{\theta}\log\pi_{\theta}(a|s) Eaπθ(as)[θlogπθ(as)]=aπθ(as)θlogπθ(as)

2. 利用对数函数的求导性质

根据对数函数求导公式 ∇ θ log ⁡ x = 1 x ∇ θ x \nabla_{\theta}\log x = \frac{1}{x}\nabla_{\theta}x θlogx=x1θx ,对于 π θ ( a ∣ s ) \pi_{\theta}(a|s) πθ(as) ,有 ∇ θ log ⁡ π θ ( a ∣ s ) = 1 π θ ( a ∣ s ) ∇ θ π θ ( a ∣ s ) \nabla_{\theta}\log\pi_{\theta}(a|s)=\frac{1}{\pi_{\theta}(a|s)}\nabla_{\theta}\pi_{\theta}(a|s) θlogπθ(as)=πθ(as)1θπθ(as)

3. 代入期望表达式并化简

∇ θ log ⁡ π θ ( a ∣ s ) = 1 π θ ( a ∣ s ) ∇ θ π θ ( a ∣ s ) \nabla_{\theta}\log\pi_{\theta}(a|s)=\frac{1}{\pi_{\theta}(a|s)}\nabla_{\theta}\pi_{\theta}(a|s) θlogπθ(as)=πθ(as)1θπθ(as) 代入 ∑ a π θ ( a ∣ s ) ∇ θ log ⁡ π θ ( a ∣ s ) \sum_{a}\pi_{\theta}(a|s)\nabla_{\theta}\log\pi_{\theta}(a|s) aπθ(as)θlogπθ(as) 中,可得:

∑ a π θ ( a ∣ s ) ∇ θ log ⁡ π θ ( a ∣ s ) = ∑ a π θ ( a ∣ s ) 1 π θ ( a ∣ s ) ∇ θ π θ ( a ∣ s ) = ∑ a ∇ θ π θ ( a ∣ s ) \begin{align*} \sum_{a}\pi_{\theta}(a|s)\nabla_{\theta}\log\pi_{\theta}(a|s)&=\sum_{a}\pi_{\theta}(a|s)\frac{1}{\pi_{\theta}(a|s)}\nabla_{\theta}\pi_{\theta}(a|s)\\ &=\sum_{a}\nabla_{\theta}\pi_{\theta}(a|s) \end{align*} aπθ(as)θlogπθ(as)=aπθ(as)πθ(as)1θπθ(as)=aθπθ(as)

4. 利用概率分布的性质

因为概率分布满足 ∑ a π θ ( a ∣ s ) = 1 \sum_{a}\pi_{\theta}(a|s)=1 aπθ(as)=1 ,对其两边关于参数 θ \theta θ 求梯度,根据求导的线性性质(和的导数等于导数的和),有 ∇ θ ∑ a π θ ( a ∣ s ) = ∑ a ∇ θ π θ ( a ∣ s ) \nabla_{\theta}\sum_{a}\pi_{\theta}(a|s)=\sum_{a}\nabla_{\theta}\pi_{\theta}(a|s) θaπθ(as)=aθπθ(as) ,而常数 1 关于参数 θ \theta θ 的梯度为 0 ,即 ∇ θ ∑ a π θ ( a ∣ s ) = 0 \nabla_{\theta}\sum_{a}\pi_{\theta}(a|s) = 0 θaπθ(as)=0 ,所以 ∑ a ∇ θ π θ ( a ∣ s ) = 0 \sum_{a}\nabla_{\theta}\pi_{\theta}(a|s)=0 aθπθ(as)=0

综上, E a ∼ π θ ( a ∣ s ) [ ∇ θ log ⁡ π θ ( a ∣ s ) ] = 0 \mathbb{E}_{a\sim\pi_{\theta}(a|s)}\left[\nabla_{\theta}\log\pi_{\theta}(a|s)\right]=0 Eaπθ(as)[θlogπθ(as)]=0 ,即对概率分布的对数求期望关于参数的梯度为 0 。

Actor-Critic 算法

我们将 Actor-Critic 分为两个部分:Actor(策略网络)和 Critic(价值网络),如图 10-1 所示。
在这里插入图片描述

  • Actor 要做的是与环境交互,并在 Critic 价值函数的指导下用策略梯度学习一个更好的策略。
  • Critic 要做的是通过 Actor 与环境交互收集的数据学习一个价值函数,这个价值函数会用于判断在当前状态什么动作是好的,什么动作不是好的,进而帮助 Actor 进行策略更新。

Actor 的更新采用策略梯度的原则,那 Critic 如何更新呢?我们将 Critic 价值网络表示为 V ω V_{\omega} Vω,参数为 ω {\omega} ω。于是,我们可以采取时序差分残差的学习方式,对于单个数据定义如下价值函数的损失函数: L ( ω ) = 1 2 ( r + γ V ω ( s t + 1 ) − V ω ( s t ) ) 2 \mathcal{L}(\omega)=\frac{1}{2}(r+\gamma V_\omega(s_{t+1})-V_\omega(s_t))^2 L(ω)=21(r+γVω(st+1)Vω(st))2与 DQN 中一样,我们采取类似于目标网络的方法,将上式中 r + γ V ω ( s t + 1 ) r+\gamma V_{\omega}(s_{t+1}) r+γVω(st+1)作为时序差分目标,不会产生梯度来更新价值函数。因此,价值函数的梯度为: ∇ ω L ( ω ) = − ( r + γ V ω ( s t + 1 ) − V ω ( s t ) ) ∇ ω V ω ( s t ) \nabla_\omega\mathcal{L}(\omega)=-(r+\gamma V_\omega(s_{t+1})-V_\omega(s_t))\nabla_\omega V_\omega(s_t) ωL(ω)=(r+γVω(st+1)Vω(st))ωVω(st)

然后使用梯度下降方法来更新 Critic 价值网络参数即可。

Actor-Critic 算法的具体流程如下:

  • 初始化策略网络参数 θ \theta θ,价值网络参数 ω \omega ω
  • for 序列 e = 1 → E e=1\to E e=1E do :
    • 用当前策略采样轨迹 { s 1 , a 1 , r 1 , s 2 , a 2 , r 2 , . . . } \{s_1,a_1,r_1,s_2,a_2,r_2,...\} {s1,a1,r1,s2,a2,r2,...}
    • 为每一步数据计算 δ t = r t + γ V ω ( s t + 1 ) − V ω ( s t ) \delta_t=r_t+\gamma V_{\omega}(s_{t+1})-V_{\omega}(s_t) δt=rt+γVω(st+1)Vω(st):
    • 更新价值参数 ω = ω + α ω ∑ t δ t ∇ ω V ω ( s t ) \omega=\omega+\alpha_{\omega}\sum_{t}\delta_t\nabla_{\omega}V_{\omega}(s_t) ω=ω+αωtδtωVω(st)
    • 更新策略参数 θ = θ + α θ ∑ t δ t ∇ θ log ⁡ π θ ( a t ∣ s t ) \theta=\theta+\alpha_{\theta}\sum_{t}\delta_t\nabla_{\theta}\log \pi_{\theta}(a_t|s_t) θ=θ+αθtδtθlogπθ(atst)
  • end for

虽然这里写的是梯度,但是我们实际写代码的时候只需要把loss给写出来,梯度是loss对参数求导,所以实际上:
loss actor = mean ( ∑ t δ t log ⁡ π θ ( a t ∣ s t ) ) loss critic = mean ( ∑ t δ t V ω ( s t ) ) \text{loss}_{\text{actor}}=\text{mean}\left( \sum_t\delta_t \log\pi_{\theta}(a_t|s_t) \right)\\ \text{loss}_{\text{critic}}=\text{mean}\left( \sum_t\delta_t V_{\omega}(s_t) \right) lossactor=mean(tδtlogπθ(atst))losscritic=mean(tδtVω(st))Actor-Critic 代码实践:

# 我们仍然在车杆环境上进行 Actor-Critic 算法的实验。
import gym
import torch
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt# rl_utils是作者自己写的文件,在github上去下载: 
# https://github.com/boyu-ai/Hands-on-RL/blob/main/rl_utils.py
# kaggle上导入库操作:
from shutil import copyfile
copyfile(src='/kaggle/input/rlutils/rl_utils.py', dst = "../working/rl_utils.py")
import rl_utils# 首先定义策略网络PolicyNet(与 REINFORCE 算法一样)。
class PolicyNet(torch.nn.Module):def __init__(self, state_dim, hidden_dim, action_dim):super(PolicyNet, self).__init__()self.fc1 = torch.nn.Linear(state_dim, hidden_dim)self.fc2 = torch.nn.Linear(hidden_dim, action_dim)def forward(self, x):x = F.relu(self.fc1(x))return F.softmax(self.fc2(x), dim=1)# Actor-Critic 算法中额外引入一个价值网络,接下来的代码定义价值网络ValueNet,其输入是某个状态,输出则是状态的价值。
class ValueNet(torch.nn.Module):def __init__(self, state_dim, hidden_dim):super(ValueNet, self).__init__()self.fc1 = torch.nn.Linear(state_dim, hidden_dim)self.fc2 = torch.nn.Linear(hidden_dim, 1)def forward(self, x):x = F.relu(self.fc1(x))return self.fc2(x)# 现在定义ActorCritic算法,主要包含采取动作(take_action())和更新网络参数(update())两个函数。
class ActorCritic:def __init__(self, state_dim, hidden_dim, action_dim, actor_lr, critic_lr,gamma, device):# 策略网络self.actor = PolicyNet(state_dim, hidden_dim, action_dim).to(device)self.critic = ValueNet(state_dim, hidden_dim).to(device)  # 价值网络# 策略网络优化器self.actor_optimizer = torch.optim.Adam(self.actor.parameters(),lr=actor_lr)self.critic_optimizer = torch.optim.Adam(self.critic.parameters(),lr=critic_lr)  # 价值网络优化器self.gamma = gammaself.device = devicedef take_action(self, state):state = torch.tensor([state], dtype=torch.float).to(self.device)probs = self.actor(state)action_dist = torch.distributions.Categorical(probs)action = action_dist.sample()return action.item()def update(self, transition_dict):states = torch.tensor(transition_dict['states'],dtype=torch.float).to(self.device)actions = torch.tensor(transition_dict['actions']).view(-1, 1).to(self.device)rewards = torch.tensor(transition_dict['rewards'],dtype=torch.float).view(-1, 1).to(self.device)next_states = torch.tensor(transition_dict['next_states'],dtype=torch.float).to(self.device)dones = torch.tensor(transition_dict['dones'],dtype=torch.float).view(-1, 1).to(self.device)# 时序差分目标td_target = rewards + self.gamma * self.critic(next_states) * (1 -dones)td_delta = td_target - self.critic(states)  # 时序差分误差log_probs = torch.log(self.actor(states).gather(1, actions))actor_loss = torch.mean(-log_probs * td_delta.detach())# 均方误差损失函数critic_loss = torch.mean(F.mse_loss(self.critic(states), td_target.detach()))self.actor_optimizer.zero_grad()self.critic_optimizer.zero_grad()actor_loss.backward()  # 计算策略网络的梯度critic_loss.backward()  # 计算价值网络的梯度self.actor_optimizer.step()  # 更新策略网络的参数self.critic_optimizer.step()  # 更新价值网络的参数# 定义好 Actor 和 Critic,我们就可以开始实验了,看看 Actor-Critic 在车杆环境上表现如何吧!
actor_lr = 1e-3
critic_lr = 1e-2
num_episodes = 1000
hidden_dim = 128
gamma = 0.98
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")env_name = 'CartPole-v0'
env = gym.make(env_name)
env.seed(0)
torch.manual_seed(0)
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n
agent = ActorCritic(state_dim, hidden_dim, action_dim, actor_lr, critic_lr,gamma, device)return_list = rl_utils.train_on_policy_agent(env, agent, num_episodes)

在这里插入图片描述

在 CartPole-v0 环境中,满分就是 200 分。和 REINFORCE 相似,接下来我们绘制训练过程中每一条轨迹的回报变化图以及其经过平滑处理的版本。

episodes_list = list(range(len(return_list)))
plt.plot(episodes_list, return_list)
plt.xlabel('Episodes')
plt.ylabel('Returns')
plt.title('Actor-Critic on {}'.format(env_name))
plt.show()mv_return = rl_utils.moving_average(return_list, 9)
plt.plot(episodes_list, mv_return)
plt.xlabel('Episodes')
plt.ylabel('Returns')
plt.title('Actor-Critic on {}'.format(env_name))
plt.show()

在这里插入图片描述根据实验结果我们可以发现,Actor-Critic 算法很快便能收敛到最优策略,并且训练过程非常稳定,抖动情况相比 REINFORCE 算法有了明显的改进,这说明价值函数的引入减小了方差。

本章讲解了 Actor-Critic 算法,它是基于值函数的方法和基于策略的方法的叠加。价值模块 Critic 在策略模块 Actor 采样的数据中学习分辨什么是好的动作,什么不是好的动作,进而指导 Actor 进行策略更新(都体现在loss上了)。随着 Actor 的训练的进行,其与环境交互所产生的数据分布也发生改变,这需要 Critic 尽快适应新的数据分布并给出好的判别(给它一个更大的学习率)。

Actor-Critic 算法非常实用, TRPO、PPO、DDPG、SAC 等深度强化学习算法都是在 Actor-Critic 框架下进行发展的。深入了解 Actor-Critic 算法对读懂目前深度强化学习的研究热点大有裨益。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/18811.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构——二叉树(2025.2.12)

目录 一、树 1.定义 (1)树的构成 (2)度 2.二叉树 (1)定义 (2)二叉树的遍历 (3)遍历特性 二、练习 1.二叉树 (1)创建二叉树…

安科瑞光伏发电防逆流解决方案——守护电网安全,提升能源效率

安科瑞 华楠 18706163979 在当今大力发展清洁能源的时代背景下,光伏发电作为一种可持续的能源解决方案, 正得到越来越广泛的应用。然而,光伏发电过程中出现的逆流问题,给电网的安全稳定 运行带来了诸多挑战。若不能有效解决&…

3、树莓派5 安装VNC查看器 开启VNC服务器

在前序文章中( 2、树莓派5第一次开机),可以使用三种方式开机,其中使用网线及wifi的方式均需要使用到VNC查看器进行远程桌面控制,本文将介绍如何下载安装并配置及使用VNC查看器及服务器,对前序文章做一些补充…

牛客周赛 Round 80

前言 这场比赛是很有意思的,紧跟时事IG杯,大卞"神之举手",0胜拿下比赛,我当时也是完整的看完三场比赛,在第二次说直接两次罚下的时候我真是直接暴起了,然后第三场当时我正在吃饭,看到…

文档格式转换引擎开发:支持PDF与OFD的技术实现

最新技术资源(建议收藏) https://www.grapecity.com.cn/resources/ 前言 近年来,中国在信息技术领域持续追求自主创新和供应链安全,伴随信创上升为国家战略,一些行业也开始明确要求文件导出的格式必须为 OFD 格式。OF…

VSCode Error Lens插件介绍(代码静态检查与提示工具)(vscode插件)

文章目录 VSCode Error Lens 插件介绍**功能概述****开发背景****使用方法****适用场景** VSCode Error Lens 插件介绍 功能概述 Error Lens 是一款增强 VS Code 错误提示的扩展工具,通过 内联显示错误和警告信息,直接定位代码问题,提升开发…

快速幂(算法)的原理

快速幂算法 快速幂数学原理算法实现OJ题展示不用高精度计算二进制指数的高精度计算数学题等差数列和等比数列计数原理 快速幂 求 ( a b ) % n (a^b)\%n (ab)%n的结果(即 a a a的 b b b次方,再除以 n n n得到的余数)。 利用程序求解时&#…

无人机遥感在农林信息提取中的实现方法与GIS融合应用

在新一轮互联网信息技术大发展的现今,无人机、大数据、人工智能、物联网等新兴技术在各行各业都处于大爆发的前夜。为了将人工智能方法引入农业生产领域。首先在种植、养护等生产作业环节,逐步摆脱人力依赖;在施肥灌溉环节构建智慧节能系统&a…

Android设备 网络安全检测

八、网络与安全机制 6.1 网络框架对比 volley: 功能 基于HttpUrlConnection;封装了UIL图片加载框架,支持图片加载;网络请求的排序、优先级处理缓存;多级别取消请求;Activity和生命周期的联动(Activity结束生命周期同时取消所有网络请求 …

【油猴脚本/Tampermonkey】DeepSeek 服务器繁忙无限重试(20250214优化)

目录 一、 引言 二、 逻辑 三、 源代码 四、 添加新脚本 五、 使用 六、 BUG 七、 优化日志 1.获取最后消息内容报错 2.对话框切换无法正常使用 一、 引言 deepseek演都不演了,每次第一次提问就正常,后面就开始繁忙了,有一点阴招全…

C++ Primer 函数重载

欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…

【c++初阶】类和对象②默认成员函数以及运算符重载初识

目录 ​编辑 默认成员函数: 构造函数 构造函数的特性: 析构函数: 拷贝构造函数: 1. 拷贝构造函数是构造函数的一个重载形式。 2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报…

基于AIOHTTP、Websocket和Vue3一步步实现web部署平台,无延迟控制台输出,接近原生SSH连接

背景:笔者是一名Javaer,但是最近因为某些原因迷上了Python和它的Asyncio,至于什么原因?请往下看。在着迷”犯浑“的过程中,也接触到了一些高并发高性能的组件,通过简单的学习和了解,aiohttp这个…

【鸿蒙HarmonyOS Next实战开发】lottie动画库

简介 lottie是一个适用于OpenHarmony和HarmonyOS的动画库,它可以解析Adobe After Effects软件通过Bodymovin插件导出的json格式的动画,并在移动设备上进行本地渲染。 下载安裝 ohpm install ohos/lottieOpenHarmony ohpm 环境配置等更多内容&#xff0c…

UE_C++ —— UObject Instance Creation

目录 一,UObject Instance Creation NewObject NewNamedObject ConstructObject Object Flags 二,Unreal Object Handling Automatic Property Initialization Automatic Updating of References Serialization Updating of Property Values …

PHP本地商家卡券管理系统

本地商家卡券管理系统 —— 引领智慧消费新时代 本地商家卡券管理系统,是基于ThinkPHPUni-appuView尖端技术匠心打造的一款微信小程序,它彻底颠覆了传统优惠方式,开创了多商家联合发行优惠卡、折扣券的全新模式,发卡类型灵活多变…

什么是HTTP Error 429以及如何修复

为了有效管理服务器资源并确保所有用户都可以访问,主机提供商一般都会对主机的请求发送速度上做限制,一旦用户在规定时间内向服务器发送的请求超过了允许的限额,就可能会出现429错误。 例如,一个API允许每个用户每小时发送100个请…

无人机不等同轴旋翼架构设计应用探究

“结果显示,对于不等组合,用户应将较小的螺旋桨置于上游以提高能效,但若追求最大推力,则两个相等的螺旋桨更为理想。” 在近期的研究《不等同轴旋翼性能特性探究》中,Max Miles和Stephen D. Prior博士深入探讨了不同螺…

节目选择器安卓软件编写(针对老年人)

文章目录 需求来源软件界面演示效果源码获取 对爬虫、逆向感兴趣的同学可以查看文章,一对一小班教学:https://blog.csdn.net/weixin_35770067/article/details/142514698 需求来源 由于现在的视频软件过于复杂,某客户想开发一个针对老年人、…

Vue的简单入门 一

声明:本版块根据B站学习,创建的是vue3项目,用的是vue2语法风格,仅供初学者学习。 目录 一、Vue项目的创建 1.已安装15.0或更高版本的Node.js 2.创建项目 二、 简单认识目录结构 三、模块语法中的指令 1.v-html 1.文本插值…