【强化学习】13 —— Actor-Critic 算法

2023-11-01 11:15

本文主要是介绍【强化学习】13 —— Actor-Critic 算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • REINFORCE 存在的问题
  • Actor-Critic
  • A2C: Advantageous Actor-Critic
  • 代码实践
    • 结果
  • 参考

REINFORCE 存在的问题

  • 基于片段式数据的任务
    • 通常情况下,任务需要有终止状态,REINFORCE才能直接计算累计折扣奖励
  • 低数据利用效率
    • 实际中,REINFORCE需要大量的训练数据
  • 高训练方差(最重要的缺陷
    • 从单个或多个片段中采样到的值函数具有很高的方差

Actor-Critic

在 REINFORCE 算法中,目标函数的梯度中有一项轨迹回报,用于指导策略的更新。REINFOCE 算法用蒙特卡洛方法来估计 Q ( s , a ) Q(s,a) Q(s,a),能不能考虑拟合一个值函数来指导策略进行学习呢?这正是 Actor-Critic 算法所做的。
在这里插入图片描述
评论家Critic Q Φ ( s , a ) Q_\Phi (s,a) QΦ(s,a):

  • 学会准确估计当前演员策略(actor policy)的动作价值。通过 Actor 与环境交互收集的数据学习一个价值函数,这个价值函数会用于判断在当前状态什么动作是好的,什么动作不是好的,进而帮助 Actor 进行策略更新。 Q Φ ( s , a ) ≃ r ( s , a ) + γ E s ′ ∼ p ( s ′ ∣ s , a ) , a ′ ∼ π θ ( a ′ ∣ s ′ ) [ Q Φ ( s ′ , a ′ ) ] Q_\Phi(s,a)\simeq r(s,a)+\gamma\mathbb{E}_{s^{\prime}\thicksim p(s^{\prime}|s,a),a^{\prime}\thicksim\pi_\theta(a^{\prime}|s^{\prime})}[Q_\Phi(s^{\prime},a^{\prime})] QΦ(s,a)r(s,a)+γEsp(ss,a),aπθ(as)[QΦ(s,a)]

演员Actor π θ ( s , a ) \pi_\theta(s,a) πθ(s,a):

  • 要做的是与环境交互,并在 Critic 价值函数的指导下用策略梯度学习一个更好的策略。 J ( θ ) = E s ∼ p , π θ [ π θ ( a ∣ s ) Q Φ ( s , a ) ] ∂ f ( θ ) ∂ θ = E π θ [ ∂ log ⁡ π θ ( a ∣ s ) ∂ θ Q Φ ( s , a ) ] \begin{aligned}J(\theta)&=\mathbb{E}_{s\sim p,\pi_\theta}[\pi_\theta(a|s)Q_\Phi(s,a)]\\\\\frac{\partial f(\theta)}{\partial\theta}&=\mathbb{E}_{\pi_\theta}\left[\frac{\partial\log\pi_\theta(a|s)}{\partial\theta}Q_\Phi(s,a)\right]\end{aligned} J(θ)θf(θ)=Esp,πθ[πθ(as)QΦ(s,a)]=Eπθ[θlogπθ(as)QΦ(s,a)]

A2C: Advantageous Actor-Critic

思想:通过减去一个基线函数来标准化评论家的打分

  • 更多信息指导:降低较差动作概率,提高较优动作概率
  • 进一步降低方差

优势函数(Advantage Function) A π ( s , a ) = Q π ( s , a ) − V π ( s ) A^\pi(s,a)=Q^\pi(s,a)-V^\pi(s) Aπ(s,a)=Qπ(s,a)Vπ(s)
在这里插入图片描述
若只采用动作值的方式,虽然也会选择A2,但是方差相对会更大,同时所有的动作都是出于上升的状态,只是上升程度的问题。而采用优势函数的方式,部分动作的优势函数值是负的,可以直接降低相应动作的概率,同时方差更小。

状态-动作值和状态值函数 Q π ( s , a ) = r ( s , a ) + γ E s ′ ∼ p ( s ′ ∣ s , a ) , a ′ ∼ π θ ( a ′ ∣ s ′ ) [ Q Φ ( s ′ , a ′ ) ] = r ( s , a ) + γ E s ′ ∼ p ( s ′ ∣ s , a ) [ V π ( s ′ ) ] \begin{aligned} Q^{\pi}(s,a)& =r(s,a)+\gamma\mathbb{E}_{s^{\prime}\sim p(s^{\prime}|s,a),a^{\prime}\sim\pi_\theta(a^{\prime}|s^{\prime})}\left[Q_\Phi(s^{\prime},a^{\prime})\right] \\ &=r(s,a)+\gamma\mathbb{E}_{s^{\prime}\sim p(s^{\prime}|s,a)}[V^{\pi}(s^{\prime})] \end{aligned} Qπ(s,a)=r(s,a)+γEsp(ss,a),aπθ(as)[QΦ(s,a)]=r(s,a)+γEsp(ss,a)[Vπ(s)]

因此我们只需要拟合状态值函数来拟合优势函数 A π ( s , a ) = Q π ( s , a ) − V π ( s ) = r ( s , a ) + γ E s ′ ∼ p ( s ′ ∣ s , a ) [ V π ( s ′ ) − V π ( s ) ] ≃ r ( s , a ) + γ ( V π ( s ′ ) − V π ( s ) ) \begin{aligned} A^{\pi}(s,a)& =Q^\pi(s,a)-V^\pi(s) \\ &=r(s,a)+\gamma\mathbb{E}_{s^{\prime}\sim p(s^{\prime}|s,a)}[V^{\pi}(s^{\prime})-V^{\pi}(s)] \\ &\simeq r(s,a)+\gamma(V^{\pi}(s^{\prime})-V^{\pi}(s)) \end{aligned} Aπ(s,a)=Qπ(s,a)Vπ(s)=r(s,a)+γEsp(ss,a)[Vπ(s)Vπ(s)]r(s,a)+γ(Vπ(s)Vπ(s))


在策略梯度中,可以把梯度写成下面这个更加一般的形式: 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}}:\textit{轨迹的总回报;} \\ &2.\sum_{t^{\prime}=t}^T\gamma^{t^{\prime}-t}r_{t^{\prime}}:\textit{动作}a_t\textit{之后的回报;} \\ &\begin{aligned}3.\sum_{t^{\prime}=t}^T\gamma^{t^{\prime}-t}r_{t^{\prime}}-b(s_t):\textit{基准线版本的改进};\end{aligned} \\ &4.Q^{\pi_\theta}(s_t,a_t):\textit{动作价值函数;} \\ &5.A^{\pi_\theta}(s_t,a_t):\textit{优势函数;} \\ &6.r_t+\gamma V^{\pi_\theta}(s_{t+1})-V^{\pi_\theta}(s_t):\textit{时序差分残差。} \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)引入基线函数 b ( s t ) b(s_t) b(st)(baseline function)来减小方差。此外,我们也可以采用 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)。

Actor 的更新采用策略梯度的原则,那 Critic 如何更新呢?我们将 Critic 价值网络表示为 V ω V_\omega Vω,参数为 ω \omega ω。于是,我们可以采取时序差分残差的学习方式,对于单个数据定义如下价值函数的损失函数: L ( ω ) = 1 2 ( r + γ V ω ( s t + 1 ) − V ω ( s t ) ) 2 \mathcal{L}(\omega)=\frac12(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 价值网络参数即可。

算法伪代码:

在这里插入图片描述

代码实践

import gymnasium as gym
import numpy as np
from tqdm import tqdm
import torch
import torch.nn.functional as F
import utilclass 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)# 输入是某个状态,输出则是状态的价值。
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)class ActorCritic:def __init__(self, state_dim, hidden_dim, action_dim, actor_lr, critic_lr, gamma,device, numOfEpisodes, env):self.actor = PolicyNet(state_dim, hidden_dim, action_dim).to(device)self.critic = ValueNet(state_dim, hidden_dim).to(device)self.critic_optimizer = torch.optim.Adam(self.critic.parameters(), lr=critic_lr)self.actor_optimizer = torch.optim.Adam(self.actor.parameters(), lr=actor_lr)self.gamma = gammaself.device = deviceself.env = envself.numOfEpisodes = numOfEpisodes# 根据动作概率分布随机采样def takeAction(self, state):state = torch.tensor(np.array([state]), dtype=torch.float).to(self.device)action_probs = self.actor(state)action_dist = torch.distributions.Categorical(action_probs)action = action_dist.sample()return action.item()def update(self, transition_dict):states = torch.tensor(np.array(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(np.array(transition_dict['next_states']), dtype=torch.float).to(self.device)terminateds = torch.tensor(transition_dict['terminateds'], dtype=torch.float).view(-1, 1).to(self.device)truncateds = torch.tensor(transition_dict['truncateds'], dtype=torch.float).view(-1, 1).to(self.device)# 时序差分目标td_target = rewards + self.gamma * self.critic(next_states) * (1 - terminateds + truncateds)# 时序差分误差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()def ACTrain(self):returnList = []for i in range(10):with tqdm(total=int(self.numOfEpisodes / 10), desc='Iteration %d' % i) as pbar:for episode in range(int(self.numOfEpisodes / 10)):# initialize statestate, info = self.env.reset()terminated = Falsetruncated = FalseepisodeReward = 0transition_dict = {'states': [],'actions': [],'next_states': [],'rewards': [],'terminateds': [],'truncateds': []}# Loop for each step of episode:while 1:action = self.takeAction(state)next_state, reward, terminated, truncated, info = self.env.step(action)transition_dict['states'].append(state)transition_dict['actions'].append(action)transition_dict['next_states'].append(next_state)transition_dict['rewards'].append(reward)transition_dict['terminateds'].append(terminated)transition_dict['truncateds'].append(truncated)state = next_stateepisodeReward += rewardif terminated or truncated:breakself.update(transition_dict)returnList.append(episodeReward)if (episode + 1) % 10 == 0:  # 每10条序列打印一下这10条序列的平均回报pbar.set_postfix({'episode':'%d' % (self.numOfEpisodes / 10 * i + episode + 1),'return':'%.3f' % np.mean(returnList[-10:])})pbar.update(1)return returnList

结果

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

参考

[1] 伯禹AI
[2] https://www.davidsilver.uk/teaching/
[3] 动手学强化学习
[4] Reinforcement Learning

这篇关于【强化学习】13 —— Actor-Critic 算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/322571

相关文章

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖