第五课下半部分学完了,这一部分的内容密度比前面几课都要高。如果说上半场还在围绕价值函数和DQN的各种变体打转,下半场真正切入了策略优化的核心命题:不学价值函数,能不能直接优化策略本身?答案是能,而且这条路最终通向现代强化学习的主流范式。这一篇笔记我会把课程里讲到的策略梯度定理、REINFORCE算法、baseline的作用,以及Actor-Critic这条演进主线完整梳理一遍,并补上我自己在复现过程中踩过的坑和验证过的细节,希望能给同样在啃这门课的朋友提供一份能“抄作业”的参考。
1. 第五课下半部分整体脉络与核心定位
1.1 从价值函数到策略梯度的思路转向
课程前半部分一直围绕“值函数”展开——Q-learning、DQN、Double DQN、Dueling DQN,思路都是先学出一个打分器,再根据打分器选动作。这一套在离散动作空间里很自然,但到了连续动作空间就开始吃力了。比如控制一个机械臂,动作是七个关节的力矩,每个维度都是连续值,你没法枚举所有动作去取最大值。你可以用DDPG这类方法让网络输出最优动作,但更直接的做法是:干脆让神经网络自己输出动作分布,然后用梯度下降直接提升好动作的概率。
这就是策略梯度方法的基本出发点。第五课下半部分的第一层逻辑就是把“学价值”和“用价值”合并成了一个过程——策略网络直接接受状态作为输入,输出动作的概率分布,我们通过调整网络参数,让那些带来高回报的动作被采样的概率变大,低回报的动作概率变小。
这一步转向的意义在于:策略梯度是on-policy方法,天然适合连续动作和随机策略,后面所有进阶方法(TRPO、PPO、A3C、SAC)都是在策略梯度这条主线上做改进。所以这一课是整个强化学习课程的分水岭,理解充分了,后面会顺利很多。
1.2 这一部分在整个“10周强化学习纲要”中的位置
粗略看整个课程安排,前四课是基础建模和动态规划、蒙特卡洛与时序差分,第五课上半场是值函数逼近和DQN族,第五课下半场则是策略优化。你可以把第五课下半部分看作一个承前启后的枢纽:承前是之前所有的价值函数思想都会以“critic”的形式继续存在;启后是策略梯度和Actor-Critic架构会直接服务于第6到第9课那些大名鼎鼎的算法。
从学习笔记的角度说,这一部分有四个必须吃透的落点。第一是策略梯度定理的来龙去脉和推导直觉;第二是REINFORCE算法的完整流程,尤其是reward-to-go的理解;第三是baseline为什么能减小方差而不改变期望;第四是从REINFORCE到Actor-Critic的演进动机。把这四件事串起来,策略优化这一章的骨架就算立住了。
1.3 适合谁重点阅读这一部分的笔记
如果你正在跟着这门课自学,第五课下半部分可能是第一个让你需要反复回看的地方。前面几课你只要有动态规划或者监督学习的基础,基本能顺畅走下来,但策略梯度涉及概率分布、期望、方差这些统计概念,推导又多,很容易看着看着就丢了主线。这份笔记会把课程里看起来“跳跃”的地方拆开揉碎,适合正在学第五课但有些卡壳的读者。同时,如果你想在CartPole、HalfCheetah这类环境上亲手实现一个策略梯度算法,这篇文章里关于reward-to-go和baseline的细节应该能帮你少走不少弯路。
2. 策略梯度定理:核心直觉与关键推导
2.1 为什么要用“期望回报的梯度”而不是“回报的梯度”
课程里直接给出了策略梯度的目标函数——最大化期望回报,对参数求梯度。但第一次看这里的人很容易犯迷糊:既然一个episode的回报可以直接算出来,为什么不能直接对这条轨迹的回报求梯度?
关键问题在于:一条轨迹的回报是环境动态、动作采样和策略参数共同作用的结果。环境动态你不知道(或者说不需要知道),动作采样又是一个随机过程,如果只是简单地“跑一条轨迹,算回报,然后反向传播”,梯度根本传不到策略网络的参数上去,因为你没法对“随机采样”这个操作求导。这就像你在一个随机路口左转得到了奖励,你想把“左转”这个行为固化下来,但问题是“左转”本身是一个随机事件,你没法直接用梯度告诉网络“多左转一点”。
策略梯度定理解决的就是这个麻烦。它通过对“动作的对数概率”求梯度,巧妙地绕开了对环境和采样过程求导的问题,把“提高好动作概率”这个目标转化成了一个可以直接反向传播的形式。
2.2 log trick:从期望到梯度的关键一步
课程推导里最核心的一步就是利用恒等式:
∇θ πθ(a|s) = πθ(a|s) · ∇θ log πθ(a|s)
这个公式初看平淡无奇,其实就是把对概率本身求梯度,换成了对概率的对数求梯度再乘回原概率。但它带来的效果是决定性的:原来的∇θπθ(a|s)不能直接和“回报”相乘后求期望,因为你手头只有一个采样的回报,不是一个完整分布的积分;但改写之后,∇θlogπθ(a|s)这个量可以直接在采样出来的动作上计算,再利用πθ(a|s)作为权重去近似期望。
换句话说,log trick让我们可以从“采样”中学习。你不需要算所有动作的概率加权和,只需要用“这次实际采到的动作”的梯度乘上“这次动作带来的总回报”,就可以得到目标函数梯度的无偏估计。这是一个典型的蒙特卡洛估计套路,后面Actor-Critic也仍然沿用这个框架。
2.3 理解策略梯度定理的两种视角
学这一部分我建议用两种视角对照理解,能避免死记公式。
第一种视角是“加权最大似然”。正常做监督学习时,我们是在给定输入和标签后最大化正确类别的对数概率。策略梯度本质上也在做类似的事,只不过标签不再是外部给定,而是由“这次动作产生的回报”决定:回报高的动作,相当于给了一个高权重的标签,让网络更容易“学习”这个动作;回报低甚至为负的动作,权重也为负,让网络远离它。这样策略梯度就变成了一个回报加权的最大似然估计。
第二种视角是“用梯度上升去调整分布”。我们可以把策略想象成一组骰子的参数,梯度告诉我们:如果这次动作得到的回报是正的,就朝让这个动作概率增大的方向挪动参数。问题只在于“挪多少”。REINFORCE算法回答的是“回报是多少就挪多少”,Actor-Critic回答的是“回报高出平均多少就挪多少”,这直接引出下一层内容。
3. REINFORCE算法:流程拆解与实操要点
3.1 完整流程与每一步在做什么
REINFORCE是最朴素的策略梯度实现,课程里给了流程,我按实际写代码时的逻辑重新组织了一下:
第一步,初始化策略网络参数。网络输入是状态,输出是各动作的概率,一般最后一层用Softmax(离散动作)或者高斯分布的均值和方差(连续动作)。
第二步,用当前策略采样一整条轨迹。从初始状态开始,每一步都按策略网络输出的概率采样动作,和环境交互,记录每一步的状态、动作、奖励,直到终止状态。
第三步,计算每一步的累积回报。这一步有个关键设计,课程里特别强调了:用“从当前时刻到episode结束的累计奖励”而不是“整条轨迹的总奖励”。前者的名称是reward-to-go,后者是full-trajectory return。这也是实现中第一个容易出问题的地方。
第四步,把累积回报看作权重,计算每一步动作的log概率梯度,加权后求和,得到策略梯度的估计值。
第五步,用这个梯度做一次梯度上升更新。注意是上升,不是下降,因为我们在最大化期望回报,但实际PyTorch/TensorFlow里的优化器都是做最小化的,所以实现时一般把目标函数写成负的。
3.2 reward-to-go与完整return的区别
这一小节值得单独拎出来说。
课程在推导理论公式时,用的是整条轨迹的回报,这是从数学定义出发的无偏估计。但在实际实现时,应该使用reward-to-go。原因很简单:某个时刻之前已经发生的奖励,不会因为当前动作而改变,它对于当前动作的梯度贡献只是一个常数,放进期望里不会影响梯度的方向,但会显著增加方差。试想一个动作发生后还要跑100步才结束,这100步的奖励全都压在这个动作的梯度上,早、中、后期的动作都用同一个总回报去加权,梯度噪声自然大得多。
我当时在CartPole上做过一个对照实验:一组用整条轨迹总回报,一组用reward-to-go。结果前者的收敛速度慢了很多,而且训练曲线抖动明显更剧烈,有时候明明已经学到不错的表现了,下一次更新又能把策略拉回很差的区域。换成reward-to-go之后,训练曲线稳定了很多,收敛步数大概能减少三分之一。
课程笔记里写得很简洁,但这一步实现上的细节直接决定了算法能不能在合理时间内收敛。强烈建议第一次实现REINFORCE时就把reward-to-go做对。
3.3 从实现角度看方差问题
REINFORCE的一个显著问题是方差大。本质上,你是在用一次采样结果去估计一个期望,单次采样的噪声全部进入了梯度。在实际操作中,这种高方差会表现出几个症状:训练曲线像心电图、明明跑出了高回报的episode下一次策略却变差了、调学习率非常敏感。
降低方差有几个常用手段。第一个是增加batch size,多跑几个episode把梯度平均一下,这是最简单也最有效的做法。第二个就是用baseline。第三个是用折扣因子,让远处奖励对当前动作的影响衰减,这不仅符合直觉,也能有效降低方差。课程里反复强调折扣因子是避免无穷累积奖励的数学工具,但从实验角度看,它在方差控制上的作用也非常明显。
4. 深入理解baseline:为什么不影响期望却能减小方差
4.1 从“回报”到“优势”的关键转变
课程讲解baseline时,核心结论是:从累积回报里减去一个只与状态有关的量b(s),梯度期望不变,但方差会减小。这个b(s)最自然的选择就是状态价值函数V(s),这样累积回报减去V(s),得到的就是“实际回报比预期好多少”,这就是优势函数(advantage function)的概念。
这一步理解起来不难,但很值得琢磨。想一想如果没有baseline,一个状态本身就很适合生存,随便做什么动作都能拿到高回报,那所有动作的梯度都是正的大权重,网络就分不清到底是“状态好”还是“动作好”。减去V(s)之后,“状态好”这部分被剔除了,留下的只是动作带来的额外好(或坏),策略网络的更新就有了方向感。
4.2 常数的baseline与状态相关的baseline
减少方差的一个简单做法是使用一个常量baseline,例如取所有轨迹回报的平均值。这个做法在课程推导里比较容易理解,但它只能消除整条轨迹层面的均值偏移,没法解决“某些状态天然回报高”带来的混淆。状态相关的baseline,也就是V(s),更精细——它在每一个时间步都做一次归一化,把“这个状态按理说能拿多少回报”的先验知识直接减掉。
我实际测试下来,常值baseline的提升效果大约只有状态baseline的一半。如果只是交作业,常值baseline足够;如果想让算法在更复杂的任务上真正跑出效果,状态baseline几乎是必需品。
4.3 baseline对梯度估计的修正效果
从方差分解的角度看,策略梯度的方差主要来自于两个方面:一是动作采样的随机性,二是回报的随机性。baseline主要抑制的是后者。你可以想象每个时间步的回报是“真实优势函数加上一个均值不为零的噪声”,baseline就是把这个均值估计出来并减掉,让剩下的噪声围绕零附近波动。这样一来,正负梯度互相抵消的机会更多,累计梯度的方差自然下降。
注意:实际实现baseline时,如果用另一个网络来估计V(s),那么它和策略网络会交替更新,形成Actor-Critic的雏形。但如果两个网络使用同一个参数或共享大量底层特征,更新时容易出现互相干扰。课程里这部分没有展开,但这是我在之后实现中遇到的问题,后面会专门讲。
5. Actor-Critic:从蒙特卡洛到时序差分的自然演进
5.1 单独训练critic网络的意义
从REINFORCE到Actor-Critic,看似只是把baseline换成了一个可学习的神经网络,但背后是一个方法论的改变。REINFORCE是蒙特卡洛方法,必须跑完一个episode才能更新一次,学习速度慢,方差高;而Actor-Critic引入了critic网络,可以随时给出当前状态的预估价值,于是策略更新就可以借助时序差分(TD)思想,做到“走一步更新一步”,不用再等episode结束。
Critic在这个架构里做的事,就是“带基线状态价值网络的实时评估员”。它的输入是状态,输出是该状态的期望回报预估。这个预估虽然在训练初期可能非常不准,但随着critic网络的误差不断被TD目标校正,它提供的信息会越来越接近真实价值函数,从而让advantage估计越来越准确。
换一种更容易理解的说法:REINFORCE是“考完试再对答案”,Actor-Critic是“做一题看一题解析”。后者反馈频率更高,样本利用率自然就高。
5.2 Actor网络和Critic网络的分工与互动
Actor和Critic的分工很清晰——Actor负责输出策略(动作概率分布),Critic负责评估状态好坏。互动方式是:Actor每走一步,Critic给一个打分;Actor根据这个打分调整自己的动作概率;而Critic的打分标准又根据环境反馈的实际奖励不断校准。
这种分工有一个潜在风险:两个网络有可能陷入“互相欺骗”。Actor如果采取了某种策略,Critic会根据这个策略产生的数据调整自己对价值的估计,但如果Critic的估计有偏,Actor又会根据这个有偏的估计调整策略,最终两者可能一起漂移到局部最优。课程里给的解决思路本质上是通过TD误差来更新critic,让critic始终锚定在真实环境反馈上,从而抑制这种漂移。
5.3 从one-step到n-step:反馈步数选择问题
实现Actor-Critic时,一个绕不开的选择是critic更新时用多长时间跨度的回报。用一步TD(只看下一步的奖励加下一状态的价值)方差低但偏差可能较大;用蒙特卡洛式完整回报偏差低但方差大。n-step介于两者之间,通过调整n来控制偏差和方差的相对权重。
我个人的实践结论是:在类似CartPole这种episode比较短、奖励信息密度较高的环境里,一步TD加上合适的折扣因子就能工作;但在更复杂、奖励稀疏的环境里,一步TD会让critic学得比较慢,n-step(比如n=8或n=16)往往能带来更稳定的提升。这个参数值得在项目里做几次对照实验,非常划算。
6. 策略梯度实现中反复踩到的实践坑
6.1 学习率与梯度裁剪的敏感性问题
策略梯度算法对学习率的敏感程度,比监督学习高出很多。监督学习里,一次更新学过头了,下次迭代还能修正回来;策略梯度里,一次更新如果步子迈太大,策略就可能坍缩到“只会输出一种动作”的状态,而这个动作如果恰好是较差的动作,再想跳出来就非常困难。
我自己在HalfCheetah上复现策略梯度时,learning rate从3e-4调到1e-3,前者的训练曲线平稳上升,后者直接在前几百步内把策略梯度冲到一个“只会原地转圈”的区域,后面再也无法恢复。建议做两件事:一是用一个非常保守的学习率起步,二是加梯度裁剪或最大梯度范数限制,保证每步更新的幅度可控。
6.2 策略熵正则的意外作用
课程里在讲探索与利用时提过熵正则,但很多人在实现时觉得这是锦上添花,实际上它是防止策略过早坍缩的重要保障。策略的熵衡量的是输出分布的随机程度。容易坍缩时,网络会迅速把某些动作的概率推到接近1,其他动作概率接近0。此时梯度信号几乎为零,因为log概率的梯度在这种极端分布下非常小,网络就处于“想学但学不动”的停滞状态。
给目标函数加一项熵正则(比如减去β乘以熵),就能给策略分布一个“保持随机性”的牵引力。这就像谈判时给自己留一条退路,让策略不会一头扎进某个动作。这个技巧在早期训练阶段尤其重要,建议β值从0.01开始调。
6.3 经验数据的相关性问题和on-policy约束
策略梯度更新的数据来自当前策略的采样,一旦网络参数更新,之前采的数据就“过期”了——它们是旧策略产生的行为分布,严格来说是off-policy的。课程里提到这个问题时,强调的是重要性采样修正,但实际项目中更常见的做法是“用一轮更新一批数据,用完就丢”。
这一点和DQN的experience replay机制形成鲜明对比。DQN可以反复回放历史数据,因为Q函数不直接依赖策略;而策略梯度必须谨慎对待数据新鲜度,重放旧数据容易导致策略朝错误方向优化。这也是为什么Actor-Critic类算法通常需要一个专门的采样器进程,边采样边更新,保证数据尽可能新鲜。
7. 从第五课出发:通往现代强化学习算法的衔接与延展
7.1 策略梯度与Q-learning的统一视角
课程学到这一步,一个自然的问题是:策略梯度和Q-learning,到底哪种更好?其实它们本来就是从两个角度解决同一个问题。Q-learning利用贝尔曼方程反复迭代,学一个精准的价值函数,再用价值函数推导策略;策略梯度则直接参数化策略,用回报加权最大似然的方式优化。
两者各有所长。Q-learning对离散问题和样本利用率高的场景更有利;策略梯度在连续动作、随机策略需求、以及策略本身的参数化更为灵活的场合几乎不可替代。现代算法往往把两者结合——用价值函数做基线和critic,用策略网络做优化目标,这就是Actor-Critic思想的延伸。
7.2 为TRPO和PPO做的知识准备
第五课下半部分讲到的方差问题、更新步长问题、on-policy约束问题,在TRPO和PPO中有系统的解决方案。TRPO用KL散度约束限制每次更新的步长,防止策略因为一次大步更新而坍缩;PPO则用裁剪目标函数实现类似效果,但计算量更小、实现更简单。如果第五课的策略梯度部分你没学扎实,后面看到PPO的裁剪公式一定一头雾水。现在打好底子,等于给后面的课程铺好了路。
7.3 reward shaping与任务设计的提醒
最后补充一个课程里提得不多但在实际项目中绕不开的问题。策略梯度的学习信号完全来自奖励函数的设计:如果奖励设计得不合理,比如奖励只在episode结束时才出现,那Reward-to-go的大部分量都是零,梯度信号会非常稀疏,策略几乎学到不东西。对于这类稀疏奖励场景,建议先从奖励塑形入手——给靠近目标的行为提供逐步递进的密集奖励,或者利用课程之一的潜在奖励设定替代方案。强化学习项目里,调reward函数花费的时间经常比调网络结构还多一些,这并不夸张。
8. 学习建议与复现实验的体会
如果你听完了第五课下半部分想要动手跑一个最小实现,我给你一个参考路径:先不要碰任何现成的强化学习库,从零写一个REINFORCE,环境用CartPole。这个环境简单、训练快、反馈明显,非常适合观察算法行为。写完REINFORCE之后再逐步加baseline、加critic、改n-step,一步步看训练曲线的变化,你会对算法每一个改进点的效果有非常直观的感受。
我自己在复现过程中的一个重要体会是:reproduce一个算法,最大的难点往往不是数学推导,而是“理解曲线在说什么”。比如loss上升不一定代表策略在变差,因为策略梯度是最大化目标的过程,曲线形态和分类loss完全不一样。刚开始复现时,我盯着不断下降的“负回报”曲线困惑了很久,后来才意识到这只是目标函数取了负号之后的表现。
课程第五课下半部分的最后还提到,这个方向上未来还有很多工作要做,包括分布式训练、大规模并行采样等工程化议题。这些内容已经超出了本课范围,但如果你跟我一样打算把强化学习应用到实际项目里,后面值得关注的东西还有很多。至少就当前这一课来说,把策略梯度、REINFORCE、baseline和Actor-Critic这四件事彻底吃透,就已经拿到了通向现代强化学习算法的第一张通行证。