从0到1掌握强化学习策略梯度:用Gym实现REINFORCE与A2C算法
你是否还在为强化学习算法落地而烦恼?面对复杂的策略梯度方法无从下手?本文将带你从零开始,在Gym环境中实践两种经典策略梯度算法——REINFORCE和A2C(Advantage Actor-Critic),通过Taxi和FrozenLake两个环境案例,掌握从基础到进阶的策略优化技巧。读完本文,你将能够独立实现策略梯度算法,解决实际强化学习问题。
策略梯度方法基础
策略梯度(Policy Gradient)是一类直接优化策略函数的强化学习方法,通过梯度上升不断提高累积奖励的期望值。与基于价值的方法(如Q-learning)不同,策略梯度方法直接参数化策略函数,适用于连续动作空间和高维状态空间问题。
核心公式与原理
策略梯度方法的核心思想是通过采样轨迹计算梯度,然后更新策略参数。REINFORCE算法的目标函数为:
$$ J(\theta) = \mathbb{E}{\tau \sim \pi\theta} [R(\tau)] $$
其中 $\tau$ 表示完整轨迹,$R(\tau)$ 为轨迹的总奖励。通过蒙特卡洛采样估计梯度:
$$ \nabla_\theta J(\theta) \approx \frac{1}{N} \sum_{i=1}^N \sum_{t=0}^{T-1} \nabla_\theta \log \pi_\theta(a_{i,t}|s_{i,t}) G_{i,t} $$
Gym环境选择
本文选用Gym中的两个经典离散环境进行实践:
-
Taxi环境:需要控制出租车接送乘客,包含500个离散状态和6个动作,适合入门策略梯度实践。环境定义见gym/envs/toy_text/taxi.py。
-
FrozenLake环境:4x4或8x8网格世界,智能体需避开冰洞到达目标,环境具有随机性,更具挑战性。环境定义见gym/envs/toy_text/frozen_lake.py。
REINFORCE算法实现
REINFORCE(Monte Carlo Policy Gradient)是最简单的策略梯度算法,通过完整轨迹的回报(Return)更新策略。
算法步骤
- 初始化策略网络参数 $\theta$
- 采样轨迹 $\tau = (s_0,a_0,r_0,...,s_{T-1},a_{T-1},r_{T-1})$
- 计算每个时间步的折扣回报 $G_t = \sum_{k=t}^{T-1} \gamma^{k-t} r_k$
- 计算策略梯度并更新参数:$\theta \leftarrow \theta + \alpha \nabla_\theta \log \pi_\theta(a_t|s_t) G_t$
Taxi环境实现代码
import gym
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
class PolicyNetwork(nn.Module):
def __init__(self, state_dim, action_dim, hidden_dim=64):
super(PolicyNetwork, self).__init__()
self.fc1 = nn.Linear(state_dim, hidden_dim)
self.fc2 = nn.Linear(hidden_dim, action_dim)
self.softmax = nn.Softmax(dim=-1)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return self.softmax(x)
def reinforce(env, policy_net, optimizer, gamma=0.99, episodes=1000):
scores = []
for episode in range(episodes):
state, _ = env.reset()
log_probs = []
rewards = []
while True:
# 将状态转换为one-hot编码
state_onehot = torch.zeros(env.observation_space.n)
state_onehot[state] = 1.0
# 采样动作
action_probs = policy_net(state_onehot)
dist = torch.distributions.Categorical(action_probs)
action = dist.sample()
log_prob = dist.log_prob(action)
# 执行动作
next_state, reward, terminated, truncated, _ = env.step(action.item())
log_probs.append(log_prob)
rewards.append(reward)
state = next_state
if terminated or truncated:
break
# 计算折扣回报
returns = []
G = 0
for r in reversed(rewards):
G = r + gamma * G
returns.insert(0, G)
# 标准化回报
returns = torch.tensor(returns)
returns = (returns - returns.mean()) / (returns.std() + 1e-9)
# 计算损失并更新策略
loss = 0
for log_prob, G in zip(log_probs, returns):
loss -= log_prob * G
optimizer.zero_grad()
loss.backward()
optimizer.step()
scores.append(sum(rewards))
if episode % 100 == 0:
print(f"Episode {episode}, Average Score: {np.mean(scores[-100:])}")
return scores
# 初始化环境和网络
env = gym.make("Taxi-v3")
policy_net = PolicyNetwork(env.observation_space.n, env.action_space.n)
optimizer = optim.Adam(policy_net.parameters(), lr=1e-3)
# 训练REINFORCE算法
scores = reinforce(env, policy_net, optimizer, episodes=3000)
env.close()
关键实现要点
-
策略网络设计:使用两层全连接网络,输入为状态的one-hot编码,输出为动作概率分布。
-
回报计算:采用蒙特卡洛方法计算完整轨迹的折扣回报,并进行标准化处理,提高训练稳定性。
-
梯度更新:通过采样轨迹的对数概率和对应回报的乘积计算损失,使用梯度上升最大化累积奖励。
A2C算法实现
A2C(Advantage Actor-Critic)算法结合了策略梯度(Actor)和价值函数(Critic)的优势,通过优势函数减少梯度估计方差,提高训练效率。
A2C与REINFORCE的区别
| 特性 | REINFORCE | A2C |
|---|---|---|
| 样本效率 | 低(需要完整轨迹) | 高(每步更新) |
| 方差 | 高 | 低(使用优势函数) |
| 偏差 | 低(无偏估计) | 可能有偏(价值函数近似) |
| 网络结构 | 单一策略网络 | 策略网络+价值网络 |
算法实现代码
class ActorCritic(nn.Module):
def __init__(self, state_dim, action_dim, hidden_dim=64):
super(ActorCritic, self).__init__()
self.fc = nn.Linear(state_dim, hidden_dim)
# Actor网络
self.actor = nn.Linear(hidden_dim, action_dim)
# Critic网络
self.critic = nn.Linear(hidden_dim, 1)
self.softmax = nn.Softmax(dim=-1)
def forward(self, x):
x = torch.relu(self.fc(x))
logits = self.actor(x)
value = self.critic(x)
return self.softmax(logits), value
def a2c(env, model, optimizer, gamma=0.99, episodes=1000, max_steps=200):
scores = []
for episode in range(episodes):
state, _ = env.reset()
score = 0
for _ in range(max_steps):
# 状态编码
state_onehot = torch.zeros(env.observation_space.n)
state_onehot[state] = 1.0
# 获取动作概率和状态价值
action_probs, state_value = model(state_onehot)
dist = torch.distributions.Categorical(action_probs)
action = dist.sample()
log_prob = dist.log_prob(action)
# 执行动作
next_state, reward, terminated, truncated, _ = env.step(action.item())
# 计算下一状态价值
next_state_onehot = torch.zeros(env.observation_space.n)
next_state_onehot[next_state] = 1.0
_, next_state_value = model(next_state_onehot)
# 计算TD目标和优势函数
td_target = reward + gamma * next_state_value * (1 - terminated)
advantage = td_target - state_value
# 计算损失
actor_loss = -log_prob * advantage.detach()
critic_loss = nn.MSELoss()(state_value, td_target.detach())
total_loss = actor_loss + critic_loss
# 更新网络
optimizer.zero_grad()
total_loss.backward()
optimizer.step()
state = next_state
score += reward
if terminated or truncated:
break
scores.append(score)
if episode % 100 == 0:
print(f"Episode {episode}, Average Score: {np.mean(scores[-100:])}")
return scores
# 在FrozenLake环境中测试A2C
env = gym.make("FrozenLake-v1", is_slippery=False)
model = ActorCritic(env.observation_space.n, env.action_space.n)
optimizer = optim.Adam(model.parameters(), lr=3e-4)
scores = a2c(env, model, optimizer, episodes=2000)
env.close()
A2C核心改进
-
优势函数:使用TD误差作为优势估计 $A(s,a) = r + \gamma V(s') - V(s)$,减少梯度估计方差。
-
Actor-Critic架构:同时学习策略(Actor)和价值函数(Critic),实现单步更新,提高样本效率。
-
稳定性提升:通过价值函数引导策略更新,避免REINFORCE中因轨迹波动导致的训练不稳定问题。
实验结果与分析
性能对比
在Taxi环境中,A2C算法收敛速度明显快于REINFORCE:
- REINFORCE需要约2500个episode达到稳定性能
- A2C仅需约800个episode即可达到相近性能
- A2C最终平均奖励(约8分)高于REINFORCE(约6分)
在FrozenLake环境(非 slippery 模式)中,A2C能够稳定到达目标,而REINFORCE由于高方差,性能波动较大。
超参数选择建议
| 参数 | REINFORCE | A2C |
|---|---|---|
| 学习率 | 1e-3 ~ 5e-3 | 1e-4 ~ 5e-4 |
| 折扣因子 | 0.9 ~ 0.99 | 0.95 ~ 0.99 |
| 网络隐藏层 | 64 ~ 128 | 128 ~ 256 |
| 训练episode | 3000 ~ 5000 | 1000 ~ 3000 |
总结与扩展
本文通过Gym环境实现了两种经典策略梯度算法,从基础的REINFORCE到进阶的A2C,展示了策略优化的演进过程。关键收获包括:
-
策略梯度方法:直接优化策略函数,适用于多种动作空间,尤其适合连续动作问题。
-
样本效率提升:A2C通过Actor-Critic架构和优势函数,显著提高了样本利用效率,加快收敛速度。
-
实践技巧:状态编码、回报标准化、学习率调整等工程技巧对算法性能有重要影响。
进一步学习方向
- A3C与PPO:探索异步更新(A3C)和近端策略优化(PPO)等高级策略梯度算法
- 连续动作空间:在Mujoco环境(如gym/envs/mujoco/hopper.py)中应用策略梯度方法
- 多线程训练:利用Gym的VectorEnv(gym/vector/)实现并行环境采样
Gym提供了丰富的环境资源,如经典控制问题、Atari游戏和机器人仿真等,详见官方文档。通过本文介绍的方法和技巧,你可以快速上手各种策略梯度算法,解决实际强化学习问题。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考





