深入理解TRPO与PPO:On-Policy强化学习算法原理与实现教程

作者:4042026.11.04 11:23浏览量:0

简介:本文面向强化学习开发者与研究者,系统讲解为什么TRPO和PPO被归类为On-Policy算法,并围绕置信域策略优化的核心思想、策略更新的数据依赖关系、算法实现要点与工程实践展开。读者将掌握On-Policy与Off-Policy的本质区别,理解TRPO的置信域约束如何保证训练稳定性,以及PPO如何通过裁剪目标函数简化约束优化过程,最终能够独立完成算法选型、伪代码实现与调参验证。

深入理解TRPO与PPO:On-Policy强化学习算法原理与实现教程

教程目标

本教程旨在帮助读者完成以下学习任务:

  1. 明确On-Policy与Off-Policy算法的本质区别,尤其是数据采样策略与目标更新策略之间的关系。
  2. 深入理解TRPO(Trust Region Policy Optimization,置信域策略优化)如何将数值优化中的置信域方法引入强化学习,以及为什么它天然属于On-Policy算法。
  3. 掌握PPO(Proximal Policy Optimization,近端策略优化)如何通过裁剪目标函数简化TRPO的约束优化过程,同时保留On-Policy采样的核心特征。
  4. 能够基于通用框架实现一个简化版PPO训练循环,并理解每一步操作背后的数学动机与工程考量。
  5. 学会验证训练结果、排查常见收敛问题,并根据实际场景选择合适的策略梯度方法。

阅读完本文后,读者应当能够从数据依赖的角度解释“为什么TRPO和PPO是On-Policy算法”,并在自己的强化学习项目中正确设计采样与更新流程。

适用场景

本文适合以下技术场景与读者群体:

  • 正在学习深度强化学习,希望理解策略梯度方法中On-Policy与Off-Policy分类依据的开发者;
  • 需要在连续控制、机器人操作、游戏AI等任务中选用稳定策略优化算法的研究人员;
  • 负责强化学习训练框架搭建与调优的工程师,尤其是关注训练稳定性与样本效率的团队;
  • 希望从数学原理和工程实现两个层面系统掌握TRPO与PPO的技术负责人。

前置准备

在开始学习之前,建议读者具备以下基础知识与环境准备:

1. 数学基础

  • 掌握概率论基础,尤其是条件概率、期望、重要性采样等概念;
  • 了解策略梯度定理,理解策略函数、状态价值函数、动作价值函数和优势函数的基本定义;
  • 对数值优化中的梯度上升、约束优化、拉格朗日乘子法和KKT条件有初步认识;
  • 了解KL散度(Kullback-Leibler Divergence)在衡量概率分布差异时的含义与计算方式。

2. 强化学习基础

  • 熟悉马尔可夫决策过程(MDP)的五元组表示:状态空间、动作空间、状态转移概率、奖励函数、折扣因子;
  • 理解策略梯度的基本更新公式,以及REINFORCE等基础算法的采样与更新流程;
  • 能够区分随机策略与确定性策略,了解策略网络输出动作分布而不是单一动作的原因。

3. 工程环境

  • 具备Python编程基础,了解面向对象编程与模块化设计;
  • 准备一个支持自动微分的数值计算框架(例如业界常用的深度学习框架);
  • 准备一个简单的连续控制仿真环境,如倒立摆、小车爬山等经典任务,用于验证算法实现;
  • 如有条件,准备一个支持向量化采样的环境包装器,以提高数据收集效率。

4. 数据与权限

  • 本教程为算法原理与实现教程,不涉及具体云服务账号权限;
  • 如需在集群上训练,建议准备支持CPU与GPU混合计算的运行环境;
  • 训练日志与模型检查点的存储可接入通用对象存储或本地文件系统,便于回溯与比较实验。

核心概念:什么是On-Policy与Off-Policy

在深入TRPO与PPO之前,必须先厘清强化学习中两个基本分类:On-Policy(同策略)与Off-Policy(异策略)。

策略与数据的关系

强化学习的目标是优化一个策略π(a|s),使得智能体在环境中获得的期望累计奖励最大。策略优化通常需要数据来估计梯度或更新目标。数据来自智能体与环境的交互,而交互时使用的是某个“行为策略”(behavior policy)。同时,我们正在优化的策略称为“目标策略”(target policy)。

  • 如果行为策略与目标策略是同一个策略,即用当前待优化的策略去采集数据,再用这些数据更新同一个策略,这种算法就是On-Policy的。
  • 如果行为策略与目标策略不同,例如用一个旧的策略或一个完全独立的行为策略采集数据,然后更新目标策略,这种算法就是Off-Policy的。

为什么这个区别重要

On-Policy算法在数据使用上有一个强约束:每一次策略更新之后,之前采集的数据在理论上就“过时”了,因为数据来自旧策略,而目标策略已经改变。严格来说,旧策略下采集的样本不能直接用于估计新策略的梯度,除非使用重要性采样进行修正。但重要性采样会引入高方差,尤其在策略差异较大时,修正效果会很差。

TRPO和PPO都采用了一种实用的做法:在策略更新时,显式或隐式地限制新旧策略之间的差异。只要差异足够小,就可以近似认为旧策略采集的数据仍然对当前策略有效,从而避免重要性采样带来的方差爆炸。这种做法本质上仍然要求数据来自当前策略或与之非常接近的策略,因此它们被归类为On-Policy算法。

与Off-Policy算法的对比

Off-Policy算法的典型代表包括Q-Learning和基于经验回放(Experience Replay)的深度Q网络及其变体。这些算法可以从历史数据中反复采样学习,数据利用率高,但通常需要处理行为策略与目标策略不一致带来的偏差修正问题。

On-Policy算法的数据利用率较低,因为每次更新后原则上需要丢弃旧数据并重新采集。但它们通常具有更好的训练稳定性,因为学习信号与当前策略的分布更加一致。TRPO和PPO在On-Policy框架下,通过置信域约束和裁剪机制进一步提升了稳定性。

TRPO的置信域思想与On-Policy属性

置信域方法回顾

置信域方法源自数值优化领域。考虑一个无约束最大化问题:

  1. max θ J(θ)

其中J(θ)是目标函数,θ是参数。在每次迭代中,我们不直接在整个参数空间上最大化J(θ),而是在当前参数θ_now附近的一个邻域内构造一个近似函数L(θ|θ_now),并在这个邻域内寻找使L最大的新参数θ_new。这个邻域称为置信域。

置信域的定义通常为:

  1. N(θ_now) = { θ | ||θ - θ_now||₂ ≤ Δ }

其中Δ是置信域半径。如果近似函数L在置信域内与目标函数J足够接近,那么在这个邻域内优化L就相当于近似优化J。

置信域方法的关键优势在于:它限制了每次更新的步长,避免因目标函数局部近似不准确而导致的剧烈震荡或性能崩溃。这与深度学习中常用的学习率衰减有相似动机,但更加系统化。

将置信域引入策略优化

TRPO将置信域思想从参数空间转移到策略空间。在策略优化中,目标函数通常是期望累计奖励:

  1. J(π_θ) = E_{τ~π_θ} [ Σ γ^t r(s_t, a_t) ]

其中τ表示轨迹,γ是折扣因子。直接对J进行梯度上升虽然可行,但步长选择非常敏感:步长过大容易导致策略发生灾难性退化,步长过小则训练效率低下。

TRPO的做法是:在每次更新时,构造一个代理目标函数(surrogate objective),并在一个基于KL散度的置信域内最大化该代理目标。具体而言,TRPO求解如下约束优化问题:

  1. max θ E_{s~ρ_old, a~π_old} [ π_θ(a|s) / π_old(a|s) * A_old(s, a) ]
  2. subject to E_{s~ρ_old} [ D_KL( π_old(·|s) || π_θ(·|s) ) ] ≤ δ

其中:

  • π_old是更新前的策略;
  • A_old是使用旧策略采集数据估计的优势函数;
  • ρ_old是旧策略访问的状态分布;
  • δ是置信域半径,通常是一个较小的常数(如0.01)。

为什么TRPO是On-Policy的

从上述约束优化问题的形式可以看出,TRPO的代理目标函数和约束条件都依赖旧策略π_old采集到的数据,包括状态分布ρ_old和优势函数A_old。也就是说,每一次更新使用的数据必须由当前策略(或者说更新前的那个策略)采集。

一旦策略完成更新,新的策略πθ不再等于π_old。如果继续使用π_old采集的旧数据来更新πθ,代理目标中的重要性采样比率π_θ/π_old会逐渐偏离1,KL散度约束也可能被违反,导致近似失效。因此,TRPO在每一次或每几步更新之后,都需要用更新后的策略重新采集数据。这种“采集—更新—再采集—再更新”的循环正是On-Policy算法的典型模式。

TRPO并没有引入经验回放机制来重复利用历史数据。这一方面是因为历史数据来自旧策略,与当前策略的分布不匹配;另一方面是因为重复利用旧数据需要更复杂的重要性采样修正,而TRPO的置信域约束本身就是为了避免这种修正。因此,TRPO的数据依赖关系决定了它必须是On-Policy的。

TRPO的求解流程

TRPO的具体求解通常包含以下步骤:

  1. 采样阶段:使用当前策略π_old与环境交互,采集一批完整的轨迹数据,包括状态、动作、奖励、下一状态和终止标志。
  2. 优势估计:基于采集到的数据,使用广义优势估计(Generalized Advantage Estimation,GAE)等方法计算每个时间步的优势函数A_t。
  3. 构建代理目标:计算代理目标函数关于策略参数θ的梯度。
  4. 求解约束优化:使用共轭梯度法和线性搜索求解带KL散度约束的最大化问题,得到新的策略参数θ_new。
  5. 更新策略:将θ_new赋值给当前策略,进入下一轮采样。

整个流程中,数据在策略更新后即被丢弃或标记为过期,不会跨轮次重复使用。这是On-Policy特性的直接体现。

PPO的On-Policy本质与实现简化

从约束优化到裁剪目标

TRPO虽然训练稳定,但每次更新需要计算Fisher信息矩阵与共轭梯度,实现复杂且计算开销较大。PPO提出了一种更简洁的替代方案:通过修改代理目标函数,将KL散度约束转化为目标函数中的裁剪项,从而将约束优化问题转化为无约束优化问题。

PPO的目标函数为:

  1. L_CLIP(θ) = E_t [ min( r_t(θ) * A_t, clip( r_t(θ), 1-ε, 1+ε ) * A_t ) ]

其中:

  • rt(θ) = πθ(a_t|s_t) / π_old(a_t|s_t) 是重要性采样比率;
  • ε是裁剪系数,通常为0.1或0.2;
  • A_t是优势函数的估计值。

这个目标函数的核心思想是:当优势为正时,鼓励策略增加该动作的概率,但一旦比率r_t超过1+ε,目标函数停止增长,防止策略更新幅度过大;当优势为负时,鼓励策略降低该动作的概率,但一旦比率r_t低于1-ε,目标函数同样停止增长。通过这种方式,PPO隐式地限制了新旧策略之间的差异,其效果与TRPO的KL散度约束类似。

为什么PPO仍然是On-Policy的

PPO的目标函数中,r_t(θ)的分母π_old(a_t|s_t)是更新前策略的概率。这意味着目标函数的计算依赖旧策略采集的数据。优势函数A_t同样需要使用旧策略与环境交互才能获得。

与TRPO一样,PPO在一次更新后,策略π_θ已经改变,如果继续使用旧数据计算r_t(θ),分母将不再对应实际采样策略,重要性采样比率会偏离有效范围,目标函数的近似偏差也会增大。因此,PPO在每次更新后(或经过若干次小批量梯度更新后),需要重新使用当前策略采集数据。

PPO允许在每一轮采集的数据上执行多轮小批量梯度更新(例如4到10个epoch),这在一定程度上提高了数据利用率,但本质上仍然要求数据由最近的策略采集。这种做法被称为“近同策略”(approximately on-policy),是在数据利用效率和策略更新稳定性之间的一种折中。从分类角度看,PPO仍属于On-Policy算法范畴,因为它不维护跨轮次的经验回放池,也不使用来自显著旧策略的数据进行训练。

PPO与TRPO的对比

维度 TRPO PPO
约束形式 显式KL散度约束 目标函数裁剪
优化问题类型 带约束优化 无约束优化
实现复杂度 高,需要共轭梯度与线性搜索 低,普通随机梯度下降即可
数据需求 每轮采样后单次或少量更新 每轮采样后多轮小批量更新
稳定性 较好,但实现复杂 较好,易于调参
On-Policy属性 严格On-Policy 近似On-Policy

实施步骤:实现一个简化版PPO训练循环

下面提供一个通用的PPO实现流程,使用伪代码形式展示核心步骤。该示例不依赖任何特定第三方库的专有接口,仅使用通用的数组计算与自动微分能力。

步骤1:初始化策略网络与价值网络

策略网络输入状态,输出动作分布的参数(例如高斯分布的均值与标准差)。价值网络输入状态,输出状态价值的估计值。两者可以使用多层感知机结构。

  1. 初始化策略网络 policy_network,参数为 θ
  2. 初始化价值网络 value_network,参数为 φ
  3. 设置裁剪系数 ε = 0.2
  4. 设置更新轮数 K = 10
  5. 设置小批量大小 batch_size
  6. 设置折扣因子 γ = 0.99
  7. 设置GAE参数 λ = 0.95

步骤2:采集轨迹数据

使用当前策略与环境交互,采集一批完整轨迹。为了便于后续计算优势函数,需要保存每一步的状态、动作、奖励、下一状态、终止标志以及旧策略在该状态下选择该动作的对数概率。

  1. trajectories = []
  2. for episode in range(num_episodes_per_iteration):
  3. state = env.reset()
  4. done = False
  5. while not done:
  6. action, log_prob_old = policy_network.sample(state)
  7. next_state, reward, done, info = env.step(action)
  8. store (state, action, reward, next_state, done, log_prob_old)
  9. state = next_state
  10. trajectories.append(stored_transitions)

这一步骤是On-Policy特性的关键体现:数据必须由当前策略采样,更新后即失效。

步骤3:计算优势函数与回报

使用广义优势估计计算每个时间步的优势函数。优势函数衡量当前动作相对于平均水平的优劣,是策略更新的核心信号。

  1. for each trajectory:
  2. 使用 value_network 计算每个状态的价值 V(s_t)
  3. 计算 TD 残差:δ_t = r_t + γ * V(s_{t+1}) * (1 - done_t) - V(s_t)
  4. 计算 GAE 优势:A_t = Σ (γλ)^l * δ_{t+l}
  5. 计算目标回报:R_t = A_t + V(s_t)

步骤4:多轮小批量更新

在采集到的数据上执行K轮更新。每一轮中,将数据随机打乱并划分为小批量。对每个小批量:

  1. 使用策略网络重新计算当前策略下动作的对数概率log_prob_new;
  2. 计算重要性采样比率:r = exp(log_prob_new - log_prob_old);
  3. 计算裁剪后的代理损失:L = -mean( min( r A, clip(r, 1-ε, 1+ε) A ) );
  4. 计算价值网络损失:L_value = mean( (R - V(s))^2 );
  5. 合并总损失,执行梯度下降更新策略网络和价值网络参数。
  1. for epoch in range(K):
  2. for minibatch in shuffled_data:
  3. log_prob_new = policy_network.log_prob(minibatch.states, minibatch.actions)
  4. r = exp(log_prob_new - minibatch.log_probs_old)
  5. L_policy = -mean( min( r * minibatch.advantages,
  6. clip(r, 1-ε, 1+ε) * minibatch.advantages ) )
  7. L_value = mean( (minibatch.returns - value_network(minibatch.states))^2 )
  8. total_loss = L_policy + c1 * L_value - c2 * entropy_bonus
  9. 更新策略网络参数 θ 和价值网络参数 φ

步骤5:迭代训练

重复步骤2至步骤4,直到策略达到预期性能或训练轮次达到预设上限。每轮迭代后,记录平均奖励、平均KL散度、策略损失和价值损失等指标,用于监控训练过程。

配置说明与参数选择

裁剪系数ε

裁剪系数ε控制策略更新的最大幅度。较大的ε允许更大幅度的策略变化,可能加快学习速度,但也可能导致不稳定;较小的ε使更新更保守,训练更稳定但可能变慢。经验上,ε=0.1到0.2是常见选择。建议从0.2开始,如果训练出现震荡则降低至0.1。

更新轮数K与小批量大小

每轮采集的数据可以执行多次更新,以充分利用数据。K过大会导致策略过度偏离旧策略,破坏On-Policy假设;K过小则数据利用率低。经验上,K=4到10是合理范围。小批量大小取决于数据总量和硬件资源,通常为64到256。如果检测到每轮结束时的平均KL散度快速增大,说明K可能过大,应适当减小。

折扣因子γ与GAE参数λ

折扣因子γ决定未来奖励的衰减速度,γ接近1表示更重视长期回报,但可能引入更大方差;γ较小则更关注近期回报。连续控制任务中,γ=0.99是常见起点。GAE参数λ在偏差与方差之间权衡,λ=0.95通常效果良好。λ=1时GAE退化为蒙特卡洛估计,方差较大;λ=0时退化为一步TD误差,偏差较大。

价值网络系数c1与熵奖励系数c2

价值网络损失系数c1通常设为0.5到1之间。熵奖励系数c2鼓励策略保持探索性,防止过早收敛到确定性策略。c2的常见范围为0.01到0.1。如果训练中策略过早收敛且性能不理想,可以适当增大c2。

结果验证

训练指标监控

在训练过程中,应持续记录以下指标:

  • 平均回合奖励:每轮迭代后,使用当前策略(不包含探索噪声)评估若干回合的平均奖励,用于判断性能是否提升;
  • 平均KL散度:计算新旧策略在采集数据上的平均KL散度,理想情况下应保持在0.01到0.05之间。如果KL散度过大,说明更新幅度超出置信域,需要减小ε或K;
  • 策略损失:裁剪后的代理损失应整体呈下降趋势,但允许局部波动;
  • 价值损失:价值网络的均方误差应持续下降,表明价值估计越来越准确。

性能基准测试

在完成训练后,应进行独立的性能评估。评估时关闭训练噪声和探索机制,使用策略的确定性动作(如高斯分布的均值)运行若干回合,记录平均奖励与标准差。如果平均奖励达到任务预设的阈值,且标准差较小,说明策略已稳定收敛。

与理论预期对比

验证过程中,可以观察策略更新前后的KL散度变化。如果KL散度始终远小于ε对应的阈值,说明策略更新过于保守,可以适当增大ε或K。如果KL散度经常超过阈值且训练不稳定,说明更新幅度过大,需要收紧约束。

常见问题与排查

问题1:训练初期策略迅速变为确定性策略,性能停滞

可能原因:熵奖励系数过小,探索不足;优势函数估计偏差较大,导致策略过早收敛到次优解。

排查思路:增大熵奖励系数c2;检查优势函数计算是否正确,尤其是终止状态的处理;尝试降低学习率。

问题2:训练曲线剧烈震荡,平均奖励不稳定

可能原因:策略更新幅度过大,超出置信域范围;价值网络学习率过高或不稳定;数据批次之间方差过大。

排查思路:减小裁剪系数ε;减小更新轮数K;降低策略网络和价值网络的学习率;增大每轮采样的数据量。

问题3:KL散度在每轮更新后持续增大

可能原因:更新轮数K过多;裁剪机制未能有效限制策略变化;学习率过大。

排查思路:减小K;降低学习率;检查裁剪目标函数实现是否正确,特别是ratio的计算是否有数值溢出。

问题4:价值网络损失不下降或发散

可能原因:回报R_t计算错误;价值网络结构过小,不足以拟合价值函数;学习率过小或过大。

排查思路:检查GAE计算中的终止标志处理;增大价值网络隐藏层宽度;调整价值网络学习率。

优化建议

数据利用率与训练加速

在保持On-Policy属性的前提下,可以通过向量化环境并行采样来加速数据收集。多个环境实例同时运行,每轮迭代可收集更多样本,降低梯度估计方差。此外,可以使用多轮小批量更新(但不宜过多)来提高数据利用率。

稳定性与收敛性

保持策略更新与价值更新之间的平衡。价值网络过弱会导致优势估计不准确,影响策略学习;价值网络过强可能导致策略更新过于保守。可以尝试对价值网络使用独立的目标网络或梯度裁剪。

超参数自动调节

实际应用中,可以监控每轮更新后的平均KL散度,并动态调整学习率或裁剪系数。例如,如果KL散度持续低于目标区间,可以适当增大学习率;如果KL散度频繁超过阈值,则降低学习率。这种自适应策略有助于适应不同环境和任务特性。

与云基础设施的结合

在较大规模的强化学习训练中,可以将采样与训练分离。采样进程在多个计算节点上并行运行,将交互数据写入通用消息队列或对象存储;训练进程从队列中拉取数据执行更新。这种架构需要处理策略版本同步问题:采样节点应定期拉取最新策略参数,确保数据相对新鲜。虽然引入了轻微异步,只要策略版本差异控制在一定范围内,仍可视为近似On-Policy训练。

总结

本文从策略优化的数据依赖关系出发,系统解释了TRPO和PPO为何属于On-Policy算法。TRPO通过置信域约束显式限制新旧策略的KL散度,保证更新稳定性,但其实现复杂度较高。PPO通过目标函数裁剪将约束转化为无约束优化,在保持近似On-Policy属性的同时大幅简化了实现。两者的共同点是:数据必须由当前策略(或与之非常接近的策略)采集,策略一旦更新,旧数据原则上失效,需要重新采样。

掌握这一本质,读者可以更好地理解On-Policy算法的设计取舍,在实际项目中合理选择算法、设计采样流程、配置超参数并诊断训练问题。后续学习方向可以包括:Off-Policy策略梯度方法、经验回放与重要性采样的结合、分布式强化学习训练框架设计,以及在不同任务上的系统化调参方法论。