一、Policy Gradients 是什么?
1.1 算法定义
Policy Gradient Softmax是一种基于策略的强化学习算法,使用参数化的策略函数 πθ(a∣s)\pi_\theta(a|s)πθ(a∣s)(通常建模为Softmax分布),通过梯度上升直接优化策略参数 θ\thetaθ。其核心创新点在于:
- 策略参数化:用神经网络表示策略 πθ(a∣s)=exp(zθ(s,a))∑a′exp(zθ(s,a′))\pi_\theta(a|s) = \frac{\exp(z_\theta(s,a))}{\sum_{a'}\exp(z_\theta(s,a'))}πθ(a∣s)=∑a′exp(zθ(s,a′))exp(zθ(s,a)),其中 zθ(s,a)z_\theta(s,a)zθ(s,a) 是动作偏好函数。
- 梯度上升优化:通过计算策略梯度 ∇θJ(θ)≈Eπ[∇θlogπθ(a∣s)⋅Rt]\nabla_\theta J(\theta) \approx \mathbb{E}_\pi\left[\nabla_\theta \log\pi_\theta(a|s) \cdot R_t\right]∇θJ(θ)≈Eπ[∇θlogπθ(a∣s)⋅Rt],直接最大化累积奖励 J(θ)=Eτ∼πθ[R(τ)]J(\theta) = \mathbb{E}_{\tau\sim\pi_\theta}[R(\tau)]J(θ)=Eτ∼πθ[R(τ)]。
公式 1:目标函数
- J(θ)=Eτ∼πθ[R(τ)]J(\theta) = \mathbb{E}_{\tau \sim \pi_{\theta}}[R(\tau)]J(θ)=Eτ∼πθ[R(τ)]
符号 | 含义 |
---|---|
J(θJ(\thetaJ(θ) | 目标函数:策略 ( \pi_{\theta} ) 的期望累积奖励(需最大化) |
θ\thetaθ | 策略参数:神经网络的权重 |
τ\tauτ | 轨迹(Trajectory):一个完整的状态-动作序列 (s0,a0,s1,a1,…,sT)(s_0,a_0,s_1,a_1,\dots,s_T)(s0,a0,s1,a1,…,sT) |
R(τ)R(\tau)R(τ) | 累积奖励:轨迹 ( \tau ) 的总奖励(通常为折扣奖励和 ∑t=0Tγtrt\sum_{t=0}^T \gamma^t r_t∑t=0Tγtrt) |
Eτ∼πθ\mathbb{E}_{\tau \sim \pi_{\theta}}Eτ∼πθ | 期望:在策略 πθ\pi_{\theta}πθ下所有可能轨迹的期望值 |
公式 2:策略梯度
- ∇θJ(θ)≈Eπ[∇θlogπθ(a∣s)⋅Rt]\nabla_{\theta} J(\theta) \approx \mathbb{E}_{\pi} [\nabla_{\theta} \log \pi_{\theta}(a|s) \cdot R_t]∇θJ(θ)≈Eπ[∇θlogπθ(a∣s)⋅Rt]
符号 | 含义 |
---|---|
∇θJ(θ)\nabla_{\theta} J(\theta)∇θJ(θ) | 目标函数的梯度:参数空间中最速上升方向 |
∇θlogπθ(a∣s)\nabla_{\theta} \log \pi_{\theta}(a|s)∇θlogπθ(a∣s) | Score Function:策略对数概率关于参数 ( \theta ) 的梯度 |
RtR_tRt | 累积奖励:从时刻 ttt 开始的未来累积奖励(Rt=∑k=tTγk−trkR_t = \sum_{k=t}^T \gamma^{k-t} r_kRt=∑k=tTγk−trk) |
Eπ\mathbb{E}_{\pi}Eπ | 期望:在策略 πθ\pi_{\theta}πθ下状态-动作对的期望 |
1.2 核心概念
- 不同于传统方法:不学习价值函数(如Q值),直接学习策略(动作选择规则)
- 神经网络输出:动作的概率分布(而非动作价值)
动作概率 = π(a|s; θ) # θ是神经网络参数
1.3 与基于值的方法对比
特性 | 基于值的方法(如DQN) | Policy Gradients |
---|---|---|
输出 | 动作价值(Q值) | 动作概率 |
动作选择 | 选择最高Q值的动作 | 按概率分布采样动作 |
动作空间 | 适合离散动作 | 适合连续动作(如转向角度) |
策略类型 | 确定性策略 | 随机性策略(更灵活) |
二、核心思想:奖励驱动的学习🎯
2.1 基本机制
2.2 直观理解
- 好动作:获得正奖励 → 增加选择概率(下次更可能选)
- 坏动作:获得负奖励 → 减少选择概率(下次更少选)
就像训练宠物:做对给零食(强化行为),做错说"No"(弱化行为)
三、算法实现:
3.1 算法流程(伪代码)
初始化神经网络参数 θ
for 每个回合 do
收集轨迹 {s₁,a₁,r₂,s₂,a₂,...,r_T}
for 每个时间步 t do
计算累积奖励 Gₜ = Σ γᵏ⁻ᵗ rₖ (k从t到T)
更新参数:θ ← θ + α ∇θ logπ(aₜ|sₜ) Gₜ
end
end
3.2 关键组件
- logπ(aₜ|sₜ):动作概率的对数(“惊讶度”)
- 概率小 → 对数大(更惊讶)
- 概率大 → 对数小(不惊讶)
- Gₜ:累积折扣奖励
- α:学习率
3.3 算法步骤
-
初始化:
- 策略网络 πθ(a∣s)\pi_\theta(a|s)πθ(a∣s)(通常为Softmax输出层);
- 优化器(如Adam);
- 设置参数:学习率 α\alphaα,折扣因子 γ\gammaγ。
-
对于每个episode:
- 初始化状态 s1s_1s1,轨迹 τ={}\tau = \{\}τ={};
- 对于每个时间步 ttt:
- 根据当前策略 πθ(a∣st)\pi_\theta(a|s_t)πθ(a∣st) 采样动作 ata_tat;
- 执行动作 ata_tat,获得奖励 rtr_trt 和下一状态 st+1s_{t+1}st+1;
- 将 (st,at,rt)(s_t,a_t,r_t)(st,at,rt) 添加到轨迹 τ\tauτ 中;
- 计算累积回报:
对于每个时间步 ttt,计算从 ttt 开始的累积折扣回报 Rt=∑k=tTγk−trkR_t = \sum_{k=t}^T \gamma^{k-t} r_kRt=∑k=tTγk−trk; - 计算损失并更新策略:
损失函数:L(θ)=−1T∑t=0Tlogπθ(at∣st)⋅Rt\mathcal{L}(\theta) = -\frac{1}{T}\sum_{t=0}^T \log\pi_\theta(a_t|s_t) \cdot R_tL(θ)=−T1∑t=0Tlogπθ(at∣st)⋅Rt;
通过梯度上升更新参数:θ←θ+α∇θL(θ)\theta \leftarrow \theta + \alpha \nabla_\theta \mathcal{L}(\theta)θ←θ+α∇θL(θ)。
四、神经网络架构🧠
4.1 网络结构
4.2 TensorFlow 实现
class PolicyGradient:
def __init__(self, n_actions, n_features, learning_rate=0.01, reward_decay=0.95):
self.n_actions = n_actions
self.n_features = n_features
self.lr = learning_rate
self.gamma = reward_decay
# 存储回合数据
self.ep_obs = [] # 状态
self.ep_as = [] # 动作
self.ep_rs = [] # 奖励
self._build_net()
self.sess = tf.Session()
self.sess.run(tf.global_variables_initializer())
def _build_net(self):
# 输入层
self.tf_obs = tf.placeholder(tf.float32, [None, self.n_features])
self.tf_acts = tf.placeholder(tf.int32, [None])
self.tf_vt = tf.placeholder(tf.float32, [None]) # 折扣奖励
# 隐藏层
layer = tf.layers.dense(
inputs=self.tf_obs,
units=10,
activation=tf.nn.tanh
)
# 输出层
all_act = tf.layers.dense(
inputs=layer,
units=self.n_actions,
activation=None
)
# 动作概率
self.all_act_prob = tf.nn.softmax(all_act)
# 损失函数:-log(prob)*vt
neg_log_prob = tf.reduce_sum(
-tf.log(self.all_act_prob)*tf.one_hot(self.tf_acts, self.n_actions),
axis=1
)
loss = tf.reduce_mean(neg_log_prob * self.tf_vt)
# 优化器
self.train_op = tf.train.AdamOptimizer(self.lr).minimize(loss)
五、训练流程详解🔧
5.1 主训练循环
env = gym.make('CartPole-v0')
RL = PolicyGradient(n_actions=env.action_space.n,
n_features=env.observation_space.shape[0],
learning_rate=0.02,
reward_decay=0.99)
for i_episode in range(3000):
observation = env.reset()
while True:
# 1. 选择动作(基于概率)
action = RL.choose_action(observation)
# 2. 执行动作
observation_, reward, done, info = env.step(action)
# 3. 存储数据
RL.store_transition(observation, action, reward)
if done:
# 4. 计算折扣奖励
vt = RL.learn()
break
observation = observation_
5.2 关键方法实现
def choose_action(self, observation):
prob_weights = self.sess.run(
self.all_act_prob,
feed_dict={self.tf_obs: observation[np.newaxis, :]}
)
# 按概率选择动作
action = np.random.choice(range(prob_weights.shape[1]), p=prob_weights.ravel())
return action
def store_transition(self, s, a, r):
self.ep_obs.append(s)
self.ep_as.append(a)
self.ep_rs.append(r)
def learn(self):
# 计算折扣奖励
discounted_ep_rs = self._discount_and_norm_rewards()
# 训练网络
self.sess.run(self.train_op, feed_dict={
self.tf_obs: np.vstack(self.ep_obs),
self.tf_acts: np.array(self.ep_as),
self.tf_vt: discounted_ep_rs,
})
# 清空回合数据
self.ep_obs, self.ep_as, self.ep_rs = [], [], []
return discounted_ep_rs
六、损失函数深度解析📊
6.1 损失函数:
- loss=−log(π(a∣s))×Gloss = -log(π(a|s)) \times Gloss=−log(π(a∣s))×G
- −log(π(a∣s))-log(π(a|s))−log(π(a∣s)):动作概率的对数的负值
- 概率小 → 值大(“惊讶”)
- 概率大 → 值小(“不惊讶”)
- GGG:累积奖励
- 正奖励 → 增加动作概率
- 负奖励 → 减少动作概率
6.2 物理意义
场景 | 动作概率 | 奖励 | 更新效果 |
---|---|---|---|
好动作但概率低 | 小 → -log大 | +50 | 大幅提升概率 |
好动作概率高 | 大 → -log小 | +50 | 小幅提升概率 |
坏动作概率高 | 大 → -log小 | -100 | 大幅降低概率 |
坏动作概率低 | 小 → -log大 | -100 | 小幅降低概率 |
七、优缺点分析⚖️
7.1 核心优势
优势 | 说明 |
---|---|
连续动作空间 | 直接输出连续值(如转速0-100%) |
随机策略 | 天然支持概率性决策 |
简单高效 | 无需复杂价值函数估计 |
探索能力 | 内置随机性,无需ε-greedy |
7.2 主要挑战
挑战 | 解决方案 |
---|---|
高方差 | 使用基线(如Actor-Critic) |
样本效率低 | 结合经验回放(如PPO) |
回合制更新 | 使用TD误差进行单步更新 |
八、实际应用技巧💡
8.1 奖励处理技巧
def _discount_and_norm_rewards(self):
discounted_rs = np.zeros_like(self.ep_rs)
running_add = 0
# 反向计算折扣奖励
for t in reversed(range(len(self.ep_rs))):
running_add = running_add * self.gamma + self.ep_rs[t]
discounted_rs[t] = running_add
# 标准化奖励(重要!)
discounted_rs -= np.mean(discounted_rs)
discounted_rs /= np.std(discounted_rs)
return discounted_rs
8.2 超参数设置建议
params = {
'learning_rate': 0.01, # 通常比 DQN 大
'gamma': 0.99, # 折扣因子
'hidden_units': 20, # 隐藏层神经元数
'entropy_coef': 0.01, # 探索鼓励因子
}
九、扩展知识
9.1 算法演进
算法 | 创新点 | 优势 |
---|---|---|
REINFORCE | 基础PG算法 | 简单直观 |
Actor-Critic | 添加价值函数 | 降低方差 |
PPO | 限制策略更新幅度 | 稳定训练 |
TRPO | 理论保证的优化 | 可靠收敛 |
9.2 常见问题解答
Q:为什么用 −log(π)-log(π)−log(π) 而不是 −π-π−π?
A:−log(π)-log(π)−log(π) 在概率接近0时梯度大,能更快调整低概率动作,类似交叉熵损失。
Q:如何平衡探索与利用?
A:神经网络初始输出均匀概率,训练中自动调整,也可添加熵正则化项鼓励探索。
Q:是否支持在线更新?
A:基础REINFORCE需要完整回合,但Actor-Critic变种支持单步更新。
总结:Policy Gradients 让强化学习从"评价动作"转向"直接生成动作",特别适合连续控制问题。就像学习骑自行车 - 不是计算每个动作的价值,而是直接训练肌肉记忆!🚴♂️
好的,我们用简单易懂的方式向初学者介绍一下 Policy Gradient(策略梯度):
十、直观理解
想象一下你在训练一个玩游戏的智能体。它需要决定在屏幕上看到不同画面(状态)时,是选择“跳”、“射击”还是“向左跑”(动作)。最终目标是尽可能多地得分(获得奖励)。
- 传统方法(Value-Based): 很多早期方法(如 Q-Learning)是让 智能体 学习一个“价值表”或“价值函数”。这个函数告诉 智能体:“在某个状态下,选择某个动作,未来大概能得多少分”。智能体 学会这个表后,每次都选“未来得分最高”的那个动作。
- Policy Gradient 方法(策略梯度): 它走了一条更直接的路!它直接学习并优化一个策略本身。
- 策略是什么? 策略就是一个“决策指南”。它告诉 智能体:“在某个状态下,选择每个动作的概率分别是多少”。
- 优化什么? 它有一个包含参数的函数(比如神经网络),这个函数直接输出动作的概率分布(例如:跳:70%,射击:20%,左移:10%)。Policy Gradient 的目标就是调整这个函数的参数,使得智能体执行动作后获得的总奖励(回报)的期望值最大化。
🌐 怎么优化?
- 试错: 智能体用当前的策略玩一回合游戏。它会根据策略的概率分布随机选择动作。
- 记录: 记下它看到的状态、它选择的动作、以及它因为这个动作(和后续动作)得到的奖励。
- 评估好坏: 计算这回合游戏得到的总奖励(或者更精确地说,从选择动作那一刻起获得的“回报”)。
- 调整策略:
- 关键点: 如果一个动作(在某个状态下)带来了高回报,我们就提高策略在未来遇到类似状态时选择这个动作的概率。
- 如果一个动作带来了低回报(或惩罚),我们就降低策略选择它的概率。
- 数学工具(梯度): 这个“提高”或“降低”概率的过程,在数学上是通过计算一个“梯度”来实现的。这个梯度指明了“为了增加期望回报,策略参数应该朝哪个方向(增大还是减小)调整”。然后我们用类似爬山的“梯度上升”方法来更新策略参数。
🌐 为什么叫“梯度”?
因为它使用了微积分中的“梯度”概念。目标是最大化期望回报 J(θ)
(其中 θ
是策略函数的参数)。策略梯度定理告诉我们,这个目标的梯度 ∇J(θ)
可以通过智能体与环境交互的经验来估计。更新规则就是:θ = θ + α * ∇J(θ)
(α
是学习率)。