机器人强化学习中的 PPO:从价值估计到策略更新
机器人执行动作,环境返回奖励;优化器更新的却是策略网络参数。奖励怎样变成参数的梯度,中间要经过回报、价值估计和优势函数。理解这条计算过程后,才能说清 GAE 改善了什么、PPO 的裁剪限制了什么,以及为什么它适合大量并行的机器人仿真训练。
本文按基本概念、Bellman 方程、TD、策略梯度和 Actor–Critic 的顺序展开,参考赵世钰老师《强化学习的数学原理》的讲解脉络。数值例子独立编写;TRPO、PPO 与 SAC 放在同一条参数更新主线上对照,较长的实现推导折叠供选读。教材与课程官方入口
1. 状态、动作、策略与参数,各是什么
设机器人正在站立。当前身体倾斜角、关节角和速度等信息组成状态 s;策略根据这些信息,选择一个动作 a,机器人执行后得到下一状态和一个即时奖励 r。这一条记录就是:
下标 t 表示第几步。本文把“执行动作后得到的奖励”记为 r_t,有些教材将同一个奖励记为 r_{t+1},只是编号约定不同。
策略是选择动作的规则,参数是这个规则内部可以学习的数值。 对随机策略,用下面的记号表示:
其中 pi 表示策略,theta 表示神经网络的权重和偏置;竖线表示“给定当前状态”。符号 ~ 表示从分布中采样。策略可以认为在某个状态下两个动作各有一半机会,也可以输出连续动作的高斯分布。
动作是某一次决策的结果。网络参数改变后,以后遇到状态时的动作分布会改变;已经执行过的那个动作,仍然是经验记录中的原值。后面会把这个区别算出来。
为了先讲清数学,前半篇假定状态可以完整观察。真实机器人 actor 一般只能看到观测 o,例如编码器、IMU 和动作历史;训练 critic 可以额外获得仿真状态。这个信息差在工程中要处理,暂时不与价值函数的定义混在一起。
2. Reward 是一步评分,Return 是往后累计的评分
机器人这一刻得到 +1,不意味着这个动作长期合算。例如迈大步可能立刻提高速度奖励,却在几步以后导致摔倒。因此要累计往后的奖励,得到回报 G:
gamma 是折扣因子,通常位于 0 与 1 之间。它决定较远奖励在当前计算中占多大分量,不是学习率。
举一个纯数值例子:一段回合还剩三次奖励 1、2、3,之后结束,取 gamma=0.9。则:
这里 r_0=1,G_0=5.23。两者回答不同的问题:一个是这一步拿到多少,另一个是从这一步开始,后面总共拿到多少。
把第一项拿出来,可以直接得到一个以后反复使用的关系:
它没有增加任何假设,只是把同一个和式重新分组。Bellman 方程就是从这里接上条件期望。
3. V 和 Q 为什么要分成两个函数
V:处在这个状态,按当前策略继续,平均能拿多少
即使从同一站姿出发,策略可能选到不同动作,接触结果也可能有随机性,所以一次实际回报 G 不能代表所有情况。对它取平均,得到状态价值:
期望可以先理解为“按发生概率加权平均”;右上角 pi 提醒我们,这个平均水平属于某个策略。同一个站姿,交给不同控制策略,往后的平均回报可以不同。
Q:这个状态下先指定一个动作,再按当前策略继续,平均能拿多少
动作价值比 V 多固定了第一步动作:
“指定第一步动作”不表示以后每步都重复这个动作。第一步之后,仍由 pi 决策。
下面用一个只有两种动作的简化决策贯穿全文。它是计算例子,不是某个真实机器人的训练结果。在状态 s,下列两条路径的结果是确定的:
- 动作 a₊:这一刻奖励 1,进入下一状态 s₁;随后得到奖励 10,回合结束。仍取 gamma=0.9,因此 Q(s,a₊)=1+0.9×10=10。
- 动作 a₋:立即得到奖励 6,回合结束,因此 Q(s,a₋)=6。
当前策略在 s 下各用 50% 的概率选择这两个动作,那么:
所以 V=8 不是第三种动作的评分,而是当前选动作规则下的平均水平。一般地,离散动作满足:
连续动作把求和换成积分,含义相同。还可以注意到:a₊ 的即时奖励只有 1,却比即时奖励为 6 的 a₋ 更值得选。只拿当前 reward 评价动作,会在这里判断反了。
4. Bellman 方程怎样从回报推出来
刚才已经有 G_t = r_t + gamma × G_{t+1}。现在问“处在 s,按 pi 继续,平均得到多少”,就是在等式两边取对应的条件期望:
右侧先选动作,再由环境产生奖励与下一状态,因此平均包含策略和环境两部分随机性。它的意思是:当前状态的价值,等于眼前奖励加上下一状态价值的折扣平均。
如果把第一步动作也固定,得到:
沿用 a₊ 的路径:s₁ 后面还有一次奖励 10,所以 V(s₁)=10;当前动作价值就是 1 + 0.9 × 10 = 10。
Bellman 方程提供了“如何把相邻时刻的价值联系起来”的规则。它不是另给价值贴一个定义,也不是知道下一状态之后,就已经知道了整个未来。实际算法仍要估计右侧的 V。
5. 不知道真实 V,critic 怎么学:从 MC 到 TD error
等回合结束再评分:Monte Carlo
前面 V 和 Q 的定义都包含平均未来回报。一个直接方法是多跑几次,记录每次真实发生的 G,再让网络拟合这些回报。这个价值网络通常称为 critic,用 phi 表示它的参数:
例如真的执行 a₊,看到后续奖励 1、10,就能算出 G_0=10,拿它作为本次拟合目标。另一回合执行 a₋,目标为 6;两个动作各占一半时,同一状态的平方误差回归会趋向平均值 8。
这种方法要等后面的奖励发生,而且不同回合的累计结果可能波动很大。
只等一步:Temporal Difference
Bellman 方程提示我们:既然还没看到完整未来,可以先用下一状态的价值估计代替它。用这一步真实奖励,加上下一状态的估计,构成 TD target:
再用“新目标减旧预测”,得到 TD error:
TD 是 temporal difference,指利用相邻时刻的价值关系更新估计。它不只是 下一步 V − 当前 V,还必须包括眼前奖励和折扣。
例如当前估计 V(s)=8、下一状态估计 V(s₁)=9。这次执行 a₊,得到 r=1,则 TD target 为 1 + 0.9 × 9 = 9.1,TD error 为 9.1 − 8 = 1.1。这条经验告诉 critic:这次观察得到的目标,比刚才的预测高 1.1。
如果 V 直接存成表格,最简单的 TD 更新就是:
取学习率 alpha=0.1,表格中的 8 会变为 8.11。换成神经网络,则通过回归损失更新 phi:
1 | # 每个样本对应一个标量,张量形状均为 [B] |
no_grad 的意思是这一步更新把 target 当成固定评分目标。critic 当前的预测向它靠近,而不是同时反向修改 target。用一个估计帮助更新另一个估计,称为 bootstrap;它节省了等待完整回合的成本,也把下一状态估计的误差带进了目标。
这里 a₊ 的真实回报是 10,TD target 却是 9.1,正是因为下一状态被低估了。TD target 不是自动正确的真值。 需要通过持续采样和价值更新逐步改善估计。
真实终止后没有未来价值,bootstrap_mask 应为 0;只是采样时间到、任务本来还会继续时,情况不同,后面再处理。
6. 优势函数 A 从哪里来
动作价值 Q 告诉我们“这样选平均有多少回报”,状态价值 V 告诉我们“当前策略通常有多少回报”。两者相减,就能比较这次选择相对通常水平好多少:
沿用 Q(a₊)=10、Q(a₋)=6、V=8 的例子:
正优势表示高于当前平均水平,负优势表示低于当前平均水平。a₋ 的奖励是正数、Q 也是正数,但优势仍然为负;因此“有奖励就多做”不是正确的更新规则。
为什么 TD error 能拿来估计优势
从动作价值的 Bellman 方程减去 V(s):
括号里的量正是使用真实 V 时的一步 TD error。因此,给定状态和动作,TD error 的条件平均等于优势。
要区分三个层次:A 是一个条件期望;某一次 delta 是一条经验产生的样本;代码中的 V 又只是 critic 的估计。所以实际 delta 会包含环境随机性和价值估计误差,不能说“每次 delta 都精确等于 A”。
如果下一状态估计准确,为 10,这条 a₊ 样本的 delta 就是 1 + 0.9 × 10 − 8 = 2。刚才下一状态被估成 9,delta 才变成 1.1。这也解释了为什么 actor 的学习质量依赖 critic。
7. GAE:把后面几步的 TD error 也利用起来
只用一步 delta,下一状态估计不准时会受影响。等到回合结束再用完整回报,又可能有更大的采样波动。GAE 用衰减权重把后面的 TD error 累加:
帽子表示估计值。gamma 仍是奖励的时间折扣;lambda 是另一个参数,用来控制后续 TD error 参与多少。lambda=0 时只保留当前 delta。对于一条完整结束的轨迹,lambda=1 时,各个 V 项会抵消,得到实际回报减当前价值估计;在相同估计与采样设置下,这是典型的偏差与方差折中,不能把某个 lambda 说成普遍最优。
继续用同一条 a₊ 轨迹:奖励为 1、10,critic 估计为 8、9,第二步结束。取 gamma=0.9、lambda=0.95:
一步 TD 只给出 1.1;后一步的 +1 说明 s₁ 原来被低估了,GAE 把一部分修正传回前面。若 lambda=1,则得到 1.1 + 0.9 = 2,正好是这次实际回报 10 减当前预测 8。
这些权重为什么这样取
还可以从“用几步奖励来评分”理解同一个计算。本例只有两步,因此有两种估计:一步估计用真实奖励 1,再接 critic 预测的 9;两步估计用真实奖励 1、10,一直看到终止:
两步估计在本例中更准,但实际任务的后续奖励会随接触、随机扰动和探索动作变化,等得越久不一定越可靠。GAE 把不同步数的估计混合。在这条两步终止的轨迹上,权重分别是 1−lambda 和 lambda:
它与上面的 TD error 累加完全相同,因为两步估计就是 delta₀ + gamma × delta₁。展开到更长的轨迹时,多步估计的权重按 lambda 衰减,整理后就得到前面的 GAE 和式;有限轨迹最后一项要保留剩余权重,并正确处理终止或 bootstrap。
lambda 较小,更多依赖短步 critic 预测,通常采样波动较小,但更容易受价值估计偏差影响;lambda 较大,更多采用后面实际发生的奖励,减轻这种依赖,也可能带入更多轨迹噪声。GAE 改善的是“这次动作该怎样评分”的估计,不负责限制网络更新幅度,也不是 PPO 独有的组件。
训练 critic 的一个常见回报目标为:
本例中是 1.955+8=9.955。这里的 return 是由 GAE 构造的拟合目标,不要求与实际完整回报 10 完全相同。后面如果对 actor 使用的优势做标准化,应先保存这个 critic 目标,不能把标准化后的优势再加回 V。
代码为什么从后往前算
上面的和式可以改写成递推:
最后一步之后的累计量已知,从后向前就能一次算完。b 决定是否对下一状态 bootstrap,c 决定是否沿着这条轨迹继续累计,两者用途不同:
1 | # values / next_values 为采集时保存的预测;这里只计算固定目标 |
机器人摔倒、任务真实结束时,b=0、c=0。回合只是达到时间上限、实际任务仍可继续时,通常 b=1、c=0:保留最终状态的价值,不能把 reset 后的新站姿接进旧回合。rollout 长度到头但回合没结束时,也要保留末状态 bootstrap。GAE 原论文
8. 为什么优化网络参数,而不是把 action 改好
现在已经有了某次执行记录,以及“这次选择相对平均水平怎样”的估计。接下来需要把这个评价用来改变选动作的规则。
PPO 优化器持有的是 actor 的网络参数 theta。过去执行过的 a 是训练数据,给它改个数值,不会改掉机器人已经发生过的运动;而部署时机器人还会遇到其他状态,需要网络继续产生动作。
用连续动作的最小例子看梯度。固定当前状态,只让策略的均值 mu 可训练,标准差 sigma=0.5 不训练;mu 就是这个玩具策略的唯一参数。采集时 mu=0,恰好采到了 a=0.5。其对数概率密度满足:
把这条样本的优势估成 +2,使用目标 A × logpi 做一次学习率为 0.05 的梯度上升:
被改成 0.2 的是均值参数 mu;训练记录里的 a 仍为 0.5。 以后采样时,高斯分布中心向正方向移动,因此附近正动作更容易被采到。若同一条样本的优势是 −2,则梯度为 −4,mu 变成 −0.2,降低对该已采样动作的偏好。
点击更新,观察参数、固定样本和概率密度分别发生什么。这是固定方差、单样本的一次普通策略梯度更新,用来说明参数学习,不是完整 PPO 训练。
真实 actor 的均值一般是 mu = network_theta(obs),不是一个直接存储的标量。因此反向传播还会通过 mu 计算各层权重的梯度。网络参数共享,一条样本的更新也可能改变其他状态的输出;需要用整批经验平衡这些影响。
采集与更新分开写,大致如下:
1 | # 采集:记录一次已执行的动作,不保存采样过程的梯度图 |
这里的 saved_action 是常量,但 logp 仍依赖 actor 参数,所以能反向传播。advantage.detach() 则把动作评分当作这一轮的固定数据,避免沿评分误更新 critic。
如果直接写 loss = -saved_reward,保存的 reward 只是环境已经给出的数值,没有连回 actor 参数的计算图,不能靠它告诉网络该改哪些权重。logp × advantage 在“评分”与“选动作的规则”之间建立了可求导的联系。
这说的是 PPO 的策略学习方式。轨迹优化可以把整段动作当作优化变量;SAC 更新 actor 时也会保留新采样动作的可导路径,但最终部署策略的优化器仍更新网络参数,后文会说明。
9. 策略梯度为什么能用优势来加权
先固定一个状态,把这一轮评估出的 Q 当作常量,考虑怎样调整动作概率。局部目标为:
在前面的两动作例子中,当前平均回报是 8;若把 a₊ 的概率从 0.5 提高到 0.6,a₋ 降到 0.4,这个局部平均会变为 0.6 × 10 + 0.4 × 6 = 8.4。评价动作,再调整选择概率,就是这一步的目的。
对动作概率求导,并用“概率的导数 = 概率 × 对数概率的导数”改写:
右侧变成了“按策略采样后求平均”的形式,因此可以用实际采到的动作估计梯度。我们不需要知道每一种动作的真实 Q,只需要能从经验中给动作估计一个评分。
为什么可以把 Q 换成 Q−V?在固定状态下,V 对所有动作都是同一个基准。减去它带来的梯度项为:
所以减去一个与当前动作无关、在这次求导中固定的基准,不改变这个期望梯度,却通常能减少采样估计的波动。这是优势进入策略梯度的数学依据;近似的优势估计仍可能引入误差。
完整策略优化还包含状态访问随策略改变的影响。策略梯度定理处理了这层依赖,得到对数概率梯度乘动作价值/优势的形式;上面的固定状态推导用于先看清这个计算结构,不能把一次局部改进直接当作完整任务性能的保证。策略梯度理论补充
把最大化改写成优化器常用的最小化,就得到上一节的负号。Actor 负责改变动作分布,critic 负责估计价值,两者合起来称为 Actor–Critic。它不是 actor 学动作标签、critic 给动作打固定分类分数。
10. 从普通策略梯度到 TRPO:为什么不能一批数据一直改
到这里,普通策略梯度的关键步骤已经齐了:采集经验、估计价值与优势,再更新参数。问题是,评分来自采集时的旧策略;参数更新几次后,当前策略已经变了。
因此采集时需要保存动作原来的 log probability,更新时再算当前策略对同一个动作的 log probability,构造概率比率:
例如离散动作原概率 0.5、现概率 0.6,比率为 1.2;连续动作比较的是概率密度。它描述对这条旧动作的偏好变化,不是把动作乘了 1.2。更新过程中,old_logp、旧动作和本轮优势都固定。
TRPO 的思路是最大化比率加权优势,同时限制新旧动作分布的平均 KL 距离:
KL 在这里衡量两个动作分布差多少,delta 是允许的变化范围。重点是“允许改善,但别在这一批旧数据上把策略改得太远”。概率比率只修正给定状态下的动作分布,不能完整消除状态访问分布变化的影响。
选读:TRPO 为什么要共轭梯度和线搜索
在旧参数附近,目标做一阶展开,KL 做二阶展开,得到:
F 是 KL 的局部曲率矩阵,方向与 F 的逆作用于 g 有关。参数很多时,不显式构造逆矩阵,而是用自动微分计算矩阵—向量积,再通过共轭梯度近似求方向:
1 | old_params = flat_parameters(actor).clone() |
线搜索重新检查实际 KL 与目标。有限样本、局部近似及平均 KL 约束,都不能直接解释为真实机器人每次更新后必然更好。TRPO 原论文
11. PPO:把“别改太远”写进目标函数
PPO-Clip 继续使用 old_logp、ratio 和 advantage,将两个候选目标取较小值:
先逐个读符号:rho 是刚才的概率比率;A 是这次动作高于或低于平均水平的估计;clip 把比率临时裁到一段范围;min 让策略采用较保守的那个收益估计。epsilon 常取 0.2,于是比较范围为 [0.8,1.2]。
正优势 +2 的样本,希望提高动作概率。比率从 1 增到 1.2,目标从 2 增到 2.4;再增到 1.4,未裁剪项虽变成 2.8,PPO 仍取 2.4,停止奖励这条样本在这个方向上的进一步变化。
负优势 −2 的样本,希望降低动作概率。比率从 1 降到 0.8,目标从 −2 提高到 −1.6;再降到 0.6,PPO 仍取 −1.6。注意“最大化 −1.6 比最大化 −2 更好”,不要因负号把更新方向读反。
先看正优势,再切换负优势,拖动概率比率。这里画的是需要最大化的单样本目标;下面代码将其加负号,交给做梯度下降的优化器。
1 | ratio = (new_logp - old_logp).exp() |
min 还保留了纠错方向:正优势动作如果被错误压到 ratio=0.6,目标仍为 0.6 × 2,会提供提高概率的梯度;负优势动作若被提高到 ratio=1.4,仍会提供降低概率的梯度。只用 clamp(ratio) × advantage,会把这两种纠错梯度也一起裁掉。
裁剪的是某条样本的替代目标,不是电机动作,也不是把参数锁在一个区间。其他样本和共享网络参数仍会改变策略,所以更新后 ratio 也可能越过 [0.8,1.2]。相比 TRPO,PPO 可以用普通一阶优化器做多轮 minibatch 更新。PPO 原论文
PPO 和 GAE 分别解决哪一步的问题
前面的两个问题到这里才接在一起:GAE 负责估计优势,PPO-Clip 根据这个优势更新策略,同时抑制对同一批旧数据的过度优化。 前者在处理评分的偏差与方差,后者在处理新旧策略偏离。两者经常一起用,但不能互相替代。
例如 critic 严重高估后续价值,就可能给一个长期吃亏的动作算出正优势。clip 仍会按这个正优势鼓励提高动作概率,只是在超过阈值后不再增加这条样本的目标收益;它不会自动发现评分算错了。反过来,即使优势估计准确,没有更新约束也可能一次把策略改得过远。
把一轮训练从头接起来
下面是省略网络定义的教学代码。先采集并计算固定目标,再更新两个网络;每个样本的标量整理成 [B],避免意外广播。
1 | # 采集时不建立梯度图:保存动作、旧概率、旧价值与状态转移 |
actor_loss 改策略参数 theta,让高于平均的选择更受偏好;critic_loss 改价值参数 phi,让预测接近回报目标。熵项鼓励保留一定探索。示例采用两个独立网络;如果共享编码器,还需明确哪些损失共同更新共享参数。
连续动作的 log_prob(...).sum(-1) 把独立动作维度的对数密度相加,得到整个动作向量的联合对数密度。真实机器人原始 action 再经过动作尺度、默认姿态与 PD 转成执行器命令,这在第 13 节说明。
PPO 的好处,放到全身控制训练里看
相对直接反复优化普通策略梯度,PPO 给一批数据的多次利用加了约束。 普通目标里的 ratio × advantage 可以随着某个正优势动作的概率继续增大;但优势来自旧策略,不能一直当成当前策略的可靠评分。PPO 在有利方向超过阈值后去掉继续提高该样本目标的激励,因此可以在一批经验上做有限轮更新,再换新数据。这是批内复用;它没有把 PPO 变成可以长期回放任意旧经验的 off-policy 算法。
相对 TRPO,PPO 保留了控制策略变化的意图,更新过程更容易实现。 上面的 actor loss 直接交给 Adam,不需要求共轭梯度方向和反复线搜索。对全身控制实验,修改观测、网络或加入辅助损失后,仍可沿用这套一阶优化流程。代价是 clip 只作用于替代目标,没有 TRPO 那样显式检查的 KL 约束,更不保证每次真实回报都提高。
它也适合这里“大量并行仿真、短段采集、整批更新”的组织方式。 actor 一次输出整组关节的连续分布,不需要枚举关节动作组合;critic 帮助从短段经验构造学习目标。训练时给 critic 更多仿真信息、给 actor 部署能获得的观测,也能接入这套流程。不过连续策略、并行仿真和非对称 actor–critic 都不是 PPO 独占的能力,不能把这些工程选择都算成 clip 的贡献。
这里的适用条件是仿真能持续提供新数据。如果每条经验都要由真机采集,PPO 更新几轮就换新数据的成本会更突出,SAC 一类经验回放方法就值得比较。不能仅凭 PPO 在仿真里常用,就断言它比 SAC 更省样本或部署更安全。
用一份实际训练配置算一遍
以 FALCON 分组全身控制实现的一组默认配置为例,下面是配置值及其计算含义,不是运行日志或性能对比结果;具体实验覆盖参数后还要重新核对。
| 配置 | 数值 | 在这一轮训练里做什么 |
|---|---|---|
| 并行环境数 × 每环境采样步数 | 4096 × 24 | 收集 98,304 条新状态转移 |
| minibatch 数 × 更新轮数 | 4 × 5 | 每个控制组做 20 次 actor 更新及相应 critic 更新 |
| gamma / lambda | 0.99 / 0.95 | 分别控制奖励折扣与 GAE 的后续 TD error 权重 |
| clip epsilon | 0.2 | 正、负优势对应的有利方向分别在 ratio=1.2、0.8 后进入平台 |
| 初始 actor / critic 学习率 | 各 1e−4 | 控制参数步长,后续结合 KL 自适应调整 |
| desired KL | 0.01 | 用于学习率调节,不是每次更新必须满足的硬上限 |
采样量和优化量要分开算。 每个 minibatch 有 24,576 条经验,5 轮让同一批经验各参与 5 次训练,总计 491,520 次样本使用;新采集的数据仍只有 98,304 条。每组的 old_logp 和优势在这些更新中固定。继续增加 epoch,增加的是计算和旧数据使用次数,不能当成获得了更多经验;新旧策略偏离太大时,旧优势也越来越不适合指导当前策略。
仿真频率为 200 Hz、每 4 个物理步执行一次策略,策略间隔为 0.02 s;24 步对应每个环境 0.48 s 的采样片段,而不是一整段任务。没有终止时,片段尾部通过 critic 的价值预测接上更远的未来,所以短片段也能训练长期任务,前提是 bootstrap 和终止处理正确。
这组 GAE 参数给出 gamma × lambda = 0.9405。后面第 10 步的 TD error,传到当前优势时乘约 0.541;第 20 步乘约 0.293。它们分别相隔 0.2 s 和 0.4 s:后续修正能传回来,但越远越弱。这些是 TD error 的权重,不是把 0.4 s 之后的奖励丢掉。 奖励仍按 gamma 折扣,更远的价值还会通过 bootstrap 进入估计;lambda 也不是机器人的控制频率或固定规划时域。
clip 之外,这份实现还根据实际高斯分布的平均 KL 调学习率。KL 大于 0.02 时学习率除以 1.5;处于 0 到 0.005 之间时乘以 1.5。它针对的是“这一批参数改得快不快”,与 GAE 针对的“评分是否可靠”分工不同。
训练不稳时,怎样沿着这条逻辑查
如果 KL 突然变大,应先检查学习率、每批更新轮数以及动作分布的标准差;clip 不是硬约束,不能因为 epsilon=0.2 就认定策略变化已被锁住。如果还记录了裁剪比例,要先看日志统计的是“ratio 越界”,还是“目标真正进入裁剪平台”,两者不等价。大量样本越界时,继续堆 epoch 未必能学到更多。
如果 KL 很小,跟踪效果却一直不改善,就不能只缩小更新。要回到评分这一侧,检查 critic 对回报目标的拟合、优势的分布、摔倒与超时的处理,以及各项奖励是否把好行为评成了高分。价值损失下降只说明更接近当前目标;目标算错,它也可以下降。本文后面的奖励表就是为了把这个评分来源拆开看。
如果仿真回报很好、机器人仍然抖动或接触失败,则要继续检查动作尺度、PD、力矩饱和与碰撞模型。PPO 能优化给定仿真和奖励中的策略,不能替代执行器建模,也不会由 clip 自动产生柔顺性。需要比较算法时,应在相同任务、奖励和评估条件下分别记录采样量、耗时、跟踪误差和失败率;这里的配置计算本身不能证明哪个算法效果更好。
选读:FALCON 实现中的分组 PPO、KL 和超时处理
FALCON 分组控制实现对各控制组分别维护 actor、critic 与优化器,每组内先对动作维度求联合 log probability;没有把每个关节当成独立 PPO 样本。它先给 ratio×advantage 取负号,再取 maximum,与上文取 minimum 后加负号等价。
更新时用新旧高斯均值和标准差计算解析 KL。学习率按上文阈值调整,并限制在 1e−5 到 1e−2。这个机制调整后续更新速度,不撤回刚才的参数。
实现将超时补偿先加进 reward,再用 done 截断 GAE;严格的最终状态 bootstrap 要使用截断前的下一状态价值,而不是自动 reset 后的价值。应核对补偿读取 value 的具体时刻。
每个控制组独立计算自己的优势与联合概率比率。上文的 20 次更新是每组的更新次数,不表示把每个关节分别更新 20 次,也不表示执行了 20 次物理控制。
面试问“为什么选 PPO”,可以怎样回答
对这里的全身控制仿真,首先需要用经验判断动作的长期好坏:critic 估计 V,TD error 提供一步修正,GAE 把不同步数的修正组合起来,在价值估计偏差与轨迹噪声之间折中。然后才是更新策略:PPO 用新旧动作概率比率乘优势,并通过 clip 抑制一批旧数据上的过度优化,因此能够对同一批经验做有限轮 minibatch 更新。相比 TRPO,它可以直接使用一阶优化器,实现和修改都更方便。
具体到这组配置,4096 个环境各采 24 步,每批 98,304 条经验,分 4 个 minibatch 训练 5 轮;gamma=0.99、lambda=0.95、epsilon=0.2,并用 KL 调整学习率。这与并行仿真不断提供新数据的方式相配合。但 GAE 不是 PPO 独有的,clip 也不保证回报单调上升;真机数据昂贵时还要比较 SAC 的回放收益,动作尺度和接触模型仍需单独验证。
PPO 的批内复用仍受新旧策略差异限制。接下来换一个问题:如果希望更长期地保留经验,怎样在旧状态上评价当前策略新产生的动作?这就引出了 SAC 的 Q 网络和经验回放。
12. SAC 是什么:让旧经验留下来,学习动作价值 Q
PPO 的 critic 主要估计状态价值 V,帮助构造优势;更新 actor 时评价的是本轮执行过的动作。SAC 则学习动作价值 Q(s,a),把状态转移长期保存在经验回放 replay 中,并反复抽样更新。
actor 在 replay 抽出的状态上重新产生一个动作,交给可求导的 Q 网络评价,再根据这个评价更新自身参数。这里的新动作可以处在梯度路径上,但优化器更新的仍是 actor 参数;replay 中机器人过去真正执行的动作不会被改写。
SAC 还把熵纳入目标,控制追求高回报与保留探索之间的权衡。它不需要 PPO 的 old_logp 比率,但增加了 Q 估计、目标网络、回放分布与温度之间的耦合。先理解到这一步,再看下面的完整方程即可。
- 采集
- 存储
- 更新
- 下一批
教学流程:卡片数量、更新轮数和采样组合仅用于说明数据生命周期。
用“下一步”对比数据的去向:PPO 一轮更新结束后换新数据,SAC 在 replay 中保留新旧经验。
选读:SAC 的目标函数、可导采样与 FastSAC 实现
SAC 将熵写入控制目标。对连续策略,熵由动作概率密度的负对数估计:
它在回报和探索之间做权衡。 是熵温度,奖励尺度变化时也要重新检查其相对作用。使用双 Q 与目标网络的常见实现,以如下目标更新 critic:
其中, 是经验回放分布, 表示真实终止,横线 Q 是目标网络;actor 的动作通过重参数化 生成。Q 的目标 y 停止梯度,actor 更新则保留 Q 对动作的梯度。对应下面的 no_grad、rsample_and_log_prob 和冻结 Q 参数三处代码。SAC 的目标与更新方程
先看常见的标量双 Q 版本
下面每个 batch 的标量都是 [B];alpha 是熵温度,polyak_update 将目标 Q 缓慢移向当前 Q。截断时保留最终 next_obs,只有真实任务终止才关闭 bootstrap。
1 | batch = replay.sample(batch_size) |
Q 更新使用 replay 中真的执行过的动作;actor 更新使用当前策略新采样的动作,经 Q 对动作的梯度反传。这就是这里不需要 old_logp 和 PPO ratio 的原因。
目标中的 −alpha * logp 奖励策略保留熵。双 Q 取较小值以减轻过估计,目标网络降低 bootstrap 目标随优化剧烈变化的问题。这里采用后续常用的双目标 Q 形式;SAC 初版还有独立的 soft value 网络。SAC 原论文、后续算法与自动温度
Tanh 动作为什么还要修改 log probability
连续控制常先采高斯 ,再输出 。概率密度必须包含变换的 Jacobian:
Holosoma 的 FastSAC actor 对 tanh 和动作缩放都做了修正。漏掉 tanh 项会改变 actor 梯度;固定缩放项对 actor 参数是常数,但会改变熵的数值,进而影响自动温度更新。
FastSAC 对这段基础代码又改了什么
Holosoma FastSAC 使用分布型 critic:每个 Q 输出离散支持点上的概率,target 要先投影回这些支持点,再计算交叉熵。因此上面的 Q 均方误差只是基础 SAC 的教学写法,不能拿去替代它的 critic loss。actor 用分布的期望 Q,温度通过 log_alpha 学习。FastSAC 实现
看训练日志时也就多了一项:目标回报有没有大量堆在价值分布的两端。若奖励量级超过支持范围,先调整奖励尺度或支持范围;只增加网络层数无法消除截断。
13. 接到机器人上:动作尺度和采样时间仍要对齐
算法里的 action 最后通常经过位置目标和 PD:
未饱和时,动作到力矩的局部增益是 。例如上肢 Kp=60,S=0.5 时动作变动 0.1 对应 3 N·m;改成 S=0.7 就对应 4.2 N·m。策略的标准差相同,物理探索幅度也已经不同。
时间尺度同样影响训练。50 Hz 控制下采 24 步,覆盖 0.48 s,之后的回报由 critic bootstrap。若改成 100 Hz 却保持折扣 gamma 不变,以秒计的折扣视野会缩短;固定连续时间折扣率 时应按 换算。
PPO 适合高吞吐并行仿真中反复采新数据;SAC 的 replay 可以降低对新数据的需求,但增加了 Q 估计、目标网络和数据分布的耦合。动作跟踪任务还要把参考动作或相位放进条件,否则 replay 中同样的机器人姿态可能对应不同目标。
比较两者时,至少同时记录环境交互步数、优化步数和耗时。KL/clip fraction 用来看 PPO 更新,Q 值与温度用来看 SAC;跟踪误差、跌倒率、关节力矩饱和率则用来看机器人实际完成了什么。
14. 任务奖励:基础预设和 FastSAC 预设差在哪里
PPO 和 SAC 都不规定机器人必须使用哪套任务奖励。下面以 Holosoma 的全身跟踪任务为例,对照基础奖励预设与 FastSAC 预设。两套预设有三项权重不同。
RewardManager 使用 sum(weight * raw_reward * dt)。FastSAC 预设同时改变了 anchor 位置、身体位置和 action rate 三项,因此两条训练曲线的差异不能全部归因于算法。要比较算法效率,应固定任务奖励,或明确同时调参的实验设置。
点击名称可跳到对应的公式与实现说明,并自动展开。
| 名称 | 基础预设 | FastSAC 预设 | 尺度/定义 | 作用 |
|---|---|---|---|---|
motion_global_ref_position_error_exp |
0.5 | 1 | std = 0.3 m | 限制 anchor 全局漂移 |
motion_global_ref_orientation_error_exp |
0.5 | 0.5 | std = 0.4 rad | 跟住 anchor 朝向 |
motion_relative_body_position_error_exp |
1 | 2 | std = 0.3 m | 保留身体相对几何 |
motion_relative_body_orientation_error_exp |
1 | 1 | std = 0.4 rad | 保留各身体姿态 |
motion_global_body_lin_vel |
1 | 1 | std = 1 m/s | 匹配平移速度 |
motion_global_body_ang_vel |
1 | 1 | std = 3.14 rad/s | 匹配转动速度 |
action_rate_l2 |
−0.1 | −1 | 原始动作平方和 | 抑制动作抖动 |
limits_dof_pos |
−10 | −10 | 软限位越界量,rad | 远离关节限位 |
undesired_contacts |
−0.1 | −0.1 | 阈值 1 N | 减少不允许的身体碰撞 |
逐项实现
motion_global_ref_position_error_exp
motion_global_ref_position_error_exp 对 anchor 三轴位置差取平方和,再做指数核。权重 0.5 控制该项的贡献,0.3 m 控制容忍尺度。误差 0.3 m 时原始值约 0.3679;它不能保证机器人永不漂移。
1 | err2 = (p_anchor_ref - p_anchor).square().sum(-1) |
motion_global_ref_orientation_error_exp
motion_global_ref_orientation_error_exp 使用四元数的最短旋转角误差,先平方,再除以 0.4²。不要将四个四元数分量直接相减:q 和 −q 表示同一旋转。
1 | angle = quat_error_magnitude(q_ref, q_actual) |
motion_relative_body_position_error_exp
motion_relative_body_position_error_exp 比较经过 anchor/yaw 对齐的参考身体位置与实际位置:先对 xyz 求平方和,再对身体取均值,最后求一次 exp。它不是逐身体 exp 后求平均。身体列表改变后,每个部位在均值中的占比也会改变。
1 | err2 = (p_body_aligned - p_body).square().sum(-1) |
motion_relative_body_orientation_error_exp
motion_relative_body_orientation_error_exp 对每个身体计算最短旋转角,平方后在身体维度平均,再用 0.4 rad 核。相对目标的构造与位置项共享参考约定,不能把局部和世界四元数混用。
1 | angle = quat_error_magnitude(q_body_aligned, q_body) |
motion_global_body_lin_vel
motion_global_body_lin_vel 比较世界系身体线速度,三轴平方和后对身体平均;1 m/s 是误差尺度。位置很接近但身体仍在快速冲过目标时,这项会降低奖励。
1 | err2 = (v_ref_w - v_w).square().sum(-1) |
motion_global_body_ang_vel
motion_global_body_ang_vel 比较世界系身体角速度。3.14 rad/s 是指数核尺度,不是机器人最大允许角速度。它补充姿态项,但不能替代力矩限制。
1 | err2 = (omega_ref_w - omega_w).square().sum(-1) |
action_rate_l2
Holosoma 的 action_rate_l2 返回连续两次动作之差的平方和,配置乘负权重。它没有除以控制周期,因此不是物理意义上的关节加速度。动作幅度和控制频率变化后,同一系数的效果也会变。
1 | cost = (action - previous_action).square().sum(-1) |
limits_dof_pos
Holosoma 的 limits_dof_pos 对上下软限位之外的距离取正部,按关节相加。原始量非负、权重为负,且这里不是平方惩罚。它是奖励代价,不能替代执行器硬限位。 本预设以关节硬范围中点为中心,将半宽乘 0.9 得到软限位;参数来自该奖励自己的 soft_dof_pos_limit。
1 | cost = ((lower_soft - q).clamp_min(0) |
undesired_contacts
Holosoma 的 UndesiredContacts 先在接触历史窗取每个身体的力范数峰值,超过 1 N 的身体记为 1,再求和。脚和允许接触的部位必须从筛选集合排除;阈值判断意味着超过 1 N 与超过 100 N 对同一个身体贡献一样。
1 | peak = contact_forces_history.norm(dim=-1).amax(dim=1) |
环境奖励和优化器损失分两层看
FALCON 的分组全身控制 PPO 中,clip 参数是 0.2、value loss coefficient 为 1.0、entropy coefficient 为 0.01;它们进入参数更新目标,不应塞进环境奖励表当作每步机器人奖励。TRPO 的 KL 阈值、SAC 的温度同样属于优化规则。SAC 若自动学习温度,不能拿初始温度当成训练全程不变的常数。
相对原生算法,当前讨论的工程差异包括分组 critic/动作接口、回报处理和任务预设。它们不改变“PPO 使用同批 rollout 的概率比率,SAC 从 replay 中学习双 Q”这两个核心机制。机器人型号、action scale 和控制周期改变后,奖励分布也会改变,直接复用一组损失系数不保证同样稳定。