策略梯度(Policy Gradient)绝对是强化学习入门时最绕不过去的一座山,也是我当年从"看懂公式"到"真能调通代码"之间花时间最多的一环。别的算法顶多是参数多、调试烦,策略梯度是那种——明明每一步推导都看得懂,一跑到真实环境里就各种不收敛、崩溃、奖励曲线像心电图一样乱跳。后来踩坑踩多了,才慢慢把这条线捋清楚。
这篇文章我把策略梯度的完整脉络整理了一遍,从它到底解决了什么问题,到REINFORCE的数学魔法,再到方差控制、Actor-Critic、PPO,最后附上我这几年的实操调参心得。内容偏长,但每一节都是为了让你看完真能跑通、真能用起来。不管你是刚接触强化学习的新手,还是已经跑过几个环境、想要彻底搞懂原理的进阶玩家,这篇都值得收藏。
1. 策略梯度到底在干什么:从"不能直接求导的决策"说起
1.1 强化学习的核心矛盾:决策过程没法直接算梯度
先回到最原始的问题。强化学习研究的是一类序贯决策问题:智能体(Agent)处在某个环境(Environment)里,每个时刻观测到状态 (s_t),按照某个策略 ( \pi(a|s) ) 选出动作 (a_t),环境给出奖励 (r_t) 并转移到下一个状态 (s_{t+1})。目标很简单——让整个轨迹上的累计奖励期望最大。
这看起来就是一个标准的优化问题,那直接梯度上升不就行了?问题出在"决策"这个动作上。决策是离散的(选动作1还是动作2)、随机采样的,也就是说,我们最终要优化的目标是一个"采样得到的随机量"的期望。你没法直接把一条轨迹的奖励对策略参数求导,因为奖励函数对参数 ( \theta ) 的依赖是间接且复杂的:参数 ( \theta ) 影响动作分布,动作分布影响环境转移,环境转移又影响后续奖励。这里面每一步都可能不可导(比如环境是仿真器、游戏、甚至真实机器人),所以传统的反向传播思路在这儿直接卡死。
1.2 值函数方法为什么不够用
很多人会问:既然决策难优化,那用Q-learning这类值函数方法绕开不就行了?确实,值函数方法把问题从"直接优化策略"变成了"估计每个状态动作对的价值",然后在决策时贪心地选择价值最高的动作。这个思路在离散动作空间里非常好用,但有两个先天短板。
第一,连续动作空间很难处理。如果要选的动作不是"上/下/左/右"而是"扭矩多大、油门踩多少",你总不能对每个连续值都算一遍Q值再取最大。第二,随机策略表达不了。值函数方法最后得到的基本都是确定性策略——给定状态永远选同一个最优动作。但很多真实场景里,随机策略才是最优解:比如石头剪刀布,如果你永远出石头,对手马上就能针对你。更微妙的是,在某些部分可观测的环境里,随机策略本身就是一种"信息保护",确定性策略反而容易暴露意图。
策略梯度走的是另一条路:把策略本身参数化成一个概率分布 ( \pi_\theta(a|s) ),然后直接对"策略参数"求梯度,去最大化期望奖励。这条路线天然支持连续动作(动作可以从高斯分布里采样),天然支持随机策略(分布本身就是随机策略),而且因为优化的是参数而非动作,整个问题变得可导了。从工程角度看,这几乎是解决连续控制问题最自然的方式。
1.3 一条轨迹的奖励期望怎么定义
先把目标函数写清楚:
[ J(\theta) = \mathbb{E}{\tau \sim \pi\theta} \left[ R(\tau) \right] ]
其中 ( \tau = (s_0, a_0, r_0, s_1, a_1, r_1, \dots) ) 是一条完整轨迹,( R(\tau) ) 是这条轨迹的累计奖励。我们的任务是调整 ( \theta ),让从策略里采样出来的轨迹平均奖励最高。
这里的关键是:期望的下标是 ( \tau \sim \pi_\theta ),意思是轨迹分布的来源就是策略本身。策略参数一动,整个轨迹分布就动,这个"动态的期望"就是梯度的难点。下一节我们就揭开这个动态期望怎么求导。
2. 核心数学拆解:REINFORCE与log-prob魔法的来龙去脉
2.1 对数导数技巧:把不可导的期望变成可采样估计
能不能直接对 ( J(\theta) ) 求梯度?直觉上,你把 ( \theta ) 稍微动一点,轨迹分布会变,期望奖励也会变,但这个变化率没法用解析式表达,因为你不知道"分布移动了多少"对奖励期望的贡献有多大。
REINFORCE算法解决这个问题只用了一个高中数学公式:对数导数。回顾一下:
[ \nabla_\theta \log \pi_\theta(a|s) = \frac{\nabla_\theta \pi_\theta(a|s)}{\pi_\theta(a|s)} ]
所以:
[ \nabla_\theta \pi_\theta(a|s) = \pi_\theta(a|s) \cdot \nabla_\theta \log \pi_\theta(a|s) ]
这个恒等式本身没什么神奇的,但把它代进期望的梯度里就会发生奇妙的事情:
[ \nabla_\theta J(\theta) = \int \nabla_\theta \pi_\theta(\tau) R(\tau) d\tau ]
[ = \int \pi_\theta(\tau) \nabla_\theta \log \pi_\theta(\tau) R(\tau) d\tau = \mathbb{E}{\tau \sim \pi\theta} \left[ \nabla_\theta \log \pi_\theta(\tau) \cdot R(\tau) \right] ]
看到了吗?求导算子从"奖励函数"上挪到了"概率分布的对数"上。奖励函数不需要可导,环境也不需要可导,我们只需要能对策略网络的输出分布求导——这个是神经网络天然支持的。于是不可导的期望梯度,变成了一个可以靠采样来无偏估计的量。
2.2 轨迹级别的分解:为什么只需要每一步的log-prob
上面得到的是轨迹级别的公式,但实际操作中我们不会把整条轨迹当成一个黑盒去求 ( \nabla_\theta \log \pi_\theta(\tau) )。把轨迹的联合概率展开:
[ \pi_\theta(\tau) = p(s_0) \prod_{t=0}^{T} \pi_\theta(a_t|s_t) \cdot p(s_{t+1}|s_t, a_t) ]
取对数后连乘变成连加:
[ \nabla_\theta \log \pi_\theta(\tau) = \sum_{t=0}^{T} \nabla_\theta \log \pi_\theta(a_t|s_t) ]
环境动态 ( p(s_{t+1}|s_t, a_t) ) 对 ( \theta ) 求导等于零,因为它们和策略参数无关。这意味着我们根本不需要环境模型,就能知道梯度的方向。这就是为什么策略梯度属于"无模型"(model-free)方法。
一步到位,REINFORCE的梯度估计就是:
[ \nabla_\theta J(\theta) \approx \frac{1}{N} \sum_{i=1}^{N} \left( \sum_{t=0}^{T_i} \nabla_\theta \log \pi_\theta(a_{i,t}|s_{i,t}) \right) \cdot R(\tau_i) ]
用一句话总结:一条轨迹总共获取(累计奖励)这么多"正向信号",然后把这份信号按比例分配给轨迹里每一个动作的概率梯度。表现好的轨迹里所有动作的概率都抬升,表现差的轨迹里所有动作的概率都被压低。
2.3 关键直觉:这其实是一种"运气归因"
理解REINFORCE有一个特别重要的视角:它本质上是在做"归因"(credit assignment),而且是很粗暴的归因。一条轨迹最终拿到100分还是-10分,里面混杂了大量因素——策略好不好占一部分,环境随机性、初始状态运气也占一部分,甚至动作采样时候的随机种子都能影响结果。
REINFORCE不管这些,它把整条轨迹的总回报均匀地当作每个动作的贡献度。如果某个动作出现在表现好的轨迹里,它的概率就增大;出现在表现差的轨迹里,概率就减小。时间一长,虽然每次估计噪声很大,但平均下来方向是对的——这就是它的理论保证:无偏估计。
无偏听起来很美,代价就是方差极高。打个比方,REINFORCE像是一个每次考试只看总分的老师,他没法分辨高分是学生真实水平高,还是碰巧题目简单。每次反馈都充满了运气成分,学习自然慢。这个问题直接催生了第三部分要讲的Baseline和Actor-Critic。
3. 方差这个老大难:Baseline机制与Actor-Critic分家史
3.1 高方差问题到底有多严重
REINFORCE的无偏性让很多人掉以轻心,觉得"反正只要采样够多,总归能收敛"。但真实跑起来会发现,如果奖励范围很大(比如几百到几千),或者轨迹长度很长(比如几百步),那个梯度估计的方差会爆炸式增长。高方差带来的直接后果是:明明平均方向是对的,每次更新却像是随机乱撞,学习率稍微大一点直接发散,小一点则慢到难以接受。
为什么方差高?看一下梯度估计的形式:每一步的 ( \nabla_\theta \log \pi_\theta(a_t|s_t) \times R(\tau) )。注意 ( R(\tau) ) 是被乘在整个轨迹的每一项上的。也就是说,如果一条轨迹总回报是1000,那每一步的梯度都会被放大1000倍。环境稍微有点随机波动,这个数值就可能在-1000到1000之间剧烈抖动。
3.2 Baseline的数学直觉:减去一个"不该算的均值"
解决方差的经典方案是引入基线(Baseline)。我们把梯度估计改成:
[ \nabla_\theta J(\theta) \approx \sum_{t} \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot (R(\tau) - b) ]
这里 ( b ) 是一个与当前动作无关的常数或函数。关键性质是:只要 ( b ) 不依赖于当前动作 ( a_t ),那么减去它不会改变梯度的期望。用数学证明就是:
[ \mathbb{E}{a_t \sim \pi\theta} \left[ \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot b \right] = b \cdot \mathbb{E}{a_t \sim \pi\theta} \left[ \nabla_\theta \log \pi_\theta(a_t|s_t) \right] = 0 ]
因为 ( \sum_a \pi_\theta(a|s) \nabla_\theta \log \pi_\theta(a|s) = \sum_a \nabla_\theta \pi_\theta(a|s) = \nabla_\theta 1 = 0 )。
直觉上,基线做的事情是"去除轨迹回报里的均值成分"。原来动不动就上千的 ( R(\tau) ),减去一个差不多大小的基线后,变成几百、几十甚至正负几的波动值。方差一下子降了一个量级,训练稳定性大幅提升。
3.3 选什么做基线:从常数到价值函数
最简单的基线是轨迹回报的平均值:( b = \bar{R} )。实现简单,效果也比不加强不少。但还不够好,因为不同状态下轨迹的回报差异巨大——有些状态天生奖励就高,有些状态注定要完蛋。用同一个平均值去减,并不能精准反映"当前决策到底做得好不好"。
更聪明的做法是让基线变成状态相关的函数 ( b(s_t) )。回想一下,状态价值函数 ( V^\pi(s) ) 的定义就是"从状态 ( s ) 出发按照策略 ( \pi ) 继续走,未来累计奖励的期望"。这不就是最自然的基线吗?如果某个动作让你拿到了超出预期的回报(( R(\tau) - V(s_t) > 0 )),说明这个动作优于平均水平,应该被加强;反之则削弱。
这里引出一个重要的量——优势函数(Advantage Function):
[ A(s_t, a_t) = Q^\pi(s_t, a_t) - V^\pi(s_t) ]
它衡量的是"在状态 ( s_t ) 下选了动作 ( a_t ) 比平均策略好多少"。策略梯度的理想形式其实是:
[ \nabla_\theta J(\theta) \approx \sum_{t} \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot A(s_t, a_t) ]
3.4 Actor-Critic:策略与价值的相互成就
既然理想梯度里需要 ( A(s_t, a_t) ),那我们就有两个网络:一个是策略网络(Actor),负责输出动作分布;另一个是价值网络(Critic),负责估计状态价值或动作价值,用来算优势。这就是Actor-Critic架构的基本盘。
实际实现里,我一般用一个Critic网络估计 ( V_\phi(s_t) ),再用当前轨迹回报的未来折扣部分去计算一个粗略的 ( Q )。常见做法是用TD残差:
[ \delta_t = r_t + \gamma V_\phi(s_{t+1}) - V_\phi(s_t) ]
这个 ( \delta_t ) 其实就是优势函数的一个估计(GAE的雏形)。用它替代 ( R(\tau) - V(s_t) ),不仅方差更低,而且偏置可控。后面我们要讲的Generalized Advantage Estimation(GAE)就是在这个残差上做加权平均,进一步平衡偏差和方差。
到这里,策略梯度从最原始的REINFORCE进化成了Actor-Critic,算是真正迈进现代强化学习的门槛了。
| 方法 | 梯度形式 | 方差 | 偏差 | 实现复杂度 |
|---|---|---|---|---|
| REINFORCE | ( \sum_t \nabla \log \pi (R(\tau)) ) | 极高 | 无偏 | 极低 |
| REINFORCE + Baseline | ( \sum_t \nabla \log \pi (R(\tau) - b) ) | 中 | 无偏(基线无关时) | 低 |
| Actor-Critic (TD) | ( \sum_t \nabla \log \pi \delta_t ) | 较低 | 有偏(受价值网络准确度影响) | 中 |
| Actor-Critic (GAE) | ( \sum_t \nabla \log \pi A^{\text{GAE}}_t ) | 低 | 可由 ( \lambda ) 调节 | 中高 |
4. 从TRPO到PPO:为什么大家都在用它训练策略
4.1 大步子改策略的灾难:一个反例
用Actor-Critic训练时,我们每一步都在根据当前采样到的优势值更新策略。表面看起来没什么问题,但实际操作中会发现:策略更新幅度稍微一失控,整轮训练直接崩溃。
原因在于,更新策略参数 ( \theta ) 后,我们其实并不知道新策略到底好不好。因为我们用来评估优势的数据全部来自旧策略采样。参数一旦大步改动,新旧策略的分布差异可能巨大,旧数据就不再可靠,之前估计的优势全部失真。这个"分布偏移"问题是单步策略梯度方法最致命的隐患。
从数值上看,如果策略是一个高斯分布 ( \mathcal{N}(\mu, \sigma^2) ),你用一个很大的学习率更新 ( \mu ),分布直接偏出去好几个标准差,采样出来的动作和环境期望完全对不上,整个训练就像在悬崖边开车。
4.2 TRPO的核心思想:限制KL散度
Trust Region Policy Optimization(TRPO)解决这个问题的方法是给策略更新加上一个"信任区域"约束——新策略和旧策略之间的KL散度不能超过某个阈值 ( \delta )。KL散度衡量的是两个概率分布的差异程度,限制它,就等于限制每次更新后策略形状不能变化太大。
数学上,TRPO的优化目标是:
[ \max_\theta \mathbb{E}{s,a \sim \pi{\theta_{\text{old}}}} \left[ \frac{\pi_\theta(a|s)}{\pi_{\theta_{\text{old}}}(a|s)} A(s,a) \right] ]
满足约束:
[ \mathbb{E}{s \sim \pi{\theta_{\text{old}}}} \left[ \mathrm{KL}(\pi_{\theta_{\text{old}}}(\cdot|s) | \pi_\theta(\cdot|s)) \right] \le \delta ]
这个约束看起来很美,但实际求解涉及共轭梯度法(conjugate gradient)和线性搜索(line search),实现复杂度比较高。很多初学者看到TRPO的代码直接劝退,这也是PPO后来大火的原因之一——它用一阶优化就能近似实现TRPO的效果,而且稳定性和性能一点不差。
4.3 PPO的截断目标:用一次min操作替代复杂约束
PPO(Proximal Policy Optimization)的核心只有一行目标函数,简洁得让人难以置信:
[ L^{\text{CLIP}}(\theta) = \mathbb{E}_{s,a} \left[ \min\left( r_t(\theta) A(s,a), ; \text{clip}(r_t(\theta), 1-\epsilon, 1+\epsilon) A(s,a) \right) \right] ]
其中概率比 ( r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{\text{old}}}(a_t|s_t)} )。这个min加clip的操作,用一句话解释就是:当优势为正时,我最多把该动作的概率往上推 ( 1+\epsilon ) 倍;当优势为负时,我最多把该动作的概率往下压 ( 1-\epsilon ) 倍。超出这个范围的梯度直接截断为0,防止策略一次更新迈太多步。
这个设计精妙在什么地方?它没有显式计算KL散度,没有共轭梯度,没有线性搜索,却达到了和TRPO类似的"信任区域"效果。你用一行代码、一个梯度上升就能训练,工程上极其友好。我现在跑实验,九十%以上的场景无脑上PPO,只有在特别在意样本效率或者需要严格保证策略单调提升时,才会回头用TRPO。
4.4 GAE:控制偏差-方差平衡的最后一块拼图
把PPO和GAE搭配,才算组装完全体。GAE(Generalized Advantage Estimation)用参数 ( \lambda ) 对多步TD误差做指数加权平均:
[ A^{\text{GAE}}t = \sum{l=0}^{\infty} (\gamma \lambda)^l \delta_{t+l} ]
其中 ( \delta_t = r_t + \gamma V(s_{t+1}) - V(s_t) )。
这个公式表达的东西其实很直观:( \lambda=0 ) 时,GAE退化成一步TD误差,偏差大但方差极小;( \lambda=1 ) 时,GAE近似蒙特卡洛回报,无偏但方差大。调 ( \lambda ) 就是在偏差和方差之间选一个折中。我在实际项目里一般取 ( \gamma=0.99 )、( \lambda=0.95 )。这不是什么玄学,而是经过大量实验后的常见合理默认值。
5. 实践中的七大典型翻车场景与对策
5.1 奖励范围没归一化,梯度直接爆炸
刚上手策略梯度的人最容易踩的坑,就是直接把环境给的原始奖励丢进优势计算。如果奖励数值动辄上千,而策略网络的激活函数输出范围有限,那么这个巨大的梯度信号会在反向传播里急剧放大,整个网络参数一次更新就飞到外太空。
对策很简单:在训练开始时收集一批轨迹,计算奖励的均值和标准差,然后把奖励标准化到零均值单位方差附近。注意不能用全局统计量,要用当前batch的在线统计,否则会引入信息泄漏。更彻底的做法是对优势值做标准化——即使原始奖励分布不合理,优势标准化也能让训练稳定很多。
5.2 折扣因子 ( \gamma ) 拍脑袋设错
( \gamma ) 决定了智能体"看得多远"。设得太小(比如0.9),智能体只顾眼前利益,很难学会需要长期规划的任务;设得太大(比如0.9999),方差会急剧上升,因为远期的奖励波动被持续累加。我习惯先看任务的时间尺度:如果单条轨迹长度不超过几百步,( \gamma=0.99 ) 基本够用;如果轨迹上万步,可能需要 ( \gamma=0.995 ) 甚至更高,同时要配合更强的方差抑制手段(GAE的 ( \lambda ) 调低一点)。
5.3 策略网络输出的标准差直接退化到0
连续动作空间里,策略通常建模成高斯分布,输出均值和标准差。训练初期如果学习率不当,标准差会快速收缩到接近0。此时策略退化成确定性策略,看起来好像"学到东西了",但其实是灾难——模型失去了探索能力,一旦当前策略不是全局最优,它就永远困在局部最优里出不来。
对策是给标准差设置一个下界(比如0.1),或者使用熵正则项,把策略的熵加到损失函数里一起优化。熵正则的系数不宜过大,否则策略会一直保持高随机性,学不到有效动作。我一般从0.01起步,如果发现熵降得过快就适当提高。
5.4 网络容量和气馁:Actor和Critic失衡
我在项目里见过很多次:Critic网络太小,价值估计不准,优势函数到处都是噪声;或者Actor网络比Critic大太多,策略学得快但价值函数完全跟不上,导致策略更新基于错误的方向判断。
经验法则:Critic网络容量应不低于Actor,通常取相同结构或稍大一点。因为价值函数是策略学习的"老师",老师水平太差,学生学得再好也没用。另外,Critic的更新可以使用更大的学习率,因为它是一回归任务,损失信号相对平滑,学得快一点反而有助于优势估计跟上策略变化。
5.5 过时数据继续用:策略与环境脱钩
策略梯度算法在理论上要求数据来自当前策略(on-policy)。但实际中,很多人图省事,把旧轨迹存入缓冲区反复训练,这会带来严重的分布偏移——旧数据对应的优势值是基于旧策略算的,新策略下这些优势已经不再准确。用错误信号更新新策略,轻则训练震荡,重则完全发散。
这和DQN里的经验回放完全是两回事。我在工程实践中严格遵守:PPO每一轮迭代用当前策略采集一批数据,更新后这批数据直接丢弃,不用作多轮训练。如果做大规模分布式训练,就通过replay buffer的容量和采样策略来缓解,但核心原则不变——更新时的数据必须尽量接近当前策略。
5.6 采样轨迹长度不足,梯度估计噪声淹没信号
不少人喜欢设很小的batch size(比如几十条轨迹)就开始训练。策略梯度的梯度估计本来方差就大,batch太小时,几条好运轨迹可能把整个梯度方向带偏。一个实用的经验是:至少保证每条更新迭代有几千到几万个状态-动作对(取决于任务复杂度),连续控制任务中我用2048到4096,复杂任务甚至上万。
5.7 只盯训练曲线,忽略行为可视化
训练奖励曲线不是唯一指标。有时奖励曲线一直上涨,但实际行为完全不对——这通常是奖励函数设计有隐藏漏洞。我在每个项目里都会定期把策略采样的轨迹渲染出来看,观察动作是否符合直觉。这一招救了我很多次,比任何曲线监控都管用。
6. 我的调参笔记:一整套可以直接照抄的实操建议
6.1 一份通用的训练超参数模版
以下是我跑PPO类算法时起步用的参数组合,可直接套用到大多数连续控制任务:
| 参数 | 取值 | 备注 |
|---|---|---|
| ( \gamma ) | 0.99 | 任务时间尺度大时调到0.995-0.999 |
| GAE ( \lambda ) | 0.95 | 方差高时降到0.9 |
| PPO clip ( \epsilon ) | 0.2 | 复杂任务可降到0.1 |
| 学习率 | 3e-4 | Adam,Actor和Critic可分别设 |
| 每轮更新次数 | 10 | 过多会导致过拟合当前batch |
| batch size | 2048 | 复杂任务增大 |
| 熵正则系数 | 0.01 | 熵降太快时增大 |
| 隐藏层 | 256x2 | 从MLP起步 |
| 标准差下界 | 0.1 | 防止探索退化 |
6.2 训练过程的监控指标
不要只盯着episode reward一条曲线。我训练时至少同时看几样东西:
- 策略熵:应当缓慢下降但保持正值。快速归零说明探索崩溃。
- KL散度:新旧策略之间的KL在每轮更新后应保持在小范围内(比如0.01-0.05)。KL太大说明学习率过高或clip约束失效。
- 价值函数损失:应当稳定下降,如果剧烈波动,检查优势标准化和GAE参数。
- 接受比率(rewards vs. 预测价值):如果优势估计经常出现极端值,说明Critic还没学好,此时降低学习率重来比硬着头皮继续更明智。
6.3 不同任务的调参倾向
离散动作空间(比如Atari游戏)和连续动作空间(比如机器人控制)的调法差异很大。离散场景里,策略是Categorical分布,熵正则的系数通常比连续场景更重要;连续场景里则要密切关注标准差下界,否则探索崩得更快。稀疏奖励任务里,我倾向调低 ( \gamma ) 或者把GAE ( \lambda ) 调低,让学习信号更聚焦于近期奖励——因为远期奖励几乎全是噪声。
6.4 从失败到成功的调试顺序
如果从头开始一个新环境,我不会一上来就追求最先进算法,而是按这个顺序排查:
- 先用随机策略采样,确认奖励范围合理、轨迹长度正常。
- 跑一个最简单的REINFORCE+Baseline,验证梯度链路没有bug。
- 升级到Actor-Critic,确认价值函数能拟合回报。
- 最后上PPO+GAE,调参优化样本效率。
这四步踩稳了再谈加速和扩展。很多人直接从PPO开始,一旦不收敛,很难分清到底是算法实现bug、超参问题、还是环境本身设计的问题。从简到繁的调试路径虽然慢,但每一步都有确定的信号,能大幅缩短排查时间。
6.5 工程实现的细节提醒
最后说几个写代码时容易忽略但影响巨大的细节:
- 保存模型时一定要保存随机数生成器的状态,否则恢复训练时探索行为完全对不上。
- 计算GAE时要按轨迹维度处理,不能把不同轨迹的数据混在一个tensor里做末位累加,否则时间顺序全乱。
- 对策略输出的logits做数值稳定性处理(如减去最大值再算softmax),避免出现过大的log-prob导致梯度溢出。
- 分布式训练时注意数据并行和模型并行的区别——策略梯度通常是数据并行,每个worker采集数据、中心节点更新参数,通信频率要权衡好。
- 跑长轨迹任务时记得设上限步数,防止智能体卡在某个状态里无限循环,浪费训练时间。
我在实际项目中最深的体会是:策略梯度这套方法,数学上并不算复杂,真正的复杂性全部藏在工程细节和方差控制里。能跑通的代码到处都是,能稳定跑通、还能在陌生任务上快速调出好效果的经验,才是这个领域真正的门槛。希望这篇文章能帮你少走我当年走过的那些弯路。最后再分享一个小技巧——每次训练前,把随机种子固定一组、每组多跑几次取中位数结果,你会省下非常多"看着像改进其实是运气差异"的纠结时间。