当前位置: 首页 > news >正文

Actor-Critic算法实战:从QAC到A2C,用PyTorch一步步实现策略梯度与价值评估的结合

Actor-Critic算法实战:从QAC到A2C的PyTorch实现指南

在强化学习领域,Actor-Critic算法因其结合了策略梯度与价值评估的双重优势而备受关注。本文将带您从零开始,用PyTorch实现从基础的QAC到进阶的A2C算法,解决实际编码中的关键问题。

1. 环境搭建与核心概念

在开始编码前,我们需要明确几个核心组件。Actor负责生成动作策略,Critic则评估这些策略的价值。这种分工协作的模式,使得算法既能保持策略梯度方法的灵活性,又能利用价值评估的稳定性。

首先安装必要的库:

pip install torch gym numpy matplotlib

对于离散动作空间的环境(如CartPole),我们可以定义如下网络结构:

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, 64), nn.ReLU(), nn.Linear(64, 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, 64), nn.ReLU(), nn.Linear(64, 1) ) def forward(self, state): return self.fc(state)

提示:初始学习率设置为0.001通常是个不错的起点,但需要根据具体环境调整

2. QAC算法实现

QAC(Q Actor-Critic)是最基础的Actor-Critic算法,它直接使用动作价值函数Q作为Critic的评估标准。以下是训练循环的关键步骤:

  1. 数据收集:使用当前策略与环境交互
  2. 价值估计:Critic网络评估状态-动作对的价值
  3. 策略更新:根据Critic的评估调整Actor策略
def train_qac(env, actor, critic, episodes=1000): actor_optim = optim.Adam(actor.parameters(), lr=1e-3) critic_optim = optim.Adam(critic.parameters(), lr=1e-3) for episode in range(episodes): state = env.reset() done = False while not done: # 选择动作 prob = actor(torch.FloatTensor(state)) action = torch.multinomial(prob, 1).item() # 执行动作 next_state, reward, done, _ = env.step(action) # Critic更新 q_value = critic(torch.FloatTensor(state)) next_q = critic(torch.FloatTensor(next_state)) if not done else 0 target = reward + 0.99 * next_q critic_loss = nn.MSELoss()(q_value, torch.tensor([target])) critic_optim.zero_grad() critic_loss.backward() critic_optim.step() # Actor更新 advantage = target - q_value.detach() actor_loss = -torch.log(prob[action]) * advantage actor_optim.zero_grad() actor_loss.backward() actor_optim.step() state = next_state

常见问题调试表:

问题现象可能原因解决方案
回报不增长学习率过高逐步降低学习率
训练不稳定批次大小不足增加交互步数再更新
策略过早收敛探索不足增加熵正则项

3. A2C算法进阶实现

A2C(Advantage Actor-Critic)通过引入优势函数减少方差,通常能获得更稳定的训练效果。优势函数的核心公式为:

A(s,a) = Q(s,a) - V(s)

改进后的Critic网络现在评估状态价值V而非动作价值Q:

class A2CCritic(nn.Module): def __init__(self, state_dim): super(A2CCritic, self).__init__() self.fc = nn.Sequential( nn.Linear(state_dim, 64), nn.ReLU(), nn.Linear(64, 1) ) def forward(self, state): return self.fc(state)

训练循环中需要计算TD误差作为优势估计:

def train_a2c(env, actor, critic, episodes=1000): actor_optim = optim.Adam(actor.parameters(), lr=1e-4) critic_optim = optim.Adam(critic.parameters(), lr=1e-3) for episode in range(episodes): state = env.reset() done = False while not done: # 收集轨迹数据 states, actions, rewards = [], [], [] for _ in range(5): # 5步更新 prob = actor(torch.FloatTensor(state)) action = torch.multinomial(prob, 1).item() next_state, reward, done, _ = env.step(action) states.append(state) actions.append(action) rewards.append(reward) state = next_state if done: break # 计算回报和优势 returns = [] advantages = [] R = critic(torch.FloatTensor(state)).item() if not done else 0 for r in reversed(rewards): R = r + 0.99 * R returns.insert(0, R) values = critic(torch.FloatTensor(np.array(states))).squeeze() advantages = torch.FloatTensor(returns) - values.detach() # 更新Critic critic_loss = nn.MSELoss()(values, torch.FloatTensor(returns)) critic_optim.zero_grad() critic_loss.backward() critic_optim.step() # 更新Actor probs = actor(torch.FloatTensor(np.array(states))) selected_probs = probs.gather(1, torch.LongTensor(actions).unsqueeze(1)) actor_loss = (-torch.log(selected_probs) * advantages).mean() actor_optim.zero_grad() actor_loss.backward() actor_optim.step()

注意:A2C中n步回报的步数需要根据环境特性调整,对于延迟奖励的环境需要更大的步数

4. 连续动作空间处理

对于连续动作空间环境(如Pendulum),需要对Actor网络进行修改:

class ContinuousActor(nn.Module): def __init__(self, state_dim, action_dim): super(ContinuousActor, self).__init__() self.fc_mean = nn.Sequential( nn.Linear(state_dim, 64), nn.ReLU(), nn.Linear(64, action_dim), nn.Tanh() # 假设动作范围在[-1,1] ) self.fc_std = nn.Sequential( nn.Linear(state_dim, 64), nn.ReLU(), nn.Linear(64, action_dim), nn.Softplus() # 标准差必须为正 ) def forward(self, state): mean = self.fc_mean(state) std = self.fc_std(state) return torch.distributions.Normal(mean, std)

训练时需要从分布中采样动作:

def continuous_action_train(env, actor, critic, episodes=1000): # ...初始化优化器... for episode in range(episodes): state = env.reset() done = False while not done: dist = actor(torch.FloatTensor(state)) action = dist.sample() log_prob = dist.log_prob(action).sum() next_state, reward, done, _ = env.step(action.numpy()) # 计算优势 value = critic(torch.FloatTensor(state)) next_value = critic(torch.FloatTensor(next_state)) if not done else 0 advantage = reward + 0.99 * next_value - value.detach() # 更新Critic... # 更新Actor...

5. 实战技巧与性能优化

在实际项目中,我发现以下几个技巧能显著提升训练效果:

  1. 梯度裁剪:防止梯度爆炸

    torch.nn.utils.clip_grad_norm_(actor.parameters(), 0.5) torch.nn.utils.clip_grad_norm_(critic.parameters(), 0.5)
  2. 熵正则化:鼓励探索

    entropy = dist.entropy().mean() actor_loss = actor_loss - 0.01 * entropy # 系数可调
  3. 学习率衰减:后期稳定训练

    scheduler = optim.lr_scheduler.StepLR(actor_optim, step_size=100, gamma=0.9)
  4. 并行环境:加速数据收集

    from multiprocessing import Process, Pipe

调试过程中,记录这些指标有助于分析:

  • 每回合总回报
  • 平均优势值
  • 策略熵(反映探索程度)
  • 价值损失
  • 梯度幅值

在Pendulum环境中,经过3000回合训练后,使用A2C算法通常能达到-200以下的稳定回报。一个常见的误区是过早停止训练——即使回报看似稳定,网络参数可能仍在微调,过早停止会导致最终性能不佳。

http://www.jsqmd.com/news/722175/

相关文章:

  • APK-Installer:Windows上一站式安卓应用安装解决方案
  • 【VS Code Dev Containers 生产级优化指南】:20年专家亲授5大避坑法则,90%团队忽略的容器启动性能瓶颈
  • 英超第三十四轮
  • TVA在显示面板制造与检测中的实践与挑战(2)
  • 成都金点原子锁全场景技术适配与实测细节分享:龙泉,青羊,德阳成都c级锁,成都人脸识别锁,成都密码锁,排行一览! - 优质品牌商家
  • 量子计算云平台评测:AWS与Azure性能优化实战
  • 如何将影像组学与病理组学特征与透明细胞肾细胞癌的肿瘤异质性建立关联,并进一步解释其与术后复发预后及辅助治疗风险分层的机制联系
  • ARM PMU性能监控单元原理与实战应用
  • 数据驱动牵引整流单元接触器故障诊断【附代码】
  • PostgreSQL 索引失效?我用 pg_stat_statements + EXPLAIN 15 分钟定位了隐式类型转换
  • 从天气预报App到航空飞行:聊聊‘锋面’如何影响你的日常生活与出行决策
  • TVA在显示面板制造与检测中的实践与挑战(3)
  • 告别手动操作!用Python+华为云OBS打造自动化文件同步工具(附完整源码)
  • 如何用Win11Debloat一键清理Windows系统:让电脑运行如新的完整指南
  • TypeScript 5.2 升级引发 NestJS 构建失败的解决方案.txt
  • 9 款 AI 写论文哪个好?2026 深度实测:真文献 + 真图表 + 全流程,虎贲等考 AI 完胜通用工具
  • 告别手动开终端!用Python写ROS2 Launch文件,一键启动你的机器人项目
  • .NET SlSugar多线程下SlSugarClient 的线程安全陷阱
  • 【12.MyBatis源码剖析与架构实战】12.SqlSource解析源码剖析-MyBatis初始化流程
  • 港口海事孪生应用,看镜像视界标杆实践——实景孪生头部方案,助力智慧航运升级
  • AI 写代码越来越快,Web 测试为什么更需要一只“猴子”?
  • ARM架构HDFGWTR_EL2寄存器原理与虚拟化安全实践
  • 密封与防水结构设计|工程人必看干货
  • 如何用microeco包从零构建微生物生态网络:从数据清洗到网络可视化的完整指南
  • 实证论文卡壳在数据分析?虎贲等考 AI:真数据 + 全模型 + 自动解读,毕业论文一次通关
  • Vivado 2019.2里AXI总线地址位宽报错?别慌,手把手教你定位并修复这个‘必须大于12’的坑
  • 最低成本的个人品牌建设与影响力投资:软件测试从业者的专业指南
  • 从4G EPC到5G核心网:手把手拆解NFV如何成为运营商升级的“神助攻”
  • 抖音批量下载工具:5步实现无水印视频高效采集
  • MinIO Windows部署踩坑实录:从默认密码警告到9000/9090端口配置全解析