强化学习讲座:策略梯度与深度 Q 网络(DQN)
开场白
大家好!欢迎来到今天的强化学习讲座。今天我们要聊聊两个非常重要的概念:策略梯度 和 深度 Q 网络(DQN)。这两个方法在强化学习领域中都有着举足轻重的地位,帮助我们训练智能体(agents)在各种环境中做出最优决策。😊
如果你之前已经接触过强化学习,可能会对这些名词有些熟悉。但如果你是新手,也不用担心,我会尽量用通俗易懂的语言来解释这些概念,并且会穿插一些代码示例,帮助你更好地理解。
1. 强化学习的基本概念
在进入正题之前,我们先快速回顾一下强化学习的基本概念。强化学习是一种通过与环境交互来学习如何做出决策的机器学习方法。智能体通过执行动作(actions),观察环境的状态(states),并根据环境的反馈(rewards)来调整自己的行为,以最大化长期累积的奖励。
三大要素:
- 状态(State):智能体当前所处的环境信息。
- 动作(Action):智能体可以采取的行为。
- 奖励(Reward):环境对智能体行为的反馈,通常是数值形式。
目标:
智能体的目标是学会一个策略(Policy),即在给定状态下选择动作的方式,使得长期累积的奖励最大化。
2. 策略梯度(Policy Gradient)
什么是策略梯度?
策略梯度是一种直接优化策略的方法。它不依赖于值函数(如 Q 值),而是直接学习一个从状态到动作的概率分布。换句话说,策略梯度试图找到一个最优的策略函数 ( pi(a|s) ),表示在状态 ( s ) 下选择动作 ( a ) 的概率。
为什么需要策略梯度?
有时候,我们并不想通过间接的方式来学习策略,比如通过 Q 值来推导出最优动作。策略梯度提供了一种更直接的方式,允许我们直接优化策略本身。这种方式特别适合那些动作空间连续的任务,比如机器人控制或自动驾驶。
策略梯度的核心公式
策略梯度的核心思想是通过梯度上升来更新策略参数 ( theta )。具体来说,我们希望最大化期望回报 ( J(theta) ),即:
[
J(theta) = mathbb{E}{tau sim pitheta} [R(tau)]
]
其中,( tau ) 是一个完整的轨迹(episode),( R(tau) ) 是该轨迹的总奖励。为了优化 ( J(theta) ),我们可以使用以下梯度公式:
[
nablatheta J(theta) = mathbb{E}{tau sim pitheta} left[ sum{t=0}^T nablatheta log pitheta(a_t | s_t) R(tau) right]
]
这个公式告诉我们,我们可以通过采样多个轨迹,并计算每个动作的梯度来更新策略参数。简单来说,就是“做得好的动作,增加其概率;做得不好的动作,减少其概率”。
简单的策略梯度实现
让我们来看一个简单的策略梯度实现。假设我们有一个二元动作空间(例如左/右),并且我们使用一个简单的神经网络来表示策略。
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
# 定义策略网络
class PolicyNet(nn.Module):
def __init__(self, state_dim, action_dim):
super(PolicyNet, self).__init__()
self.fc = nn.Linear(state_dim, action_dim)
def forward(self, state):
return torch.softmax(self.fc(state), dim=-1)
# 初始化网络和优化器
state_dim = 4 # 状态维度
action_dim = 2 # 动作维度
policy_net = PolicyNet(state_dim, action_dim)
optimizer = optim.Adam(policy_net.parameters(), lr=0.01)
# 训练循环
def train_policy_gradient(episodes, env):
for episode in range(episodes):
states, actions, rewards = [], [], []
state = env.reset()
while True:
# 根据当前策略选择动作
action_probs = policy_net(torch.tensor(state, dtype=torch.float32))
action = np.random.choice(action_dim, p=action_probs.detach().numpy())
# 执行动作并记录结果
next_state, reward, done, _ = env.step(action)
states.append(state)
actions.append(action)
rewards.append(reward)
if done:
break
state = next_state
# 计算累积奖励
G = 0
returns = []
for r in reversed(rewards):
G = r + 0.99 * G # 折扣因子为 0.99
returns.insert(0, G)
# 更新策略
optimizer.zero_grad()
for i in range(len(states)):
action_prob = policy_net(torch.tensor(states[i], dtype=torch.float32))[actions[i]]
loss = -torch.log(action_prob) * returns[i]
loss.backward()
optimizer.step()
print(f"Episode {episode + 1}, Total Reward: {sum(rewards)}")
# 运行训练
train_policy_gradient(100, env)
这段代码展示了如何使用策略梯度来训练一个简单的智能体。我们通过采样轨迹、计算累积奖励,并使用反向传播来更新策略网络的参数。
3. 深度 Q 网络(DQN)
什么是 DQN?
深度 Q 网络(Deep Q-Network, DQN)是强化学习中的一种经典算法,由 DeepMind 在 2013 年提出。DQN 结合了 Q 学习和深度学习的思想,使用神经网络来近似 Q 函数(Q-value function)。Q 函数表示在给定状态下采取某个动作的预期未来奖励。
DQN 的核心思想
DQN 的目标是学习一个 Q 函数 ( Q(s, a) ),它能够预测在状态 ( s ) 下采取动作 ( a ) 后的预期累积奖励。为了实现这一点,DQN 使用了一个神经网络来近似 Q 函数,并通过最小化以下损失函数来更新网络参数:
[
L(theta) = mathbb{E}{(s, a, r, s’) sim D} left[ (r + gamma max{a’} Q(s’, a’; theta^-) – Q(s, a; theta))^2 right]
]
其中,( theta ) 是当前网络的参数,( theta^- ) 是目标网络的参数(用于稳定训练),( gamma ) 是折扣因子,( D ) 是经验回放缓冲区(experience replay buffer)。
经验回放(Experience Replay)
DQN 中的一个重要技巧是经验回放。为了避免数据之间的相关性,DQN 将智能体与环境交互的经验存储在一个缓冲区中,并在训练时随机抽取一批样本进行更新。这有助于打破时间上的相关性,提高训练的稳定性。
固定 Q 目标(Fixed Q-Targets)
另一个重要的技巧是固定 Q 目标。为了避免 Q 值的快速波动,DQN 使用两个网络:一个是行为网络(behavior network),用于选择动作;另一个是目标网络(target network),用于计算 Q 值的目标。目标网络的参数每隔一段时间才会更新一次,从而保持稳定。
简单的 DQN 实现
接下来,我们来看一个简单的 DQN 实现。假设我们正在玩一个经典的 Atari 游戏,比如 Breakout。
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import random
from collections import deque
# 定义 Q 网络
class DQN(nn.Module):
def __init__(self, state_dim, action_dim):
super(DQN, self).__init__()
self.fc = nn.Sequential(
nn.Linear(state_dim, 128),
nn.ReLU(),
nn.Linear(128, 128),
nn.ReLU(),
nn.Linear(128, action_dim)
)
def forward(self, state):
return self.fc(state)
# 初始化网络和优化器
state_dim = 4 # 状态维度
action_dim = 2 # 动作维度
q_network = DQN(state_dim, action_dim)
target_network = DQN(state_dim, action_dim)
target_network.load_state_dict(q_network.state_dict())
optimizer = optim.Adam(q_network.parameters(), lr=0.001)
# 经验回放缓冲区
replay_buffer = deque(maxlen=10000)
# 训练 DQN
def train_dqn(episodes, env, batch_size=64, gamma=0.99, epsilon=0.1):
for episode in range(episodes):
state = env.reset()
total_reward = 0
while True:
# 选择动作(epsilon-greedy)
if random.random() < epsilon:
action = env.action_space.sample()
else:
with torch.no_grad():
q_values = q_network(torch.tensor(state, dtype=torch.float32))
action = q_values.argmax().item()
# 执行动作并记录经验
next_state, reward, done, _ = env.step(action)
replay_buffer.append((state, action, reward, next_state, done))
state = next_state
total_reward += reward
if done:
break
# 从经验回放缓冲区中采样一批数据
if len(replay_buffer) > batch_size:
batch = random.sample(replay_buffer, batch_size)
states, actions, rewards, next_states, dones = zip(*batch)
# 计算 Q 值的目标
with torch.no_grad():
next_q_values = target_network(torch.tensor(next_states, dtype=torch.float32))
max_next_q_values = next_q_values.max(dim=1)[0]
targets = torch.tensor(rewards, dtype=torch.float32) + gamma * max_next_q_values * (1 - torch.tensor(dones, dtype=torch.float32))
# 计算当前 Q 值
q_values = q_network(torch.tensor(states, dtype=torch.float32)).gather(1, torch.tensor(actions).unsqueeze(1)).squeeze()
# 更新 Q 网络
loss = nn.MSELoss()(q_values, targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 更新目标网络
if episode % 10 == 0:
target_network.load_state_dict(q_network.state_dict())
print(f"Episode {episode + 1}, Total Reward: {total_reward}")
# 运行训练
train_dqn(100, env)
这段代码展示了如何使用 DQN 来训练一个智能体。我们通过经验回放缓冲区存储经验,并在每次训练时从中采样一批数据进行更新。此外,我们还使用了固定 Q 目标来提高训练的稳定性。
4. 策略梯度 vs DQN
现在我们已经了解了策略梯度和 DQN 的基本原理,那么它们之间有什么区别呢?我们可以通过以下表格来对比两者的优缺点:
特性 | 策略梯度 | DQN |
---|---|---|
适用场景 | 动作空间连续或离散 | 动作空间离散 |
学习方式 | 直接优化策略 | 间接优化策略(通过 Q 值) |
收敛速度 | 较慢,容易陷入局部最优 | 较快,但可能不稳定 |
稳定性 | 稳定性较好 | 需要经验回放和固定 Q 目标来稳定 |
探索方式 | 自然探索(基于概率分布) | epsilon-greedy 探索 |
内存需求 | 较小,不需要存储经验 | 需要较大的经验回放缓冲区 |
应用场景 | 机器人控制、自动驾驶等连续任务 | 游戏、网格世界等离散任务 |
5. 总结
今天我们介绍了两种重要的强化学习方法:策略梯度和 DQN。策略梯度通过直接优化策略来学习最优行为,而 DQN 则通过近似 Q 函数来间接优化策略。两者各有优缺点,适用于不同的场景。
希望今天的讲座对你有所帮助!如果你有任何问题或想法,欢迎在评论区留言讨论。😊
参考文献
- Sutton, R. S., & Barto, A. G. (2018). Reinforcement Learning: An Introduction. MIT Press.
- Mnih, V., Kavukcuoglu, K., Silver, D., et al. (2015). Human-level control through deep reinforcement learning. Nature, 518(7540), 529-533.
感谢大家的聆听!下次见!👋