跳到主要内容强化学习:演员评论家 Actor-Critic 算法 | 极客日志PythonAI算法
强化学习:演员评论家 Actor-Critic 算法
Actor-Critic 算法结合策略梯度与值函数估计。Actor 负责动作选择,Critic 评估价值并降低方差。通过 TD 误差指导策略更新,解决高方差和收敛慢问题。包含数学推导、伪代码及 PyTorch 实战示例,适用于 CartPole 等环境训练。
协议工匠17 浏览 演员评论家 Actor-Critic 算法
Actor-Critic 算法理解
Actor-Critic 算法是一种强化学习中的方法,结合了'演员'(Actor)和'评论家'(Critic)两个部分。下面用一个生活中的比喻来说明它的原理:
1. 角色设定
想象你是一名学习爬山的机器人,而你的目标是找到山顶(获得最高的奖励)。在爬山过程中:
- Actor(行动者):它就像一个'冒险家',负责决定下一步往哪里走(比如往左一步还是往右一步)。但它并不总是很聪明,可能会选错方向。
- Critic(评论者):它就像一个'导师',站在一旁,评价冒险家的表现。它会告诉 Actor:'这一步走得好,接近山顶了'或者'走错了,离山顶更远了'。
2. 两者如何协作
Actor-Critic 算法的运作过程大致如下:
- **Actor(冒险家)**观察环境(如坡度、方向),根据它的'策略'(Policy)选择一个动作(比如往左走)。
- **Critic(导师)**会根据冒险家的动作和环境的反馈(如高度增加或减少),计算一个'价值'(Value),来表示这个动作的好坏。
- Actor 根据 Critic 的评价,调整自己的策略,使未来能更聪明地选择动作。
3. 学习的核心
- Actor 的目标:学习一个好的策略,尽可能选择能达到山顶的动作。
- Critic 的目标:准确地评估每一步的表现,帮助 Actor 改进。
通过这种合作方式,Actor 不断优化动作策略,而 Critic 不断提升评价的准确性。
4. 为什么叫 Actor-Critic?
这个名字直接反映了两者的分工:
- Actor 负责行动(选择动作)。
- Critic 负责评价(估算价值)。
两者的结合比单独使用 Actor 或 Critic 效果更好,因为它们互相弥补了对方的不足。
生活中例子:
就像你学习开车,你是 Actor,根据道路选择要踩油门还是刹车,而你的驾驶教练就是Critic,告诉你哪个动作更安全、更接近目标。
Actor-Critic 算法的背景与来源
Actor-Critic 算法是强化学习领域的一种重要方法,它结合了值函数估计和策略优化的优点。在理解其背景时,需要从强化学习的演化历史、策略梯度方法的局限性以及如何通过值函数辅助优化策略展开。
1. 强化学习的起源
强化学习的目标是使智能体通过与环境的交互,学会在不同状态下选择最优动作,从而最大化长期收益。主要研究方法可以分为以下几类:
- 值函数方法(如 Q 学习):估算每个状态或状态 - 动作对的价值,并依据最大价值选择动作;
- 策略方法:直接优化动作选择的概率分布(策略),通过采样环境反馈进行改进;
- 策略 - 值函数结合的方法:例如 Actor-Critic,综合两者的优点。
随着强化学习问题复杂度的增加,仅依赖值函数方法会面临高维状态空间下的维度灾难,而纯策略方法在优化过程中可能收敛速度较慢。因此,结合策略与值函数的 Actor-Critic 应运而生。
2. 策略梯度方法的局限性
策略梯度方法通过优化策略函数直接解决强化学习问题,核心思想是通过以下公式更新策略参数:
$$\nabla_\theta J(\theta) = \mathbb{E}{\pi\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \cdot A^\pi(s, a) \right]$$
其中 $A^\pi(s, a)$ 是优势函数,用于衡量动作的相对好坏。
局限性:
- 高方差:直接使用环境反馈(奖励)计算梯度会导致策略梯度的方差很高,影响优化效率;
- 低效率:由于奖励信号传递较慢,可能需要大量采样才能学到有效的策略。
为了解决这些问题,研究者引入了Critic,用于降低方差并加速策略优化。
3. Actor-Critic 的提出
3.1 概念来源
Actor-Critic 算法由策略梯度和值函数估计结合而成:
- Actor(行动者):策略网络,决定在每个状态下采取的动作;
- Critic(评论者):值函数网络,估算当前状态或状态 - 动作对的价值,用于指导 Actor 改进。
这一框架的核心思想是利用 Critic 降低策略梯度的方差,同时保留策略方法的灵活性。
3.2 数学依据
Critic 通过估算值函数 $V^\pi(s)$ 或 $Q^\pi(s, a)$ 来计算时间差分(TD)误差:
$$\delta_t = r_t + \gamma V^\pi(s_{t+1}) - V^\pi(s_t)$$
- Critic 最小化 TD 误差的平方,学习状态值函数;
- Actor 利用 TD 误差调整策略,使得策略向更优的方向发展。
这一机制使 Actor-Critic 算法既可以高效地采样环境反馈,又能够快速调整策略参数。
4. 历史发展与应用
4.1 最早提出
Actor-Critic 算法最早由 Sutton 等人提出(1980 年代),作为策略梯度方法的变体,用于解决高方差问题。
4.2 演化与扩展
- A3C(Asynchronous Advantage Actor-Critic):
- 提出时间:2016 年,由 DeepMind 引入。
- 关键点:通过多线程并行化显著提升学习效率。
- PPO(Proximal Policy Optimization):
- 提出时间:2017 年,由 OpenAI 提出。
- 关键点:限制策略更新的幅度,改进稳定性。
Actor-Critic 算法流程的推导
Actor-Critic 算法结合了策略梯度方法(Policy Gradient)和值函数估计,核心是通过 Actor(策略函数)选择动作,通过 Critic(值函数)评估这些动作,并相互协作改进。以下是基于数学公式推导的算法流程。
1. 强化学习的优化目标
$$J(\theta) = \mathbb{E}{\pi\theta} \left[ \sum_{t=0}^\infty \gamma^t r_t \right]$$
- $V^\pi(s)$:状态值函数
- $\gamma$:折扣因子,控制未来奖励的权重。
- $r_t$:时间 t 的即时奖励;
- $\pi_\theta(a|s)$:策略函数,表示在状态 s 下选择动作 a 的概率;
2. 策略梯度定理
为了优化策略函数 $\pi_\theta$,我们计算目标函数 $J(\theta)$ 对参数 $\theta$ 的梯度:
$$\nabla_\theta J(\theta) = \mathbb{E}{\pi\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \cdot A^\pi(s, a) \right]$$
- $A^\pi(s, a)$:优势函数,衡量动作 a 的相对优势。
- $\nabla_\theta \log \pi_\theta(a|s)$:策略的对数梯度,指示如何调整策略参数以提升选取当前动作的概率;
$$A^\pi(s, a) \approx r + \gamma V^\pi(s') - V^\pi(s)$$
- $s'$:动作 a 执行后的下一状态。
- $V^\pi(s)$:状态值函数,表示在状态 s 时累积奖励的期望;
3. Critic:值函数估计
Critic 的目标是通过最小化均方误差,学习状态值函数 $V^\pi(s)$:
$$L(w) = \frac{1}{2} \mathbb{E} \left[ \left( r + \gamma V^\pi(s') - V^\pi(s) \right)^2 \right]$$
参数 $w$ 是 Critic 网络的权重;
Critic 的梯度更新公式:
$$\nabla_w L(w) = \left( r + \gamma V^\pi(s') - V^\pi(s) \right) \nabla_w V^\pi(s)$$
4. Actor:策略优化
Actor 根据 Critic 的反馈来优化策略参数 $\theta$。更新公式为:
$$\theta \leftarrow \theta + \alpha \cdot \nabla_\theta \log \pi_\theta(a|s) \cdot \delta$$
- $\alpha$:学习率。
- $\delta = r + \gamma V^\pi(s') - V^\pi(s)$:时间差分(TD)误差,衡量当前状态值预测的偏差;
Actor 的更新方向由 Critic 计算的 TD 误差指导。
5. 完整算法流程
结合上述部分,Actor-Critic 的算法流程如下:
- 重复以下步骤直到收敛:
- 初始化 Actor 和 Critic 网络的参数 $\theta, w$;
- 在状态 s 下,Actor 根据 $\pi_\theta(a|s)$ 采样动作 a;
- 执行动作 a,获得奖励 r 和下一状态 s';
- Critic 计算 TD 误差:$\delta = r + \gamma V^\pi(s') - V^\pi(s)$;
- Actor 更新:$\theta \leftarrow \theta + \alpha \cdot \nabla_\theta \log \pi_\theta(a|s) \cdot \delta$;
- Critic 更新:$w \leftarrow w + \beta \cdot \delta \cdot \nabla_w V^\pi(s)$;
[Python] Actor-Critic 算法实现
算法伪代码
结合上述公式,以下是 Actor-Critic 的简化伪代码:
theta = 初始化 Actor 参数
w = 初始化 Critic 参数
for episode in range(最大迭代次数):
初始化环境
s = 初始状态
while not done:
a = 从π_theta(s)中采样动作
s_next, r, done = 环境.step(a)
V_s = Critic 网络预测值 (s, w)
V_s_next = Critic 网络预测值 (s_next, w)
delta = r + gamma * V_s_next - V_s
w = w + alpha_critic * delta * ∇_w V_s
theta = theta + alpha_actor * delta * ∇_theta log π_theta(a | s)
s = s_next
算法示例代码
以下是使用 PyTorch 实现的 Actor-Critic 算法的示例代码:
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
class Actor(nn.Module):
def __init__(self, state_dim, action_dim):
super(Actor, self).__init__()
self.fc = nn.Sequential(
nn.Linear(state_dim, 128),
nn.ReLU(),
nn.Linear(128, action_dim),
nn.Softmax(dim=-1)
)
def forward(self, state):
return self.fc(state)
class Critic(nn.Module):
def __init__(self, state_dim):
super(Critic, self).__init__()
self.fc = nn.Sequential(
nn.Linear(state_dim, 128),
nn.ReLU(),
nn.Linear(128, 1)
)
def forward(self, state):
return self.fc(state)
class ActorCritic:
def __init__(self, state_dim, action_dim, gamma=0.99, lr=1e-3):
self.actor = Actor(state_dim, action_dim)
self.critic = Critic(state_dim)
self.gamma = gamma
self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=lr)
self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=lr)
def select_action(self, state):
state = torch.tensor(state, dtype=torch.float32)
probs = self.actor(state)
action = torch.multinomial(probs, 1).item()
return action, probs[action]
def update(self, state, action_prob, reward, next_state, done):
state = torch.tensor(state, dtype=torch.float32)
next_state = torch.tensor(next_state, dtype=torch.float32)
reward = torch.tensor(reward, dtype=torch.float32)
done = torch.tensor(done, dtype=torch.float32)
value = self.critic(state)
next_value = self.critic(next_state)
target = reward + self.gamma * next_value * (1 - done)
td_error = target - value
critic_loss = td_error.pow(2)
self.critic_optimizer.zero_grad()
critic_loss.backward()
self.critic_optimizer.step()
actor_loss = -torch.log(action_prob) * td_error.detach()
self.actor_optimizer.zero_grad()
actor_loss.backward()
self.actor_optimizer.step()
Actor-Critic 算法实战代码
下面是基于 Python 和 PyTorch 的 Actor-Critic 算法的项目实代码:
"""《Actor-Critic 算法》"""
import torch
from torch import nn
from torch.nn import functional as F
import numpy as np
class PolicyNet(nn.Module):
def __init__(self, n_states, n_hiddens, n_actions):
super(PolicyNet, self).__init__()
self.fc1 = nn.Linear(n_states, n_hiddens)
self.fc2 = nn.Linear(n_hiddens, n_actions)
def forward(self, x):
x = self.fc1(x)
x = F.relu(x)
x = self.fc2(x)
x = F.softmax(x, dim=1)
return x
class ValueNet(nn.Module):
def __init__(self, n_states, n_hiddens):
super(ValueNet, self).__init__()
self.fc1 = nn.Linear(n_states, n_hiddens)
self.fc2 = nn.Linear(n_hiddens, 1)
def forward(self, x):
x = self.fc1(x)
x = F.relu(x)
x = self.fc2(x)
return x
Actor-Critic 算法
class ActorCritic:
def __init__(self, n_states, n_hiddens, n_actions, actor_lr, critic_lr, gamma):
self.gamma = gamma
self.actor = PolicyNet(n_states, n_hiddens, n_actions)
self.critic = ValueNet(n_states, n_hiddens)
self.actor_optimizer = torch.optim.Adam(self.actor.parameters(), lr=actor_lr)
self.critic_optimizer = torch.optim.Adam(self.critic.parameters(), lr=critic_lr)
def take_action(self, state):
state = torch.tensor(state[np.newaxis, :])
probs = self.actor(state)
action_dist = torch.distributions.Categorical(probs)
action = action_dist.sample().item()
return action
def update(self, transition_dict):
states = torch.tensor(transition_dict['states'], dtype=torch.float)
actions = torch.tensor(transition_dict['actions']).view(-1,1)
rewards = torch.tensor(transition_dict['rewards'], dtype=torch.float).view(-1,1)
next_states = torch.tensor(transition_dict['next_states'], dtype=torch.float)
dones = torch.tensor(transition_dict['dones'], dtype=torch.float).view(-1,1)
td_value = self.critic(states)
td_target = rewards + self.gamma * self.critic(next_states) * (1-dones)
td_delta = td_target - td_value
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()
算法测试代码
有一个简单的 CartPole 环境,以下是训练代码:
import numpy as np
import matplotlib.pyplot as plt
import gym
import torch
from Actor_Critic import ActorCritic
num_episodes = 100
gamma = 0.9
actor_lr = 1e-3
critic_lr = 1e-2
n_hiddens = 16
env_name = 'CartPole-v1'
return_list = []
env = gym.make(env_name, render_mode="human")
n_states = env.observation_space.shape[0]
n_actions = env.action_space.n
agent = ActorCritic(n_states=n_states,
n_hiddens=n_hiddens,
n_actions=n_actions,
actor_lr=actor_lr,
critic_lr=critic_lr,
gamma=gamma)
for i in range(num_episodes):
state = env.reset()[0]
done = False
episode_return = 0
transition_dict = {
'states': [],
'actions': [],
'next_states': [],
'rewards': [],
'dones': [],
}
while not done:
action = agent.take_action(state)
next_state, reward, done, _, _ = 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['dones'].append(done)
state = next_state
episode_return += reward
return_list.append(episode_return)
agent.update(transition_dict)
print(f'iter:{i}, return:{np.mean(return_list[-10:])}')
plt.plot(return_list)
plt.title('return')
plt.show()
[Notice] 关键点总结
- Critic 的稳定性:Critic 的误差直接影响 Actor 的梯度更新。
- 熵正则化:为了鼓励探索,可以对 Actor 的损失函数加入熵项。
- 多线程优化:使用 A3C(Asynchronous Advantage Actor-Critic)可以提升性能。
- PPO 改进:限制更新范围,解决策略更新过程中的不稳定性。
环境配置:Python 3.11.5, torch 2.1.0, torchvision 0.16.0, gym 0.26.2
总结
Actor-Critic 算法的提出源于策略梯度方法的高方差问题,通过结合值函数(Critic)降低优化方差,提高学习效率。随着强化学习的不断发展,Actor-Critic 及其扩展(如 A3C、PPO)成为复杂任务中广泛使用的算法。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- 随机西班牙地址生成器
随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online