赞
踩
Actor-Critic
算法是一种基于策略梯度(Policy Gradient)
和价值函数(Value Function)
的强化学习方法,通常被用于解决连续动作空间和高维状态空间下的强化学习问题。该算法将一个Actor
网络和一个Critic
网络组合在一起,通过Actor
网络产生动作,并通过Critic
网络估计状态值函数或状态-动作值函数,最终通过策略梯度算法训练Actor
网络和Critic
网络。Actor-Critic
算法的优点是在处理大型状态空间时具有较高的效率和可扩展性。
Actor-Critic
算法中的Actor
网络用于学习策略,用于生成动作。Critic
网络则用于学习值函数,用于评估状态或状态动作对的价值。Actor
和Critic
网络之间的交互便是Actor-Critic
算法的核心机制。
Actor-Critic
算法中,我们有两个更新任务:Actor
网络的策略梯度更新和Critic
网络的值函数更新。
在Actor-Critic
算法中使用的策略梯度方法是REINFORCE
算法,该算法的公式如下:
∇ θ J ( θ ) = E t [ ∇ θ l o g π ( a t ∣ s t ) ( Q π ( s t , a t ) − b t ) ] ∇_θ J(θ)=E_t[∇_θ logπ(a_t∣s_t)(Q^π (s_t ,a_t )−b_t )] ∇θJ(θ)=Et[∇θlogπ(at∣st)(Qπ(st,at)−bt)]
其中 J ( θ ) J(\theta) J(θ)表示目标策略的性能, ∇ θ J ( θ ) ∇_θ J ( θ ) ∇θJ(θ)表示策略梯度, π ( a t ∣ s t ) π ( a_t ∣ s_t ) π(at∣st)表示在状态 s t s_t st 下选择动作 a t a_t at 的概率。
虽然REINFORCE
算法在Actor-Critic
算法中被广泛使用,但它存在两个问题***:高方差和计算效率低***。
为了解决这两个问题,我们可以引入一个基准函数
B
(
s
t
)
B ( s_t )
B(st),并将奖励
Q
π
(
s
t
,
a
t
)
−
B
(
s
t
)
Q^π ( s_t , a_t ) − B ( s_t )
Qπ(st,at)−B(st)作为更新中的优势函数
A
π
(
s
t
,
a
t
)
A^π ( s_t , a_t )
Aπ(st,at) ,公式变为:
∇ θ J ( θ ) = E t [ ∇ θ l o g π ( a t ∣ s t ) A π ( s t , a t ) ] ∇_θJ(θ)=E_t [∇_θ logπ(a_t ∣s_t )A^π (s_t ,a_t)] ∇θJ(θ)=Et[∇θlogπ(at∣st)Aπ(st,at)]
其中, A π ( s t , a t ) = Q π ( s t , a t ) − B ( s t ) A^π ( s_t , a_t ) = Q^π ( s_t , a_t ) − B ( s_t ) Aπ(st,at)=Qπ(st,at)−B(st)表示相对于基准函数的优势函数。
参数化的值函数可以通过状态价值函数V(s)
或动作价值函数Q(s,a)
来表示,取决于我们需要估计的是状态价值函数还是状态-动作价值函数。对于Critic
网络的值函数更新,我们可以使用TD误差
来计算当前状态值和下一时刻状态值之间的误差:
δ = r + γ V ( s ′ ) − V ( s ) δ=r+γV(s^′)−V(s) δ=r+γV(s′)−V(s)
其中r
是当前时刻的奖励,γ
是折扣因子,
V
(
s
′
)
V ( s^′ )
V(s′)是下一时刻的状态值,
V
(
s
)
V (s)
V(s)是当前时刻的状态值。
我们可以使用每个状态s
的TD(Temporal Difference)
误差
δ
δ
δ的平方来衡量当前值函数
V
(
s
)
V ( s )
V(s)的误差,并用该误差更新Critic
网络的参数。
整体算法流程如下:
伪代码如下:
算法代码如下:
import torch import torch.nn as nn import torch.nn.functional as F import numpy as np from torch.distributions import Categorical class Actor(nn.Module): ''' 演员Actor网络 ''' def __init__(self, action_dim, state_dim): super(Actor, self).__init__() self.fc1 = nn.Linear(state_dim, 300) self.fc2 = nn.Linear(300, action_dim) self.ln = nn.LayerNorm(300) def forward(self, s): if isinstance(s, np.ndarray): s = torch.FloatTensor(s) x = self.ln(F.relu(self.fc1(s))) out = F.softmax(self.fc2(x), dim=-1) return out class Critic(nn.Module): ''' 评论家Critic网络 ''' def __init__(self, state_dim): super(Critic, self).__init__() self.fc1 = nn.Linear(state_dim, 300) self.fc2 = nn.Linear(300, 1) self.ln = nn.LayerNorm(300) def forward(self, s): if isinstance(s, np.ndarray): s = torch.FloatTensor(s) x = self.ln(F.relu(self.fc1(s))) out = self.fc2(x) return out class Actor_Critic: def __init__(self, env): self.gamma = 0.99 self.lr_a = 3e-4 self.lr_c = 5e-4 self.env = env self.action_dim = self.env.action_space.n #获取描述行动的数据维度 self.state_dim = self.env.observation_space.shape[0] #获取描述环境的数据维度 self.actor = Actor(self.action_dim, self.state_dim) #创建演员网络 self.critic = Critic(self.state_dim) #创建评论家网络 self.actor_optim = torch.optim.Adam(self.actor.parameters(), lr=self.lr_a) self.critic_optim = torch.optim.Adam(self.critic.parameters(), lr=self.lr_c) self.loss = nn.MSELoss() def get_action(self, s): a = self.actor(s) dist = Categorical(a) action = dist.sample() #可采取的action log_prob = dist.log_prob(action) #每种action的概率 return action.detach().numpy(), log_prob def learn(self, log_prob, s, s_, rew): #使用Critic网络估计状态值 v = self.critic(s) v_ = self.critic(s_) critic_loss = self.loss(self.gamma * v_ + rew, v) self.critic_optim.zero_grad() critic_loss.backward() self.critic_optim.step() td = self.gamma * v_ + rew - v #计算TD误差 loss_actor = -log_prob * td.detach() self.actor_optim.zero_grad() loss_actor.backward() self.actor_optim.step()
我们将以OpenAI Gym
中的CartPole
(倒立摆)游戏为应用场景,基于pytorch
实现一个基础的Actor-Critic
算法,让算法去玩这个游戏。
程序共分为两个文件:
train.py
文件:主要负责调用算法实现整体功能model.py
文件:主要实现一个完整的Actor-Critic
算法(上面的代码)train.py
代码如下:
import gym from model import Actor_Critic import matplotlib.pyplot as plt if __name__ == "__main__": env = gym.make('CartPole-v0') model = Actor_Critic(env) #实例化Actor_Critic算法类 reward = [] for episode in range(200): s = env.reset() #获取环境状态 env.render() #界面可视化 done = False #记录当前回合游戏是否结束 ep_r = 0 while not done: # 通过Actor_Critic算法对当前环境做出行动 a,log_prob = model.get_action(s) # 获得在做出a行动后的最新环境 s_,rew,done,_ = env.step(a) #计算当前reward ep_r += rew #训练模型 model.learn(log_prob,s,s_,rew) #更新环境 s = s_ reward.append(ep_r) print(f"episode:{episode} ep_r:{ep_r}") plt.plot(reward) plt.show()
训练效果如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。