强化学习Model Free入门:从Q-Learning到PPO的算法演进与实战
1. 从“无模型”三个字说起为什么它是强化学习入门的必经之路刚接触强化学习那会儿我对“Model free”这个说法一直有点似懂非懂。字面翻译是“无模型”可强化学习本身不就是在训练一个模型吗怎么又“无模型”了后来踩过几次坑、跑废过几个实验之后才慢慢想明白这里的“模型”指的压根不是我们要训练的策略网络而是环境本身的动力学模型——也就是“做了动作A之后状态会怎么变、奖励会拿多少”这套转移规律。把这个概念理清楚很多困惑就迎刃而解了。所谓Model free方法就是我们在训练智能体的时候不去显式地学习或已知环境的转移概率和奖励函数而是让智能体直接跟环境交互从一条条真实的经验轨迹里学“什么状态下该做什么动作”。与之相对的Model based方法则会先想办法把环境“建模”出来再基于这个模型做规划。为什么说Model free是入门的必经之路原因很实在。第一绝大多数真实场景里你根本拿不到精确的环境模型。比如让机械臂抓取一个形状不规则的物体接触力、摩擦、形变这些东西的精确物理方程极其复杂与其费劲去建模不如让智能体自己多试几次。第二Model free的方法逻辑更直接代码实现相对简单特别适合用来建立对强化学习核心概念状态、动作、回报、价值函数的直觉。第三现在工业界大量落地的方案比如游戏AI、推荐系统里的策略优化主力仍然是Model free这一套。这篇文章我打算把Model free这条线从头到尾捋一遍。不是那种教科书式的罗列而是按照我自己学习和实践的顺序把价值函数方法、策略梯度方法、以及两者融合的Actor-Critic框架这几大块讲透。中间会穿插大量我踩过的坑、参数调优的经验以及那些文档里不会写但实际很关键的小细节。如果你刚开始学强化学习或者已经看过一些资料但脑子里还是一团浆糊那这篇应该能帮你把脉络理清楚。2. 价值函数方法从Q表到DQN的进化逻辑2.1 蒙特卡洛与时序差分两种“算账”方式的本质区别要理解价值函数方法得先搞清楚一个核心问题我们怎么估计某个状态到底“值多少钱”。这里的“值钱”就是价值函数V(s)或者动作价值函数Q(s,a)代表从当前状态出发未来能拿到的累计回报期望。最朴素的想法是蒙特卡洛Monte Carlo简称MC。它的逻辑特别像记账我完整地跑完一整局看看从状态s开始到最后总共拿了多少回报然后把这个数字当作V(s)的一个样本多跑几局取平均。这个方法的好处是无偏——只要样本够多估计就会收敛到真实值。但问题也很明显必须等到一局结束才能更新如果是那种没有终点的连续任务直接就歇菜了。而且整局回报的方差很大因为中间任何一步的随机性都会累积到最后的总回报里。时序差分Temporal Difference简称TD就聪明多了。它不需要等一局结束走一步就能更新。核心思想是自举bootstrapping用下一步的估计值来更新当前步的估计值。公式写出来就是V(s) ← V(s) α [r γV(s) - V(s)]这个r γV(s)叫TD目标r γV(s) - V(s)叫TD误差。直观理解就是我本来以为从s出发能拿V(s)结果实际走了一步拿到奖励r到了s而s那边告诉我还能拿V(s)那我修正一下对s的估计。我刚开始学的时候总觉得TD有点“自己骗自己”——用估计值去更新估计值能靠谱吗后来想通了这其实是一种用偏差换方差的权衡。TD估计是有偏的因为依赖当前的估计但方差比MC小得多而且能在线学习、单步更新实用性吊打MC。实际项目里除非是那种回合制特别短、回报方差很小的场景否则基本都是TD系的方法唱主角。这里有个经验之谈TD(0)、TD(λ)这些参数里的λ本质上是在MC和TD之间做插值。λ0就是纯单步TDλ1就退化成MC。实践中λ取0.9左右往往是个不错的折中但具体还得看任务。我做过一个迷宫导航的实验λ0.95比λ0收敛快将近一倍但λ再往上加方差带来的抖动就开始拖后腿了。2.2 Q-Learning与SARSA一个字母之差行为天差地别说到价值函数方法绕不开两个经典算法Q-Learning和SARSA。它们长得几乎一样就差在更新目标上但学出来的策略风格完全不同。Q-Learning的更新目标是Q(s,a) ← Q(s,a) α [r γ max_a Q(s,a) - Q(s,a)]注意那个max。它假设下一步我会选当前估计下最优的动作。这意味着Q-Learning学的是最优策略的价值不管实际执行时用的是什么策略比如ε-greedy探索。这种“离线策略”off-policy的特性让它很灵活可以从历史数据里学也可以边探索边学最优。SARSA的更新目标是Q(s,a) ← Q(s,a) α [r γ Q(s,a) - Q(s,a)]这里用的是实际下一步会执行的动作a而不是max。所以SARSA学的是当前执行策略的价值是“在线策略”on-policy的。这个区别在什么场景下会要命经典例子是悬崖行走Cliff Walking。悬崖边上有一条最优路径但一旦掉下去就吃大惩罚。Q-Learning因为总是按max来更新它会认为悬崖边的状态价值很高因为最优策略下确实能安全通过于是学出来的策略会贴着悬崖走。而SARSA考虑到探索时可能随机乱走掉下悬崖所以它会学得保守一些离悬崖远一点。我实际跑过这个实验Q-Learning收敛后的路径确实更短但更“危险”SARSA的路径绕一点但更稳。如果你的应用场景里探索带来的代价很高比如真实机器人、医疗决策SARSA这种保守风格往往更合适如果是仿真环境里追求最优性能Q-Learning更直接。2.3 DQN让Q-Learning能处理图像输入的三个关键设计Q-Learning用表格存Q值状态一多就爆炸。当状态是图像这种高维连续输入时表格法彻底没戏。DQNDeep Q-Network的思路很自然用神经网络来拟合Q(s,a)输入状态输出每个动作的Q值。但直接把Q-Learning和神经网络拼一起会出大问题。我最早自己试着搭的时候损失曲线跟心电图似的根本不收敛。后来才明白DQN能work靠的是三个关键设计第一个是经验回放Experience Replay。把智能体跟环境交互得到的(s, a, r, s)存进一个缓冲区训练时从里面随机采样batch。这么做解决了两个问题一是打破了样本之间的时间相关性连续的经验高度相关直接拿来训练会让网络在局部数据上过拟合二是提高了样本利用率一条经验可以被反复使用。第二个是目标网络Target Network。如果更新时用的TD目标里的Q(s,a)也是用当前正在训练的网络算的那目标本身在动训练就像追着自己的尾巴跑。DQN的做法是搞一个结构相同但参数更新滞后的目标网络每隔C步把主网络的参数复制过去。这样一段时间内目标相对稳定训练就稳多了。第三个是奖励裁剪Reward Clipping。DQN那篇经典工作里把奖励统一裁剪到[-1, 1]区间。这招在当时是为了让不同游戏用同一套超参数但副作用是丢失了奖励的绝对大小信息。现在很多实现里已经不强制裁剪了但如果你发现Q值爆炸裁剪一下往往能救急。这里分享一个我踩过的坑经验回放缓冲区的大小很关键。太小了样本多样性不够容易过拟合最近的经验太大了旧的经验可能跟当前策略差太远反而拖累学习。Atari游戏上常用的100万条对大多数任务来说太大了我做过的一些连续控制任务10万条左右效果就不错。这个值得你根据自己的任务多试几组。3. 策略梯度直接对策略“动刀”的思路3.1 为什么有了价值方法还需要策略梯度价值函数方法有个隐含的假设策略是从价值函数里“导出”的比如ε-greedy或者直接取argmax。这在离散动作空间里没问题但遇到连续动作就尴尬了——你没法对连续动作求argmax总不能把动作空间离散化吧维度一高就组合爆炸。策略梯度方法换了个思路直接参数化策略π(a|s; θ)然后想办法调整θ让期望回报变大。这样一来连续动作空间天然支持网络直接输出动作分布的参数比如高斯分布的均值和方差而且策略可以是随机的这在需要探索或者博弈场景里很重要。从数学上看策略梯度的核心是策略梯度定理∇J(θ) E[∇log π(a|s; θ) * Q(s,a)]这个公式的直观理解是如果某个动作带来的回报高就增大它被选中的概率回报低就减小。∇log π给出了“怎么调参数能让这个动作概率变大”的方向Q值则告诉我们这个动作到底好不好。我第一次看到这个公式的时候觉得挺神奇后来用“似然比”的角度理解就顺了。它本质上是一种得分函数估计器用采样来估计梯度的期望不需要知道环境模型也不需要可微的环境通用性极强。3.2 REINFORCE的方差问题与基线技巧最基础的策略梯度算法是REINFORCE它用整条轨迹的回报G_t来估计Q(s,a)。实现简单到令人发指跑完一局算每一步的回报然后按∇log π * G_t做梯度上升。但REINFORCE有个致命问题方差巨大。因为G_t是整条轨迹的累计回报中间任何随机性都会影响它。我最早跑CartPole的时候REINFORCE要几千局才能稳定而且不同随机种子跑出来的曲线能差出好几倍。解决方差问题的第一个利器是引入基线Baseline。把更新量从∇log π * G_t改成∇log π * (G_t - b(s))其中b(s)是只依赖状态不依赖动作的基线。数学上可以证明这不会引入偏差但能显著降低方差。最常用的基线就是价值函数V(s)这样G_t - V(s)就变成了优势函数A(s,a)的估计衡量的是“这个动作比平均水平好多少”。这个技巧的效果立竿见影。我在同一个任务上对比过加基线之后收敛速度大概提升了3到5倍而且曲线平滑多了。基线本质上是在做“相对评价”而不是“绝对评价”这跟人类学习的直觉也一致——我们更关注“比预期好还是差”而不是绝对分数。另一个降低方差的技巧是奖励折扣与归一化。把回报做标准化减均值除标准差在实践中几乎总是有益的尤其是奖励尺度差异大的任务。还有因果性技巧t时刻的更新只应该用t时刻之后的回报因为之前的奖励跟当前动作无关。这个在实现时体现为对回报做反向累积而不是简单求和。3.3 从REINFORCE到PPO重要性采样与信任域REINFORCE是离线策略的吗严格说它是在线策略的——每次更新后策略变了旧数据就不能用了得重新采样。这导致样本效率极低。要复用旧数据就得用重要性采样E_{π_θ}[f] E_{π_old}[ (π_θ/π_old) * f ]但重要性采样的方差会随着新旧策略差异变大而爆炸。TRPOTrust Region Policy Optimization的思路是限制新旧策略之间的KL散度在这个约束下最大化改进。它理论上漂亮但实现复杂要算Fisher信息矩阵、做共轭梯度调起来也麻烦。PPOProximal Policy Optimization是TRPO的实用简化版现在几乎是策略梯度方法的默认选择。它的核心是裁剪的重要性采样比L min( ratio * A, clip(ratio, 1-ε, 1ε) * A )当ratio偏离1太多时梯度就被截断了相当于软性地限制策略更新幅度。这个设计简单、稳定、效果好我在好几个项目里用PPO都是“开箱即用”的感觉超参数不敏感ε取0.1到0.2之间基本都行。不过PPO也不是万能的。它属于在线策略方法样本效率仍然不如离线的价值方法。而且它对优势估计的质量比较敏感实践中一般用GAEGeneralized Advantage Estimation来算优势λ取0.95左右。如果你的任务采样成本很高比如真实机器人PPO可能不是最优选择但如果是仿真环境PPO的稳定性和易用性很难被替代。4. Actor-Critic把价值方法和策略梯度拧成一股绳4.1 AC框架的分工逻辑演员与评论家Actor-CriticAC框架的思路特别符合直觉Actor演员负责选动作Critic评论家负责评价动作好不好。Actor就是策略网络π(a|s; θ)Critic就是价值网络V(s; w)或Q(s,a; w)。Actor根据Critic的评价来调整策略Critic则根据实际回报来修正自己的评价。这个分工解决了纯策略梯度方差大的问题——Critic提供的优势估计比整条轨迹的回报稳定得多。同时也解决了纯价值方法难以处理连续动作的问题——Actor直接输出动作分布。我第一次把AC跑通的时候感觉像是找到了强化学习的“标准答案”。但很快发现AC的训练稳定性是个大问题。Actor和Critic同时在学Critic估计不准的时候Actor会被带偏Actor变了之后Critic又得重新适应两者容易陷入恶性循环。4.2 A2C与A3C同步与异步的工程取舍A2CAdvantage Actor-Critic是AC的一个直接改进用优势函数A(s,a) Q(s,a) - V(s)来指导Actor更新同时用n步回报来平衡偏差和方差。实现上通常是同步并行——开多个环境同时采样凑够一个batch一起更新。A3CAsynchronous Advantage Actor-Critic则是异步并行——多个线程各自跟自己的环境交互各自算梯度异步地更新全局参数。这个设计当年很惊艳因为异步带来的探索多样性让训练更稳而且不需要经验回放各线程的经验天然去相关。但实际用下来A3C的异步更新会带来梯度陈旧的问题——某个线程算梯度的时候用的是旧参数等它更新的时候全局参数已经变了好几轮。A2C虽然看起来“笨”一点同步等待但梯度总是基于最新参数反而更稳。现在很多实现里A2C的性价比其实高于A3C尤其是配合GPU并行环境的时候。我自己的经验是如果环境本身很快比如简单的控制任务A2C同步并行的效率更高如果环境很慢或者异构比如不同难度的任务混在一起A3C的异步特性可能更有优势。但总体来说现在新项目我基本都直接从PPO起步它本质上是A2C加上信任域约束的进化版。4.3 GAE优势估计的偏差-方差调节旋钮GAEGeneralized Advantage Estimation是AC框架里绕不开的一个技术点。它用指数加权的方式把不同步数的TD误差组合起来A_t^GAE(γ,λ) Σ (γλ)^l * δ_{tl}其中δ是TD误差。λ0时退化成单步TD误差低方差高偏差λ1时接近蒙特卡洛回报高方差低偏差。λ这个参数就是调节偏差-方差权衡的旋钮。实践中λ取0.92到0.98之间最常见0.95是个万能起点。我做过一个对比实验在连续控制任务上λ0.95比λ0.9和λ0.99的样本效率都高收敛也更稳。但这个值跟任务的时间跨度有关——如果任务里关键决策的间隔很长λ可能需要调大一点让优势估计能看到更远的未来。GAE的实现有个容易出错的细节反向累积。因为A_t依赖A_{t1}必须从轨迹末尾往前算。我最早写的时候正着算结果优势全是错的训练完全不收敛排查了半天才发现是这个低级错误。这个坑值得每个刚上手的人注意。5. 实操中的那些坑从理论到跑通的最后一公里5.1 超参数敏感度学习率、折扣因子与网络结构强化学习对超参数极其敏感这是它跟监督学习最大的区别之一。监督学习里学习率差个几倍可能只是收敛快慢的问题强化学习里学习率大一点直接导致策略崩溃。学习率方面策略网络和价值网络的学习率往往需要分开设。我的经验是策略网络的学习率通常要比价值网络小因为策略更新太激进容易把好不容易学到的行为毁掉。常见配置是策略网络3e-4价值网络1e-3。但这只是起点具体任务得调。折扣因子γ决定了智能体看多远。γ0.99意味着大约100步的视野γ0.999就是1000步。如果任务需要长期规划比如迷宫寻路γ得设大如果任务短平快γ小一点反而学得快。有个经验公式是γ ≈ 1 - 1/TT是任务的典型步数。但这不是铁律还是得试。网络结构上策略网络和价值网络可以共享底层特征提取层也可以完全分开。共享的好处是特征复用、参数少、学得快坏处是两个目标可能冲突互相干扰。我一般先试共享如果训练不稳再改成分开。对于图像输入CNN是标配对于低维状态两三层全连接每层64到256个单元通常就够了。别一上来就堆很深的网络强化学习里网络越大越难训。5.2 奖励设计与归一化智能体到底在学什么奖励函数是强化学习里最“玄学”的部分。理论上只要奖励设计得合理任何方法都能学到东西但实践中奖励设计不好再好的算法也白搭。最常见的坑是稀疏奖励——只有任务完成才给奖励中间过程全是0。这种情况下智能体很难学到东西因为随机探索几乎不可能碰巧完成任务。解决办法有几种一是奖励塑形在中间过程给一些引导性的小奖励二是课程学习从简单任务开始逐步加难度三是事后经验回放把失败轨迹重新标注成“如果目标是实际到达的状态那这条轨迹就是成功的”。奖励归一化也很关键。如果奖励尺度差异很大比如有的步骤奖励是0.1有的是100价值网络很难拟合。我一般会维护一个奖励的滑动均值和标准差做在线归一化。这招在连续控制任务里几乎是必备的。还有个容易忽略的点是奖励的时间尺度。如果每一步都给正奖励智能体可能学会“磨洋工”——故意拖长回合来累积奖励。这时候要么给每步加个小的负奖励时间惩罚要么用折扣因子让远期奖励贬值。这个坑我在一个导航任务里踩过智能体学会了在原地转圈因为转圈也能拿奖励。5.3 训练不收敛的排查清单训练不收敛是强化学习日常我总结了一套排查顺序基本能覆盖八成问题第一步看数据。把智能体的轨迹打印出来看看它到底在干什么。很多时候问题一目了然——比如动作全是同一个值策略塌缩了或者状态归一化没做导致输入尺度爆炸。第二步看价值估计。把V(s)的预测值和实际回报画在一起。如果两者差很远说明Critic没学好这时候Actor的更新就是基于错误信息的。可以先冻结Actor只训Critic等Critic靠谱了再放开。第三步看梯度。梯度爆炸或消失是常见问题。梯度裁剪clip grad norm几乎是标配一般裁到0.5到1.0之间。如果梯度一直很小可能是网络太深或者激活函数选得不好。第四步看超参数。学习率、batch size、GAE的λ、PPO的clip范围这些都得试。我一般会做小规模的网格搜索每个配置跑几个随机种子看均值和方差。第五步看随机种子。强化学习的随机性极大不同种子跑出来的结果可能天差地别。永远不要用单个种子的结果下结论至少跑3到5个种子取平均。我见过太多“调了半天发现只是种子运气好”的情况。5.4 评估与复现别被单次结果骗了最后说说评估。强化学习的评估跟监督学习很不一样因为策略在训练过程中不断变化而且环境本身有随机性。评估策略时要用确定性策略比如取动作分布的均值或argmax而不是训练时的随机策略。否则评估结果会被探索噪声干扰。同时要在独立的环境实例上评估不能拿训练用的环境来测否则就是自己考自己。复现性方面固定随机种子是基础但还不够。深度学习框架的某些操作比如GPU上的某些卷积本身有非确定性要完全复现得开deterministic模式但这会拖慢训练。我的建议是开发阶段固定种子方便调试最终报告结果时跑多个种子给出统计。还有个实用技巧是定期保存检查点并且记录每个检查点的评估性能。强化学习经常出现“中期表现最好后期反而退化”的情况过拟合或者策略塌缩。有了检查点你至少能回滚到最好的版本而不是眼睁睁看着模型越训越差。6. 写在最后Model free的边界与我的使用心得Model free方法撑起了强化学习落地的大半壁江山但它不是没有边界。样本效率低是它最大的软肋——DQN在Atari上要玩几千万帧才能达到人类水平而人类可能几十分钟就学会了。这个差距在真实物理系统里是致命的因为采样成本太高。所以现在一个明显的趋势是Model free和Model based的融合。比如用Model free方法学一个策略同时用学到的环境模型来做规划或者生成虚拟经验两者互相促进。还有离线强化学习试图从固定数据集里学策略不跟环境交互这对那些交互成本高或者危险的场景特别有价值。但不管技术怎么演进Model free这套东西都是基础。价值函数、策略梯度、Actor-Critic这些概念以及它们背后的偏差-方差权衡、探索与利用的平衡是理解一切强化学习方法的钥匙。我自己的体会是把Model free的几大经典方法亲手实现一遍比看十篇综述都管用。实现的过程中你会被迫面对每一个细节而这些细节恰恰是论文里一笔带过、但实际决定成败的东西。如果让我给刚入门的人一个建议那就是从Q-Learning表格法开始跑通一个简单环境然后上DQN理解经验回放和目标网络接着写REINFORCE感受策略梯度的方差问题最后用PPO收尾体会现代算法的稳定性。这条路走下来你对强化学习的理解会扎实得多。至于那些更 fancy 的方法等你把基础打牢了看起来都会觉得顺理成章。