强化学习在人工智能领域中具有广泛的应用,它可以通过与环境互动来学习如何做出最佳决策。本文将介绍一种常用的强化学习算法:Actor-Critic并且附上基于pytorch实现的代码。
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网络的值函数更新。对于Actor网络的策略梯度更新,我们需要使用Glearning策略梯度定理根据当前的策略 计算更新梯度,以更新Actor网络的参数;而对于Critic网络的值函数更新,则需要先计算出每一次的Reward,然后使用TD误差计算当前状态值和下一时刻状态值之间的误差,进而更新Critic网络的参数。
在Actor-Critic算法中使用的策略梯度方法是REINFORCE算法,该算法的公式如下:
∇ θ J ( θ ) = E t [ ∇ θ l o g π ( a t ∣ s t ) ( Q π ( s t , a t ) − b t ) ] \nabla_\theta J(\theta) = E_t[\nabla_\theta log\pi(a_t|s_t)(Q^\pi(s_t,a_t) - b_t)] ∇θJ(θ)=Et[∇θlogπ(at∣st)(Qπ(st,at)−bt)]
其中, J ( θ ) J(\theta) J(θ)表示目标策略的性能, ∇ θ J ( θ ) \nabla_\theta J(\theta) ∇θJ(θ)表示策略梯度, π ( a t ∣ s t ) \pi(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^\pi(s_t,a_t) - B(s_t) Qπ(st,at)−B(st)作为更新中的优势函数 A π ( s t , a t ) A^\pi(s_t,a_t) Aπ(st,at),公式变为:
∇ θ J ( θ ) = E t [ ∇ θ l o g π ( a t ∣ s t ) A π ( s t , a t ) ] \nabla_\theta J(\theta) = E_t[\nabla_\theta log\pi(a_t|s_t)A^\pi(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^\pi(s_t,a_t)=Q^\pi(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 ) \delta = r + \gamma V(s') - V(s) δ=r+γV(s′)−V(s)
其中 r r r是当前时刻的奖励, γ \gamma γ是折扣因子, V ( s ′ ) V(s') V(s′)是下一时刻的状态值, V ( s ) V(s) V(s)是当前时刻的状态值。我们可以使用每个状态 s s s的TD(Temporal Difference)误差 δ \delta δ的平方来衡量当前值函数 V ( s ) V(s) V(s)的误差,并用该误差更新Critic网络的参数。
Actor-Critic算法中,Actor网络和Critic网络可以使用不同的神经网络架构(如前馈神经网络或卷积神经网络)来表示。Actor网络的输出通常是代表各个动作的概率分布,而Critic网络的输出则是代表状态值或状态-动作值的估计值。Actor网络和Critic网络的优化可以使用不同的优化器(如Adam优化器)和损失函数(如均方误差损失函数)来进行。
以下是Actor-Critic算法的主要步骤:
经过多轮的迭代,Actor和Critic网络的参数将会逐渐趋于最优状态,从而实现高效的连续动作和高维状态空间下的强化学习任务。
我们将以OpenAI Gym中的CartPole(倒立摆)游戏为应用场景,基于pytorch实现一个基础的Actor-Critic算法,让算法去玩这个游戏。
程序共分为两个文件:
下面是main.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()
model.py中的程序:
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()
Actor-Critic算法是一种基于策略梯度和值函数的强化学习算法,针对连续动作和高维状态空间等实际应用中较为复杂的强化学习问题,具有以下优缺点:
优点:
缺点:
以下是我对于Actor-Critic算法的使用心得:
总之,应用Actor-Critic算法需要考虑到具体的问题场景和实际需求,确定好应用场景、网络架构、策略目标和探索机制,并且对算法的表现进行监控和调试,才能更好地应用该算法。
总体来说,Actor-Critic算法是一种具有广泛适用性的强化学习算法,可以针对多种实际应用场景进行调整和改进。其中,Actor Critic 升级版: Deep Deterministic Policy Gradient、Asynchronous Advantage Actor-Critic (A3C)等都是比较优秀的Actor-Critic改进算法。在工程应用时可以有限考虑这些算法。